EXPORT_SYMBOL(scsi_device_type);
struct scsi_host_cmd_pool {
- struct kmem_cache *slab;
- unsigned int users;
- char *name;
- unsigned int slab_flags;
- gfp_t gfp_mask;
+ 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 = {
- .name = "scsi_cmd_cache",
+ .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 = {
- .name = "scsi_cmd_cache(DMA)",
+ .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_pool_alloc_command - internal function to get a fully allocated command
+ * @pool: slab pool to allocate the command from
+ * @gfp_mask: mask for the allocation
+ *
+ * Returns a fully allocated command (with the allied sense buffer) or
+ * NULL on failure
+ */
+static struct scsi_cmnd *
+scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask)
+{
+ struct scsi_cmnd *cmd;
+
+ cmd = kmem_cache_alloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
+ if (!cmd)
+ return NULL;
+
+ memset(cmd, 0, sizeof(*cmd));
+
+ cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
+ gfp_mask | pool->gfp_mask);
+ if (!cmd->sense_buffer) {
+ kmem_cache_free(pool->cmd_slab, cmd);
+ return NULL;
+ }
+
+ return cmd;
+}
+
+/**
+ * scsi_pool_free_command - internal function to release a command
+ * @pool: slab pool to allocate the command from
+ * @cmd: command to release
+ *
+ * the command must previously have been allocated by
+ * scsi_pool_alloc_command.
+ */
+static void
+scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
+ struct scsi_cmnd *cmd)
+{
+ kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
+ kmem_cache_free(pool->cmd_slab, cmd);
+}
+
/**
* __scsi_get_command - Allocate a struct scsi_cmnd
* @shost: host to transmit command
struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
struct scsi_cmnd *cmd;
+ unsigned char *buf;
- cmd = kmem_cache_alloc(shost->cmd_pool->slab,
- gfp_mask | shost->cmd_pool->gfp_mask);
+ cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
if (unlikely(!cmd)) {
unsigned long flags;
list_del_init(&cmd->list);
}
spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+ if (cmd) {
+ buf = cmd->sense_buffer;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->sense_buffer = buf;
+ }
}
return cmd;
if (likely(cmd != NULL)) {
unsigned long flags;
- memset(cmd, 0, sizeof(*cmd));
cmd->device = dev;
init_timer(&cmd->eh_timeout);
INIT_LIST_HEAD(&cmd->list);
spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (likely(cmd != NULL))
- kmem_cache_free(shost->cmd_pool->slab, cmd);
+ scsi_pool_free_command(shost->cmd_pool, cmd);
put_device(dev);
}
mutex_lock(&host_cmd_pool_mutex);
pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
if (!pool->users) {
- pool->slab = kmem_cache_create(pool->name,
- sizeof(struct scsi_cmnd), 0,
- pool->slab_flags, NULL);
- if (!pool->slab)
+ pool->cmd_slab = kmem_cache_create(pool->cmd_name,
+ sizeof(struct scsi_cmnd), 0,
+ pool->slab_flags, NULL);
+ if (!pool->cmd_slab)
+ goto fail;
+
+ pool->sense_slab = kmem_cache_create(pool->sense_name,
+ SCSI_SENSE_BUFFERSIZE, 0,
+ pool->slab_flags, NULL);
+ if (!pool->sense_slab) {
+ kmem_cache_destroy(pool->cmd_slab);
goto fail;
+ }
}
pool->users++;
/*
* Get one backup command for this host.
*/
- cmd = kmem_cache_alloc(shost->cmd_pool->slab,
- GFP_KERNEL | shost->cmd_pool->gfp_mask);
+ cmd = scsi_pool_alloc_command(shost->cmd_pool, GFP_KERNEL);
if (!cmd)
goto fail2;
- list_add(&cmd->list, &shost->free_list);
+
+ list_add(&cmd->list, &shost->free_list);
return 0;
fail2:
- if (!--pool->users)
- kmem_cache_destroy(pool->slab);
- return -ENOMEM;
+ mutex_lock(&host_cmd_pool_mutex);
+ if (!--pool->users) {
+ kmem_cache_destroy(pool->cmd_slab);
+ kmem_cache_destroy(pool->sense_slab);
+ }
fail:
mutex_unlock(&host_cmd_pool_mutex);
return -ENOMEM;
-
}
/**
cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
list_del_init(&cmd->list);
- kmem_cache_free(shost->cmd_pool->slab, cmd);
+ scsi_pool_free_command(shost->cmd_pool, cmd);
}
mutex_lock(&host_cmd_pool_mutex);
- if (!--shost->cmd_pool->users)
- kmem_cache_destroy(shost->cmd_pool->slab);
+ if (!--shost->cmd_pool->users) {
+ kmem_cache_destroy(shost->cmd_pool->cmd_slab);
+ kmem_cache_destroy(shost->cmd_pool->sense_slab);
+ }
mutex_unlock(&host_cmd_pool_mutex);
}
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- good_bytes = cmd->request_bufflen;
+ good_bytes = scsi_bufflen(cmd) + cmd->request->extra_len;
if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
drv = scsi_cmd_to_driver(cmd);
if (drv->done)
EXPORT_SYMBOL(starget_for_each_device);
/**
- * __starget_for_each_device - helper to walk all devices of a target
- * (UNLOCKED)
+ * __starget_for_each_device - helper to walk all devices of a target (UNLOCKED)
* @starget: target whose devices we want to iterate over.
+ * @data: parameter for callback @fn()
+ * @fn: callback function that is invoked for each device
*
* This traverses over each device of @starget. It does _not_
* take a reference on the scsi_device, so the whole loop must be