linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / scsi / scsi_scan.c
index 1a5474b..f9ecc3d 100644 (file)
@@ -205,11 +205,12 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        int display_failure_msg = 1, ret;
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 
-       sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
+       sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
                       GFP_ATOMIC);
        if (!sdev)
                goto out;
 
+       memset(sdev, 0, sizeof(*sdev));
        sdev->vendor = scsi_null_device_strs;
        sdev->model = scsi_null_device_strs;
        sdev->rev = scsi_null_device_strs;
@@ -251,7 +252,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                /* release fn is set up in scsi_sysfs_device_initialise, so
                 * have to free and put manually here */
                put_device(&starget->dev);
-               kfree(sdev);
                goto out;
        }
 
@@ -288,7 +288,10 @@ static void scsi_target_dev_release(struct device *dev)
 {
        struct device *parent = dev->parent;
        struct scsi_target *starget = to_scsi_target(dev);
+       struct Scsi_Host *shost = dev_to_shost(parent);
 
+       if (shost->hostt->target_destroy)
+               shost->hostt->target_destroy(starget);
        kfree(starget);
        put_device(parent);
 }
@@ -330,13 +333,13 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
                + shost->transportt->target_size;
        struct scsi_target *starget;
        struct scsi_target *found_target;
-       int error;
 
-       starget = kzalloc(size, GFP_KERNEL);
+       starget = kmalloc(size, GFP_KERNEL);
        if (!starget) {
                printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
                return NULL;
        }
+       memset(starget, 0, size);
        dev = &starget->dev;
        device_initialize(dev);
        starget->reap_ref = 1;
@@ -348,8 +351,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        starget->channel = channel;
        INIT_LIST_HEAD(&starget->siblings);
        INIT_LIST_HEAD(&starget->devices);
-       starget->state = STARGET_RUNNING;
- retry:
        spin_lock_irqsave(shost->host_lock, flags);
 
        found_target = __scsi_find_target(parent, channel, id);
@@ -360,20 +361,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        spin_unlock_irqrestore(shost->host_lock, flags);
        /* allocate and add */
        transport_setup_device(dev);
-       error = device_add(dev);
-       if (error) {
-               dev_err(dev, "target device_add failed, error %d\n", error);
-               spin_lock_irqsave(shost->host_lock, flags);
-               list_del_init(&starget->siblings);
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               transport_destroy_device(dev);
-               put_device(parent);
-               kfree(starget);
-               return NULL;
-       }
+       device_add(dev);
        transport_add_device(dev);
        if (shost->hostt->target_alloc) {
-               error = shost->hostt->target_alloc(starget);
+               int error = shost->hostt->target_alloc(starget);
 
                if(error) {
                        dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
@@ -392,15 +383,8 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        found_target->reap_ref++;
        spin_unlock_irqrestore(shost->host_lock, flags);
        put_device(parent);
-       if (found_target->state != STARGET_DEL) {
-               kfree(starget);
-               return found_target;
-       }
-       /* Unfortunately, we found a dying target; need to
-        * wait until it's dead before we can get a new one */
-       put_device(&found_target->dev);
-       flush_scheduled_work();
-       goto retry;
+       kfree(starget);
+       return found_target;
 }
 
 static void scsi_target_reap_usercontext(void *data)
@@ -409,15 +393,21 @@ static void scsi_target_reap_usercontext(void *data)
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
 
-       transport_remove_device(&starget->dev);
-       device_del(&starget->dev);
-       transport_destroy_device(&starget->dev);
        spin_lock_irqsave(shost->host_lock, flags);
-       if (shost->hostt->target_destroy)
-               shost->hostt->target_destroy(starget);
-       list_del_init(&starget->siblings);
+
+       if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
+               list_del_init(&starget->siblings);
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               transport_remove_device(&starget->dev);
+               device_del(&starget->dev);
+               transport_destroy_device(&starget->dev);
+               put_device(&starget->dev);
+               return;
+
+       }
        spin_unlock_irqrestore(shost->host_lock, flags);
-       put_device(&starget->dev);
+
+       return;
 }
 
 /**
@@ -431,23 +421,7 @@ static void scsi_target_reap_usercontext(void *data)
  */
 void scsi_target_reap(struct scsi_target *starget)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       unsigned long flags;
-
-       spin_lock_irqsave(shost->host_lock, flags);
-
-       if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
-               BUG_ON(starget->state == STARGET_DEL);
-               starget->state = STARGET_DEL;
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               execute_in_process_context(scsi_target_reap_usercontext,
-                                          starget, &starget->ew);
-               return;
-
-       }
-       spin_unlock_irqrestore(shost->host_lock, flags);
-
-       return;
+       scsi_execute_in_process_context(scsi_target_reap_usercontext, starget);
 }
 
 /**
@@ -673,7 +647,6 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
        case TYPE_MEDIUM_CHANGER:
        case TYPE_ENCLOSURE:
        case TYPE_COMM:
-       case TYPE_RAID:
        case TYPE_RBC:
                sdev->writeable = 1;
                break;
@@ -716,8 +689,12 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
        if (inq_result[7] & 0x10)
                sdev->sdtr = 1;
 
+       sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
+                               sdev->host->host_no, sdev->channel,
+                               sdev->id, sdev->lun);
+
        /*
-        * End sysfs code.
+        * End driverfs/devfs code.
         */
 
        if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
@@ -738,13 +715,6 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
        if (*bflags & BLIST_SELECT_NO_ATN)
                sdev->select_no_atn = 1;
 
-       /*
-        * Maximum 512 sector transfer length
-        * broken RA4x00 Compaq Disk Array
-        */
-       if (*bflags & BLIST_MAX_512)
-               blk_queue_max_sectors(sdev->request_queue, 512);
-
        /*
         * Some devices may not want to have a start command automatically
         * issued when a device is added.
@@ -901,19 +871,6 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
                goto out_free_result;
        }
 
-       /*
-        * Non-standard SCSI targets may set the PDT to 0x1f (unknown or
-        * no device type) instead of using the Peripheral Qualifier to
-        * indicate that no LUN is present.  For example, USB UFI does this.
-        */
-       if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) {
-               SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
-                                       "scsi scan: peripheral device type"
-                                       " of 31, no device added\n"));
-               res = SCSI_SCAN_TARGET_PRESENT;
-               goto out_free_result;
-       }
-
        res = scsi_add_lun(sdev, result, &bflags);
        if (res == SCSI_SCAN_LUN_PRESENT) {
                if (bflags & BLIST_KEY) {
@@ -1131,13 +1088,10 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
         * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
         * support more than 8 LUNs.
         */
-       if (bflags & BLIST_NOREPORTLUN)
-               return 1;
-       if (starget->scsi_level < SCSI_2 &&
-           starget->scsi_level != SCSI_UNKNOWN)
-               return 1;
-       if (starget->scsi_level < SCSI_3 &&
-           (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8))
+       if ((bflags & BLIST_NOREPORTLUN) || 
+            starget->scsi_level < SCSI_2 ||
+           (starget->scsi_level < SCSI_3 && 
+            (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) )
                return 1;
        if (bflags & BLIST_NOLUN)
                return 0;
@@ -1307,8 +1261,9 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
 struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
                                      uint id, uint lun, void *hostdata)
 {
-       struct scsi_device *sdev = ERR_PTR(-ENODEV);
+       struct scsi_device *sdev;
        struct device *parent = &shost->shost_gendev;
+       int res;
        struct scsi_target *starget;
 
        starget = scsi_alloc_target(parent, channel, id);
@@ -1317,8 +1272,12 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
 
        get_device(&starget->dev);
        mutex_lock(&shost->scan_mutex);
-       if (scsi_host_scan_allowed(shost))
-               scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+       if (scsi_host_scan_allowed(shost)) {
+               res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
+                                            hostdata);
+               if (res != SCSI_SCAN_LUN_PRESENT)
+                       sdev = ERR_PTR(-ENODEV);
+       }
        mutex_unlock(&shost->scan_mutex);
        scsi_target_reap(starget);
        put_device(&starget->dev);