aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r--drivers/scsi/scsi.c354
1 files changed, 1 insertions, 353 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 75455d4dab68..7bfbcfa7af40 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -98,176 +98,6 @@ EXPORT_SYMBOL(scsi_sd_probe_domain);
ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
EXPORT_SYMBOL(scsi_sd_pm_domain);
-struct scsi_host_cmd_pool {
- struct kmem_cache *cmd_slab;
- struct kmem_cache *sense_slab;
- unsigned int users;
- char *cmd_name;
- char *sense_name;
- unsigned int slab_flags;
- gfp_t gfp_mask;
-};
-
-static struct scsi_host_cmd_pool scsi_cmd_pool = {
- .cmd_name = "scsi_cmd_cache",
- .sense_name = "scsi_sense_cache",
- .slab_flags = SLAB_HWCACHE_ALIGN,
-};
-
-static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
- .cmd_name = "scsi_cmd_cache(DMA)",
- .sense_name = "scsi_sense_cache(DMA)",
- .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
- .gfp_mask = __GFP_DMA,
-};
-
-static DEFINE_MUTEX(host_cmd_pool_mutex);
-
-/**
- * scsi_host_free_command - internal function to release a command
- * @shost: host to free the command for
- * @cmd: command to release
- *
- * the command must previously have been allocated by
- * scsi_host_alloc_command.
- */
-static void
-scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
- struct scsi_host_cmd_pool *pool = shost->cmd_pool;
-
- if (cmd->prot_sdb)
- kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
- kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
- kmem_cache_free(pool->cmd_slab, cmd);
-}
-
-/**
- * scsi_host_alloc_command - internal function to allocate command
- * @shost: SCSI host whose pool to allocate from
- * @gfp_mask: mask for the allocation
- *
- * Returns a fully allocated command with sense buffer and protection
- * data buffer (where applicable) or NULL on failure
- */
-static struct scsi_cmnd *
-scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
-{
- struct scsi_host_cmd_pool *pool = shost->cmd_pool;
- struct scsi_cmnd *cmd;
-
- cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
- if (!cmd)
- goto fail;
-
- cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
- gfp_mask | pool->gfp_mask);
- if (!cmd->sense_buffer)
- goto fail_free_cmd;
-
- if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
- cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
- if (!cmd->prot_sdb)
- goto fail_free_sense;
- }
-
- return cmd;
-
-fail_free_sense:
- kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
-fail_free_cmd:
- kmem_cache_free(pool->cmd_slab, cmd);
-fail:
- return NULL;
-}
-
-/**
- * __scsi_get_command - Allocate a struct scsi_cmnd
- * @shost: host to transmit command
- * @gfp_mask: allocation mask
- *
- * Description: allocate a struct scsi_cmd from host's slab, recycling from the
- * host's free_list if necessary.
- */
-static struct scsi_cmnd *
-__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
-{
- struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);
-
- if (unlikely(!cmd)) {
- unsigned long flags;
-
- spin_lock_irqsave(&shost->free_list_lock, flags);
- if (likely(!list_empty(&shost->free_list))) {
- cmd = list_entry(shost->free_list.next,
- struct scsi_cmnd, list);
- list_del_init(&cmd->list);
- }
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
-
- if (cmd) {
- void *buf, *prot;
-
- buf = cmd->sense_buffer;
- prot = cmd->prot_sdb;
-
- memset(cmd, 0, sizeof(*cmd));
-
- cmd->sense_buffer = buf;
- cmd->prot_sdb = prot;
- }
- }
-
- return cmd;
-}
-
-/**
- * scsi_get_command - Allocate and setup a scsi command block
- * @dev: parent scsi device
- * @gfp_mask: allocator flags
- *
- * Returns: The allocated scsi command structure.
- */
-struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
-{
- struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
- unsigned long flags;
-
- if (unlikely(cmd == NULL))
- return NULL;
-
- cmd->device = dev;
- INIT_LIST_HEAD(&cmd->list);
- INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
- spin_lock_irqsave(&dev->list_lock, flags);
- list_add_tail(&cmd->list, &dev->cmd_list);
- spin_unlock_irqrestore(&dev->list_lock, flags);
- cmd->jiffies_at_alloc = jiffies;
- return cmd;
-}
-
-/**
- * __scsi_put_command - Free a struct scsi_cmnd
- * @shost: dev->host
- * @cmd: Command to free
- */
-static void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
- unsigned long flags;
-
- if (unlikely(list_empty(&shost->free_list))) {
- spin_lock_irqsave(&shost->free_list_lock, flags);
- if (list_empty(&shost->free_list)) {
- list_add(&cmd->list, &shost->free_list);
- cmd = NULL;
- }
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
- }
-
- if (likely(cmd != NULL))
- scsi_host_free_command(shost, cmd);
-}
-
/**
* scsi_put_command - Free a scsi command block
* @cmd: command block to free
@@ -287,188 +117,6 @@ void scsi_put_command(struct scsi_cmnd *cmd)
spin_unlock_irqrestore(&cmd->device->list_lock, flags);
BUG_ON(delayed_work_pending(&cmd->abort_work));
-
- __scsi_put_command(cmd->device->host, cmd);
-}
-
-static struct scsi_host_cmd_pool *
-scsi_find_host_cmd_pool(struct Scsi_Host *shost)
-{
- if (shost->hostt->cmd_size)
- return shost->hostt->cmd_pool;
- if (shost->unchecked_isa_dma)
- return &scsi_cmd_dma_pool;
- return &scsi_cmd_pool;
-}
-
-static void
-scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
-{
- kfree(pool->sense_name);
- kfree(pool->cmd_name);
- kfree(pool);
-}
-
-static struct scsi_host_cmd_pool *
-scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
-{
- struct scsi_host_template *hostt = shost->hostt;
- struct scsi_host_cmd_pool *pool;
-
- pool = kzalloc(sizeof(*pool), GFP_KERNEL);
- if (!pool)
- return NULL;
-
- pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->proc_name);
- pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->proc_name);
- if (!pool->cmd_name || !pool->sense_name) {
- scsi_free_host_cmd_pool(pool);
- return NULL;
- }
-
- pool->slab_flags = SLAB_HWCACHE_ALIGN;
- if (shost->unchecked_isa_dma) {
- pool->slab_flags |= SLAB_CACHE_DMA;
- pool->gfp_mask = __GFP_DMA;
- }
-
- if (hostt->cmd_size)
- hostt->cmd_pool = pool;
-
- return pool;
-}
-
-static struct scsi_host_cmd_pool *
-scsi_get_host_cmd_pool(struct Scsi_Host *shost)
-{
- struct scsi_host_template *hostt = shost->hostt;
- struct scsi_host_cmd_pool *retval = NULL, *pool;
- size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
-
- /*
- * Select a command slab for this host and create it if not
- * yet existent.
- */
- mutex_lock(&host_cmd_pool_mutex);
- pool = scsi_find_host_cmd_pool(shost);
- if (!pool) {
- pool = scsi_alloc_host_cmd_pool(shost);
- if (!pool)
- goto out;
- }
-
- if (!pool->users) {
- pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
- pool->slab_flags, NULL);
- if (!pool->cmd_slab)
- goto out_free_pool;
-
- pool->sense_slab = kmem_cache_create(pool->sense_name,
- SCSI_SENSE_BUFFERSIZE, 0,
- pool->slab_flags, NULL);
- if (!pool->sense_slab)
- goto out_free_slab;
- }
-
- pool->users++;
- retval = pool;
-out:
- mutex_unlock(&host_cmd_pool_mutex);
- return retval;
-
-out_free_slab:
- kmem_cache_destroy(pool->cmd_slab);
-out_free_pool:
- if (hostt->cmd_size) {
- scsi_free_host_cmd_pool(pool);
- hostt->cmd_pool = NULL;
- }
- goto out;
-}
-
-static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
-{
- struct scsi_host_template *hostt = shost->hostt;
- struct scsi_host_cmd_pool *pool;
-
- mutex_lock(&host_cmd_pool_mutex);
- pool = scsi_find_host_cmd_pool(shost);
-
- /*
- * This may happen if a driver has a mismatched get and put
- * of the command pool; the driver should be implicated in
- * the stack trace
- */
- BUG_ON(pool->users == 0);
-
- if (!--pool->users) {
- kmem_cache_destroy(pool->cmd_slab);
- kmem_cache_destroy(pool->sense_slab);
- if (hostt->cmd_size) {
- scsi_free_host_cmd_pool(pool);
- hostt->cmd_pool = NULL;
- }
- }
- mutex_unlock(&host_cmd_pool_mutex);
-}
-
-/**
- * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
- * @shost: host to allocate the freelist for.
- *
- * Description: The command freelist protects against system-wide out of memory
- * deadlock by preallocating one SCSI command structure for each host, so the
- * system can always write to a swap file on a device associated with that host.
- *
- * Returns: Nothing.
- */
-int scsi_setup_command_freelist(struct Scsi_Host *shost)
-{
- const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
- struct scsi_cmnd *cmd;
-
- spin_lock_init(&shost->free_list_lock);
- INIT_LIST_HEAD(&shost->free_list);
-
- shost->cmd_pool = scsi_get_host_cmd_pool(shost);
- if (!shost->cmd_pool)
- return -ENOMEM;
-
- /*
- * Get one backup command for this host.
- */
- cmd = scsi_host_alloc_command(shost, gfp_mask);
- if (!cmd) {
- scsi_put_host_cmd_pool(shost);
- shost->cmd_pool = NULL;
- return -ENOMEM;
- }
- list_add(&cmd->list, &shost->free_list);
- return 0;
-}
-
-/**
- * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
- * @shost: host whose freelist is going to be destroyed
- */
-void scsi_destroy_command_freelist(struct Scsi_Host *shost)
-{
- /*
- * If cmd_pool is NULL the free list was not initialized, so
- * do not attempt to release resources.
- */
- if (!shost->cmd_pool)
- return;
-
- while (!list_empty(&shost->free_list)) {
- struct scsi_cmnd *cmd;
-
- cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
- list_del_init(&cmd->list);
- scsi_host_free_command(shost, cmd);
- }
- shost->cmd_pool = NULL;
- scsi_put_host_cmd_pool(shost);
}
#ifdef CONFIG_SCSI_LOGGING
@@ -590,7 +238,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"(result %x)\n", cmd->result));
good_bytes = scsi_bufflen(cmd);
- if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+ if (!blk_rq_is_passthrough(cmd->request)) {
int old_good_bytes = good_bytes;
drv = scsi_cmd_to_driver(cmd);
if (drv->done)