From: James Smart <jsmart2021@gmail.com>
To: linux-scsi@vger.kernel.org
Cc: James Smart <jsmart2021@gmail.com>,
Ram Vegesna <ram.vegesna@broadcom.com>
Subject: [PATCH 04/32] elx: libefc_sli: queue create/destroy/parse routines
Date: Wed, 23 Oct 2019 14:55:29 -0700 [thread overview]
Message-ID: <20191023215557.12581-5-jsmart2021@gmail.com> (raw)
In-Reply-To: <20191023215557.12581-1-jsmart2021@gmail.com>
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@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
---
drivers/scsi/elx/include/efc_common.h | 18 +
drivers/scsi/elx/libefc_sli/sli4.c | 2155 +++++++++++++++++++++++++++++++++
2 files changed, 2173 insertions(+)
diff --git a/drivers/scsi/elx/include/efc_common.h b/drivers/scsi/elx/include/efc_common.h
index dbabc4f6ee5e..62d0f3b3f936 100644
--- a/drivers/scsi/elx/include/efc_common.h
+++ b/drivers/scsi/elx/include/efc_common.h
@@ -23,4 +23,22 @@ struct efc_dma_s {
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)
+
#endif /* __EFC_COMMON_H__ */
diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c
index 68ccd3ad8ac8..6b62b7d8b5a4 100644
--- a/drivers/scsi/elx/libefc_sli/sli4.c
+++ b/drivers/scsi/elx/libefc_sli/sli4.c
@@ -24,3 +24,2158 @@ 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},
};
+
+/*
+ * @brief Convert queue type enum (SLI_QTYPE_*) into a string.
+ */
+static char *SLI_QNAME[] = {
+ "Event Queue",
+ "Completion Queue",
+ "Mailbox Queue",
+ "Work Queue",
+ "Receive Queue",
+ "Undefined"
+};
+
+/**
+ * @ingroup sli
+ * @brief Write a SLI_CONFIG command to the provided buffer.
+ *
+ * @param sli4 SLI context pointer.
+ * @param buf Virtual pointer to the destination buffer.
+ * @param size Buffer size, in bytes.
+ * @param length Length in bytes of attached command.
+ * @param dma DMA buffer for non-embedded commands.
+ *
+ * @return Returns the number of bytes written.
+ */
+static void *
+sli_config_cmd_init(struct sli4_s *sli4, void *buf,
+ size_t size, u32 length,
+ struct efc_dma_s *dma)
+{
+ struct sli4_cmd_sli_config_s *sli_config = NULL;
+ u32 flags = 0;
+
+ if (length > sizeof(sli_config->payload.embed) && !dma) {
+ efc_log_info(sli4, "length(%d) > payload(%ld)\n",
+ length, sizeof(sli_config->payload.embed));
+ return NULL;
+ }
+
+ sli_config = buf;
+
+ memset(buf, 0, size);
+
+ sli_config->hdr.command = MBX_CMD_SLI_CONFIG;
+ if (!dma) {
+ flags |= SLI4_SLICONF_EMB;
+ sli_config->dw1_flags = cpu_to_le32(flags);
+ sli_config->payload_len = cpu_to_le32(length);
+ } else {
+ flags = SLI4_SLICONF_PMDCMD_VAL_1; /* pmd_count = 1 */
+ flags &= ~SLI4_SLICONF_EMB;
+ sli_config->dw1_flags = cpu_to_le32(flags);
+
+ sli_config->payload.mem.addr.low =
+ cpu_to_le32(lower_32_bits(dma->phys));
+ sli_config->payload.mem.addr.high =
+ cpu_to_le32(upper_32_bits(dma->phys));
+ sli_config->payload.mem.length =
+ cpu_to_le32(dma->size & SLI4_SLICONFIG_PMD_LEN);
+ sli_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;
+ }
+
+ return buf + offsetof(struct sli4_cmd_sli_config_s, payload.embed);
+}
+
+/**
+ * @brief Write a COMMON_CREATE_CQ command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param eq_id Associated EQ_ID
+ * @param ignored This parameter carries the ULP
+ * which is only used for WQ and RQs
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+static int
+sli_cmd_common_create_cq(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem,
+ u16 eq_id)
+{
+ struct sli4_rqst_cmn_create_cq_v2_s *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;
+
+ /* 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;
+
+ cqv2->hdr.opcode = CMN_CREATE_CQ;
+ cqv2->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ cqv2->hdr.dw3_version = cpu_to_le32(CMD_V2);
+ cmd_size = CFG_RQST_PYLD_LEN_VAR(cmn_create_cq_v2,
+ SZ_DMAADDR * num_pages);
+ cqv2->hdr.request_length = cmd_size;
+ 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_COMMON_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 -1;
+ }
+
+ 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;
+}
+
+/**
+ * @brief Write a COMMON_DESTROY_CQ command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param cq_id CQ ID
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+static int
+sli_cmd_common_destroy_cq(struct sli4_s *sli4, void *buf,
+ size_t size, u16 cq_id)
+{
+ struct sli4_rqst_cmn_destroy_cq_s *cq = NULL;
+
+ /* Payload length must accommodate both request and response */
+ cq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(cmn_destroy_cq), NULL);
+ if (!cq)
+ return EFC_FAIL;
+
+ cq->hdr.opcode = CMN_DESTROY_CQ;
+ cq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ cq->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_destroy_cq);
+ cq->cq_id = cpu_to_le16(cq_id);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @brief Write a COMMON_CREATE_EQ command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param ignored1 Ignored
+ * (used for consistency among queue creation functions).
+ * @param ignored2 Ignored
+ * (used for consistency among queue creation functions).
+ *
+ * @note Other queue creation routines use the last parameter to pass in
+ * the associated Q_ID and ULP. EQ doesn't have an associated queue or ULP,
+ * so these parameters are ignored
+ *
+ * @note This creates a Version 0 message
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+static int
+sli_cmd_common_create_eq(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem,
+ u16 ignored1)
+{
+ struct sli4_rqst_cmn_create_eq_s *eq = NULL;
+ u32 p;
+ uintptr_t addr;
+ u16 num_pages;
+ u32 dw5_flags = 0;
+ u32 dw6_flags = 0;
+
+ eq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(cmn_create_eq), NULL);
+
+ eq->hdr.opcode = CMN_CREATE_EQ;
+ eq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ eq->hdr.dw3_version = cpu_to_le32(CMD_V2);
+
+ eq->hdr.request_length = 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_info(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;
+}
+
+/**
+ * @brief Write a COMMON_DESTROY_EQ command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param eq_id Queue ID to destroy.
+ *
+ * @note Other queue creation routines use the last parameter to pass in
+ * the associated Q_ID. EQ doesn't have an associated queue so this
+ * parameter is ignored.
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+static int
+sli_cmd_common_destroy_eq(struct sli4_s *sli4, void *buf, size_t size,
+ u16 eq_id)
+{
+ struct sli4_rqst_cmn_destroy_eq_s *eq = NULL;
+
+ eq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(cmn_destroy_eq), NULL);
+ if (!eq)
+ return EFC_FAIL;
+
+ eq->hdr.opcode = CMN_DESTROY_EQ;
+ eq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ eq->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_destroy_eq);
+
+ eq->eq_id = cpu_to_le16(eq_id);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @brief Write a COMMON_CREATE_MQ_EXT command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ * @param ignored This parameter carries the ULP
+ * which is only used for WQ and RQs
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+static int
+sli_cmd_common_create_mq_ext(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem,
+ u16 cq_id)
+{
+ struct sli4_rqst_cmn_create_mq_ext_s *mq = NULL;
+ 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;
+
+ mq->hdr.opcode = CMN_CREATE_MQ_EXT;
+ mq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ mq->hdr.request_length = 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;
+}
+
+/**
+ * @brief Write a COMMON_DESTROY_MQ command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param mq_id MQ ID
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+static int
+sli_cmd_common_destroy_mq(struct sli4_s *sli4, void *buf, size_t size,
+ u16 mq_id)
+{
+ struct sli4_rqst_cmn_destroy_mq_s *mq = NULL;
+
+ mq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(cmn_destroy_mq), NULL);
+ if (!mq)
+ return EFC_FAIL;
+
+ mq->hdr.opcode = CMN_DESTROY_MQ;
+ mq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
+ mq->hdr.request_length = CFG_RQST_PYLD_LEN(cmn_destroy_mq);
+
+ mq->mq_id = cpu_to_le16(mq_id);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an WQ_CREATE command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_wq_create(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem, u16 cq_id)
+{
+ struct sli4_rqst_wq_create_s *wq = NULL;
+ u32 p;
+ uintptr_t addr;
+
+ wq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(wq_create), NULL);
+ if (!wq)
+ return EFC_FAIL;
+
+ wq->hdr.opcode = SLI4_OPC_WQ_CREATE;
+ wq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ wq->hdr.request_length = CFG_RQST_PYLD_LEN(wq_create);
+
+ /* valid values for number of pages: 1-4 (sec 4.5.1) */
+ wq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
+ if (!wq->num_pages ||
+ wq->num_pages > SLI4_WQ_CREATE_V0_MAX_PAGES)
+ return EFC_FAIL;
+
+ wq->cq_id = cpu_to_le16(cq_id);
+
+ for (p = 0, addr = qmem->phys;
+ p < wq->num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ 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;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an WQ_CREATE_V1 command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_wq_create_v1(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem,
+ u16 cq_id)
+{
+ struct sli4_rqst_wq_create_v1_s *wq = NULL;
+ 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_v1), NULL);
+ if (!wq)
+ return EFC_FAIL;
+
+ wq->hdr.opcode = SLI4_OPC_WQ_CREATE;
+ wq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ wq->hdr.request_length = CFG_RQST_PYLD_LEN(wq_create_v1);
+ wq->hdr.dw3_version = cpu_to_le32(CMD_V1);
+
+ n_wqe = qmem->size / sli4->wqe_size;
+
+ /*
+ * This heuristic to determine the page size is simplistic but could
+ * be made more sophisticated
+ */
+ 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 0;
+ }
+ page_bytes = page_size * SLI_PAGE_SIZE;
+
+ /* valid values for number of 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_V1_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;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an WQ_DESTROY command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param wq_id WQ_ID.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_wq_destroy(struct sli4_s *sli4, void *buf, size_t size,
+ u16 wq_id)
+{
+ struct sli4_rqst_wq_destroy_s *wq = NULL;
+
+ wq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(wq_destroy), NULL);
+ if (!wq)
+ return EFC_FAIL;
+
+ wq->hdr.opcode = SLI4_OPC_WQ_DESTROY;
+ wq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ wq->hdr.request_length = CFG_RQST_PYLD_LEN(wq_destroy);
+
+ wq->wq_id = cpu_to_le16(wq_id);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an RQ_CREATE command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ * @param buffer_size Buffer size pointed to by each RQE.
+ *
+ * @note This creates a Version 0 message.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_rq_create(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem,
+ u16 cq_id, u16 buffer_size)
+{
+ struct sli4_rqst_rq_create_s *rq = NULL;
+ 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;
+
+ rq->hdr.opcode = SLI4_OPC_RQ_CREATE;
+ rq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ rq->hdr.request_length = 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;
+ }
+
+ /*
+ * 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;
+ }
+ rq->buffer_size = cpu_to_le16(buffer_size);
+
+ rq->cq_id = cpu_to_le16(cq_id);
+
+ for (p = 0, addr = qmem->phys;
+ p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ rq->page_phys_addr[p].low =
+ cpu_to_le32(lower_32_bits(addr));
+ rq->page_phys_addr[p].high =
+ cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an RQ_CREATE_V1 command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ * @param buffer_size Buffer size pointed to by each RQE.
+ *
+ * @note This creates a Version 0 message
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_rq_create_v1(struct sli4_s *sli4, void *buf, size_t size,
+ struct efc_dma_s *qmem, u16 cq_id,
+ u16 buffer_size)
+{
+ struct sli4_rqst_rq_create_v1_s *rq = NULL;
+ u32 p;
+ uintptr_t addr;
+ u32 num_pages;
+
+ rq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(rq_create_v1), NULL);
+ if (!rq)
+ return EFC_FAIL;
+
+ rq->hdr.opcode = SLI4_OPC_RQ_CREATE;
+ rq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ rq->hdr.request_length = CFG_RQST_PYLD_LEN(rq_create_v1);
+ rq->hdr.dw3_version = cpu_to_le32(CMD_V1);
+
+ /* Disable "no buffer warnings" to avoid Lancer bug */
+ rq->dim_dfd_dnb |= SLI4_RQ_CREATE_V1_DNB;
+
+ /* 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_V1_MAX_PAGES) {
+ efc_log_info(sli4, "num_pages %d not valid, max %d\n",
+ num_pages, SLI4_RQ_CREATE_V1_MAX_PAGES);
+ return EFC_FAIL;
+ }
+
+ /*
+ * RQE count is the total number of entries (note not lg2(# entries))
+ */
+ rq->rqe_count = cpu_to_le16(qmem->size / SLI4_RQE_SIZE);
+
+ rq->rqe_size_byte |= SLI4_RQE_SIZE_8;
+
+ rq->page_size = SLI4_RQ_PAGE_SIZE_4096;
+
+ if (buffer_size < sli4->rq_min_buf_size ||
+ buffer_size > sli4->rq_max_buf_size) {
+ efc_log_err(sli4, "buffer_size %d out of range (%d-%d)\n",
+ buffer_size,
+ sli4->rq_min_buf_size,
+ sli4->rq_max_buf_size);
+ return EFC_FAIL;
+ }
+ rq->buffer_size = cpu_to_le32(buffer_size);
+
+ rq->cq_id = cpu_to_le16(cq_id);
+
+ for (p = 0, addr = qmem->phys;
+ p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ rq->page_phys_addr[p].low =
+ cpu_to_le32(lower_32_bits(addr));
+ rq->page_phys_addr[p].high =
+ cpu_to_le32(upper_32_bits(addr));
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an RQ_CREATE_V2 command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param qmem DMA memory for the queue.
+ * @param cq_id Associated CQ_ID.
+ * @param buffer_size Buffer size pointed to by each RQE.
+ *
+ * @note This creates a Version 0 message
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+static int
+sli_cmd_rq_create_v2(struct sli4_s *sli4, u32 num_rqs,
+ struct sli4_queue_s *qs[], u32 base_cq_id,
+ u32 header_buffer_size,
+ u32 payload_buffer_size, struct efc_dma_s *dma)
+{
+ struct sli4_rqst_rq_create_v2_s *req = NULL;
+ u32 i, p, offset;
+ u32 payload_size, page_count;
+ uintptr_t addr;
+ u32 num_pages;
+
+ page_count = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE) * num_rqs;
+
+ /* Payload length must accommodate both request and response */
+ payload_size = max(CFG_RQST_CMDSZ(rq_create_v2) +
+ SZ_DMAADDR * page_count,
+ sizeof(struct sli4_rsp_cmn_create_queue_set_s));
+
+ dma->size = payload_size;
+ dma->virt = dma_alloc_coherent(&sli4->pcidev->dev, dma->size,
+ &dma->phys, GFP_DMA);
+ if (!dma->virt)
+ return EFC_FAIL;
+
+ memset(dma->virt, 0, payload_size);
+
+ req = sli_config_cmd_init(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
+ payload_size, dma);
+ if (!req)
+ return EFC_FAIL;
+
+ /* Fill Header fields */
+ req->hdr.opcode = SLI4_OPC_RQ_CREATE;
+ req->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ req->hdr.dw3_version = cpu_to_le32(CMD_V2);
+ req->hdr.request_length = CFG_RQST_PYLD_LEN_VAR(rq_create_v2,
+ SZ_DMAADDR * page_count);
+
+ /* Fill Payload fields */
+ req->dim_dfd_dnb |= SLI4_RQCREATEV2_DNB;
+ num_pages = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE);
+ req->num_pages = cpu_to_le16(num_pages);
+ req->rqe_count = cpu_to_le16(qs[0]->dma.size / SLI4_RQE_SIZE);
+ req->rqe_size_byte |= SLI4_RQE_SIZE_8;
+ req->page_size = SLI4_RQ_PAGE_SIZE_4096;
+ req->rq_count = num_rqs;
+ req->base_cq_id = cpu_to_le16(base_cq_id);
+ req->hdr_buffer_size = cpu_to_le16(header_buffer_size);
+ req->payload_buffer_size = cpu_to_le16(payload_buffer_size);
+
+ for (i = 0; i < num_rqs; i++) {
+ for (p = 0, addr = qs[i]->dma.phys; p < num_pages;
+ p++, addr += SLI_PAGE_SIZE) {
+ req->page_phys_addr[offset].low =
+ cpu_to_le32(lower_32_bits(addr));
+ req->page_phys_addr[offset].high =
+ cpu_to_le32(upper_32_bits(addr));
+ offset++;
+ }
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Write an RQ_DESTROY command.
+ *
+ * @param sli4 SLI context.
+ * @param buf Destination buffer for the command.
+ * @param size Buffer size, in bytes.
+ * @param rq_id RQ_ID.
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_cmd_rq_destroy(struct sli4_s *sli4, void *buf, size_t size,
+ u16 rq_id)
+{
+ struct sli4_rqst_rq_destroy_s *rq = NULL;
+
+ rq = sli_config_cmd_init(sli4, buf, size,
+ SLI_CONFIG_PYLD_LENGTH(rq_destroy), NULL);
+ if (!rq)
+ return EFC_FAIL;
+
+ rq->hdr.opcode = SLI4_OPC_RQ_DESTROY;
+ rq->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ rq->hdr.request_length = CFG_RQST_PYLD_LEN(rq_destroy);
+ rq->rq_id = cpu_to_le16(rq_id);
+
+ return EFC_SUCCESS;
+}
+/**
+ * @ingroup sli
+ * @brief Destroy a queue object.
+ *
+ * @par Description
+ * This destroys the sli4_queue_s object members, including the underlying
+ * DMA memory.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to queue object.
+ *
+ */
+static void
+__sli_queue_destroy(struct sli4_s *sli4, struct sli4_queue_s *q)
+{
+ if (!q->dma.size)
+ return;
+
+ dma_free_coherent(&sli4->pcidev->dev, q->dma.size,
+ q->dma.virt, q->dma.phys);
+
+}
+/**
+ * @ingroup sli
+ * @brief Initialize a queue object.
+ *
+ * @par Description
+ * This initializes the sli4_queue_s object members, including the underlying
+ * DMA memory.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to queue object.
+ * @param qtype Type of queue to create.
+ * @param size Size of each entry.
+ * @param n_entries Number of entries to allocate.
+ * @param align Starting memory address alignment.
+ *
+ * @note Checks if using the existing DMA memory (if any) is possible. If not,
+ * it frees the existing memory and re-allocates.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+__sli_queue_init(struct sli4_s *sli4, struct sli4_queue_s *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_s));
+
+ 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_s));
+ efc_log_err(sli4, "%s allocation failed\n",
+ SLI_QNAME[qtype]);
+ return -1;
+ }
+
+ memset(q->dma.virt, 0, size * n_entries);
+
+ spin_lock_init(&q->lock);
+
+ q->type = qtype;
+ q->size = size;
+ q->length = n_entries;
+
+ if (q->type == SLI_QTYPE_EQ || q->type == SLI_QTYPE_CQ) {
+ /* For prism, phase will be flipped after
+ * a sweep through eq and cq
+ */
+ q->phase = 1;
+ }
+
+ /* Limit to hwf the queue size per interrupt */
+ q->proc_limit = n_entries / 2;
+
+ switch (q->type) {
+ case SLI_QTYPE_EQ:
+ q->posted_limit = q->length / 2;
+ break;
+ default:
+ q->posted_limit = 64;
+ break;
+ }
+ } else {
+ efc_log_err(sli4, "%s failed\n", __func__);
+ return EFC_FAIL;
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Allocate a receive queue.
+ *
+ * @par Description
+ * Allocates DMA memory and configures the requested queue type.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object for the header.
+ * @param n_entries Number of entries to allocate.
+ * @param buffer_size buffer size for the queue.
+ * @param cq Associated CQ.
+ * @param is_hdr Used to validate the rq_id and set the type of queue
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_fc_rq_alloc(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u32 n_entries, u32 buffer_size,
+ struct sli4_queue_s *cq, bool is_hdr)
+{
+ if (__sli_queue_init(sli4, q, SLI_QTYPE_RQ, SLI4_RQE_SIZE,
+ n_entries, SLI_PAGE_SIZE))
+ return EFC_FAIL;
+
+ if (!sli_cmd_rq_create_v1(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
+ &q->dma, cq->id, buffer_size)) {
+ if (__sli_create_queue(sli4, q)) {
+ efc_log_info(sli4, "Create queue failed %d\n", q->id);
+ goto error;
+ }
+ if (is_hdr && q->id & 1) {
+ efc_log_info(sli4, "bad header RQ_ID %d\n", q->id);
+ goto error;
+ } else if (!is_hdr && (q->id & 1) == 0) {
+ efc_log_info(sli4, "bad data RQ_ID %d\n", q->id);
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+ if (is_hdr)
+ q->u.flag.dword |= SLI4_QUEUE_FLAG_HDR;
+ else
+ q->u.flag.dword &= ~SLI4_QUEUE_FLAG_HDR;
+ return EFC_SUCCESS;
+error:
+ __sli_queue_destroy(sli4, q);
+ return EFC_FAIL;
+}
+
+/**
+ * @ingroup sli_fc
+ * @brief Allocate a receive queue set.
+ *
+ * @param sli4 SLI context.
+ * @param num_rq_pairs to create
+ * @param qs Pointers to the queue objects for both header and data.
+ * Length of this arrays should be 2 * num_rq_pairs
+ * @param base_cq_id. Assumes base_cq_id : (base_cq_id + num_rq_pairs) cqs as
+ * allotted.
+ * @param n_entries number of entries in each RQ queue.
+ * @param header_buffer_size
+ * @param payload_buffer_size
+ *
+ * @return Returns zero for success and non-zero for failure.
+ */
+int
+sli_fc_rq_set_alloc(struct sli4_s *sli4, u32 num_rq_pairs,
+ struct sli4_queue_s *qs[], u32 base_cq_id,
+ u32 n_entries, u32 header_buffer_size,
+ u32 payload_buffer_size)
+{
+ u32 i;
+ struct efc_dma_s dma = {0};
+ struct sli4_rsp_cmn_create_queue_set_s *rsp = NULL;
+ void __iomem *db_regaddr = NULL;
+ u32 num_rqs = num_rq_pairs * 2;
+
+ for (i = 0; i < num_rqs; i++) {
+ if (__sli_queue_init(sli4, qs[i], SLI_QTYPE_RQ,
+ SLI4_RQE_SIZE, n_entries,
+ SLI_PAGE_SIZE)) {
+ goto error;
+ }
+ }
+
+ if (sli_cmd_rq_create_v2(sli4, num_rqs, qs, base_cq_id,
+ header_buffer_size, payload_buffer_size, &dma)) {
+ goto error;
+ }
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_err(sli4, "bootstrap mailbox write failed RQSet\n");
+ goto error;
+ }
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ db_regaddr = sli4->reg[1] + SLI4_IF6_RQ_DB_REG;
+ else
+ db_regaddr = sli4->reg[0] + SLI4_RQ_DB_REG;
+
+ rsp = dma.virt;
+ if (rsp->hdr.status) {
+ efc_log_err(sli4, "bad create RQSet status=%#x addl=%#x\n",
+ rsp->hdr.status, rsp->hdr.additional_status);
+ goto error;
+ } else {
+ for (i = 0; i < num_rqs; i++) {
+ qs[i]->id = i + le16_to_cpu(rsp->q_id);
+ if ((qs[i]->id & 1) == 0)
+ qs[i]->u.flag.dword |= SLI4_QUEUE_FLAG_HDR;
+ else
+ qs[i]->u.flag.dword &= ~SLI4_QUEUE_FLAG_HDR;
+
+ qs[i]->db_regaddr = db_regaddr;
+ }
+ }
+
+ dma_free_coherent(&sli4->pcidev->dev, dma.size, dma.virt, dma.phys);
+
+ return EFC_SUCCESS;
+
+error:
+ for (i = 0; i < num_rqs; i++)
+ __sli_queue_destroy(sli4, qs[i]);
+
+ if (dma.virt)
+ dma_free_coherent(&sli4->pcidev->dev, dma.size, dma.virt,
+ dma.phys);
+
+ return EFC_FAIL;
+}
+
+/**
+ * @brief Check the SLI_CONFIG response.
+ *
+ * @par Description
+ * Function checks the SLI_CONFIG response and the payload status.
+ *
+ * @param buf Pointer to SLI_CONFIG response.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+static int
+sli_res_sli_config(struct sli4_s *sli4, void *buf)
+{
+ struct sli4_cmd_sli_config_s *sli_config = buf;
+
+ /* sanity check */
+ if (!buf || sli_config->hdr.command !=
+ MBX_CMD_SLI_CONFIG) {
+ efc_log_err(sli4, "bad parameter buf=%p cmd=%#x\n", buf,
+ buf ? sli_config->hdr.command : -1);
+ return EFC_FAIL;
+ }
+
+ if (le16_to_cpu(sli_config->hdr.status))
+ return le16_to_cpu(sli_config->hdr.status);
+
+ if (le32_to_cpu(sli_config->dw1_flags) & SLI4_SLICONF_EMB)
+ return sli_config->payload.embed[4];
+
+ efc_log_info(sli4, "external buffers not supported\n");
+ return EFC_FAIL;
+}
+
+/**
+ * @ingroup sli
+ * @brief Issue the command to create a queue.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to queue object.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+__sli_create_queue(struct sli4_s *sli4, struct sli4_queue_s *q)
+{
+ struct sli4_rsp_cmn_create_queue_s *res_q = NULL;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail %s\n",
+ SLI_QNAME[q->type]);
+ return EFC_FAIL;
+ }
+ if (sli_res_sli_config(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad status create %s\n",
+ SLI_QNAME[q->type]);
+ return EFC_FAIL;
+ }
+ res_q = (void *)((u8 *)sli4->bmbx.virt +
+ offsetof(struct sli4_cmd_sli_config_s, payload));
+
+ if (res_q->hdr.status) {
+ efc_log_err(sli4, "bad create %s status=%#x addl=%#x\n",
+ SLI_QNAME[q->type], res_q->hdr.status,
+ res_q->hdr.additional_status);
+ return EFC_FAIL;
+ }
+ q->id = le16_to_cpu(res_q->q_id);
+ switch (q->type) {
+ case SLI_QTYPE_EQ:
+ /* No doorbell information in response for EQs */
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] + SLI4_IF6_EQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] +
+ SLI4_EQCQ_DB_REG;
+ break;
+ case SLI_QTYPE_CQ:
+ /* No doorbell information in response for CQs */
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] +
+ SLI4_IF6_CQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] +
+ SLI4_EQCQ_DB_REG;
+ break;
+ case SLI_QTYPE_MQ:
+ /* No doorbell information in response for MQs */
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] +
+ SLI4_IF6_MQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] +
+ SLI4_MQ_DB_REG;
+ break;
+ case SLI_QTYPE_RQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] +
+ SLI4_IF6_RQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] +
+ SLI4_RQ_DB_REG;
+ break;
+ case SLI_QTYPE_WQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ q->db_regaddr = sli4->reg[1] +
+ SLI4_IF6_WQ_DB_REG;
+ else
+ q->db_regaddr = sli4->reg[0] +
+ SLI4_IO_WQ_DB_REG;
+ break;
+ default:
+ break;
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Get queue entry size.
+ *
+ * Get queue entry size given queue type.
+ *
+ * @param sli4 SLI context
+ * @param qtype Type for which the entry size is returned.
+ *
+ * @return Returns > 0 on success (queue entry size),
+ * or a negative value on failure.
+ */
+int
+sli_get_queue_entry_size(struct sli4_s *sli4, u32 qtype)
+{
+ u32 size = 0;
+
+ switch (qtype) {
+ case SLI_QTYPE_EQ:
+ size = sizeof(u32);
+ break;
+ case SLI_QTYPE_CQ:
+ size = 16;
+ break;
+ case SLI_QTYPE_MQ:
+ size = 256;
+ break;
+ case SLI_QTYPE_WQ:
+ size = sli4->wqe_size;
+ break;
+ case SLI_QTYPE_RQ:
+ size = SLI4_RQE_SIZE;
+ break;
+ default:
+ efc_log_info(sli4, "unknown queue type %d\n", qtype);
+ return -1;
+ }
+ return size;
+}
+
+/**
+ * @ingroup sli
+ * @brief Allocate a queue.
+ *
+ * @par Description
+ * Allocates DMA memory and configures the requested queue type.
+ *
+ * @param sli4 SLI context.
+ * @param qtype Type of queue to create.
+ * @param q Pointer to the queue object.
+ * @param n_entries Number of entries to allocate.
+ * @param assoc Associated queue
+ * (that is, the EQ for a CQ, the CQ for a MQ, and so on).
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_queue_alloc(struct sli4_s *sli4, u32 qtype,
+ struct sli4_queue_s *q, u32 n_entries,
+ struct sli4_queue_s *assoc)
+{
+ int size;
+ u32 align = 0;
+
+ /* get queue size */
+ size = sli_get_queue_entry_size(sli4, qtype);
+ if (size < 0)
+ return EFC_FAIL;
+ align = SLI_PAGE_SIZE;
+
+ if (__sli_queue_init(sli4, q, qtype, size, n_entries, align)) {
+ efc_log_err(sli4, "%s allocation failed\n",
+ SLI_QNAME[qtype]);
+ return EFC_FAIL;
+ }
+
+ switch (qtype) {
+ case SLI_QTYPE_EQ:
+ if (!sli_cmd_common_create_eq(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, &q->dma,
+ assoc ? assoc->id : 0)) {
+ if (__sli_create_queue(sli4, q)) {
+ efc_log_err(sli4, "create %s failed\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ } else {
+ efc_log_err(sli4, "cannot create %s\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+
+ break;
+ case SLI_QTYPE_CQ:
+ if (!sli_cmd_common_create_cq(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, &q->dma,
+ assoc ? assoc->id : 0)) {
+ if (__sli_create_queue(sli4, q)) {
+ efc_log_err(sli4, "create %s failed\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ } else {
+ efc_log_err(sli4, "cannot create %s\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ break;
+ case SLI_QTYPE_MQ:
+ assoc->u.flag.dword |= SLI4_QUEUE_FLAG_MQ;
+ if (!sli_cmd_common_create_mq_ext(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, &q->dma,
+ assoc->id)) {
+ if (__sli_create_queue(sli4, q)) {
+ efc_log_err(sli4, "create %s failed\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ } else {
+ efc_log_err(sli4, "cannot create %s\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+
+ break;
+ case SLI_QTYPE_WQ:
+ if (!sli_cmd_wq_create_v1(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, &q->dma,
+ assoc ? assoc->id : 0)) {
+ if (__sli_create_queue(sli4, q)) {
+ efc_log_err(sli4, "create %s failed\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ } else {
+ efc_log_err(sli4, "cannot create %s\n",
+ SLI_QNAME[qtype]);
+ goto error;
+ }
+ break;
+ default:
+ efc_log_info(sli4, "unknown queue type %d\n", qtype);
+ goto error;
+ }
+
+ return EFC_SUCCESS;
+error:
+ __sli_queue_destroy(sli4, q);
+ return EFC_FAIL;
+}
+
+static int sli_cmd_cq_set_create(struct sli4_s *sli4,
+ struct sli4_queue_s *qs[], u32 num_cqs,
+ struct sli4_queue_s *eqs[],
+ struct efc_dma_s *dma)
+{
+ struct sli4_rqst_cmn_create_cq_set_v0_s *req = NULL;
+ uintptr_t addr;
+ u32 i, offset = 0, page_bytes = 0, payload_size;
+ u32 p = 0, page_size = 0, n_cqe = 0, num_pages_cq;
+ u32 dw5_flags = 0;
+ u16 dw6w1_flags = 0;
+
+
+ n_cqe = qs[0]->dma.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 -1;
+ }
+
+ page_bytes = page_size * SLI_PAGE_SIZE;
+ num_pages_cq = sli_page_count(qs[0]->dma.size, page_bytes);
+ payload_size = max(CFG_RQST_CMDSZ(cmn_create_cq_set_v0) +
+ (SZ_DMAADDR * num_pages_cq * num_cqs),
+ sizeof(struct sli4_rsp_cmn_create_queue_set_s));
+
+ dma->size = payload_size;
+ dma->virt = dma_alloc_coherent(&sli4->pcidev->dev, dma->size,
+ &dma->phys, GFP_DMA);
+ if (!dma->virt)
+ return EFC_FAIL;
+
+ memset(dma->virt, 0, payload_size);
+
+ req = sli_config_cmd_init(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
+ payload_size, dma);
+ if (!req)
+ return EFC_FAIL;
+
+ /* Fill the request structure */
+ req->hdr.opcode = CMN_CREATE_CQ_SET;
+ req->hdr.subsystem = SLI4_SUBSYSTEM_FC;
+ req->hdr.dw3_version = CMD_V0;
+ req->hdr.request_length = CFG_RQST_PYLD_LEN_VAR(cmn_create_cq_set_v0,
+ SZ_DMAADDR * num_pages_cq * num_cqs);
+ req->page_size = page_size;
+
+ req->num_pages = cpu_to_le16(num_pages_cq);
+ switch (num_pages_cq) {
+ 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);
+ dw6w1_flags |= (n_cqe & CREATE_CQSETV0_CQE_COUNT);
+ break;
+ default:
+ efc_log_info(sli4, "num_pages %d not valid\n", num_pages_cq);
+ return EFC_FAIL;
+ }
+
+ dw5_flags |= CREATE_CQSETV0_EVT;
+ dw5_flags |= CREATE_CQSETV0_VALID;
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ dw5_flags |= CREATE_CQSETV0_AUTOVALID;
+
+ dw6w1_flags &= (~CREATE_CQSETV0_ARM);
+
+ req->dw5_flags = cpu_to_le32(dw5_flags);
+ req->dw6w1_flags = cpu_to_le16(dw6w1_flags);
+
+ req->num_cq_req = cpu_to_le16(num_cqs);
+
+ /* Fill page addresses of all the CQs. */
+ for (i = 0; i < num_cqs; i++) {
+ req->eq_id[i] = cpu_to_le16(eqs[i]->id);
+ for (p = 0, addr = qs[i]->dma.phys; p < num_pages_cq;
+ p++, addr += page_bytes) {
+ req->page_phys_addr[offset].low =
+ cpu_to_le32(lower_32_bits(addr));
+ req->page_phys_addr[offset].high =
+ cpu_to_le32(upper_32_bits(addr));
+ offset++;
+ }
+ }
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Allocate a c queue set.
+ *
+ * @param sli4 SLI context.
+ * @param num_cqs to create
+ * @param qs Pointers to the queue objects.
+ * @param n_entries Number of entries to allocate per CQ.
+ * @param eqs Associated event queues
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_cq_alloc_set(struct sli4_s *sli4, struct sli4_queue_s *qs[],
+ u32 num_cqs, u32 n_entries, struct sli4_queue_s *eqs[])
+{
+ u32 i;
+ struct efc_dma_s dma = {0};
+ struct sli4_rsp_cmn_create_queue_set_s *res = NULL;
+ void __iomem *db_regaddr = NULL;
+
+ /* Align the queue DMA memory */
+ for (i = 0; i < num_cqs; i++) {
+ if (__sli_queue_init(sli4, qs[i], SLI_QTYPE_CQ,
+ SLI4_CQE_BYTES,
+ n_entries, SLI_PAGE_SIZE)) {
+ efc_log_err(sli4, "Queue init failed.\n");
+ goto error;
+ }
+ }
+
+ if (sli_cmd_cq_set_create(sli4, qs, num_cqs, eqs, &dma))
+ goto error;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox write fail CQSet\n");
+ goto error;
+ }
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ db_regaddr = sli4->reg[1] + SLI4_IF6_CQ_DB_REG;
+ else
+ db_regaddr = sli4->reg[0] + SLI4_EQCQ_DB_REG;
+
+ res = dma.virt;
+ if (res->hdr.status) {
+ efc_log_err(sli4, "bad create CQSet status=%#x addl=%#x\n",
+ res->hdr.status, res->hdr.additional_status);
+ goto error;
+ } else {
+ /* Check if we got all requested CQs. */
+ if (le16_to_cpu(res->num_q_allocated) != num_cqs) {
+ efc_log_crit(sli4, "Requested count CQs doesn't match.\n");
+ goto error;
+ }
+ /* Fill the resp cq ids. */
+ for (i = 0; i < num_cqs; i++) {
+ qs[i]->id = le16_to_cpu(res->q_id) + i;
+ qs[i]->db_regaddr = db_regaddr;
+ }
+ }
+
+ dma_free_coherent(&sli4->pcidev->dev, dma.size, dma.virt, dma.phys);
+
+ return EFC_SUCCESS;
+
+error:
+ for (i = 0; i < num_cqs; i++)
+ __sli_queue_destroy(sli4, qs[i]);
+
+ if (dma.virt)
+ dma_free_coherent(&sli4->pcidev->dev, dma.size, dma.virt,
+ dma.phys);
+
+ return EFC_FAIL;
+}
+
+/**
+ * @ingroup sli
+ * @brief Free a queue.
+ *
+ * @par Description
+ * Frees DMA memory and de-registers the requested queue.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param destroy_queues Non-zero if the mailbox commands
+ * should be sent to destroy the queues.
+ * @param free_memory Non-zero if the DMA memory associated
+ * with the queue should be freed.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_queue_free(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u32 destroy_queues, u32 free_memory)
+{
+ int rc = EFC_SUCCESS;
+
+ if (!q) {
+ efc_log_err(sli4, "bad parameter sli4=%p q=%p\n", sli4, q);
+ return EFC_FAIL;
+ }
+
+ if (destroy_queues) {
+ switch (q->type) {
+ case SLI_QTYPE_EQ:
+ rc = sli_cmd_common_destroy_eq(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, q->id);
+ break;
+ case SLI_QTYPE_CQ:
+ rc = sli_cmd_common_destroy_cq(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, q->id);
+ break;
+ case SLI_QTYPE_MQ:
+ rc = sli_cmd_common_destroy_mq(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, q->id);
+ break;
+ case SLI_QTYPE_WQ:
+ rc = sli_cmd_wq_destroy(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, q->id);
+ break;
+ case SLI_QTYPE_RQ:
+ rc = sli_cmd_rq_destroy(sli4, sli4->bmbx.virt,
+ SLI4_BMBX_SIZE, q->id);
+ break;
+ default:
+ efc_log_info(sli4, "bad queue type %d\n",
+ q->type);
+ return EFC_FAIL;
+ }
+
+ if (rc) {
+ struct sli4_rsp_hdr_s *res = NULL;
+
+ if (sli_bmbx_command(sli4)) {
+ efc_log_crit(sli4, "bootstrap mailbox fail destroy %s\n",
+ SLI_QNAME[q->type]);
+ } else if (sli_res_sli_config(sli4, sli4->bmbx.virt)) {
+ efc_log_err(sli4, "bad status destroy %s\n",
+ SLI_QNAME[q->type]);
+ } else {
+ res = (void *)((u8 *)sli4->bmbx.virt +
+ offsetof(struct sli4_cmd_sli_config_s,
+ payload));
+
+ if (res->status) {
+ efc_log_err(sli4, "destroy %s st=%#x addl=%#x\n",
+ SLI_QNAME[q->type],
+ res->status,
+ res->additional_status);
+ } else {
+ rc = EFC_SUCCESS;
+ }
+ }
+ }
+ }
+
+ if (free_memory)
+ __sli_queue_destroy(sli4, q);
+
+ return rc;
+}
+
+/**
+ * @ingroup sli
+ * @brief Arm an EQ.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to queue object.
+ * @param arm If TRUE, arm the EQ.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_queue_eq_arm(struct sli4_s *sli4, struct sli4_queue_s *q, bool arm)
+{
+ u32 val = 0;
+ unsigned long flags = 0;
+ u32 a = arm ? SLI4_EQCQ_ARM : SLI4_EQCQ_UNARM;
+
+ spin_lock_irqsave(&q->lock, flags);
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = SLI4_IF6_EQ_DOORBELL(q->n_posted, q->id, a);
+ else
+ val = SLI4_EQ_DOORBELL(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Arm a queue.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to queue object.
+ * @param arm If TRUE, arm the queue.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_queue_arm(struct sli4_s *sli4, struct sli4_queue_s *q, bool arm)
+{
+ u32 val = 0;
+ unsigned long flags = 0;
+ u32 a = arm ? SLI4_EQCQ_ARM : SLI4_EQCQ_UNARM;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ switch (q->type) {
+ case SLI_QTYPE_EQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = SLI4_IF6_EQ_DOORBELL(q->n_posted, q->id, a);
+ else
+ val = SLI4_EQ_DOORBELL(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ break;
+ case SLI_QTYPE_CQ:
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ val = SLI4_IF6_CQ_DOORBELL(q->n_posted, q->id, a);
+ else
+ val = SLI4_CQ_DOORBELL(q->n_posted, q->id, a);
+
+ writel(val, q->db_regaddr);
+ q->n_posted = 0;
+ break;
+ default:
+ efc_log_info(sli4, "should only be used for EQ/CQ, not %s\n",
+ SLI_QNAME[q->type]);
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Write a WQ entry to the queue object.
+ *
+ * Note: Assumes the q->lock will be locked and released by the caller.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Pointer to the entry contents.
+ *
+ * @return Returns queue index on success, or negative error value otherwise.
+ */
+int
+sli_wq_write(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex;
+ u32 val = 0;
+
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ if (sli4->perf_wq_id_association)
+ sli_set_wq_id_association(entry, q->id);
+
+ memcpy(qe, entry, q->size);
+ q->n_posted = 1;
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6)
+ /* non-dpp write for iftype = 6 */
+ val = SLI4_WQ_DOORBELL(q->n_posted, 0, q->id);
+ else
+ val = SLI4_WQ_DOORBELL(q->n_posted, q->index, q->id);
+
+ writel(val, q->db_regaddr);
+ q->index = (q->index + q->n_posted) & (q->length - 1);
+ q->n_posted = 0;
+
+ return qindex;
+}
+
+/**
+ * @ingroup sli
+ * @brief Write a MQ entry to the queue object.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Pointer to the entry contents.
+ *
+ * @return Returns queue index on success, or negative error value otherwise.
+ */
+int
+sli_mq_write(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex;
+ u32 val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ memcpy(qe, entry, q->size);
+ q->n_posted = 1;
+
+ val = SLI4_MQ_DOORBELL(q->n_posted, q->id);
+ writel(val, q->db_regaddr);
+ q->index = (q->index + q->n_posted) & (q->length - 1);
+ q->n_posted = 0;
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return qindex;
+}
+
+/**
+ * @ingroup sli
+ * @brief Write a RQ entry to the queue object.
+ *
+ * Note: Assumes the q->lock will be locked and released by the caller.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Pointer to the entry contents.
+ *
+ * @return Returns queue index on success, or negative error value otherwise.
+ */
+int
+sli_rq_write(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 qindex, n_posted;
+ u32 val = 0;
+
+ qindex = q->index;
+ qe += q->index * q->size;
+
+ memcpy(qe, entry, q->size);
+ q->n_posted = 1;
+
+ n_posted = q->n_posted;
+
+ /*
+ * In RQ-pair, an RQ either contains the FC header
+ * (i.e. is_hdr == TRUE) or the payload.
+ *
+ * Don't ring doorbell for payload RQ
+ */
+ if (!(q->u.flag.dword & SLI4_QUEUE_FLAG_HDR))
+ goto skip;
+
+ /*
+ * Some RQ cannot be incremented one entry at a time.
+ * Instead, the driver collects a number of entries
+ * and updates the RQ in batches.
+ */
+ if (q->u.flag.dword & SLI4_QUEUE_FLAG_RQBATCH) {
+ if (((q->index + q->n_posted) %
+ SLI4_QUEUE_RQ_BATCH)) {
+ goto skip;
+ }
+ n_posted = SLI4_QUEUE_RQ_BATCH;
+ }
+
+ val = SLI4_RQ_DOORBELL(n_posted, q->id);
+ writel(val, q->db_regaddr);
+skip:
+ q->index = (q->index + q->n_posted) & (q->length - 1);
+ q->n_posted = 0;
+
+ return qindex;
+}
+
+/**
+ * @ingroup sli
+ * @brief Read an EQ entry from the queue object.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Destination pointer for the queue entry contents.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_eq_read(struct sli4_s *sli4,
+ struct sli4_queue_s *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 *qindex = NULL;
+ unsigned long flags = 0;
+ u8 clear = false, valid = false;
+ u16 wflags = 0;
+
+ clear = (sli4->if_type == SLI4_INTF_IF_TYPE_6) ? false : true;
+
+ qindex = &q->index;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += *qindex * q->size;
+
+ /* Check if eqe is valid */
+ wflags = le16_to_cpu(((struct sli4_eqe_s *)qe)->dw0w0_flags);
+ valid = ((wflags & SLI4_EQE_VALID) == q->phase);
+ if (!valid) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return EFC_FAIL;
+ }
+
+ if (valid && clear) {
+ wflags &= ~SLI4_EQE_VALID;
+ ((struct sli4_eqe_s *)qe)->dw0w0_flags =
+ cpu_to_le16(wflags);
+ }
+
+ memcpy(entry, qe, q->size);
+ *qindex = (*qindex + 1) & (q->length - 1);
+ q->n_posted++;
+ /*
+ * For prism, the phase value will be used
+ * to check the validity of eq/cq entries.
+ * The value toggles after a complete sweep
+ * through the queue.
+ */
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6 && *qindex == 0)
+ q->phase ^= (u16)0x1;
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Read an CQ entry from the queue object.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Destination pointer for the queue entry contents.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_cq_read(struct sli4_s *sli4,
+ struct sli4_queue_s *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 *qindex = NULL;
+ unsigned long flags = 0;
+ u8 clear = false;
+ u32 dwflags = 0;
+ bool valid = false, valid_bit_set = false;
+
+ clear = (sli4->if_type == SLI4_INTF_IF_TYPE_6) ? false : true;
+
+ qindex = &q->index;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += *qindex * q->size;
+
+ /* Check if cqe is valid */
+ dwflags = le32_to_cpu(((struct sli4_mcqe_s *)qe)->dw3_flags);
+ valid_bit_set = (dwflags & SLI4_MCQE_VALID) != 0;
+
+ valid = (valid_bit_set == q->phase);
+ if (!valid) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+
+ if (valid && clear) {
+ dwflags &= ~SLI4_MCQE_VALID;
+ ((struct sli4_mcqe_s *)qe)->dw3_flags =
+ cpu_to_le32(dwflags);
+ }
+
+ memcpy(entry, qe, q->size);
+ *qindex = (*qindex + 1) & (q->length - 1);
+ q->n_posted++;
+ /*
+ * For prism, the phase value will be used
+ * to check the validity of eq/cq entries.
+ * The value toggles after a complete sweep
+ * through the queue.
+ */
+
+ if (sli4->if_type == SLI4_INTF_IF_TYPE_6 && *qindex == 0)
+ q->phase ^= (u16)0x1;
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return EFC_SUCCESS;
+}
+
+/**
+ * @ingroup sli
+ * @brief Read an MQ entry from the queue object.
+ *
+ * @param sli4 SLI context.
+ * @param q Pointer to the queue object.
+ * @param entry Destination pointer for the queue entry contents.
+ *
+ * @return Returns 0 on success, or non-zero otherwise.
+ */
+int
+sli_mq_read(struct sli4_s *sli4,
+ struct sli4_queue_s *q, u8 *entry)
+{
+ u8 *qe = q->dma.virt;
+ u32 *qindex = NULL;
+ unsigned long flags = 0;
+
+ qindex = &q->u.r_idx;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ qe += *qindex * q->size;
+
+ /* Check if mqe is valid */
+ if (q->index == q->u.r_idx) {
+ spin_unlock_irqrestore(&q->lock, flags);
+ return -1;
+ }
+
+ memcpy(entry, qe, q->size);
+ *qindex = (*qindex + 1) & (q->length - 1);
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return EFC_SUCCESS;
+}
+
+int
+sli_queue_index(struct sli4_s *sli4, struct sli4_queue_s *q)
+{
+ if (q)
+ return q->index;
+ else
+ return -1;
+}
+
+int
+sli_queue_poke(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u32 index, u8 *entry)
+{
+ int rc;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&q->lock, flags);
+ rc = _sli_queue_poke(sli4, q, index, entry);
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ return rc;
+}
+
+int
+_sli_queue_poke(struct sli4_s *sli4, struct sli4_queue_s *q,
+ u32 index, u8 *entry)
+{
+ int rc = 0;
+ u8 *qe = q->dma.virt;
+
+ if (index >= q->length)
+ return -1;
+
+ qe += index * q->size;
+
+ if (entry)
+ memcpy(qe, entry, q->size);
+
+ return rc;
+}
+
+/**
+ * @ingroup sli
+ * @brief Parse an EQ entry to retrieve the CQ_ID for this event.
+ *
+ * @param sli4 SLI context.
+ * @param buf Pointer to the EQ entry.
+ * @param cq_id CQ_ID for this entry (only valid on success).
+ *
+ * @return
+ * - 0 if success.
+ * - < 0 if error.
+ * - > 0 if firmware detects EQ overflow.
+ */
+int
+sli_eq_parse(struct sli4_s *sli4, u8 *buf, u16 *cq_id)
+{
+ struct sli4_eqe_s *eqe = (void *)buf;
+ int rc = EFC_SUCCESS;
+ u16 flags = 0;
+ u16 majorcode;
+ u16 minorcode;
+
+ if (!buf || !cq_id) {
+ efc_log_err(sli4, "bad parameters sli4=%p buf=%p cq_id=%p\n",
+ sli4, buf, cq_id);
+ return -1;
+ }
+
+ flags = le16_to_cpu(eqe->dw0w0_flags);
+ majorcode = (flags & SLI4_EQE_MJCODE) >> 1;
+ minorcode = (flags & SLI4_EQE_MNCODE) >> 4;
+ switch (majorcode) {
+ case SLI4_MAJOR_CODE_STANDARD:
+ *cq_id = le16_to_cpu(eqe->resource_id);
+ break;
+ case SLI4_MAJOR_CODE_SENTINEL:
+ efc_log_info(sli4, "sentinel EQE\n");
+ rc = EFC_FAIL;
+ break;
+ default:
+ efc_log_info(sli4, "Unsupported EQE: major %x minor %x\n",
+ majorcode, minorcode);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/**
+ * @ingroup sli
+ * @brief Parse a CQ entry to retrieve the event type and the associated queue.
+ *
+ * @param sli4 SLI context.
+ * @param cq CQ to process.
+ * @param cqe Pointer to the CQ entry.
+ * @param etype CQ event type.
+ * @param q_id Queue ID associated with this completion message
+ * (that is, MQ_ID, RQ_ID, and so on).
+ *
+ * @return
+ * - 0 if call completed correctly and CQE status is SUCCESS.
+ * - -1 if call failed (no CQE status).
+ * - Other value if call completed correctly and return value is a
+ * CQE status value.
+ */
+int
+sli_cq_parse(struct sli4_s *sli4, struct sli4_queue_s *cq, u8 *cqe,
+ enum sli4_qentry_e *etype, u16 *q_id)
+{
+ int rc = EFC_SUCCESS;
+
+ if (!cq || !cqe || !etype) {
+ efc_log_err(sli4, "bad params sli4=%p cq=%p cqe=%p etype=%p q_id=%p\n",
+ sli4, cq, cqe, etype, q_id);
+ return -1;
+ }
+
+ if (cq->u.flag.dword & SLI4_QUEUE_FLAG_MQ) {
+ struct sli4_mcqe_s *mcqe = (void *)cqe;
+
+ if (le32_to_cpu(mcqe->dw3_flags) & SLI4_MCQE_AE) {
+ *etype = SLI_QENTRY_ASYNC;
+ } else {
+ *etype = SLI_QENTRY_MQ;
+ rc = sli_cqe_mq(sli4, mcqe);
+ }
+ *q_id = -1;
+ } else {
+ rc = sli_fc_cqe_parse(sli4, cq, cqe, etype, q_id);
+ }
+
+ return rc;
+}
--
2.13.7
next prev parent reply other threads:[~2019-10-23 21:56 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-23 21:55 [PATCH 00/32] [NEW] efct: Broadcom (Emulex) FC Target driver James Smart
2019-10-23 21:55 ` [PATCH 01/32] elx: libefc_sli: SLI-4 register offsets and field definitions James Smart
2019-10-24 16:22 ` Daniel Wagner
2019-10-25 23:04 ` James Smart
2019-10-23 21:55 ` [PATCH 02/32] elx: libefc_sli: SLI Descriptors and Queue entries James Smart
2019-10-25 9:59 ` Daniel Wagner
2019-10-25 23:00 ` James Smart
2019-10-23 21:55 ` [PATCH 03/32] elx: libefc_sli: Data structures and defines for mbox commands James Smart
2019-10-25 11:19 ` Daniel Wagner
2019-10-25 12:20 ` Steffen Maier
2019-10-25 22:10 ` James Smart
2019-10-25 22:42 ` James Smart
2019-10-23 21:55 ` James Smart [this message]
2019-10-25 15:35 ` [PATCH 04/32] elx: libefc_sli: queue create/destroy/parse routines Daniel Wagner
2019-10-25 22:24 ` James Smart
2019-10-23 21:55 ` [PATCH 05/32] elx: libefc_sli: Populate and post different WQEs James Smart
2019-10-23 21:55 ` [PATCH 06/32] elx: libefc_sli: bmbx routines and SLI config commands James Smart
2019-10-23 21:55 ` [PATCH 07/32] elx: libefc_sli: APIs to setup SLI library James Smart
2019-10-23 21:55 ` [PATCH 08/32] elx: libefc: Generic state machine framework James Smart
2019-10-23 21:55 ` [PATCH 09/32] elx: libefc: Emulex FC discovery library APIs and definitions James Smart
2019-10-23 21:55 ` [PATCH 10/32] elx: libefc: FC Domain state machine interfaces James Smart
2019-10-23 21:55 ` [PATCH 11/32] elx: libefc: SLI and FC PORT " James Smart
2019-10-23 21:55 ` [PATCH 12/32] elx: libefc: Remote node " James Smart
2019-10-23 21:55 ` [PATCH 13/32] elx: libefc: Fabric " James Smart
2019-10-23 21:55 ` [PATCH 14/32] elx: libefc: FC node ELS and state handling James Smart
2019-10-23 21:55 ` [PATCH 15/32] elx: efct: Data structures and defines for hw operations James Smart
2019-10-23 21:55 ` [PATCH 16/32] elx: efct: Driver initialization routines James Smart
2019-10-23 21:55 ` [PATCH 17/32] elx: efct: Hardware queues creation and deletion James Smart
2019-10-23 21:55 ` [PATCH 18/32] elx: efct: RQ buffer, memory pool allocation and deallocation APIs James Smart
2019-10-23 21:55 ` [PATCH 19/32] elx: efct: Hardware IO and SGL initialization James Smart
2019-10-23 21:55 ` [PATCH 20/32] elx: efct: Hardware queues processing James Smart
2019-10-23 21:55 ` [PATCH 21/32] elx: efct: Unsolicited FC frame processing routines James Smart
2019-10-23 21:55 ` [PATCH 22/32] elx: efct: Extended link Service IO handling James Smart
2019-10-23 21:55 ` [PATCH 23/32] elx: efct: SCSI IO handling routines James Smart
2019-10-23 21:55 ` [PATCH 24/32] elx: efct: LIO backend interface routines James Smart
2019-10-24 22:27 ` Bart Van Assche
2019-10-28 17:49 ` James Smart
2019-10-28 18:31 ` Bart Van Assche
2019-10-23 21:55 ` [PATCH 25/32] elx: efct: Hardware IO submission routines James Smart
2019-10-23 21:55 ` [PATCH 26/32] elx: efct: link statistics and SFP data James Smart
2019-10-23 21:55 ` [PATCH 27/32] elx: efct: xport and hardware teardown routines James Smart
2019-10-23 21:55 ` [PATCH 28/32] elx: efct: IO timeout handling routines James Smart
2019-10-23 21:55 ` [PATCH 29/32] elx: efct: Firmware update, async link processing James Smart
2019-10-23 21:55 ` [PATCH 30/32] elx: efct: scsi_transport_fc host interface support James Smart
2019-10-23 21:55 ` [PATCH 31/32] elx: efct: Add Makefile and Kconfig for efct driver James Smart
2019-10-25 15:55 ` Daniel Wagner
2019-10-25 22:47 ` James Smart
2019-10-23 21:55 ` [PATCH 32/32] elx: efct: Tie into kernel Kconfig and build process James Smart
2019-10-26 0:34 ` kbuild test robot
2019-10-26 0:34 ` kbuild test robot
2019-10-26 0:39 ` Randy Dunlap
2019-10-26 0:39 ` Randy Dunlap
2019-10-26 14:13 ` kbuild test robot
2019-10-26 14:13 ` kbuild test robot
2019-10-26 14:13 ` [RFC PATCH] elx: efct: efct_libefc_templ can be static kbuild test robot
2019-10-26 14:13 ` kbuild test robot
2019-10-25 15:56 ` [PATCH 00/32] [NEW] efct: Broadcom (Emulex) FC Target driver Daniel Wagner
2019-10-25 22:31 ` James Smart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191023215557.12581-5-jsmart2021@gmail.com \
--to=jsmart2021@gmail.com \
--cc=linux-scsi@vger.kernel.org \
--cc=ram.vegesna@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.