From: Justin Tee <justintee8345@gmail.com>
To: linux-scsi@vger.kernel.org
Cc: jsmart833426@gmail.com, justin.tee@broadcom.com,
Justin Tee <justintee8345@gmail.com>
Subject: [PATCH 06/10] lpfc: Update construction of SGL when XPSGL is enabled
Date: Tue, 31 Mar 2026 13:59:24 -0700 [thread overview]
Message-ID: <20260331205928.119833-7-justintee8345@gmail.com> (raw)
In-Reply-To: <20260331205928.119833-1-justintee8345@gmail.com>
The construction of SGLs is updated to safeguard ASIC boundary
requirements when using XPSGL.
The LSP type SGE is used to notify where a continuing SGL resides.
Typically, this means that the LSP is the last SGE in an SGL because the
current SGL has reached its maximum size and the LSP is used to refer to
the next follow up SGL. Due to ASIC boundary requirements, there is a need
to ensure a 4 KB boundary is not crossed. Thus, for a maximum size of 256
byte SGLs or 16 SGEs, this means restricting the LSP to being the 12th SGE
for the very first SGL that is used for pre-registration. If additional
SGEs are needed, the LSP will be the last SGE position within that follow
up SGL as was previously implemented.
Signed-off-by: Justin Tee <justintee8345@gmail.com>
---
drivers/scsi/lpfc/lpfc_nvme.c | 30 ++++++----
drivers/scsi/lpfc/lpfc_scsi.c | 103 ++++++++++++++++++++++------------
2 files changed, 87 insertions(+), 46 deletions(-)
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 81b8fe69f2bc..71714ea390d9 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -1339,7 +1339,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
dma_addr_t physaddr = 0;
uint32_t dma_len = 0;
uint32_t dma_offset = 0;
- int nseg, i, j;
+ int nseg, i, j, k;
bool lsp_just_set = false;
/* Fix up the command and response DMA stuff. */
@@ -1379,6 +1379,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
/* for tracking the segment boundaries */
j = 2;
+ k = 5;
+ if (unlikely(!phba->cfg_xpsgl))
+ k = 1;
for (i = 0; i < nseg; i++) {
if (data_sg == NULL) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
@@ -1397,9 +1400,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
bf_set(lpfc_sli4_sge_last, sgl, 0);
/* expand the segment */
- if (!lsp_just_set &&
- !((j + 1) % phba->border_sge_num) &&
- ((nseg - 1) != i)) {
+ if (!lsp_just_set && (nseg != (i + k)) &&
+ !((j + k) % phba->border_sge_num)) {
/* set LSP type */
bf_set(lpfc_sli4_sge_type, sgl,
LPFC_SGE_TYPE_LSP);
@@ -1422,8 +1424,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
}
}
- if (!(bf_get(lpfc_sli4_sge_type, sgl) &
- LPFC_SGE_TYPE_LSP)) {
+ if (bf_get(lpfc_sli4_sge_type, sgl) !=
+ LPFC_SGE_TYPE_LSP) {
if ((nseg - 1) == i)
bf_set(lpfc_sli4_sge_last, sgl, 1);
@@ -1444,19 +1446,25 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
sgl++;
lsp_just_set = false;
+ j++;
} else {
sgl->word2 = cpu_to_le32(sgl->word2);
-
- sgl->sge_len = cpu_to_le32(
- phba->cfg_sg_dma_buf_size);
+ /* will remaining SGEs fill the next SGL? */
+ if ((nseg - i) < phba->border_sge_num)
+ sgl->sge_len =
+ cpu_to_le32((nseg - i) *
+ sizeof(*sgl));
+ else
+ sgl->sge_len =
+ cpu_to_le32(phba->cfg_sg_dma_buf_size);
sgl = (struct sli4_sge *)sgl_xtra->dma_sgl;
i = i - 1;
lsp_just_set = true;
+ j += k;
+ k = 1;
}
-
- j++;
}
} else {
lpfc_ncmd->seg_cnt = 0;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f11f2c29db89..1dce33b79beb 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1938,7 +1938,7 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t dma_len;
uint32_t dma_offset = 0;
struct sli4_hybrid_sgl *sgl_xtra = NULL;
- int j;
+ int j, k;
bool lsp_just_set = false;
status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
@@ -2001,13 +2001,16 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* assumption: caller has already run dma_map_sg on command data */
sgde = scsi_sglist(sc);
j = 3;
+ k = 5;
+ if (unlikely(!phba->cfg_xpsgl))
+ k = 1;
for (i = 0; i < datasegcnt; i++) {
/* clear it */
sgl->word2 = 0;
- /* do we need to expand the segment */
- if (!lsp_just_set && !((j + 1) % phba->border_sge_num) &&
- ((datasegcnt - 1) != i)) {
+ /* do we need to expand the segment? */
+ if (!lsp_just_set && (datasegcnt != (i + k)) &&
+ !((j + k) % phba->border_sge_num)) {
/* set LSP type */
bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP);
@@ -2026,7 +2029,7 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
}
- if (!(bf_get(lpfc_sli4_sge_type, sgl) & LPFC_SGE_TYPE_LSP)) {
+ if (bf_get(lpfc_sli4_sge_type, sgl) != LPFC_SGE_TYPE_LSP) {
if ((datasegcnt - 1) == i)
bf_set(lpfc_sli4_sge_last, sgl, 1);
physaddr = sg_dma_address(sgde);
@@ -2043,20 +2046,23 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
sgl++;
num_sge++;
+ j++;
lsp_just_set = false;
-
} else {
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size);
-
+ /* will remaining SGEs fill the next SGL? */
+ if ((datasegcnt - i) < phba->border_sge_num)
+ sgl->sge_len = cpu_to_le32((datasegcnt - i) *
+ sizeof(*sgl));
+ else
+ sgl->sge_len =
+ cpu_to_le32(phba->cfg_sg_dma_buf_size);
sgl = (struct sli4_sge *)sgl_xtra->dma_sgl;
i = i - 1;
-
+ j += k;
lsp_just_set = true;
+ k = 1;
}
-
- j++;
-
}
out:
@@ -2109,6 +2115,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct scatterlist *sgde = NULL; /* s/g data entry */
struct scatterlist *sgpe = NULL; /* s/g prot entry */
struct sli4_sge_diseed *diseed = NULL;
+ struct sli4_sge_le *lsp_sgl = NULL;
dma_addr_t dataphysaddr, protphysaddr;
unsigned short curr_prot = 0;
unsigned int split_offset;
@@ -2125,8 +2132,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t rc;
#endif
uint32_t checking = 1;
- uint32_t dma_offset = 0, num_sge = 0;
- int j = 2;
+ uint32_t dma_offset = 0, num_sge = 0, lsp_len;
+ int j = 2, k = 4;
struct sli4_hybrid_sgl *sgl_xtra = NULL;
sgpe = scsi_prot_sglist(sc);
@@ -2157,6 +2164,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
}
#endif
+ if (unlikely(!phba->cfg_xpsgl))
+ k = 0;
split_offset = 0;
do {
/* Check to see if we ran out of space */
@@ -2164,10 +2173,10 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
!(phba->cfg_xpsgl))
return num_sge + 3;
- /* DISEED and DIF have to be together */
- if (!((j + 1) % phba->border_sge_num) ||
- !((j + 2) % phba->border_sge_num) ||
- !((j + 3) % phba->border_sge_num)) {
+ /* DISEED and DIF have to be together */
+ if (!((j + k + 1) % phba->border_sge_num) ||
+ !((j + k + 2) % phba->border_sge_num) ||
+ !((j + k + 3) % phba->border_sge_num)) {
sgl->word2 = 0;
/* set LSP type */
@@ -2186,9 +2195,18 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
sgl->word2 = cpu_to_le32(sgl->word2);
sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size);
+ if (lsp_sgl) {
+ j++;
+ if (j % phba->border_sge_num) {
+ lsp_len = j * (sizeof(*sgl));
+ lsp_sgl->sge_len = cpu_to_le32(lsp_len);
+ }
+ }
+ lsp_sgl = (struct sli4_sge_le *)sgl;
sgl = (struct sli4_sge *)sgl_xtra->dma_sgl;
j = 0;
+ k = 0;
}
/* setup DISEED with what we have */
@@ -2291,7 +2309,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
return 0;
}
- if (!((j + 1) % phba->border_sge_num)) {
+ if (!((j + k + 1) % phba->border_sge_num)) {
sgl->word2 = 0;
/* set LSP type */
@@ -2313,8 +2331,11 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
sgl->word2 = cpu_to_le32(sgl->word2);
sgl->sge_len = cpu_to_le32(
phba->cfg_sg_dma_buf_size);
+ lsp_sgl = (struct sli4_sge_le *)sgl;
sgl = (struct sli4_sge *)sgl_xtra->dma_sgl;
+ j = 0;
+ k = 0;
} else {
dataphysaddr = sg_dma_address(sgde) +
split_offset;
@@ -2362,11 +2383,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* Move to the next s/g segment if possible */
sgde = sg_next(sgde);
-
sgl++;
+ j++;
}
-
- j++;
}
if (protgroup_offset) {
@@ -2381,6 +2400,14 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
sgl--;
bf_set(lpfc_sli4_sge_last, sgl, 1);
alldone = 1;
+
+ /* Reset length in previous LSP where necessary */
+ if (lsp_sgl) {
+ if (j % phba->border_sge_num) {
+ lsp_len = j * (sizeof(*sgl));
+ lsp_sgl->sge_len = cpu_to_le32(lsp_len);
+ }
+ }
} else if (curr_prot < protcnt) {
/* advance to next prot buffer */
sgpe = sg_next(sgpe);
@@ -2392,7 +2419,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"9085 BLKGRD: bug in %s\n", __func__);
}
-
} while (!alldone);
out:
@@ -3056,7 +3082,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
dma_addr_t physaddr;
uint32_t dma_len;
uint32_t dma_offset = 0;
- int nseg, i, j;
+ int nseg, i, j, k;
bool lsp_just_set = false;
struct sli4_hybrid_sgl *sgl_xtra = NULL;
@@ -3111,6 +3137,9 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
/* for tracking segment boundaries */
sgel = scsi_sglist(scsi_cmnd);
j = 2;
+ k = 5;
+ if (unlikely(!phba->cfg_xpsgl))
+ k = 1;
for (i = 0; i < nseg; i++) {
sgl->word2 = 0;
if (nseg == 1) {
@@ -3121,9 +3150,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
bf_set(lpfc_sli4_sge_last, sgl, 0);
/* do we need to expand the segment */
- if (!lsp_just_set &&
- !((j + 1) % phba->border_sge_num) &&
- ((nseg - 1) != i)) {
+ if (!lsp_just_set && (nseg != (i + k)) &&
+ !((j + k) % phba->border_sge_num)) {
/* set LSP type */
bf_set(lpfc_sli4_sge_type, sgl,
LPFC_SGE_TYPE_LSP);
@@ -3147,8 +3175,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
}
}
- if (!(bf_get(lpfc_sli4_sge_type, sgl) &
- LPFC_SGE_TYPE_LSP)) {
+ if (bf_get(lpfc_sli4_sge_type, sgl) !=
+ LPFC_SGE_TYPE_LSP) {
if ((nseg - 1) == i)
bf_set(lpfc_sli4_sge_last, sgl, 1);
@@ -3168,19 +3196,24 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
sgl++;
lsp_just_set = false;
-
+ j++;
} else {
sgl->word2 = cpu_to_le32(sgl->word2);
- sgl->sge_len = cpu_to_le32(
- phba->cfg_sg_dma_buf_size);
-
+ /* will remaining SGEs fill the next SGL? */
+ if ((nseg - i) < phba->border_sge_num)
+ sgl->sge_len =
+ cpu_to_le32((nseg - i) *
+ sizeof(*sgl));
+ else
+ sgl->sge_len =
+ cpu_to_le32(phba->cfg_sg_dma_buf_size);
sgl = (struct sli4_sge *)sgl_xtra->dma_sgl;
i = i - 1;
lsp_just_set = true;
+ j += k;
+ k = 1;
}
-
- j++;
}
} else {
sgl += 1;
--
2.38.0
next prev parent reply other threads:[~2026-03-31 20:23 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 20:59 [PATCH 00/10] Update lpfc to revision 15.0.0.0 Justin Tee
2026-03-31 20:59 ` [PATCH 01/10] lpfc: Break out of IRQ affinity assignment when mask reaches nr_cpu_ids Justin Tee
2026-03-31 20:59 ` [PATCH 02/10] lpfc: Select mailbox rq_create cmd version based on sli4 if_type Justin Tee
2026-03-31 20:59 ` [PATCH 03/10] lpfc: Log mcqe contents for mbox commands with no context Justin Tee
2026-03-31 20:59 ` [PATCH 04/10] lpfc: Add REG_VFI mailbox cmd error handling Justin Tee
2026-03-31 20:59 ` [PATCH 05/10] lpfc: Remove deprecated PBDE feature Justin Tee
2026-03-31 20:59 ` Justin Tee [this message]
2026-03-31 20:59 ` [PATCH 07/10] lpfc: Check ASIC_ID register to aid diagnostics during failed fw updates Justin Tee
2026-03-31 20:59 ` [PATCH 08/10] lpfc: Introduce 128G link speed selection and support Justin Tee
2026-03-31 20:59 ` [PATCH 09/10] lpfc: Add PCI ID support for LPe42100 series adapters Justin Tee
2026-03-31 20:59 ` [PATCH 10/10] lpfc: Update lpfc version to 15.0.0.0 Justin Tee
2026-04-03 1:37 ` [PATCH 00/10] Update lpfc to revision 15.0.0.0 Martin K. Petersen
2026-04-09 2:43 ` Martin K. Petersen
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=20260331205928.119833-7-justintee8345@gmail.com \
--to=justintee8345@gmail.com \
--cc=jsmart833426@gmail.com \
--cc=justin.tee@broadcom.com \
--cc=linux-scsi@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox