scsi: lpfc: Add support for 32 byte CDBs
authorJustin Tee <justin.tee@broadcom.com>
Mon, 29 Apr 2024 22:15:45 +0000 (15:15 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 7 May 2024 01:53:58 +0000 (21:53 -0400)
The driver's I/O path is updated to support 32 byte CDBs.

Changes to accommodate 32 byte CDBs include:

 - Updating various size fields to allow for the larger 32 byte CDB.

 - Starting the FCP command payload at an earlier offset in WQE submission
   to fit the 32 byte CDB.

 - Redefining relevant structs to __le32/__be32 data types for proper cpu
   endianness macro usage.

Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Link: https://lore.kernel.org/r/20240429221547.6842-7-justintee8345@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c

index 367e6b066d42f95d6b4d0cbd9e7ba0875083f894..500253007b1dc866f589fc1852b7503c991be326 100644 (file)
@@ -2146,6 +2146,14 @@ struct sli4_sge {        /* SLI-4 */
        uint32_t sge_len;
 };
 
+struct sli4_sge_le {
+       __le32 addr_hi;
+       __le32 addr_lo;
+
+       __le32 word2;
+       __le32 sge_len;
+};
+
 struct sli4_hybrid_sgl {
        struct list_head list_node;
        struct sli4_sge *dma_sgl;
index 10e8b8479ad9aec767da50e94eedf447f398cec7..e1dfa96c2a553a51b123c7a53814d1288922106d 100644 (file)
@@ -4773,7 +4773,10 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        shost->max_id = LPFC_MAX_TARGET;
        shost->max_lun = vport->cfg_max_luns;
        shost->this_id = -1;
-       shost->max_cmd_len = 16;
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               shost->max_cmd_len = LPFC_FCP_CDB_LEN_32;
+       else
+               shost->max_cmd_len = LPFC_FCP_CDB_LEN;
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
                if (!phba->cfg_fcp_mq_threshold ||
@@ -8231,7 +8234,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                 * our max amount and we need to limit lpfc_sg_seg_cnt
                 * to minimize the risk of running out.
                 */
-               phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+               phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd32) +
                                sizeof(struct fcp_rsp) + max_buf_size;
 
                /* Total SGEs for scsi_sg_list and scsi_sg_prot_list */
@@ -8253,7 +8256,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                 * the FCP rsp, a SGE for each, and a SGE for up to
                 * cfg_sg_seg_cnt data segments.
                 */
-               phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
+               phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd32) +
                                sizeof(struct fcp_rsp) +
                                ((phba->cfg_sg_seg_cnt + extra) *
                                sizeof(struct sli4_sge));
@@ -8316,7 +8319,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        phba->lpfc_cmd_rsp_buf_pool =
                        dma_pool_create("lpfc_cmd_rsp_buf_pool",
                                        &phba->pcidev->dev,
-                                       sizeof(struct fcp_cmnd) +
+                                       sizeof(struct fcp_cmnd32) +
                                        sizeof(struct fcp_rsp),
                                        i, 0);
        if (!phba->lpfc_cmd_rsp_buf_pool) {
index f1255e7c0445a840fe1f53285572c218808bbbfb..98ce9d97a225703fdd060d35b27151795aa9e17d 100644 (file)
@@ -600,7 +600,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
 {
        struct lpfc_io_buf *lpfc_cmd;
        struct lpfc_sli4_hdw_queue *qp;
-       struct sli4_sge *sgl;
+       struct sli4_sge_le *sgl;
        dma_addr_t pdma_phys_fcp_rsp;
        dma_addr_t pdma_phys_fcp_cmd;
        uint32_t cpu, idx;
@@ -651,23 +651,23 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
         * The balance are sg list bdes. Initialize the
         * first two and leave the rest for queuecommand.
         */
-       sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl;
+       sgl = (struct sli4_sge_le *)lpfc_cmd->dma_sgl;
        pdma_phys_fcp_cmd = tmp->fcp_cmd_rsp_dma_handle;
        sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd));
        sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd));
-       sgl->word2 = le32_to_cpu(sgl->word2);
-       bf_set(lpfc_sli4_sge_last, sgl, 0);
-       sgl->word2 = cpu_to_le32(sgl->word2);
-       sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd));
+       bf_set_le32(lpfc_sli4_sge_last, sgl, 0);
+       if (cmnd && cmnd->cmd_len > LPFC_FCP_CDB_LEN)
+               sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd32));
+       else
+               sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd));
+
        sgl++;
 
        /* Setup the physical region for the FCP RSP */
-       pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd);
+       pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd32);
        sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp));
        sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp));
-       sgl->word2 = le32_to_cpu(sgl->word2);
-       bf_set(lpfc_sli4_sge_last, sgl, 1);
-       sgl->word2 = cpu_to_le32(sgl->word2);
+       bf_set_le32(lpfc_sli4_sge_last, sgl, 1);
        sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp));
 
        if (lpfc_ndlp_check_qdepth(phba, ndlp)) {
@@ -2608,7 +2608,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba,
        iocb_cmd->ulpLe = 1;
 
        fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
-       fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
+       fcp_cmnd->fcpDl = cpu_to_be32(fcpdl);
 
        /*
         * Due to difference in data length between DIF/non-DIF paths,
@@ -3225,14 +3225,18 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
         * explicitly reinitialized.
         * all iocb memory resources are reused.
         */
-       fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
+       if (scsi_cmnd->cmd_len > LPFC_FCP_CDB_LEN)
+               ((struct fcp_cmnd32 *)fcp_cmnd)->fcpDl =
+                               cpu_to_be32(scsi_bufflen(scsi_cmnd));
+       else
+               fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
        /* Set first-burst provided it was successfully negotiated */
        if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag) &&
            vport->cfg_first_burst_size &&
            scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) {
                u32 init_len, total_len;
 
-               total_len = be32_to_cpu(fcp_cmnd->fcpDl);
+               total_len = scsi_bufflen(scsi_cmnd);
                init_len = min(total_len, vport->cfg_first_burst_size);
 
                /* Word 4 & 5 */
@@ -3420,7 +3424,10 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
        }
 
        fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
-       fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
+       if (lpfc_cmd->pCmd->cmd_len > LPFC_FCP_CDB_LEN)
+               ((struct fcp_cmnd32 *)fcp_cmnd)->fcpDl = cpu_to_be32(fcpdl);
+       else
+               fcp_cmnd->fcpDl = cpu_to_be32(fcpdl);
 
        /* Set first-burst provided it was successfully negotiated */
        if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag) &&
@@ -3428,7 +3435,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
            scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) {
                u32 init_len, total_len;
 
-               total_len = be32_to_cpu(fcp_cmnd->fcpDl);
+               total_len = fcpdl;
                init_len = min(total_len, vport->cfg_first_burst_size);
 
                /* Word 4 & 5 */
@@ -3436,8 +3443,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
                wqe->fcp_iwrite.total_xfer_len = total_len;
        } else {
                /* Word 4 */
-               wqe->fcp_iwrite.total_xfer_len =
-                       be32_to_cpu(fcp_cmnd->fcpDl);
+               wqe->fcp_iwrite.total_xfer_len = fcpdl;
        }
 
        /*
@@ -3894,7 +3900,10 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd,
                         fcprsp->rspInfo3);
 
        scsi_set_resid(cmnd, 0);
-       fcpDl = be32_to_cpu(fcpcmd->fcpDl);
+       if (cmnd->cmd_len > LPFC_FCP_CDB_LEN)
+               fcpDl = be32_to_cpu(((struct fcp_cmnd32 *)fcpcmd)->fcpDl);
+       else
+               fcpDl = be32_to_cpu(fcpcmd->fcpDl);
        if (resp_info & RESID_UNDER) {
                scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
@@ -4723,6 +4732,14 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport,
                                bf_set(wqe_iod, &wqe->fcp_iread.wqe_com,
                                       LPFC_WQE_IOD_NONE);
                }
+
+               /* Additional fcp cdb length field calculation.
+                * LPFC_FCP_CDB_LEN_32 - normal 16 byte cdb length,
+                * then divide by 4 for the word count.
+                * shift 2 because of the RDDATA/WRDATA.
+                */
+               if (scsi_cmnd->cmd_len > LPFC_FCP_CDB_LEN)
+                       fcp_cmnd->fcpCntl3 |= 4 << 2;
        } else {
                /* From the icmnd template, initialize words 4 - 11 */
                memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4],
@@ -4743,7 +4760,7 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport,
 
         /* Word 3 */
        bf_set(payload_offset_len, &wqe->fcp_icmd,
-              sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp));
+              sizeof(struct fcp_cmnd32) + sizeof(struct fcp_rsp));
 
        /* Word 6 */
        bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com,
@@ -4798,7 +4815,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd,
        int_to_scsilun(lpfc_cmd->pCmd->device->lun,
                       &lpfc_cmd->fcp_cmnd->fcp_lun);
 
-       ptr = &fcp_cmnd->fcpCdb[0];
+       ptr = &((struct fcp_cmnd32 *)fcp_cmnd)->fcpCdb[0];
        memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
        if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) {
                ptr += scsi_cmnd->cmd_len;
index eae56944f31b59ff972ba3c5299dca2d0ee268b2..e034a48124f570f7ce004a837fab027c4be75751 100644 (file)
@@ -24,6 +24,7 @@
 
 struct lpfc_hba;
 #define LPFC_FCP_CDB_LEN 16
+#define LPFC_FCP_CDB_LEN_32 32
 
 #define list_remove_head(list, entry, type, member)            \
        do {                                                    \
@@ -99,17 +100,11 @@ struct fcp_rsp {
 #define SNSCOD_BADCMD 0x20     /* sense code is byte 13 ([12]) */
 };
 
-struct fcp_cmnd {
-       struct scsi_lun  fcp_lun;
-
-       uint8_t fcpCntl0;       /* FCP_CNTL byte 0 (reserved) */
-       uint8_t fcpCntl1;       /* FCP_CNTL byte 1 task codes */
 #define  SIMPLE_Q        0x00
 #define  HEAD_OF_Q       0x01
 #define  ORDERED_Q       0x02
 #define  ACA_Q           0x04
 #define  UNTAGGED        0x05
-       uint8_t fcpCntl2;       /* FCP_CTL byte 2 task management codes */
 #define  FCP_ABORT_TASK_SET  0x02      /* Bit 1 */
 #define  FCP_CLEAR_TASK_SET  0x04      /* bit 2 */
 #define  FCP_BUS_RESET       0x08      /* bit 3 */
@@ -117,12 +112,31 @@ struct fcp_cmnd {
 #define  FCP_TARGET_RESET    0x20      /* bit 5 */
 #define  FCP_CLEAR_ACA       0x40      /* bit 6 */
 #define  FCP_TERMINATE_TASK  0x80      /* bit 7 */
-       uint8_t fcpCntl3;
 #define  WRITE_DATA      0x01  /* Bit 0 */
 #define  READ_DATA       0x02  /* Bit 1 */
 
+struct fcp_cmnd {
+       struct scsi_lun  fcp_lun;
+
+       uint8_t fcpCntl0;       /* FCP_CNTL byte 0 (reserved) */
+       uint8_t fcpCntl1;       /* FCP_CNTL byte 1 task codes */
+       uint8_t fcpCntl2;       /* FCP_CTL byte 2 task management codes */
+       uint8_t fcpCntl3;
+
        uint8_t fcpCdb[LPFC_FCP_CDB_LEN]; /* SRB cdb field is copied here */
-       uint32_t fcpDl;         /* Total transfer length */
+       __be32 fcpDl;           /* Total transfer length */
+
+};
+struct fcp_cmnd32 {
+       struct scsi_lun  fcp_lun;
+
+       uint8_t fcpCntl0;       /* FCP_CNTL byte 0 (reserved) */
+       uint8_t fcpCntl1;       /* FCP_CNTL byte 1 task codes */
+       uint8_t fcpCntl2;       /* FCP_CTL byte 2 task management codes */
+       uint8_t fcpCntl3;
+
+       uint8_t fcpCdb[LPFC_FCP_CDB_LEN_32]; /* SRB cdb field is copied here */
+       __be32 fcpDl;           /* Total transfer length */
 
 };
 
index 7f373c0b7eb5933d6bdd8ae1d18e18e470be8d17..f475e7ece41a4fe9389bad543269c749c95c6591 100644 (file)
@@ -10595,18 +10595,18 @@ lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
                        BUFF_TYPE_BDE_IMMED;
                wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
                wqe->generic.bde.addrHigh = 0;
-               wqe->generic.bde.addrLow =  88;  /* Word 22 */
+               wqe->generic.bde.addrLow =  72;  /* Word 18 */
 
                bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
                bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
 
-               /* Word 22-29  FCP CMND Payload */
-               ptr = &wqe->words[22];
-               memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
+               /* Word 18-29  FCP CMND Payload */
+               ptr = &wqe->words[18];
+               memcpy(ptr, fcp_cmnd, sgl->sge_len);
        } else {
                /* Word 0-2 - Inline BDE */
                wqe->generic.bde.tus.f.bdeFlags =  BUFF_TYPE_BDE_64;
-               wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd);
+               wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
                wqe->generic.bde.addrHigh = sgl->addr_hi;
                wqe->generic.bde.addrLow =  sgl->addr_lo;
 
@@ -22469,7 +22469,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
                }
 
                tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd +
-                               sizeof(struct fcp_cmnd));
+                               sizeof(struct fcp_cmnd32));
 
                spin_lock_irqsave(&hdwq->hdwq_lock, iflags);
                list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list);