]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: pmcraid: Select device in pmcraid_eh_bus_reset_handler()
authorHannes Reinecke <hare@suse.de>
Mon, 2 Oct 2023 15:43:26 +0000 (17:43 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 13 Oct 2023 18:23:15 +0000 (14:23 -0400)
The reset code requires a device to be selected, but we shouldn't rely on
the command to provide a device for us. So select the first device on the
bus when sending down a bus reset.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Link: https://lore.kernel.org/r/20231002154328.43718-17-hare@suse.de
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/pmcraid.c

index 50dc30051f221f537332ee3022d4d746b3108ae9..d7a331255e7188229662ee1a481a549d41af4629 100644 (file)
@@ -2691,7 +2691,7 @@ static int pmcraid_error_handler(struct pmcraid_cmd *cmd)
  *     SUCCESS / FAILED
  */
 static int pmcraid_reset_device(
-       struct scsi_cmnd *scsi_cmd,
+       struct scsi_device *scsi_dev,
        unsigned long timeout,
        u8 modifier)
 {
@@ -2703,11 +2703,11 @@ static int pmcraid_reset_device(
        u32 ioasc;
 
        pinstance =
-               (struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
-       res = scsi_cmd->device->hostdata;
+               (struct pmcraid_instance *)scsi_dev->host->hostdata;
+       res = scsi_dev->hostdata;
 
        if (!res) {
-               sdev_printk(KERN_ERR, scsi_cmd->device,
+               sdev_printk(KERN_ERR, scsi_dev,
                            "reset_device: NULL resource pointer\n");
                return FAILED;
        }
@@ -3018,16 +3018,46 @@ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
 {
        scmd_printk(KERN_INFO, scmd,
                    "resetting device due to an I/O command timeout.\n");
-       return pmcraid_reset_device(scmd,
+       return pmcraid_reset_device(scmd->device,
                                    PMCRAID_INTERNAL_TIMEOUT,
                                    RESET_DEVICE_LUN);
 }
 
 static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)
 {
-       scmd_printk(KERN_INFO, scmd,
+       struct Scsi_Host *host = scmd->device->host;
+       struct pmcraid_instance *pinstance =
+               (struct pmcraid_instance *)host->hostdata;
+       struct pmcraid_resource_entry *res = NULL;
+       struct pmcraid_resource_entry *temp;
+       struct scsi_device *sdev = NULL;
+       unsigned long lock_flags;
+
+       /*
+        * The reset device code insists on us passing down
+        * a device, so grab the first device on the bus.
+        */
+       spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
+       list_for_each_entry(temp, &pinstance->used_res_q, queue) {
+               if (scmd->device->channel == PMCRAID_VSET_BUS_ID &&
+                   RES_IS_VSET(temp->cfg_entry)) {
+                       res = temp;
+                       break;
+               } else if (scmd->device->channel == PMCRAID_PHYS_BUS_ID &&
+                          RES_IS_GSCSI(temp->cfg_entry)) {
+                       res = temp;
+                       break;
+               }
+       }
+       if (res)
+               sdev = res->scsi_dev;
+       spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags);
+       if (!sdev)
+               return FAILED;
+
+       sdev_printk(KERN_INFO, sdev,
                    "Doing bus reset due to an I/O command timeout.\n");
-       return pmcraid_reset_device(scmd,
+       return pmcraid_reset_device(sdev,
                                    PMCRAID_RESET_BUS_TIMEOUT,
                                    RESET_DEVICE_BUS);
 }
@@ -3036,7 +3066,7 @@ static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
 {
        scmd_printk(KERN_INFO, scmd,
                    "Doing target reset due to an I/O command timeout.\n");
-       return pmcraid_reset_device(scmd,
+       return pmcraid_reset_device(scmd->device,
                                    PMCRAID_INTERNAL_TIMEOUT,
                                    RESET_DEVICE_TARGET);
 }