On 12/20/19 11:36 PM, James Smart wrote: > This patch continues the libefc_sli SLI-4 library population. > > This patch adds service routines to create mailbox commands > and adds APIs to create/destroy/parse SLI-4 EQ, CQ, RQ and MQ queues. > > Signed-off-by: Ram Vegesna <ram.vegesna@xxxxxxxxxxxx> > Signed-off-by: James Smart <jsmart2021@xxxxxxxxx> > --- > drivers/scsi/elx/include/efc_common.h | 27 + > drivers/scsi/elx/libefc_sli/sli4.c | 1556 +++++++++++++++++++++++++++++++++ > drivers/scsi/elx/libefc_sli/sli4.h | 9 + > 3 files changed, 1592 insertions(+) > > diff --git a/drivers/scsi/elx/include/efc_common.h b/drivers/scsi/elx/include/efc_common.h > index 3fc48876c531..c339b22c35b5 100644 > --- a/drivers/scsi/elx/include/efc_common.h > +++ b/drivers/scsi/elx/include/efc_common.h > @@ -22,4 +22,31 @@ struct efc_dma { > struct pci_dev *pdev; > }; > > +#define efc_log_crit(efc, fmt, args...) \ > + dev_crit(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_log_err(efc, fmt, args...) \ > + dev_err(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_log_warn(efc, fmt, args...) \ > + dev_warn(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_log_info(efc, fmt, args...) \ > + dev_info(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_log_test(efc, fmt, args...) \ > + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_log_debug(efc, fmt, args...) \ > + dev_dbg(&((efc)->pcidev)->dev, fmt, ##args) > + > +#define efc_assert(cond, ...) \ > + do { \ > + if (!(cond)) { \ > + pr_err("%s(%d) assertion (%s) failed\n", \ > + __FILE__, __LINE__, #cond); \ > + dump_stack(); \ > + } \ > + } while (0) > + > #endif /* __EFC_COMMON_H__ */ > diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c > index 29d33becd334..7061f7980fad 100644 > --- a/drivers/scsi/elx/libefc_sli/sli4.c > +++ b/drivers/scsi/elx/libefc_sli/sli4.c > @@ -24,3 +24,1559 @@ static struct sli4_asic_entry_t sli4_asic_table[] = { > { SLI4_ASIC_REV_A3, SLI4_ASIC_GEN_6}, > { SLI4_ASIC_REV_A1, SLI4_ASIC_GEN_7}, > }; > + > +/* Convert queue type enum (SLI_QTYPE_*) into a string */ > +static char *SLI_QNAME[] = { > + "Event Queue", > + "Completion Queue", > + "Mailbox Queue", > + "Work Queue", > + "Receive Queue", > + "Undefined" > +}; > + > +/* > + * Write a SLI_CONFIG command to the provided buffer. > + * > + * @sli4 SLI context pointer. > + * @buf Destination buffer for the command. > + * @size size of the destination buffer(buf). > + * @length Length in bytes of attached command. > + * @dma DMA buffer for non-embedded commands. > + * > + */ > +static void * > +sli_config_cmd_init(struct sli4 *sli4, void *buf, > + size_t size, u32 length, > + struct efc_dma *dma) > +{ > + struct sli4_cmd_sli_config *config = NULL; > + u32 flags = 0; > + > + if (length > sizeof(config->payload.embed) && !dma) { > + efc_log_err(sli4, "Too big for an embedded cmd with len(%d)\n", > + length); > + return NULL; > + } > + > + config = buf; > + > + memset(buf, 0, size); > + > + config->hdr.command = MBX_CMD_SLI_CONFIG; > + if (!dma) { > + flags |= SLI4_SLICONF_EMB; > + config->dw1_flags = cpu_to_le32(flags); > + config->payload_len = cpu_to_le32(length); > + buf += offsetof(struct sli4_cmd_sli_config, payload.embed); > + return buf; > + } > + > + flags = SLI4_SLICONF_PMDCMD_VAL_1; > + flags &= ~SLI4_SLICONF_EMB; > + config->dw1_flags = cpu_to_le32(flags); > + > + config->payload.mem.addr.low = cpu_to_le32(lower_32_bits(dma->phys)); > + config->payload.mem.addr.high = cpu_to_le32(upper_32_bits(dma->phys)); > + config->payload.mem.length = > + cpu_to_le32(dma->size & SLI4_SLICONFIG_PMD_LEN); > + config->payload_len = cpu_to_le32(dma->size); > + /* save pointer to DMA for BMBX dumping purposes */ > + sli4->bmbx_non_emb_pmd = dma; > + return dma->virt; > +} > + > +/* > + * Write a COMMON_CREATE_CQ command. > + * > + * This creates a Version 2 message. > + * > + * Returns 0 on success, or non-zero otherwise. > + */ > +static int > +sli_cmd_common_create_cq(struct sli4 *sli4, void *buf, size_t size, > + struct efc_dma *qmem, > + u16 eq_id) > +{ > + struct sli4_rqst_cmn_create_cq_v2 *cqv2 = NULL; > + u32 p; > + uintptr_t addr; > + u32 page_bytes = 0; > + u32 num_pages = 0; > + size_t cmd_size = 0; > + u32 page_size = 0; > + u32 n_cqe = 0; > + u32 dw5_flags = 0; > + u16 dw6w1_arm = 0; > + __le32 len; > + > + /* First calculate number of pages and the mailbox cmd length */ > + n_cqe = qmem->size / SLI4_CQE_BYTES; > + switch (n_cqe) { > + case 256: > + case 512: > + case 1024: > + case 2048: > + page_size = 1; > + break; > + case 4096: > + page_size = 2; > + break; > + default: > + return EFC_FAIL; > + } > + page_bytes = page_size * SLI_PAGE_SIZE; > + num_pages = sli_page_count(qmem->size, page_bytes); > + > + cmd_size = CFG_RQST_CMDSZ(cmn_create_cq_v2) + SZ_DMAADDR * num_pages; > + > + cqv2 = sli_config_cmd_init(sli4, buf, size, cmd_size, NULL); > + if (!cqv2) > + return EFC_FAIL; > + > + len = CFG_RQST_PYLD_LEN_VAR(cmn_create_cq_v2, > + SZ_DMAADDR * num_pages); > + sli_cmd_fill_hdr(&cqv2->hdr, CMN_CREATE_CQ, SLI4_SUBSYSTEM_COMMON, > + CMD_V2, len); > + cqv2->page_size = page_size; > + > + /* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.3) */ > + cqv2->num_pages = cpu_to_le16(num_pages); > + if (!num_pages || num_pages > SLI4_CMN_CREATE_CQ_V2_MAX_PAGES) > + return EFC_FAIL; > + > + switch (num_pages) { > + case 1: > + dw5_flags |= CQ_CNT_VAL(256); > + break; > + case 2: > + dw5_flags |= CQ_CNT_VAL(512); > + break; > + case 4: > + dw5_flags |= CQ_CNT_VAL(1024); > + break; > + case 8: > + dw5_flags |= CQ_CNT_VAL(LARGE); > + cqv2->cqe_count = cpu_to_le16(n_cqe); > + break; > + default: > + efc_log_info(sli4, "num_pages %d not valid\n", num_pages); > + return -EFC_FAIL; > + } > + Hmm. Why do you return -EFC_FAIL here, and EFC_FAIL in the two cases above? Do you differentiate between EFC_FAIL and -EFC_FAIL? If so you should probably use different #defines ... > + if (sli4->if_type == SLI4_INTF_IF_TYPE_6) > + dw5_flags |= CREATE_CQV2_AUTOVALID; > + > + dw5_flags |= CREATE_CQV2_EVT; > + dw5_flags |= CREATE_CQV2_VALID; > + > + cqv2->dw5_flags = cpu_to_le32(dw5_flags); > + cqv2->dw6w1_arm = cpu_to_le16(dw6w1_arm); > + cqv2->eq_id = cpu_to_le16(eq_id); > + > + for (p = 0, addr = qmem->phys; p < num_pages; p++, addr += page_bytes) { > + cqv2->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr)); > + cqv2->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr)); > + } > + > + return EFC_SUCCESS; > +} > + > +/* Write a COMMON_CREATE_EQ command */ > +static int > +sli_cmd_common_create_eq(struct sli4 *sli4, void *buf, size_t size, > + struct efc_dma *qmem) > +{ > + struct sli4_rqst_cmn_create_eq *eq; > + u32 p; > + uintptr_t addr; > + u16 num_pages; > + u32 dw5_flags = 0; > + u32 dw6_flags = 0, ver; > + > + eq = sli_config_cmd_init(sli4, buf, size, > + SLI_CONFIG_PYLD_LENGTH(cmn_create_eq), NULL); > + if (!eq) > + return EFC_FAIL; > + > + if (sli4->if_type == SLI4_INTF_IF_TYPE_6) > + ver = CMD_V2; > + > + sli_cmd_fill_hdr(&eq->hdr, CMN_CREATE_EQ, SLI4_SUBSYSTEM_COMMON, > + ver, CFG_RQST_PYLD_LEN(cmn_create_eq)); > + > + /* valid values for number of pages: 1, 2, 4 (sec 4.4.3) */ > + num_pages = qmem->size / SLI_PAGE_SIZE; > + eq->num_pages = cpu_to_le16(num_pages); > + > + switch (num_pages) { > + case 1: > + dw5_flags |= SLI4_EQE_SIZE_4; > + dw6_flags |= EQ_CNT_VAL(1024); > + break; > + case 2: > + dw5_flags |= SLI4_EQE_SIZE_4; > + dw6_flags |= EQ_CNT_VAL(2048); > + break; > + case 4: > + dw5_flags |= SLI4_EQE_SIZE_4; > + dw6_flags |= EQ_CNT_VAL(4096); > + break; > + default: > + efc_log_err(sli4, "num_pages %d not valid\n", num_pages); > + return EFC_FAIL; > + } > + > + if (sli4->if_type == SLI4_INTF_IF_TYPE_6) > + dw5_flags |= CREATE_EQ_AUTOVALID; > + > + dw5_flags |= CREATE_EQ_VALID; > + dw6_flags &= (~CREATE_EQ_ARM); > + eq->dw5_flags = cpu_to_le32(dw5_flags); > + eq->dw6_flags = cpu_to_le32(dw6_flags); > + eq->dw7_delaymulti = cpu_to_le32(CREATE_EQ_DELAYMULTI); > + > + for (p = 0, addr = qmem->phys; p < num_pages; > + p++, addr += SLI_PAGE_SIZE) { > + eq->page_address[p].low = cpu_to_le32(lower_32_bits(addr)); > + eq->page_address[p].high = cpu_to_le32(upper_32_bits(addr)); > + } > + > + return EFC_SUCCESS; > +} > + > +static int > +sli_cmd_common_create_mq_ext(struct sli4 *sli4, void *buf, size_t size, > + struct efc_dma *qmem, > + u16 cq_id) > +{ > + struct sli4_rqst_cmn_create_mq_ext *mq; > + u32 p; > + uintptr_t addr; > + u32 num_pages; > + u16 dw6w1_flags = 0; > + > + mq = sli_config_cmd_init(sli4, buf, size, > + SLI_CONFIG_PYLD_LENGTH(cmn_create_mq_ext), > + NULL); > + if (!mq) > + return EFC_FAIL; > + > + sli_cmd_fill_hdr(&mq->hdr, CMN_CREATE_MQ_EXT, SLI4_SUBSYSTEM_COMMON, > + CMD_V0, CFG_RQST_PYLD_LEN(cmn_create_mq_ext)); > + > + /* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.12) */ > + num_pages = qmem->size / SLI_PAGE_SIZE; > + mq->num_pages = cpu_to_le16(num_pages); > + switch (num_pages) { > + case 1: > + dw6w1_flags |= SLI4_MQE_SIZE_16; > + break; > + case 2: > + dw6w1_flags |= SLI4_MQE_SIZE_32; > + break; > + case 4: > + dw6w1_flags |= SLI4_MQE_SIZE_64; > + break; > + case 8: > + dw6w1_flags |= SLI4_MQE_SIZE_128; > + break; > + default: > + efc_log_info(sli4, "num_pages %d not valid\n", num_pages); > + return EFC_FAIL; > + } > + > + mq->async_event_bitmap = cpu_to_le32(SLI4_ASYNC_EVT_FC_ALL); > + > + if (sli4->mq_create_version) { > + mq->cq_id_v1 = cpu_to_le16(cq_id); > + mq->hdr.dw3_version = cpu_to_le32(CMD_V1); > + } else { > + dw6w1_flags |= (cq_id << CREATE_MQEXT_CQID_SHIFT); > + } > + mq->dw7_val = cpu_to_le32(CREATE_MQEXT_VAL); > + > + mq->dw6w1_flags = cpu_to_le16(dw6w1_flags); > + for (p = 0, addr = qmem->phys; p < num_pages; > + p++, addr += SLI_PAGE_SIZE) { > + mq->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr)); > + mq->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr)); > + } > + > + return EFC_SUCCESS; > +} > + > +int > +sli_cmd_wq_create(struct sli4 *sli4, void *buf, size_t size, > + struct efc_dma *qmem, u16 cq_id) > +{ > + struct sli4_rqst_wq_create *wq; > + u32 p; > + uintptr_t addr; > + u32 page_size = 0; > + u32 page_bytes = 0; > + u32 n_wqe = 0; > + u16 num_pages; > + > + wq = sli_config_cmd_init(sli4, buf, size, > + SLI_CONFIG_PYLD_LENGTH(wq_create), NULL); > + if (!wq) > + return EFC_FAIL; > + > + sli_cmd_fill_hdr(&wq->hdr, SLI4_OPC_WQ_CREATE, SLI4_SUBSYSTEM_FC, > + CMD_V1, CFG_RQST_PYLD_LEN(wq_create)); > + n_wqe = qmem->size / sli4->wqe_size; > + > + switch (qmem->size) { > + case 4096: > + case 8192: > + case 16384: > + case 32768: > + page_size = 1; > + break; > + case 65536: > + page_size = 2; > + break; > + case 131072: > + page_size = 4; > + break; > + case 262144: > + page_size = 8; > + break; > + case 524288: > + page_size = 10; > + break; > + default: > + return EFC_FAIL; > + } > + page_bytes = page_size * SLI_PAGE_SIZE; > + > + /* valid values for number of pages(num_pages): 1-8 */ > + num_pages = sli_page_count(qmem->size, page_bytes); > + wq->num_pages = cpu_to_le16(num_pages); > + if (!num_pages || num_pages > SLI4_WQ_CREATE_MAX_PAGES) > + return EFC_FAIL; > + > + wq->cq_id = cpu_to_le16(cq_id); > + > + wq->page_size = page_size; > + > + if (sli4->wqe_size == SLI4_WQE_EXT_BYTES) > + wq->wqe_size_byte |= SLI4_WQE_EXT_SIZE; > + else > + wq->wqe_size_byte |= SLI4_WQE_SIZE; > + > + wq->wqe_count = cpu_to_le16(n_wqe); > + > + for (p = 0, addr = qmem->phys; p < num_pages; p++, addr += page_bytes) { > + wq->page_phys_addr[p].low = cpu_to_le32(lower_32_bits(addr)); > + wq->page_phys_addr[p].high = cpu_to_le32(upper_32_bits(addr)); > + } > + > + return EFC_SUCCESS; > +} > + > +int > +sli_cmd_rq_create(struct sli4 *sli4, void *buf, size_t size, > + struct efc_dma *qmem, > + u16 cq_id, u16 buffer_size) > +{ > + struct sli4_rqst_rq_create *rq; > + u32 p; > + uintptr_t addr; > + u16 num_pages; > + > + rq = sli_config_cmd_init(sli4, buf, size, > + SLI_CONFIG_PYLD_LENGTH(rq_create), NULL); > + if (!rq) > + return EFC_FAIL; > + > + sli_cmd_fill_hdr(&rq->hdr, SLI4_OPC_RQ_CREATE, SLI4_SUBSYSTEM_FC, > + CMD_V0, CFG_RQST_PYLD_LEN(rq_create)); > + /* valid values for number of pages: 1-8 (sec 4.5.6) */ > + num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE); > + rq->num_pages = cpu_to_le16(num_pages); > + if (!num_pages || > + num_pages > SLI4_RQ_CREATE_V0_MAX_PAGES) { > + efc_log_info(sli4, "num_pages %d not valid\n", num_pages); > + return 0; > + } > + '0'? Why not EFC_FAIL/EFC_SUCCESS? > + /* > + * RQE count is the log base 2 of the total number of entries > + */ > + rq->rqe_count_byte |= 31 - __builtin_clz(qmem->size / SLI4_RQE_SIZE); > + > + if (buffer_size < SLI4_RQ_CREATE_V0_MIN_BUF_SIZE || > + buffer_size > SLI4_RQ_CREATE_V0_MAX_BUF_SIZE) { > + efc_log_err(sli4, "buffer_size %d out of range (%d-%d)\n", > + buffer_size, > + SLI4_RQ_CREATE_V0_MIN_BUF_SIZE, > + SLI4_RQ_CREATE_V0_MAX_BUF_SIZE); > + return -1; > + } '-1'? Not EFC_FAIL? [ .. ] > +int > +__sli_queue_init(struct sli4 *sli4, struct sli4_queue *q, > + u32 qtype, size_t size, u32 n_entries, > + u32 align) > +{ > + if (!q->dma.virt || size != q->size || > + n_entries != q->length) { > + if (q->dma.size) > + __sli_queue_destroy(sli4, q); > + > + memset(q, 0, sizeof(struct sli4_queue)); > + > + q->dma.size = size * n_entries; > + q->dma.virt = dma_alloc_coherent(&sli4->pcidev->dev, > + q->dma.size, &q->dma.phys, > + GFP_DMA);> + if (!q->dma.virt) { > + memset(&q->dma, 0, sizeof(struct efc_dma)); > + efc_log_err(sli4, "%s allocation failed\n", > + SLI_QNAME[qtype]); > + return -1; > + } EFC_FAIL? Cheers, Hannes -- Dr. Hannes Reinecke Teamlead Storage & Networking hare@xxxxxxx +49 911 74053 688 SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), GF: Felix Imendörffer