Skip to content

Commit 0bb97f2

Browse files
jsmart-ghgregkh
authored andcommitted
scsi: lpfc: Fix FCP I/O flush functionality for TMF routines
commit cd8a36a upstream. A prior patch inadvertently caused lpfc_sli_sum_iocb() to exclude counting of outstanding aborted I/Os and ABORT IOCBs. Thus, lpfc_reset_flush_io_context() called from any TMF routine does not properly wait to flush all outstanding FCP IOCBs leading to a block layer crash on an invalid scsi_cmnd->request pointer. kernel BUG at ../block/blk-core.c:1489! RIP: 0010:blk_requeue_request+0xaf/0xc0 ... Call Trace: <IRQ> __scsi_queue_insert+0x90/0xe0 [scsi_mod] blk_done_softirq+0x7e/0x90 __do_softirq+0xd2/0x280 irq_exit+0xd5/0xe0 do_IRQ+0x4c/0xd0 common_interrupt+0x87/0x87 </IRQ> Fix by separating out the LPFC_IO_FCP, LPFC_IO_ON_TXCMPLQ, LPFC_DRIVER_ABORTED, and CMD_ABORT_XRI_CN || CMD_CLOSE_XRI_CN checks into a new lpfc_sli_validate_fcp_iocb_for_abort() routine when determining to build an ABORT iocb. Restore lpfc_reset_flush_io_context() functionality by including counting of outstanding aborted IOCBs and ABORT IOCBs in lpfc_sli_sum_iocb(). Link: https://lore.kernel.org/r/[email protected] Fixes: e136471 ("scsi: lpfc: Fix illegal memory access on Abort IOCBs") Cc: <[email protected]> # v5.12+ Co-developed-by: Justin Tee <[email protected]> Signed-off-by: Justin Tee <[email protected]> Signed-off-by: James Smart <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bea230d commit 0bb97f2

File tree

1 file changed

+78
-23
lines changed

1 file changed

+78
-23
lines changed

drivers/scsi/lpfc/lpfc_sli.c

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12488,15 +12488,54 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
1248812488
}
1248912489

1249012490
/**
12491-
* lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN
12491+
* lpfc_sli_validate_fcp_iocb_for_abort - filter iocbs appropriate for FCP aborts
12492+
* @iocbq: Pointer to iocb object.
12493+
* @vport: Pointer to driver virtual port object.
12494+
*
12495+
* This function acts as an iocb filter for functions which abort FCP iocbs.
12496+
*
12497+
* Return values
12498+
* -ENODEV, if a null iocb or vport ptr is encountered
12499+
* -EINVAL, if the iocb is not an FCP I/O, not on the TX cmpl queue, premarked as
12500+
* driver already started the abort process, or is an abort iocb itself
12501+
* 0, passes criteria for aborting the FCP I/O iocb
12502+
**/
12503+
static int
12504+
lpfc_sli_validate_fcp_iocb_for_abort(struct lpfc_iocbq *iocbq,
12505+
struct lpfc_vport *vport)
12506+
{
12507+
IOCB_t *icmd = NULL;
12508+
12509+
/* No null ptr vports */
12510+
if (!iocbq || iocbq->vport != vport)
12511+
return -ENODEV;
12512+
12513+
/* iocb must be for FCP IO, already exists on the TX cmpl queue,
12514+
* can't be premarked as driver aborted, nor be an ABORT iocb itself
12515+
*/
12516+
icmd = &iocbq->iocb;
12517+
if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
12518+
!(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) ||
12519+
(iocbq->iocb_flag & LPFC_DRIVER_ABORTED) ||
12520+
(icmd->ulpCommand == CMD_ABORT_XRI_CN ||
12521+
icmd->ulpCommand == CMD_CLOSE_XRI_CN))
12522+
return -EINVAL;
12523+
12524+
return 0;
12525+
}
12526+
12527+
/**
12528+
* lpfc_sli_validate_fcp_iocb - validate commands associated with a SCSI target
1249212529
* @iocbq: Pointer to driver iocb object.
1249312530
* @vport: Pointer to driver virtual port object.
1249412531
* @tgt_id: SCSI ID of the target.
1249512532
* @lun_id: LUN ID of the scsi device.
1249612533
* @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST
1249712534
*
12498-
* This function acts as an iocb filter for functions which abort or count
12499-
* all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return
12535+
* This function acts as an iocb filter for validating a lun/SCSI target/SCSI
12536+
* host.
12537+
*
12538+
* It will return
1250012539
* 0 if the filtering criteria is met for the given iocb and will return
1250112540
* 1 if the filtering criteria is not met.
1250212541
* If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the
@@ -12515,22 +12554,8 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
1251512554
lpfc_ctx_cmd ctx_cmd)
1251612555
{
1251712556
struct lpfc_io_buf *lpfc_cmd;
12518-
IOCB_t *icmd = NULL;
1251912557
int rc = 1;
1252012558

12521-
if (!iocbq || iocbq->vport != vport)
12522-
return rc;
12523-
12524-
if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
12525-
!(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) ||
12526-
iocbq->iocb_flag & LPFC_DRIVER_ABORTED)
12527-
return rc;
12528-
12529-
icmd = &iocbq->iocb;
12530-
if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
12531-
icmd->ulpCommand == CMD_CLOSE_XRI_CN)
12532-
return rc;
12533-
1253412559
lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq);
1253512560

1253612561
if (lpfc_cmd->pCmd == NULL)
@@ -12585,17 +12610,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
1258512610
{
1258612611
struct lpfc_hba *phba = vport->phba;
1258712612
struct lpfc_iocbq *iocbq;
12613+
IOCB_t *icmd = NULL;
1258812614
int sum, i;
12615+
unsigned long iflags;
1258912616

12590-
spin_lock_irq(&phba->hbalock);
12617+
spin_lock_irqsave(&phba->hbalock, iflags);
1259112618
for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
1259212619
iocbq = phba->sli.iocbq_lookup[i];
1259312620

12594-
if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id,
12595-
ctx_cmd) == 0)
12621+
if (!iocbq || iocbq->vport != vport)
12622+
continue;
12623+
if (!(iocbq->iocb_flag & LPFC_IO_FCP) ||
12624+
!(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ))
12625+
continue;
12626+
12627+
/* Include counting outstanding aborts */
12628+
icmd = &iocbq->iocb;
12629+
if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
12630+
icmd->ulpCommand == CMD_CLOSE_XRI_CN) {
12631+
sum++;
12632+
continue;
12633+
}
12634+
12635+
if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
12636+
ctx_cmd) == 0)
1259612637
sum++;
1259712638
}
12598-
spin_unlock_irq(&phba->hbalock);
12639+
spin_unlock_irqrestore(&phba->hbalock, iflags);
1259912640

1260012641
return sum;
1260112642
}
@@ -12662,7 +12703,11 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1266212703
*
1266312704
* This function sends an abort command for every SCSI command
1266412705
* associated with the given virtual port pending on the ring
12665-
* filtered by lpfc_sli_validate_fcp_iocb function.
12706+
* filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
12707+
* lpfc_sli_validate_fcp_iocb function. The ordering for validation before
12708+
* submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
12709+
* followed by lpfc_sli_validate_fcp_iocb.
12710+
*
1266612711
* When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the
1266712712
* FCP iocbs associated with lun specified by tgt_id and lun_id
1266812713
* parameters
@@ -12694,6 +12739,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id,
1269412739
for (i = 1; i <= phba->sli.last_iotag; i++) {
1269512740
iocbq = phba->sli.iocbq_lookup[i];
1269612741

12742+
if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
12743+
continue;
12744+
1269712745
if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
1269812746
abort_cmd) != 0)
1269912747
continue;
@@ -12726,7 +12774,11 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id,
1272612774
*
1272712775
* This function sends an abort command for every SCSI command
1272812776
* associated with the given virtual port pending on the ring
12729-
* filtered by lpfc_sli_validate_fcp_iocb function.
12777+
* filtered by lpfc_sli_validate_fcp_iocb_for_abort and then
12778+
* lpfc_sli_validate_fcp_iocb function. The ordering for validation before
12779+
* submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort
12780+
* followed by lpfc_sli_validate_fcp_iocb.
12781+
*
1273012782
* When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the
1273112783
* FCP iocbs associated with lun specified by tgt_id and lun_id
1273212784
* parameters
@@ -12764,6 +12816,9 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
1276412816
for (i = 1; i <= phba->sli.last_iotag; i++) {
1276512817
iocbq = phba->sli.iocbq_lookup[i];
1276612818

12819+
if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport))
12820+
continue;
12821+
1276712822
if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
1276812823
cmd) != 0)
1276912824
continue;

0 commit comments

Comments
 (0)