@@ -478,6 +478,7 @@ struct hv_host_device {
struct storvsc_scan_work {
struct work_struct work;
struct Scsi_Host *host;
+ struct scsi_device *sdev;
u8 lun;
u8 tgt_id;
};
@@ -531,24 +532,20 @@ static void storvsc_host_scan(struct work_struct *work)
kfree(wrk);
}
+/*
+ * On Entry we have a reference on both the host and the device.
+ * Drop them here.
+ */
static void storvsc_remove_lun(struct work_struct *work)
{
struct storvsc_scan_work *wrk;
- struct scsi_device *sdev;
wrk = container_of(work, struct storvsc_scan_work, work);
- if (!scsi_host_get(wrk->host))
- goto done;
-
- sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
- if (sdev) {
- scsi_remove_device(sdev);
- scsi_device_put(sdev);
- }
+ scsi_remove_device(wrk->sdev);
+ scsi_device_put(wrk->sdev);
scsi_host_put(wrk->host);
-done:
kfree(wrk);
}
@@ -885,6 +882,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
struct storvsc_scan_work *wrk;
void (*process_err_fn)(struct work_struct *work);
bool do_work = false;
+ struct scsi_device *sdev;
switch (SRB_STATUS(vm_srb->srb_status)) {
case SRB_STATUS_ERROR:
@@ -911,9 +909,23 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
}
break;
case SRB_STATUS_INVALID_LUN:
+ if (!scsi_host_get(host))
+ goto host_not_known;
+
+ sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
+
+ if (!sdev)
+ goto lun_not_known;
+
do_work = true;
process_err_fn = storvsc_remove_lun;
break;
+
+lun_not_known:
+ scsi_host_put(host);
+host_not_known:
+ set_host_byte(scmnd, DID_NO_CONNECT);
+ break;
case SRB_STATUS_ABORTED:
if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID &&
(asc == 0x2a) && (ascq == 0x9)) {
@@ -939,6 +951,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
return;
}
+ wrk->sdev = sdev;
wrk->host = host;
wrk->lun = vm_srb->lun;
wrk->tgt_id = vm_srb->target_id;