This is the main part. This patch implements a function
scsi_resurrect_device() which puts a sdev in state SDEV_CANCEL
back into SDEV_RUNNING.
So during scan any device in state SDEV_DEL (ie waiting to be
deleted) will be put back into SDEV_RUNNING and normal scanning
can continue on these devices. Of course there is a high likelyhood
that the device will drop back into SDEV_DEL afterwards, but it is
perfectly useable during the scan operation.
For this to work I actually had to modify the allowed state
transitions, as it's now perfectly possible to move back from
SDEV_DEL into SDEV_CANCEL.

Signed-off-by: Hannes Reinecke <[EMAIL PROTECTED]>
---
 drivers/scsi/scsi.c      |    3 ++
 drivers/scsi/scsi_lib.c  |    2 +
 drivers/scsi/scsi_scan.c |   52 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 56 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 4c1e313..11f0f0d 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -950,6 +950,9 @@ struct scsi_device *scsi_device_lookup_b
 
        spin_lock_irqsave(shost->host_lock, flags);
        sdev = __scsi_device_lookup_by_target(starget, lun);
+       /* This triggers a resurrection of the sdev */
+       if (sdev && sdev->sdev_state == SDEV_DEL)
+               scsi_device_set_state(sdev, SDEV_CANCEL);
        if (sdev && scsi_device_get(sdev))
                sdev = NULL;
        spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1f5a07b..4288572 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1945,6 +1945,7 @@ scsi_device_set_state(struct scsi_device
                case SDEV_OFFLINE:
                case SDEV_QUIESCE:
                case SDEV_BLOCK:
+               case SDEV_CANCEL:
                        break;
                default:
                        goto illegal;
@@ -1990,6 +1991,7 @@ scsi_device_set_state(struct scsi_device
                case SDEV_QUIESCE:
                case SDEV_OFFLINE:
                case SDEV_BLOCK:
+               case SDEV_DEL:
                        break;
                default:
                        goto illegal;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 2653015..75b8a78 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -698,7 +698,7 @@ static int scsi_probe_lun(struct scsi_de
  * Description:
  *    Configure an existing scsi_device. This function
  *    elevates a scsi_device from state SDEV_CREATED or
- *    SDEV_DEL into SDEV_RUNNING.
+ *    SDEV_CANCEL into SDEV_RUNNING.
  *
  * Return:
  *    0  On Success
@@ -723,6 +723,49 @@ int scsi_configure_device(struct scsi_de
 }
 
 /**
+ * scsi_resurrect_device - resurrect a deleted scsi_device
+ * @sdev:      The scsi_device to resurrect
+ *
+ * Description:
+ *    Elevate a deleted scsi_device back to SDEV_RUNNING.
+ *    A deleted scsi_device (ie in state SDEV_DEL) is only
+ *    deleted from the internal list when the ->release
+ *    function of the corresponding kobj structure is called.
+ *    Until that time it will stay visible to the host.
+ *    Whenever a scan has been initiated we thus have to
+ *    put this device back to SDEV_RUNNING and proceed
+ *    as with normal sdevs. It might be dropping back to
+ *    SDEV_DEL after scanning is completed, but is perfectly
+ *    useable during that time.
+ *
+ * Return:
+ *    0  On Success
+ *    <0 On failure.
+ *
+ **/
+int scsi_resurrect_device(struct scsi_device *sdev)
+{
+       int ret = 0;
+
+       /* Ignore devices not in state SDEV_CANCEL */
+       if (sdev->sdev_state != SDEV_CANCEL)
+               return 0;
+
+       ret = scsi_configure_device(sdev);
+       if (ret) {
+               scsi_destroy_device(sdev);
+               return ret;
+       }
+
+       /*
+        * Ok, the device is now all set up, we can
+        * register it and tell the rest of the kernel
+        * about it.
+        */
+       return scsi_sysfs_add_sdev(sdev);
+}
+
+/**
  * scsi_add_lun - allocate and fully initialze a scsi_device
  * @sdevscan:  holds information to be stored in the new scsi_device
  * @sdevnew:   store the address of the newly allocated scsi_device
@@ -1002,6 +1045,10 @@ static int scsi_probe_and_add_lun(struct
         */
        sdev = scsi_device_lookup_by_target(starget, lun);
        if (sdev) {
+               if (scsi_resurrect_device(sdev)) {
+                       scsi_device_put(sdev);
+                       return SCSI_SCAN_NO_RESPONSE;
+               }
                if (rescan || sdev->sdev_state != SDEV_CREATED) {
                        SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
                                "scsi scan: device exists on %s\n",
@@ -1319,6 +1366,9 @@ static int scsi_report_lun_scan(struct s
                        return 0;
                if (scsi_device_get(sdev))
                        return 0;
+       } else if (scsi_resurrect_device(sdev)) {
+               scsi_device_put(sdev);
+               return 0;
        }
 
        sprintf(devname, "host %d channel %d id %d",
-- 
1.4.3.4

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to