Skip to content

Commit 1e46731

Browse files
Mahesh Rajashekharamartinkpetersen
authored andcommitted
scsi: smartpqi: check for null device pointers
- wait on all outstanding I/O to complete before the device is removed. - check for null device pointers in IO entry/completion functions. Reviewed-by: Scott Teel <scott.teel@microsemi.com> Reviewed-by: Murthy Bhat <murthy.bhat@microsemi.com> Reviewed-by: Dave Carroll <david.carroll@microsemi.com> Reviewed-by: Kevin Barnett <kevin.barnett@microsemi.com> Signed-off-by: Mahesh Rajashekhara <mahesh.rajashekhara@microsemi.com> Signed-off-by: Don Brace <don.brace@microsemi.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent c1b1047 commit 1e46731

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

drivers/scsi/smartpqi/smartpqi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ struct pqi_scsi_dev {
862862
u8 volume_offline : 1;
863863
bool aio_enabled; /* only valid for physical disks */
864864
bool in_reset;
865+
bool in_remove;
865866
bool device_offline;
866867
u8 vendor[8]; /* bytes 8-15 of inquiry data */
867868
u8 model[16]; /* bytes 16-31 of inquiry data */
@@ -1063,6 +1064,7 @@ struct pqi_ctrl_info {
10631064
struct mutex lun_reset_mutex;
10641065
bool controller_online;
10651066
bool block_requests;
1067+
bool in_shutdown;
10661068
u8 inbound_spanning_supported : 1;
10671069
u8 outbound_spanning_supported : 1;
10681070
u8 pqi_mode_enabled : 1;

drivers/scsi/smartpqi/smartpqi_init.c

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
7474
struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
7575
unsigned int cdb_length, struct pqi_queue_group *queue_group,
7676
struct pqi_encryption_info *encryption_info, bool raid_bypass);
77+
static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
78+
struct pqi_scsi_dev *device, unsigned long timeout_secs);
7779

7880
/* for flags argument to pqi_submit_raid_request_synchronous() */
7981
#define PQI_SYNC_FLAGS_INTERRUPTABLE 0x1
@@ -317,6 +319,17 @@ static inline bool pqi_device_in_reset(struct pqi_scsi_dev *device)
317319
return device->in_reset;
318320
}
319321

322+
static inline void pqi_device_remove_start(struct pqi_scsi_dev *device)
323+
{
324+
device->in_remove = true;
325+
}
326+
327+
static inline bool pqi_device_in_remove(struct pqi_ctrl_info *ctrl_info,
328+
struct pqi_scsi_dev *device)
329+
{
330+
return device->in_remove & !ctrl_info->in_shutdown;
331+
}
332+
320333
static inline void pqi_schedule_rescan_worker_with_delay(
321334
struct pqi_ctrl_info *ctrl_info, unsigned long delay)
322335
{
@@ -1487,9 +1500,24 @@ static int pqi_add_device(struct pqi_ctrl_info *ctrl_info,
14871500
return rc;
14881501
}
14891502

1503+
#define PQI_PENDING_IO_TIMEOUT_SECS 20
1504+
14901505
static inline void pqi_remove_device(struct pqi_ctrl_info *ctrl_info,
14911506
struct pqi_scsi_dev *device)
14921507
{
1508+
int rc;
1509+
1510+
pqi_device_remove_start(device);
1511+
1512+
rc = pqi_device_wait_for_pending_io(ctrl_info, device,
1513+
PQI_PENDING_IO_TIMEOUT_SECS);
1514+
if (rc)
1515+
dev_err(&ctrl_info->pci_dev->dev,
1516+
"scsi %d:%d:%d:%d removing device with %d outstanding commands\n",
1517+
ctrl_info->scsi_host->host_no, device->bus,
1518+
device->target, device->lun,
1519+
atomic_read(&device->scsi_cmds_outstanding));
1520+
14931521
if (pqi_is_logical_device(device))
14941522
scsi_remove_device(device->sdev);
14951523
else
@@ -5042,7 +5070,17 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
50425070
{
50435071
struct pqi_scsi_dev *device;
50445072

5073+
if (!scmd->device) {
5074+
set_host_byte(scmd, DID_NO_CONNECT);
5075+
return;
5076+
}
5077+
50455078
device = scmd->device->hostdata;
5079+
if (!device) {
5080+
set_host_byte(scmd, DID_NO_CONNECT);
5081+
return;
5082+
}
5083+
50465084
atomic_dec(&device->scsi_cmds_outstanding);
50475085
}
50485086

@@ -5059,9 +5097,16 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost,
50595097
device = scmd->device->hostdata;
50605098
ctrl_info = shost_to_hba(shost);
50615099

5100+
if (!device) {
5101+
set_host_byte(scmd, DID_NO_CONNECT);
5102+
pqi_scsi_done(scmd);
5103+
return 0;
5104+
}
5105+
50625106
atomic_inc(&device->scsi_cmds_outstanding);
50635107

5064-
if (pqi_ctrl_offline(ctrl_info)) {
5108+
if (pqi_ctrl_offline(ctrl_info) || pqi_device_in_remove(ctrl_info,
5109+
device)) {
50655110
set_host_byte(scmd, DID_NO_CONNECT);
50665111
pqi_scsi_done(scmd);
50675112
return 0;
@@ -5214,12 +5259,23 @@ static void pqi_fail_io_queued_for_device(struct pqi_ctrl_info *ctrl_info,
52145259
}
52155260

52165261
static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
5217-
struct pqi_scsi_dev *device)
5262+
struct pqi_scsi_dev *device, unsigned long timeout_secs)
52185263
{
5264+
unsigned long timeout;
5265+
5266+
timeout = (timeout_secs * HZ) + jiffies;
5267+
52195268
while (atomic_read(&device->scsi_cmds_outstanding)) {
52205269
pqi_check_ctrl_health(ctrl_info);
52215270
if (pqi_ctrl_offline(ctrl_info))
52225271
return -ENXIO;
5272+
if (timeout_secs != NO_TIMEOUT) {
5273+
if (time_after(jiffies, timeout)) {
5274+
dev_err(&ctrl_info->pci_dev->dev,
5275+
"timed out waiting for pending IO\n");
5276+
return -ETIMEDOUT;
5277+
}
5278+
}
52235279
usleep_range(1000, 2000);
52245280
}
52255281

@@ -5345,7 +5401,8 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
53455401
msleep(PQI_LUN_RESET_RETRY_INTERVAL_MSECS);
53465402
}
53475403
if (rc == 0)
5348-
rc = pqi_device_wait_for_pending_io(ctrl_info, device);
5404+
rc = pqi_device_wait_for_pending_io(ctrl_info,
5405+
device, NO_TIMEOUT);
53495406

53505407
return rc == 0 ? SUCCESS : FAILED;
53515408
}
@@ -7188,6 +7245,8 @@ static void pqi_pci_remove(struct pci_dev *pci_dev)
71887245
if (!ctrl_info)
71897246
return;
71907247

7248+
ctrl_info->in_shutdown = true;
7249+
71917250
pqi_remove_ctrl(ctrl_info);
71927251
}
71937252

0 commit comments

Comments
 (0)