X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fscsi%2Fscsi.c;h=ab4c237306e44b802d586c5cf874e678527cb8e6;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=481bea6a4b4de2d7ae02021f5d9a2b88fce30bab;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 481bea6a4..ab4c23730 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -98,6 +98,9 @@ static unsigned long serial_number; * After the system is up, you may enable logging via the /proc interface. */ unsigned int scsi_logging_level; +#if defined(CONFIG_SCSI_LOGGING) +EXPORT_SYMBOL(scsi_logging_level); +#endif const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { "Direct-Access ", @@ -115,6 +118,7 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { "RAID ", "Enclosure ", }; +EXPORT_SYMBOL(scsi_device_types); /* * Function: scsi_allocate_request @@ -147,6 +151,7 @@ struct scsi_request *scsi_allocate_request(struct scsi_device *sdev, return sreq; } +EXPORT_SYMBOL(scsi_allocate_request); void __scsi_release_request(struct scsi_request *sreq) { @@ -187,6 +192,7 @@ void scsi_release_request(struct scsi_request *sreq) __scsi_release_request(sreq); kfree(sreq); } +EXPORT_SYMBOL(scsi_release_request); struct scsi_host_cmd_pool { kmem_cache_t *slab; @@ -244,7 +250,13 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, */ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) { - struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask); + struct scsi_cmnd *cmd; + + /* Bail if we can't get a reference to the device */ + if (!get_device(&dev->sdev_gendev)) + return NULL; + + cmd = __scsi_get_command(dev->host, gfp_mask); if (likely(cmd != NULL)) { unsigned long flags; @@ -258,10 +270,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) spin_lock_irqsave(&dev->list_lock, flags); list_add_tail(&cmd->list, &dev->cmd_list); spin_unlock_irqrestore(&dev->list_lock, flags); - } + } else + put_device(&dev->sdev_gendev); return cmd; } +EXPORT_SYMBOL(scsi_get_command); /* * Function: scsi_put_command() @@ -276,7 +290,8 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) */ void scsi_put_command(struct scsi_cmnd *cmd) { - struct Scsi_Host *shost = cmd->device->host; + struct scsi_device *sdev = cmd->device; + struct Scsi_Host *shost = sdev->host; unsigned long flags; /* serious error if the command hasn't come from a device list */ @@ -294,7 +309,10 @@ void scsi_put_command(struct scsi_cmnd *cmd) if (likely(cmd != NULL)) kmem_cache_free(shost->cmd_pool->slab, cmd); + + put_device(&sdev->sdev_gendev); } +EXPORT_SYMBOL(scsi_put_command); /* * Function: scsi_setup_command_freelist() @@ -518,6 +536,26 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) /* return 0 (because the command has been processed) */ goto out; } + + /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */ + if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) { + /* + * in SDEV_BLOCK, the command is just put back on the device + * queue. The suspend state has already blocked the queue so + * future requests should not occur until the device + * transitions out of the suspend state. + */ + scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); + + SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n")); + + /* + * NOTE: rtn is still zero here because we don't need the + * queue to be plugged on return (it's already stopped) + */ + goto out; + } + /* Assign a unique nonzero serial_number. */ /* XXX(hch): this is racy */ if (++serial_number == 0) @@ -576,9 +614,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) printk("queuecommand : command too long.\n")); cmd->result = (DID_ABORT << 16); - spin_lock_irqsave(host->host_lock, flags); scsi_done(cmd); - spin_unlock_irqrestore(host->host_lock, flags); goto out; } @@ -889,7 +925,7 @@ EXPORT_SYMBOL(scsi_finish_command); */ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) { - static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED; + static DEFINE_SPINLOCK(device_request_lock); unsigned long flags; /* @@ -931,6 +967,7 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) spin_unlock(sdev->request_queue->queue_lock); spin_unlock_irqrestore(&device_request_lock, flags); } +EXPORT_SYMBOL(scsi_adjust_queue_depth); /* * Function: scsi_track_queue_full() @@ -981,6 +1018,7 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); return depth; } +EXPORT_SYMBOL(scsi_track_queue_full); /** * scsi_device_get - get an addition reference to a scsi_device @@ -1033,6 +1071,7 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, /* skip devices that we can't get a reference to */ if (!scsi_device_get(next)) break; + next = NULL; list = list->next; } spin_unlock_irqrestore(shost->host_lock, flags); @@ -1043,6 +1082,28 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, } EXPORT_SYMBOL(__scsi_iterate_devices); +/** + * starget_for_each_device - helper to walk all devices of a target + * @starget: target whose devices we want to iterate over. + * + * This traverses over each devices of @shost. The devices have + * a reference that must be released by scsi_host_put when breaking + * out of the loop. + */ +void starget_for_each_device(struct scsi_target *starget, void * data, + void (*fn)(struct scsi_device *, void *)) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + if ((sdev->channel == starget->channel) && + (sdev->id == starget->id)) + fn(sdev, data); + } +} +EXPORT_SYMBOL(starget_for_each_device); + /** * scsi_device_lookup - find a device given the host (UNLOCKED) * @shost: SCSI host pointer @@ -1103,8 +1164,8 @@ EXPORT_SYMBOL(scsi_device_lookup); /** * scsi_device_cancel - cancel outstanding IO to this device - * @sdev: pointer to struct scsi_device - * @data: pointer to cancel value. + * @sdev: Pointer to struct scsi_device + * @recovery: Boolean instructing function to recover device or not. * **/ int scsi_device_cancel(struct scsi_device *sdev, int recovery) @@ -1146,6 +1207,7 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) return 0; } +EXPORT_SYMBOL(scsi_device_cancel); #ifdef CONFIG_HOTPLUG_CPU static int scsi_cpu_notify(struct notifier_block *self,