[SCSI] lpfc 8.3.37: Provide support for FCoE protocol dual-chute (ULP) operation
authorJames Smart <james.smart@emulex.com>
Thu, 3 Jan 2013 20:44:00 +0000 (15:44 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Wed, 30 Jan 2013 00:32:41 +0000 (11:32 +1100)
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h

index 9b7fbaf07a551adb2a93adcc8a33f0478658a5f4..7706c99ec8bbb1e8c70b051113f789cb6f97c1dd 100644 (file)
@@ -752,6 +752,15 @@ struct lpfc_hba {
        void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for
                                            PCI BAR2 */
 
+       void __iomem *pci_bar0_memmap_p; /* Kernel memory mapped address for
+                                           PCI BAR0 with dual-ULP support */
+       void __iomem *pci_bar2_memmap_p; /* Kernel memory mapped address for
+                                           PCI BAR2 with dual-ULP support */
+       void __iomem *pci_bar4_memmap_p; /* Kernel memory mapped address for
+                                           PCI BAR4 with dual-ULP support */
+#define PCI_64BIT_BAR0 0
+#define PCI_64BIT_BAR2 2
+#define PCI_64BIT_BAR4 4
        void __iomem *MBslimaddr;       /* virtual address for mbox cmds */
        void __iomem *HAregaddr;        /* virtual address for host attn reg */
        void __iomem *CAregaddr;        /* virtual address for chip attn reg */
index a47cfbdd05f28d4497ea6eab982cd13d86dde803..6e93b886cd4d3f15c327f155d904d0dd162cf8da 100644 (file)
@@ -106,6 +106,7 @@ struct lpfc_sli_intf {
 
 #define LPFC_SLI4_MB_WORD_COUNT                64
 #define LPFC_MAX_MQ_PAGE               8
+#define LPFC_MAX_WQ_PAGE_V0            4
 #define LPFC_MAX_WQ_PAGE               8
 #define LPFC_MAX_CQ_PAGE               4
 #define LPFC_MAX_EQ_PAGE               8
@@ -703,24 +704,41 @@ struct lpfc_register {
  * BAR0.  The offsets are the same so the driver must account for
  * any base address difference.
  */
-#define LPFC_RQ_DOORBELL               0x00A0
-#define lpfc_rq_doorbell_num_posted_SHIFT      16
-#define lpfc_rq_doorbell_num_posted_MASK       0x3FFF
-#define lpfc_rq_doorbell_num_posted_WORD       word0
-#define lpfc_rq_doorbell_id_SHIFT              0
-#define lpfc_rq_doorbell_id_MASK               0xFFFF
-#define lpfc_rq_doorbell_id_WORD               word0
-
-#define LPFC_WQ_DOORBELL               0x0040
-#define lpfc_wq_doorbell_num_posted_SHIFT      24
-#define lpfc_wq_doorbell_num_posted_MASK       0x00FF
-#define lpfc_wq_doorbell_num_posted_WORD       word0
-#define lpfc_wq_doorbell_index_SHIFT           16
-#define lpfc_wq_doorbell_index_MASK            0x00FF
-#define lpfc_wq_doorbell_index_WORD            word0
-#define lpfc_wq_doorbell_id_SHIFT              0
-#define lpfc_wq_doorbell_id_MASK               0xFFFF
-#define lpfc_wq_doorbell_id_WORD               word0
+#define LPFC_ULP0_RQ_DOORBELL          0x00A0
+#define LPFC_ULP1_RQ_DOORBELL          0x00C0
+#define lpfc_rq_db_list_fm_num_posted_SHIFT    24
+#define lpfc_rq_db_list_fm_num_posted_MASK     0x00FF
+#define lpfc_rq_db_list_fm_num_posted_WORD     word0
+#define lpfc_rq_db_list_fm_index_SHIFT         16
+#define lpfc_rq_db_list_fm_index_MASK          0x00FF
+#define lpfc_rq_db_list_fm_index_WORD          word0
+#define lpfc_rq_db_list_fm_id_SHIFT            0
+#define lpfc_rq_db_list_fm_id_MASK             0xFFFF
+#define lpfc_rq_db_list_fm_id_WORD             word0
+#define lpfc_rq_db_ring_fm_num_posted_SHIFT    16
+#define lpfc_rq_db_ring_fm_num_posted_MASK     0x3FFF
+#define lpfc_rq_db_ring_fm_num_posted_WORD     word0
+#define lpfc_rq_db_ring_fm_id_SHIFT            0
+#define lpfc_rq_db_ring_fm_id_MASK             0xFFFF
+#define lpfc_rq_db_ring_fm_id_WORD             word0
+
+#define LPFC_ULP0_WQ_DOORBELL          0x0040
+#define LPFC_ULP1_WQ_DOORBELL          0x0060
+#define lpfc_wq_db_list_fm_num_posted_SHIFT    24
+#define lpfc_wq_db_list_fm_num_posted_MASK     0x00FF
+#define lpfc_wq_db_list_fm_num_posted_WORD     word0
+#define lpfc_wq_db_list_fm_index_SHIFT         16
+#define lpfc_wq_db_list_fm_index_MASK          0x00FF
+#define lpfc_wq_db_list_fm_index_WORD          word0
+#define lpfc_wq_db_list_fm_id_SHIFT            0
+#define lpfc_wq_db_list_fm_id_MASK             0xFFFF
+#define lpfc_wq_db_list_fm_id_WORD             word0
+#define lpfc_wq_db_ring_fm_num_posted_SHIFT     16
+#define lpfc_wq_db_ring_fm_num_posted_MASK      0x3FFF
+#define lpfc_wq_db_ring_fm_num_posted_WORD      word0
+#define lpfc_wq_db_ring_fm_id_SHIFT             0
+#define lpfc_wq_db_ring_fm_id_MASK              0xFFFF
+#define lpfc_wq_db_ring_fm_id_WORD              word0
 
 #define LPFC_EQCQ_DOORBELL             0x0120
 #define lpfc_eqcq_doorbell_se_SHIFT            31
@@ -1131,12 +1149,22 @@ struct lpfc_mbx_wq_create {
                struct {        /* Version 0 Request */
                        uint32_t word0;
 #define lpfc_mbx_wq_create_num_pages_SHIFT     0
-#define lpfc_mbx_wq_create_num_pages_MASK      0x0000FFFF
+#define lpfc_mbx_wq_create_num_pages_MASK      0x000000FF
 #define lpfc_mbx_wq_create_num_pages_WORD      word0
+#define lpfc_mbx_wq_create_dua_SHIFT           8
+#define lpfc_mbx_wq_create_dua_MASK            0x00000001
+#define lpfc_mbx_wq_create_dua_WORD            word0
 #define lpfc_mbx_wq_create_cq_id_SHIFT         16
 #define lpfc_mbx_wq_create_cq_id_MASK          0x0000FFFF
 #define lpfc_mbx_wq_create_cq_id_WORD          word0
-                       struct dma_address page[LPFC_MAX_WQ_PAGE];
+                       struct dma_address page[LPFC_MAX_WQ_PAGE_V0];
+                       uint32_t word9;
+#define lpfc_mbx_wq_create_bua_SHIFT           0
+#define lpfc_mbx_wq_create_bua_MASK            0x00000001
+#define lpfc_mbx_wq_create_bua_WORD            word9
+#define lpfc_mbx_wq_create_ulp_num_SHIFT       8
+#define lpfc_mbx_wq_create_ulp_num_MASK                0x000000FF
+#define lpfc_mbx_wq_create_ulp_num_WORD                word9
                } request;
                struct {        /* Version 1 Request */
                        uint32_t word0; /* Word 0 is the same as in v0 */
@@ -1160,6 +1188,17 @@ struct lpfc_mbx_wq_create {
 #define lpfc_mbx_wq_create_q_id_SHIFT  0
 #define lpfc_mbx_wq_create_q_id_MASK   0x0000FFFF
 #define lpfc_mbx_wq_create_q_id_WORD   word0
+                       uint32_t doorbell_offset;
+                       uint32_t word2;
+#define lpfc_mbx_wq_create_bar_set_SHIFT       0
+#define lpfc_mbx_wq_create_bar_set_MASK                0x0000FFFF
+#define lpfc_mbx_wq_create_bar_set_WORD                word2
+#define WQ_PCI_BAR_0_AND_1     0x00
+#define WQ_PCI_BAR_2_AND_3     0x01
+#define WQ_PCI_BAR_4_AND_5     0x02
+#define lpfc_mbx_wq_create_db_format_SHIFT     16
+#define lpfc_mbx_wq_create_db_format_MASK      0x0000FFFF
+#define lpfc_mbx_wq_create_db_format_WORD      word2
                } response;
        } u;
 };
@@ -1223,14 +1262,31 @@ struct lpfc_mbx_rq_create {
 #define lpfc_mbx_rq_create_num_pages_SHIFT     0
 #define lpfc_mbx_rq_create_num_pages_MASK      0x0000FFFF
 #define lpfc_mbx_rq_create_num_pages_WORD      word0
+#define lpfc_mbx_rq_create_dua_SHIFT           16
+#define lpfc_mbx_rq_create_dua_MASK            0x00000001
+#define lpfc_mbx_rq_create_dua_WORD            word0
+#define lpfc_mbx_rq_create_bqu_SHIFT           17
+#define lpfc_mbx_rq_create_bqu_MASK            0x00000001
+#define lpfc_mbx_rq_create_bqu_WORD            word0
+#define lpfc_mbx_rq_create_ulp_num_SHIFT       24
+#define lpfc_mbx_rq_create_ulp_num_MASK                0x000000FF
+#define lpfc_mbx_rq_create_ulp_num_WORD                word0
                        struct rq_context context;
                        struct dma_address page[LPFC_MAX_WQ_PAGE];
                } request;
                struct {
                        uint32_t word0;
-#define lpfc_mbx_rq_create_q_id_SHIFT  0
-#define lpfc_mbx_rq_create_q_id_MASK   0x0000FFFF
-#define lpfc_mbx_rq_create_q_id_WORD   word0
+#define lpfc_mbx_rq_create_q_id_SHIFT          0
+#define lpfc_mbx_rq_create_q_id_MASK           0x0000FFFF
+#define lpfc_mbx_rq_create_q_id_WORD           word0
+                       uint32_t doorbell_offset;
+                       uint32_t word2;
+#define lpfc_mbx_rq_create_bar_set_SHIFT       0
+#define lpfc_mbx_rq_create_bar_set_MASK                0x0000FFFF
+#define lpfc_mbx_rq_create_bar_set_WORD                word2
+#define lpfc_mbx_rq_create_db_format_SHIFT     16
+#define lpfc_mbx_rq_create_db_format_MASK      0x0000FFFF
+#define lpfc_mbx_rq_create_db_format_WORD      word2
                } response;
        } u;
 };
@@ -1388,6 +1444,33 @@ struct lpfc_mbx_get_rsrc_extent_info {
        } u;
 };
 
+struct lpfc_mbx_query_fw_config {
+       struct mbox_header header;
+       struct {
+               uint32_t config_number;
+#define        LPFC_FC_FCOE            0x00000007
+               uint32_t asic_revision;
+               uint32_t physical_port;
+               uint32_t function_mode;
+#define LPFC_FCOE_INI_MODE     0x00000040
+#define LPFC_FCOE_TGT_MODE     0x00000080
+#define LPFC_DUA_MODE          0x00000800
+               uint32_t ulp0_mode;
+#define LPFC_ULP_FCOE_INIT_MODE        0x00000040
+#define LPFC_ULP_FCOE_TGT_MODE 0x00000080
+               uint32_t ulp0_nap_words[12];
+               uint32_t ulp1_mode;
+               uint32_t ulp1_nap_words[12];
+               uint32_t function_capabilities;
+               uint32_t cqid_base;
+               uint32_t cqid_tot;
+               uint32_t eqid_base;
+               uint32_t eqid_tot;
+               uint32_t ulp0_nap2_words[2];
+               uint32_t ulp1_nap2_words[2];
+       } rsp;
+};
+
 struct lpfc_id_range {
        uint32_t word5;
 #define lpfc_mbx_rsrc_id_word4_0_SHIFT 0
@@ -1803,51 +1886,6 @@ struct lpfc_mbx_redisc_fcf_tbl {
 #define lpfc_mbx_redisc_fcf_index_WORD         word12
 };
 
-struct lpfc_mbx_query_fw_cfg {
-       struct mbox_header header;
-       uint32_t config_number;
-       uint32_t asic_rev;
-       uint32_t phys_port;
-       uint32_t function_mode;
-/* firmware Function Mode */
-#define lpfc_function_mode_toe_SHIFT           0
-#define lpfc_function_mode_toe_MASK            0x00000001
-#define lpfc_function_mode_toe_WORD            function_mode
-#define lpfc_function_mode_nic_SHIFT           1
-#define lpfc_function_mode_nic_MASK            0x00000001
-#define lpfc_function_mode_nic_WORD            function_mode
-#define lpfc_function_mode_rdma_SHIFT          2
-#define lpfc_function_mode_rdma_MASK           0x00000001
-#define lpfc_function_mode_rdma_WORD           function_mode
-#define lpfc_function_mode_vm_SHIFT            3
-#define lpfc_function_mode_vm_MASK             0x00000001
-#define lpfc_function_mode_vm_WORD             function_mode
-#define lpfc_function_mode_iscsi_i_SHIFT       4
-#define lpfc_function_mode_iscsi_i_MASK                0x00000001
-#define lpfc_function_mode_iscsi_i_WORD                function_mode
-#define lpfc_function_mode_iscsi_t_SHIFT       5
-#define lpfc_function_mode_iscsi_t_MASK                0x00000001
-#define lpfc_function_mode_iscsi_t_WORD                function_mode
-#define lpfc_function_mode_fcoe_i_SHIFT                6
-#define lpfc_function_mode_fcoe_i_MASK         0x00000001
-#define lpfc_function_mode_fcoe_i_WORD         function_mode
-#define lpfc_function_mode_fcoe_t_SHIFT                7
-#define lpfc_function_mode_fcoe_t_MASK         0x00000001
-#define lpfc_function_mode_fcoe_t_WORD         function_mode
-#define lpfc_function_mode_dal_SHIFT           8
-#define lpfc_function_mode_dal_MASK            0x00000001
-#define lpfc_function_mode_dal_WORD            function_mode
-#define lpfc_function_mode_lro_SHIFT           9
-#define lpfc_function_mode_lro_MASK            0x00000001
-#define lpfc_function_mode_lro_WORD            function_mode
-#define lpfc_function_mode_flex10_SHIFT                10
-#define lpfc_function_mode_flex10_MASK         0x00000001
-#define lpfc_function_mode_flex10_WORD         function_mode
-#define lpfc_function_mode_ncsi_SHIFT          11
-#define lpfc_function_mode_ncsi_MASK           0x00000001
-#define lpfc_function_mode_ncsi_WORD           function_mode
-};
-
 /* Status field for embedded SLI_CONFIG mailbox command */
 #define STATUS_SUCCESS                                 0x0
 #define STATUS_FAILED                                  0x1
@@ -2965,7 +3003,7 @@ struct lpfc_mqe {
                struct lpfc_mbx_read_config rd_config;
                struct lpfc_mbx_request_features req_ftrs;
                struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
-               struct lpfc_mbx_query_fw_cfg query_fw_cfg;
+               struct lpfc_mbx_query_fw_config query_fw_cfg;
                struct lpfc_mbx_supp_pages supp_pages;
                struct lpfc_mbx_pc_sli4_params sli4_params;
                struct lpfc_mbx_get_sli4_parameters get_sli4_parameters;
index 5262049651eeca0e1928255a10896ad4340fd944..26ca2efa976e4654f8df87d89dcea52d1091bb27 100644 (file)
@@ -6233,9 +6233,11 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
                        phba->sli4_hba.conf_regs_memmap_p +
                                                LPFC_CTL_PORT_SEM_OFFSET;
                phba->sli4_hba.RQDBregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_ULP0_RQ_DOORBELL;
                phba->sli4_hba.WQDBregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_WQ_DOORBELL;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_ULP0_WQ_DOORBELL;
                phba->sli4_hba.EQCQDBregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
                phba->sli4_hba.MQDBregaddr =
@@ -6289,9 +6291,11 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
                return -ENODEV;
 
        phba->sli4_hba.RQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
-                               vf * LPFC_VFR_PAGE_SIZE + LPFC_RQ_DOORBELL);
+                               vf * LPFC_VFR_PAGE_SIZE +
+                                       LPFC_ULP0_RQ_DOORBELL);
        phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
-                               vf * LPFC_VFR_PAGE_SIZE + LPFC_WQ_DOORBELL);
+                               vf * LPFC_VFR_PAGE_SIZE +
+                                       LPFC_ULP0_WQ_DOORBELL);
        phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
                                vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL);
        phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
@@ -6987,6 +6991,19 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
                phba->sli4_hba.fcp_wq = NULL;
        }
 
+       if (phba->pci_bar0_memmap_p) {
+               iounmap(phba->pci_bar0_memmap_p);
+               phba->pci_bar0_memmap_p = NULL;
+       }
+       if (phba->pci_bar2_memmap_p) {
+               iounmap(phba->pci_bar2_memmap_p);
+               phba->pci_bar2_memmap_p = NULL;
+       }
+       if (phba->pci_bar4_memmap_p) {
+               iounmap(phba->pci_bar4_memmap_p);
+               phba->pci_bar4_memmap_p = NULL;
+       }
+
        /* Release FCP CQ mapping array */
        if (phba->sli4_hba.fcp_cq_map != NULL) {
                kfree(phba->sli4_hba.fcp_cq_map);
@@ -7050,6 +7067,53 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
        int rc = -ENOMEM;
        int fcp_eqidx, fcp_cqidx, fcp_wqidx;
        int fcp_cq_index = 0;
+       uint32_t shdr_status, shdr_add_status;
+       union lpfc_sli4_cfg_shdr *shdr;
+       LPFC_MBOXQ_t *mboxq;
+       uint32_t length;
+
+       /* Check for dual-ULP support */
+       mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3249 Unable to allocate memory for "
+                               "QUERY_FW_CFG mailbox command\n");
+               return -ENOMEM;
+       }
+       length = (sizeof(struct lpfc_mbx_query_fw_config) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_QUERY_FW_CFG,
+                        length, LPFC_SLI4_MBX_EMBED);
+
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+
+       shdr = (union lpfc_sli4_cfg_shdr *)
+                       &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (shdr_status || shdr_add_status || rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3250 QUERY_FW_CFG mailbox failed with status "
+                               "x%x add_status x%x, mbx status x%x\n",
+                               shdr_status, shdr_add_status, rc);
+               if (rc != MBX_TIMEOUT)
+                       mempool_free(mboxq, phba->mbox_mem_pool);
+               rc = -ENXIO;
+               goto out_error;
+       }
+
+       phba->sli4_hba.fw_func_mode =
+                       mboxq->u.mqe.un.query_fw_cfg.rsp.function_mode;
+       phba->sli4_hba.ulp0_mode = mboxq->u.mqe.un.query_fw_cfg.rsp.ulp0_mode;
+       phba->sli4_hba.ulp1_mode = mboxq->u.mqe.un.query_fw_cfg.rsp.ulp1_mode;
+       lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                       "3251 QUERY_FW_CFG: func_mode:x%x, ulp0_mode:x%x, "
+                       "ulp1_mode:x%x\n", phba->sli4_hba.fw_func_mode,
+                       phba->sli4_hba.ulp0_mode, phba->sli4_hba.ulp1_mode);
+
+       if (rc != MBX_TIMEOUT)
+               mempool_free(mboxq, phba->mbox_mem_pool);
 
        /*
         * Set up HBA Event Queues (EQs)
index c997b919b6fe5ad5f0a14f7af4f9c3d57584dc4c..0988b320d317c7f5c1b601dc59e78975a38332d0 100644 (file)
@@ -124,10 +124,17 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
 
        /* Ring Doorbell */
        doorbell.word0 = 0;
-       bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1);
-       bf_set(lpfc_wq_doorbell_index, &doorbell, host_index);
-       bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id);
-       writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr);
+       if (q->db_format == LPFC_DB_LIST_FORMAT) {
+               bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
+               bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index);
+               bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
+       } else if (q->db_format == LPFC_DB_RING_FORMAT) {
+               bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1);
+               bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id);
+       } else {
+               return -EINVAL;
+       }
+       writel(doorbell.word0, q->db_regaddr);
 
        return 0;
 }
@@ -456,10 +463,20 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
        /* Ring The Header Receive Queue Doorbell */
        if (!(hq->host_index % hq->entry_repost)) {
                doorbell.word0 = 0;
-               bf_set(lpfc_rq_doorbell_num_posted, &doorbell,
-                      hq->entry_repost);
-               bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id);
-               writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr);
+               if (hq->db_format == LPFC_DB_RING_FORMAT) {
+                       bf_set(lpfc_rq_db_ring_fm_num_posted, &doorbell,
+                              hq->entry_repost);
+                       bf_set(lpfc_rq_db_ring_fm_id, &doorbell, hq->queue_id);
+               } else if (hq->db_format == LPFC_DB_LIST_FORMAT) {
+                       bf_set(lpfc_rq_db_list_fm_num_posted, &doorbell,
+                              hq->entry_repost);
+                       bf_set(lpfc_rq_db_list_fm_index, &doorbell,
+                              hq->host_index);
+                       bf_set(lpfc_rq_db_list_fm_id, &doorbell, hq->queue_id);
+               } else {
+                       return -EINVAL;
+               }
+               writel(doorbell.word0, hq->db_regaddr);
        }
        return put_index;
 }
@@ -4939,7 +4956,7 @@ out_free_mboxq:
 static void
 lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
 {
-       uint8_t fcp_eqidx;
+       int fcp_eqidx;
 
        lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
        lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
@@ -11867,7 +11884,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
        struct lpfc_eqe *eqe;
        unsigned long iflag;
        int ecount = 0;
-       uint32_t fcp_eqidx;
+       int fcp_eqidx;
 
        /* Get the driver's phba structure from the dev_id */
        fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id;
@@ -11969,7 +11986,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id)
        struct lpfc_hba  *phba;
        irqreturn_t hba_irq_rc;
        bool hba_handled = false;
-       uint32_t fcp_eqidx;
+       int fcp_eqidx;
 
        /* Get the driver's phba structure from the dev_id */
        phba = (struct lpfc_hba *)dev_id;
@@ -12090,6 +12107,54 @@ out_fail:
        return NULL;
 }
 
+/**
+ * lpfc_dual_chute_pci_bar_map - Map pci base address register to host memory
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @pci_barset: PCI BAR set flag.
+ *
+ * This function shall perform iomap of the specified PCI BAR address to host
+ * memory address if not already done so and return it. The returned host
+ * memory address can be NULL.
+ */
+static void __iomem *
+lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
+{
+       struct pci_dev *pdev;
+       unsigned long bar_map, bar_map_len;
+
+       if (!phba->pcidev)
+               return NULL;
+       else
+               pdev = phba->pcidev;
+
+       switch (pci_barset) {
+       case WQ_PCI_BAR_0_AND_1:
+               if (!phba->pci_bar0_memmap_p) {
+                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR0);
+                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR0);
+                       phba->pci_bar0_memmap_p = ioremap(bar_map, bar_map_len);
+               }
+               return phba->pci_bar0_memmap_p;
+       case WQ_PCI_BAR_2_AND_3:
+               if (!phba->pci_bar2_memmap_p) {
+                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
+                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
+                       phba->pci_bar2_memmap_p = ioremap(bar_map, bar_map_len);
+               }
+               return phba->pci_bar2_memmap_p;
+       case WQ_PCI_BAR_4_AND_5:
+               if (!phba->pci_bar4_memmap_p) {
+                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
+                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
+                       phba->pci_bar4_memmap_p = ioremap(bar_map, bar_map_len);
+               }
+               return phba->pci_bar4_memmap_p;
+       default:
+               break;
+       }
+       return NULL;
+}
+
 /**
  * lpfc_modify_fcp_eq_delay - Modify Delay Multiplier on FCP EQs
  * @phba: HBA structure that indicates port to create a queue on.
@@ -12667,6 +12732,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
        union lpfc_sli4_cfg_shdr *shdr;
        uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
        struct dma_address *page;
+       void __iomem *bar_memmap_p;
+       uint32_t db_offset;
+       uint16_t pci_barset;
 
        /* sanity check on queue memory */
        if (!wq || !cq)
@@ -12690,6 +12758,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
                    cq->queue_id);
        bf_set(lpfc_mbox_hdr_version, &shdr->request,
               phba->sli4_hba.pc_sli4_params.wqv);
+
        if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) {
                bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
                       wq->entry_count);
@@ -12717,6 +12786,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
                page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys);
                page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys);
        }
+
+       if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
+               bf_set(lpfc_mbx_wq_create_dua, &wq_create->u.request, 1);
+
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
        /* The IOCTL status is embedded in the mailbox subheader. */
        shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
@@ -12734,6 +12807,47 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
                status = -ENXIO;
                goto out;
        }
+       if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
+               wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
+                                      &wq_create->u.response);
+               if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
+                   (wq->db_format != LPFC_DB_RING_FORMAT)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3265 WQ[%d] doorbell format not "
+                                       "supported: x%x\n", wq->queue_id,
+                                       wq->db_format);
+                       status = -EINVAL;
+                       goto out;
+               }
+               pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
+                                   &wq_create->u.response);
+               bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset);
+               if (!bar_memmap_p) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3263 WQ[%d] failed to memmap pci "
+                                       "barset:x%x\n", wq->queue_id,
+                                       pci_barset);
+                       status = -ENOMEM;
+                       goto out;
+               }
+               db_offset = wq_create->u.response.doorbell_offset;
+               if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
+                   (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3252 WQ[%d] doorbell offset not "
+                                       "supported: x%x\n", wq->queue_id,
+                                       db_offset);
+                       status = -EINVAL;
+                       goto out;
+               }
+               wq->db_regaddr = bar_memmap_p + db_offset;
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3264 WQ[%d]: barset:x%x, offset:x%x\n",
+                               wq->queue_id, pci_barset, db_offset);
+       } else {
+               wq->db_format = LPFC_DB_LIST_FORMAT;
+               wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
+       }
        wq->type = LPFC_WQ;
        wq->assoc_qid = cq->queue_id;
        wq->subtype = subtype;
@@ -12810,6 +12924,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
        uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+       void __iomem *bar_memmap_p;
+       uint32_t db_offset;
+       uint16_t pci_barset;
 
        /* sanity check on queue memory */
        if (!hrq || !drq || !cq)
@@ -12888,6 +13005,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
                rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
                                        putPaddrHigh(dmabuf->phys);
        }
+       if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
+               bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1);
+
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
        /* The IOCTL status is embedded in the mailbox subheader. */
        shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
@@ -12905,6 +13025,50 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
                status = -ENXIO;
                goto out;
        }
+
+       if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
+               hrq->db_format = bf_get(lpfc_mbx_rq_create_db_format,
+                                       &rq_create->u.response);
+               if ((hrq->db_format != LPFC_DB_LIST_FORMAT) &&
+                   (hrq->db_format != LPFC_DB_RING_FORMAT)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3262 RQ [%d] doorbell format not "
+                                       "supported: x%x\n", hrq->queue_id,
+                                       hrq->db_format);
+                       status = -EINVAL;
+                       goto out;
+               }
+
+               pci_barset = bf_get(lpfc_mbx_rq_create_bar_set,
+                                   &rq_create->u.response);
+               bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset);
+               if (!bar_memmap_p) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3269 RQ[%d] failed to memmap pci "
+                                       "barset:x%x\n", hrq->queue_id,
+                                       pci_barset);
+                       status = -ENOMEM;
+                       goto out;
+               }
+
+               db_offset = rq_create->u.response.doorbell_offset;
+               if ((db_offset != LPFC_ULP0_RQ_DOORBELL) &&
+                   (db_offset != LPFC_ULP1_RQ_DOORBELL)) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                       "3270 RQ[%d] doorbell offset not "
+                                       "supported: x%x\n", hrq->queue_id,
+                                       db_offset);
+                       status = -EINVAL;
+                       goto out;
+               }
+               hrq->db_regaddr = bar_memmap_p + db_offset;
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "3266 RQ[qid:%d]: barset:x%x, offset:x%x\n",
+                               hrq->queue_id, pci_barset, db_offset);
+       } else {
+               hrq->db_format = LPFC_DB_RING_FORMAT;
+               hrq->db_regaddr = phba->sli4_hba.RQDBregaddr;
+       }
        hrq->type = LPFC_HRQ;
        hrq->assoc_qid = cq->queue_id;
        hrq->subtype = subtype;
@@ -12970,6 +13134,8 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
                rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
                                        putPaddrHigh(dmabuf->phys);
        }
+       if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE)
+               bf_set(lpfc_mbx_rq_create_dua, &rq_create->u.request, 1);
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
        /* The IOCTL status is embedded in the mailbox subheader. */
        shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr;
index 44c427a45d664fce9089ca60cf5e03386707fbf5..be02b59ea2797a53972a1795dcd4b0b1c156a846 100644 (file)
@@ -139,6 +139,10 @@ struct lpfc_queue {
 
        struct lpfc_sli_ring *pring; /* ptr to io ring associated with q */
 
+       uint16_t db_format;
+#define LPFC_DB_RING_FORMAT    0x01
+#define LPFC_DB_LIST_FORMAT    0x02
+       void __iomem *db_regaddr;
        /* For q stats */
        uint32_t q_cnt_1;
        uint32_t q_cnt_2;
@@ -508,6 +512,10 @@ struct lpfc_sli4_hba {
        struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */
        struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */
 
+       uint8_t fw_func_mode;   /* FW function protocol mode */
+       uint32_t ulp0_mode;     /* ULP0 protocol mode */
+       uint32_t ulp1_mode;     /* ULP1 protocol mode */
+
        /* Setup information for various queue parameters */
        int eq_esize;
        int eq_ecount;