X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_scan.c;h=94b86d5b14696d1303e716b3c723a4114f1b4f8d;hb=6d73c8514da241c6b1b8d710a6294786604d7142;hp=be276ea8f033330d72cb631233c8801a27d7eced;hpb=1a68de5c08be8c77c4ad208306187bd95107c7cd;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index be276ea..94b86d5 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -74,7 +74,7 @@ #define SCSI_SCAN_TARGET_PRESENT 1 #define SCSI_SCAN_LUN_PRESENT 2 -static char *scsi_null_device_strs = "nullnullnullnull"; +static const char *scsi_null_device_strs = "nullnullnullnull"; #define MAX_SCSI_LUNS 512 @@ -205,12 +205,11 @@ 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 = kmalloc(sizeof(*sdev) + shost->transportt->device_size, + sdev = kzalloc(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; @@ -266,8 +265,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, /* * if LLDD reports slave not present, don't clutter * console with alloc failure messages - - */ if (ret == -ENXIO) display_failure_msg = 0; @@ -336,25 +333,11 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, struct scsi_target *starget; struct scsi_target *found_target; - /* - * Obtain the real parent from the transport. The transport - * is allowed to fail (no error) if there is nothing at that - * target id. - */ - if (shost->transportt->target_parent) { - spin_lock_irqsave(shost->host_lock, flags); - parent = shost->transportt->target_parent(shost, channel, id); - spin_unlock_irqrestore(shost->host_lock, flags); - if (!parent) - return NULL; - } - - starget = kmalloc(size, GFP_KERNEL); + starget = kzalloc(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; @@ -402,30 +385,41 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } -/** - * scsi_target_reap - check to see if target is in use and destroy if not - * - * @starget: target to be checked - * - * This is used after removing a LUN or doing a last put of the target - * it checks atomically that nothing is using the target and removes - * it if so. - */ -void scsi_target_reap(struct scsi_target *starget) +static void scsi_target_reap_usercontext(void *data) { + struct scsi_target *starget = data; 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)) { list_del_init(&starget->siblings); spin_unlock_irqrestore(shost->host_lock, flags); + transport_remove_device(&starget->dev); device_del(&starget->dev); - transport_unregister_device(&starget->dev); + transport_destroy_device(&starget->dev); put_device(&starget->dev); return; + } spin_unlock_irqrestore(shost->host_lock, flags); + + return; +} + +/** + * scsi_target_reap - check to see if target is in use and destroy if not + * + * @starget: target to be checked + * + * This is used after removing a LUN or doing a last put of the target + * it checks atomically that nothing is using the target and removes + * it if so. + */ +void scsi_target_reap(struct scsi_target *starget) +{ + scsi_execute_in_process_context(scsi_target_reap_usercontext, starget); } /** @@ -693,12 +687,8 @@ 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 driverfs/devfs code. + * End sysfs code. */ if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && @@ -863,6 +853,19 @@ 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) { @@ -1253,23 +1256,19 @@ 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; + struct scsi_device *sdev = ERR_PTR(-ENODEV); struct device *parent = &shost->shost_gendev; - int res; - struct scsi_target *starget = scsi_alloc_target(parent, channel, id); + struct scsi_target *starget; + starget = scsi_alloc_target(parent, channel, id); if (!starget) return ERR_PTR(-ENOMEM); get_device(&starget->dev); - down(&shost->scan_mutex); - 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); - } - up(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); + if (scsi_host_scan_allowed(shost)) + scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); + mutex_unlock(&shost->scan_mutex); scsi_target_reap(starget); put_device(&starget->dev); @@ -1377,10 +1376,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel, { struct Scsi_Host *shost = dev_to_shost(parent); - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) __scsi_scan_target(parent, channel, id, lun, rescan); - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); } EXPORT_SYMBOL(scsi_scan_target); @@ -1427,7 +1426,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) return -EINVAL; - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (scsi_host_scan_allowed(shost)) { if (channel == SCAN_WILD_CARD) for (channel = 0; channel <= shost->max_channel; @@ -1437,7 +1436,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, else scsi_scan_channel(shost, channel, id, lun, rescan); } - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); return 0; } @@ -1495,7 +1494,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) struct scsi_device *sdev = NULL; struct scsi_target *starget; - down(&shost->scan_mutex); + mutex_lock(&shost->scan_mutex); if (!scsi_host_scan_allowed(shost)) goto out; starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id); @@ -1509,7 +1508,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) } put_device(&starget->dev); out: - up(&shost->scan_mutex); + mutex_unlock(&shost->scan_mutex); return sdev; } EXPORT_SYMBOL(scsi_get_host_dev);