Staging: hv: storvsc: Support hot-removing of scsi devices
authorK. Y. Srinivasan <kys@microsoft.com>
Tue, 8 Nov 2011 17:01:50 +0000 (09:01 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sun, 27 Nov 2011 01:02:08 +0000 (17:02 -0800)
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>
drivers/staging/hv/storvsc_drv.c

index 7c82d148f32e5d3b9c607b16faba0bdee61ef8ed..0245143dc2f993a989a33723641cc76994431a34 100644 (file)
@@ -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))