aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSreekanth Reddy <sreekanth.reddy@broadcom.com>2019-03-04 07:26:35 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2019-03-25 21:53:48 -0400
commitc2fe742ff6e77c5b4fe4ad273191ddf28fdea25e (patch)
treef322051c55b6274f6b155e51e26eb3690e539536
parent7f5203c13ba8a7b7f9f6ecfe5a4d5567188d7835 (diff)
scsi: mpt3sas: Fix kernel panic during expander reset
During expander reset handling, the driver invokes kernel function scsi_host_find_tag() to obtain outstanding requests associated with the scsi host managed by the driver. Driver loops from tag value zero to hba queue depth to obtain the outstanding scmds. But when blk-mq is enabled, the block layer may return stale entry for one or more requests. This may lead to kernel panic if the returned value is inaccessible or the memory pointed by the returned value is reused. Reference of upstream discussion: https://patchwork.kernel.org/patch/10734933/ Instead of calling scsi_host_find_tag() API for each and every smid (smid is tag +1) from one to shost->can_queue, now driver will call this API (to obtain the outstanding scmd) only for those smid's which are outstanding at the driver level. Driver will determine whether this smid is outstanding at driver level by looking into it's corresponding MPI request frame, if its MPI request frame is empty, then it means that this smid is free and does not need to call scsi_host_find_tag() for it. By doing this, driver will invoke scsi_host_find_tag() for only those tags which are outstanding at the driver level. Driver will check whether particular MPI request frame is empty or not by looking into the "DevHandle" field. If this field is zero then it means that this MPI request is empty. For active MPI request DevHandle must be non-zero. Also driver will memset the MPI request frame once the corresponding scmd is processed (i.e. just before calling scmd->done function). Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c6
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c12
2 files changed, 18 insertions, 0 deletions
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index e57774472e75..1d8c584ec1e9 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -3281,12 +3281,18 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
3281 3281
3282 if (smid < ioc->hi_priority_smid) { 3282 if (smid < ioc->hi_priority_smid) {
3283 struct scsiio_tracker *st; 3283 struct scsiio_tracker *st;
3284 void *request;
3284 3285
3285 st = _get_st_from_smid(ioc, smid); 3286 st = _get_st_from_smid(ioc, smid);
3286 if (!st) { 3287 if (!st) {
3287 _base_recovery_check(ioc); 3288 _base_recovery_check(ioc);
3288 return; 3289 return;
3289 } 3290 }
3291
3292 /* Clear MPI request frame */
3293 request = mpt3sas_base_get_msg_frame(ioc, smid);
3294 memset(request, 0, ioc->request_sz);
3295
3290 mpt3sas_base_clear_st(ioc, st); 3296 mpt3sas_base_clear_st(ioc, st);
3291 _base_recovery_check(ioc); 3297 _base_recovery_check(ioc);
3292 return; 3298 return;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 8bb5b8f9f4d2..1ccfbc7eebe0 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1462,11 +1462,23 @@ mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
1462{ 1462{
1463 struct scsi_cmnd *scmd = NULL; 1463 struct scsi_cmnd *scmd = NULL;
1464 struct scsiio_tracker *st; 1464 struct scsiio_tracker *st;
1465 Mpi25SCSIIORequest_t *mpi_request;
1465 1466
1466 if (smid > 0 && 1467 if (smid > 0 &&
1467 smid <= ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT) { 1468 smid <= ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT) {
1468 u32 unique_tag = smid - 1; 1469 u32 unique_tag = smid - 1;
1469 1470
1471 mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
1472
1473 /*
1474 * If SCSI IO request is outstanding at driver level then
1475 * DevHandle filed must be non-zero. If DevHandle is zero
1476 * then it means that this smid is free at driver level,
1477 * so return NULL.
1478 */
1479 if (!mpi_request->DevHandle)
1480 return scmd;
1481
1470 scmd = scsi_host_find_tag(ioc->shost, unique_tag); 1482 scmd = scsi_host_find_tag(ioc->shost, unique_tag);
1471 if (scmd) { 1483 if (scmd) {
1472 st = scsi_cmd_priv(scmd); 1484 st = scsi_cmd_priv(scmd);