summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Tee <justin.tee@broadcom.com>2024-04-30 01:15:45 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2024-05-07 04:53:58 +0300
commitaf20bb73ac2591631d504f3f859f073bcdb7e11e (patch)
tree27476189c4cc54aad0d4ae0c56b197469b8bb29d
parente780c9423b1095ae9d96ce8fdbe2a92592d88073 (diff)
downloadlinux-af20bb73ac2591631d504f3f859f073bcdb7e11e.tar.xz
scsi: lpfc: Add support for 32 byte CDBs
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>
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c57
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h30
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c12
5 files changed, 80 insertions, 38 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 367e6b066d42..500253007b1d 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -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;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 10e8b8479ad9..e1dfa96c2a55 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -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) {
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f1255e7c0445..98ce9d97a225 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -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;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index eae56944f31b..e034a48124f5 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -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 */
};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7f373c0b7eb5..f475e7ece41a 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -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);