scsi: lpfc: Work around NVME cmd iu SGL type
authorJames Smart <jsmart2021@gmail.com>
Thu, 22 Feb 2018 16:18:50 +0000 (08:18 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 23 Feb 2018 01:39:29 +0000 (20:39 -0500)
The hardware offload for NVME commands was created when the
FC-NVME standard was setting SGL Descriptor Type to SGL Data
Block Descriptor (0h) and SGL Descriptor Sub Type to Address (0h).

A late change in NVMe-over-Fabrics obsoleted these values, creating
a transport SGL descriptor type with new values to go into these
fields.

For initial hardware support, in order to be compliant to the spec,
use host-supplied cmd IU buffers instead of the adapter generated
values. Later hardware will correct this.

Add a module parameter to override this offload disablement if looking
for lowest latency. This is reasonable as nothing in FC-NVME uses
the SQE SGL values.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_nvme.c
drivers/scsi/lpfc/lpfc_sli.c

index 9136a59..6c0d351 100644 (file)
@@ -782,6 +782,7 @@ struct lpfc_hba {
        uint32_t cfg_fcp_io_channel;
        uint32_t cfg_suppress_rsp;
        uint32_t cfg_nvme_oas;
+       uint32_t cfg_nvme_embed_cmd;
        uint32_t cfg_nvme_io_channel;
        uint32_t cfg_nvmet_mrq;
        uint32_t cfg_enable_nvmet;
index 14f6efc..46f6d97 100644 (file)
@@ -5042,6 +5042,18 @@ LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
             "Use OAS bit on NVME IOs");
 
 /*
+ * lpfc_nvme_embed_cmd: Use the oas bit when sending NVME/NVMET IOs
+ *
+ *      0  = Put NVME Command in SGL
+ *      1  = Embed NVME Command in WQE (unless G7)
+ *      2 =  Embed NVME Command in WQE (force)
+ *
+ * Value range is [0,2]. Default value is 1.
+ */
+LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
+            "Embed NVME Command in WQE");
+
+/*
  * lpfc_fcp_io_channel: Set the number of FCP IO channels the driver
  * will advertise it supports to the SCSI layer. This also will map to
  * the number of WQs the driver will create.
@@ -5282,6 +5294,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_task_mgmt_tmo,
        &dev_attr_lpfc_use_msi,
        &dev_attr_lpfc_nvme_oas,
+       &dev_attr_lpfc_nvme_embed_cmd,
        &dev_attr_lpfc_auto_imax,
        &dev_attr_lpfc_fcp_imax,
        &dev_attr_lpfc_fcp_cpu_map,
@@ -6306,6 +6319,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
        lpfc_use_msi_init(phba, lpfc_use_msi);
        lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
+       lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd);
        lpfc_auto_imax_init(phba, lpfc_auto_imax);
        lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
        lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
index ed5e870..37c547b 100644 (file)
@@ -2678,6 +2678,7 @@ struct lpfc_mbx_read_rev {
 #define lpfc_mbx_rd_rev_vpd_MASK               0x00000001
 #define lpfc_mbx_rd_rev_vpd_WORD               word1
        uint32_t first_hw_rev;
+#define LPFC_G7_ASIC_1                         0xd
        uint32_t second_hw_rev;
        uint32_t word4_rsvd;
        uint32_t third_hw_rev;
index ecb42ca..50bc6c6 100644 (file)
@@ -10653,11 +10653,11 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                phba->fcp_embed_io = 0;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
-                       "6422 XIB %d: FCP %d %d NVME %d %d %d\n",
+                       "6422 XIB %d: FCP %d %d NVME %d %d %d %d\n",
                        bf_get(cfg_xib, mbx_sli4_parameters),
                        phba->fcp_embed_pbde, phba->fcp_embed_io,
                        phba->nvme_support, phba->nvme_embed_pbde,
-                       phba->cfg_suppress_rsp);
+                       phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp);
 
        if ((bf_get(cfg_cqpsize, mbx_sli4_parameters) & LPFC_CQ_16K_PAGE_SZ) &&
            (bf_get(cfg_wqpsize, mbx_sli4_parameters) & LPFC_WQ_16K_PAGE_SZ) &&
index c75958d..6ea6cc3 100644 (file)
@@ -617,11 +617,21 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
                       struct lpfc_nvme_buf *lpfc_ncmd,
                       struct nvmefc_fcp_req *nCmd)
 {
+       struct lpfc_hba  *phba = vport->phba;
        struct sli4_sge *sgl;
        union lpfc_wqe128 *wqe;
        uint32_t *wptr, *dptr;
 
        /*
+        * Get a local pointer to the built-in wqe and correct
+        * the cmd size to match NVME's 96 bytes and fix
+        * the dma address.
+        */
+
+       /* 128 byte wqe support here */
+       wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
+
+       /*
         * Adjust the FCP_CMD and FCP_RSP DMA data and sge_len to
         * match NVME.  NVME sends 96 bytes. Also, use the
         * nvme commands command and response dma addresses
@@ -630,6 +640,25 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
         */
        sgl = lpfc_ncmd->nvme_sgl;
        sgl->sge_len = cpu_to_le32(nCmd->cmdlen);
+       if (phba->cfg_nvme_embed_cmd) {
+               sgl->addr_hi = 0;
+               sgl->addr_lo = 0;
+
+               /* Word 0-2 - NVME CMND IU (embedded payload) */
+               wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
+               wqe->generic.bde.tus.f.bdeSize = 56;
+               wqe->generic.bde.addrHigh = 0;
+               wqe->generic.bde.addrLow =  64;  /* Word 16 */
+       } else {
+               sgl->addr_hi = cpu_to_le32(putPaddrHigh(nCmd->cmddma));
+               sgl->addr_lo = cpu_to_le32(putPaddrLow(nCmd->cmddma));
+
+               /* Word 0-2 - NVME CMND IU Inline BDE */
+               wqe->generic.bde.tus.f.bdeFlags =  BUFF_TYPE_BDE_64;
+               wqe->generic.bde.tus.f.bdeSize = nCmd->cmdlen;
+               wqe->generic.bde.addrHigh = sgl->addr_hi;
+               wqe->generic.bde.addrLow =  sgl->addr_lo;
+       }
 
        sgl++;
 
@@ -644,27 +673,19 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
        sgl->word2 = cpu_to_le32(sgl->word2);
        sgl->sge_len = cpu_to_le32(nCmd->rsplen);
 
-       /*
-        * Get a local pointer to the built-in wqe and correct
-        * the cmd size to match NVME's 96 bytes and fix
-        * the dma address.
-        */
-
-       /* 128 byte wqe support here */
-       wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
-
-       /* Word 0-2 - NVME CMND IU (embedded payload) */
-       wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
-       wqe->generic.bde.tus.f.bdeSize = 56;
-       wqe->generic.bde.addrHigh = 0;
-       wqe->generic.bde.addrLow =  64;  /* Word 16 */
-
        /* Word 3 */
        bf_set(payload_offset_len, &wqe->fcp_icmd,
               (nCmd->rsplen + nCmd->cmdlen));
 
        /* Word 10 */
        bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1);
+
+       if (!phba->cfg_nvme_embed_cmd) {
+               bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
+               bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 0);
+               return;
+       }
+       bf_set(wqe_dbde, &wqe->generic.wqe_com, 0);
        bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
 
        /*
index 416ba8f..4ce3ca6 100644 (file)
@@ -6880,6 +6880,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
        /* Save information as VPD data */
        phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
        phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
+
+       /*
+        * This is because first G7 ASIC doesn't support the standard
+        * 0x5a NVME cmd descriptor type/subtype
+        */
+       if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+                       LPFC_SLI_INTF_IF_TYPE_6) &&
+           (phba->vpd.rev.biuRev == LPFC_G7_ASIC_1) &&
+           (phba->vpd.rev.smRev == 0) &&
+           (phba->cfg_nvme_embed_cmd == 1))
+               phba->cfg_nvme_embed_cmd = 0;
+
        phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
        phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
                                         &mqe->un.read_rev);
@@ -9096,6 +9108,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                        wqe128->generic.bde.addrLow =  88;  /* Word 22 */
 
                        bf_set(wqe_wqes, &wqe128->fcp_iwrite.wqe_com, 1);
+                       bf_set(wqe_dbde, &wqe128->fcp_iwrite.wqe_com, 0);
 
                        /* Word 22-29  FCP CMND Payload */
                        ptr = &wqe128->words[22];
@@ -9161,6 +9174,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                        wqe128->generic.bde.addrLow =  88;  /* Word 22 */
 
                        bf_set(wqe_wqes, &wqe128->fcp_iread.wqe_com, 1);
+                       bf_set(wqe_dbde, &wqe128->fcp_iread.wqe_com, 0);
 
                        /* Word 22-29  FCP CMND Payload */
                        ptr = &wqe128->words[22];
@@ -9219,6 +9233,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                        wqe128->generic.bde.addrLow =  88;  /* Word 22 */
 
                        bf_set(wqe_wqes, &wqe128->fcp_icmd.wqe_com, 1);
+                       bf_set(wqe_dbde, &wqe128->fcp_icmd.wqe_com, 0);
 
                        /* Word 22-29  FCP CMND Payload */
                        ptr = &wqe128->words[22];