diff options
author | K. Y. Srinivasan <kys@microsoft.com> | 2011-11-08 17:01:50 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-11-27 01:02:08 (GMT) |
commit | b401731985bfa7c02e4e5673a151b29ae7180fce (patch) | |
tree | fc99743c8bd1a025d2031e860e7e4508715474af | |
parent | 126757998a50659f79a3f1ff23fccfc40ff1bf5c (diff) | |
download | linux-fsl-qoriq-b401731985bfa7c02e4e5673a151b29ae7180fce.tar.xz |
Staging: hv: storvsc: Support hot-removing of scsi devices
Support hot-removing of scsi devices.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/staging/hv/storvsc_drv.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index 7c82d14..0245143 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -328,6 +328,27 @@ static void storvsc_bus_scan(struct work_struct *work) kfree(wrk); } +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, 0, wrk->lun); + + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + scsi_host_put(wrk->host); + +done: + kfree(wrk); +} + static inline struct storvsc_device *get_out_stor_device( struct hv_device *device) { @@ -1112,6 +1133,7 @@ static void storvsc_command_completion(struct hv_storvsc_request *request) void (*scsi_done_fn)(struct scsi_cmnd *); struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; + struct storvsc_scan_work *wrk; vm_srb = &request->vstor_packet.vm_srb; if (cmd_request->bounce_sgl_count) { @@ -1134,6 +1156,29 @@ static void storvsc_command_completion(struct hv_storvsc_request *request) else scmnd->result = vm_srb->scsi_status; + /* + * If the LUN is invalid; remove the device. + */ + if (vm_srb->srb_status == 0x20) { + struct storvsc_device *stor_dev; + struct hv_device *dev = host_dev->dev; + struct Scsi_Host *host; + + stor_dev = get_in_stor_device(dev); + host = stor_dev->host; + + wrk = kmalloc(sizeof(struct storvsc_scan_work), + GFP_ATOMIC); + if (!wrk) { + scmnd->result = DID_TARGET_FAILURE << 16; + } else { + wrk->host = host; + wrk->lun = vm_srb->lun; + INIT_WORK(&wrk->work, storvsc_remove_lun); + schedule_work(&wrk->work); + } + } + if (scmnd->result) { if (scsi_normalize_sense(scmnd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) |