diff options
Diffstat (limited to 'drivers/scsi/scsi_scan.c')
-rw-r--r-- | drivers/scsi/scsi_scan.c | 140 |
1 files changed, 78 insertions, 62 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 7eb3a2d40dc5..752fb5da3de4 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -9,7 +9,7 @@ * global variable (boot or module load time) settings. * * A specific LUN is scanned via an INQUIRY command; if the LUN has a - * device attached, a Scsi_Device is allocated and setup for it. + * device attached, a scsi_device is allocated and setup for it. * * For every id of every channel on the given host: * @@ -17,7 +17,7 @@ * device or storage attached to LUN 0): * * If LUN 0 has a device attached, allocate and setup a - * Scsi_Device for it. + * scsi_device for it. * * If target is SCSI-3 or up, issue a REPORT LUN, and scan * all of the LUNs returned by the REPORT LUN; else, @@ -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 @@ -266,8 +266,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; @@ -279,7 +277,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, out_device_destroy: transport_destroy_device(&sdev->sdev_gendev); - scsi_free_queue(sdev->request_queue); put_device(&sdev->sdev_gendev); out: if (display_failure_msg) @@ -337,19 +334,6 @@ 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); if (!starget) { printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__); @@ -403,6 +387,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, return found_target; } +struct work_queue_wrapper { + struct work_struct work; + struct scsi_target *starget; +}; + +static void scsi_target_reap_work(void *data) { + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct scsi_target *starget = wqw->starget; + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + unsigned long flags; + + kfree(wqw); + + 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_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 * @@ -414,19 +428,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, */ 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); + struct work_queue_wrapper *wqw = + kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { - list_del_init(&starget->siblings); - spin_unlock_irqrestore(shost->host_lock, flags); - device_del(&starget->dev); - transport_unregister_device(&starget->dev); - put_device(&starget->dev); + if (!wqw) { + starget_printk(KERN_ERR, starget, + "Failed to allocate memory in scsi_reap_target()\n"); return; } - spin_unlock_irqrestore(shost->host_lock, flags); + + INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); + wqw->starget = starget; + schedule_work(&wqw->work); } /** @@ -441,7 +454,7 @@ void scsi_target_reap(struct scsi_target *starget) * * If the INQUIRY is successful, zero is returned and the * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length - * are copied to the Scsi_Device any flags value is stored in *@bflags. + * are copied to the scsi_device any flags value is stored in *@bflags. **/ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, int result_len, int *bflags) @@ -509,8 +522,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, /* * Get any flags for this device. * - * XXX add a bflags to Scsi_Device, and replace the - * corresponding bit fields in Scsi_Device, so bflags + * XXX add a bflags to scsi_device, and replace the + * corresponding bit fields in scsi_device, so bflags * need not be passed as an argument. */ *bflags = scsi_get_device_flags(sdev, &inq_result[8], @@ -592,21 +605,21 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, } /** - * 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 + * 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 * @inq_result: holds the result of a previous INQUIRY to the LUN * @bflags: black/white list flag * * Description: - * Allocate and initialize a Scsi_Device matching sdevscan. Optionally + * Allocate and initialize a scsi_device matching sdevscan. Optionally * set fields based on values in *@bflags. If @sdevnew is not - * NULL, store the address of the new Scsi_Device in *@sdevnew (needed + * NULL, store the address of the new scsi_device in *@sdevnew (needed * when scanning a particular LUN). * * Return: - * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device - * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized + * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device + * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized **/ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) { @@ -674,7 +687,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) * * The above is vague, as it implies that we could treat 001 and * 011 the same. Stay compatible with previous code, and create a - * Scsi_Device for a PQ of 1 + * scsi_device for a PQ of 1 * * Don't set the device offline here; rather let the upper * level drivers eval the PQ to decide whether they should @@ -784,8 +797,8 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev) * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it * @starget: pointer to target device structure * @lun: LUN of target device - * @sdevscan: probe the LUN corresponding to this Scsi_Device - * @sdevnew: store the value of any new Scsi_Device allocated + * @sdevscan: probe the LUN corresponding to this scsi_device + * @sdevnew: store the value of any new scsi_device allocated * @bflagsp: store bflags here if not NULL * * Description: @@ -793,10 +806,10 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev) * allocate and set it up by calling scsi_add_lun. * * Return: - * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device + * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is * attached at the LUN - * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized + * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized **/ static int scsi_probe_and_add_lun(struct scsi_target *starget, uint lun, int *bflagsp, @@ -1046,7 +1059,7 @@ EXPORT_SYMBOL(int_to_scsilun); /** * scsi_report_lun_scan - Scan using SCSI REPORT LUN results - * @sdevscan: scan the host, channel, and id of this Scsi_Device + * @sdevscan: scan the host, channel, and id of this scsi_device * * Description: * If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN @@ -1074,6 +1087,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, struct scsi_sense_hdr sshdr; struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(&starget->dev); + int ret = 0; /* * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. @@ -1169,8 +1183,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * The device probably does not support a REPORT LUN command */ - kfree(lun_data); - return 1; + ret = 1; + goto out_err; } /* @@ -1238,6 +1252,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, } } + out_err: kfree(lun_data); out: scsi_device_put(sdev); @@ -1246,7 +1261,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, * the sdev we used didn't appear in the report luns scan */ scsi_destroy_sdev(sdev); - return 0; + return ret; } struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, @@ -1255,20 +1270,21 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, struct scsi_device *sdev; 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); + mutex_lock(&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_unlock(&shost->scan_mutex); scsi_target_reap(starget); put_device(&starget->dev); @@ -1376,10 +1392,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); @@ -1426,7 +1442,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; @@ -1436,7 +1452,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; } @@ -1472,16 +1488,16 @@ void scsi_forget_host(struct Scsi_Host *shost) /* * Function: scsi_get_host_dev() * - * Purpose: Create a Scsi_Device that points to the host adapter itself. + * Purpose: Create a scsi_device that points to the host adapter itself. * - * Arguments: SHpnt - Host that needs a Scsi_Device + * Arguments: SHpnt - Host that needs a scsi_device * * Lock status: None assumed. * - * Returns: The Scsi_Device or NULL + * Returns: The scsi_device or NULL * * Notes: - * Attach a single Scsi_Device to the Scsi_Host - this should + * Attach a single scsi_device to the Scsi_Host - this should * be made to look like a "pseudo-device" that points to the * HA itself. * @@ -1494,7 +1510,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); @@ -1508,7 +1524,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); @@ -1518,7 +1534,7 @@ EXPORT_SYMBOL(scsi_get_host_dev); * * Purpose: Free a scsi_device that points to the host adapter itself. * - * Arguments: SHpnt - Host that needs a Scsi_Device + * Arguments: SHpnt - Host that needs a scsi_device * * Lock status: None assumed. * |