#include <linux/delay.h>
#include <linux/init.h>
#include <linux/completion.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/unistd.h>
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
+#include <linux/mutex.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "scsi_logging.h"
static void scsi_done(struct scsi_cmnd *cmd);
-static int scsi_retry_command(struct scsi_cmnd *cmd);
/*
* Definitions and constants.
const int size = offset + sizeof(struct request);
struct scsi_request *sreq;
- sreq = kmalloc(size, gfp_mask);
+ sreq = kzalloc(size, gfp_mask);
if (likely(sreq != NULL)) {
- memset(sreq, 0, size);
sreq->sr_request = (struct request *)(((char *)sreq) + offset);
sreq->sr_device = sdev;
sreq->sr_host = sdev->host;
.gfp_mask = __GFP_DMA,
};
-static DECLARE_MUTEX(host_cmd_pool_mutex);
+static DEFINE_MUTEX(host_cmd_pool_mutex);
static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
gfp_t gfp_mask)
* Select a command slab for this host and create it if not
* yet existant.
*/
- down(&host_cmd_pool_mutex);
+ 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,
pool->users++;
shost->cmd_pool = pool;
- up(&host_cmd_pool_mutex);
+ mutex_unlock(&host_cmd_pool_mutex);
/*
* Get one backup command for this host.
kmem_cache_destroy(pool->slab);
return -ENOMEM;
fail:
- up(&host_cmd_pool_mutex);
+ mutex_unlock(&host_cmd_pool_mutex);
return -ENOMEM;
}
kmem_cache_free(shost->cmd_pool->slab, cmd);
}
- down(&host_cmd_pool_mutex);
+ mutex_lock(&host_cmd_pool_mutex);
if (!--shost->cmd_pool->users)
kmem_cache_destroy(shost->cmd_pool->slab);
- up(&host_cmd_pool_mutex);
+ mutex_unlock(&host_cmd_pool_mutex);
}
#ifdef CONFIG_SCSI_LOGGING
* isn't running --- used by scsi_times_out */
void __scsi_done(struct scsi_cmnd *cmd)
{
- unsigned long flags;
+ struct request *rq = cmd->request;
/*
* Set the serial numbers back to zero
if (cmd->result)
atomic_inc(&cmd->device->ioerr_cnt);
+ BUG_ON(!rq);
+
/*
- * Next, enqueue the command into the done queue.
- * It is a per-CPU queue, so we just disable local interrupts
- * and need no spinlock.
+ * The uptodate/nbytes values don't matter, as we allow partial
+ * completes and thus will check this in the softirq callback
*/
- local_irq_save(flags);
- list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));
- raise_softirq_irqoff(SCSI_SOFTIRQ);
- local_irq_restore(flags);
-}
-
-/**
- * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
- *
- * This is the consumer of the done queue.
- *
- * This is called with all interrupts enabled. This should reduce
- * interrupt latency, stack depth, and reentrancy of the low-level
- * drivers.
- */
-static void scsi_softirq(struct softirq_action *h)
-{
- int disposition;
- LIST_HEAD(local_q);
-
- local_irq_disable();
- list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);
- local_irq_enable();
-
- while (!list_empty(&local_q)) {
- struct scsi_cmnd *cmd = list_entry(local_q.next,
- struct scsi_cmnd, eh_entry);
- /* The longest time any command should be outstanding is the
- * per command timeout multiplied by the number of retries.
- *
- * For a typical command, this is 2.5 minutes */
- unsigned long wait_for
- = cmd->allowed * cmd->timeout_per_command;
- list_del_init(&cmd->eh_entry);
-
- disposition = scsi_decide_disposition(cmd);
- if (disposition != SUCCESS &&
- time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
- sdev_printk(KERN_ERR, cmd->device,
- "timing out command, waited %lus\n",
- wait_for/HZ);
- disposition = SUCCESS;
- }
-
- scsi_log_completion(cmd, disposition);
- switch (disposition) {
- case SUCCESS:
- scsi_finish_command(cmd);
- break;
- case NEEDS_RETRY:
- scsi_retry_command(cmd);
- break;
- case ADD_TO_MLQUEUE:
- scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
- break;
- default:
- if (!scsi_eh_scmd_add(cmd, 0))
- scsi_finish_command(cmd);
- }
- }
+ rq->completion_data = cmd;
+ blk_complete_request(rq);
}
/*
* level drivers should not become re-entrant as a result of
* this.
*/
-static int scsi_retry_command(struct scsi_cmnd *cmd)
+int scsi_retry_command(struct scsi_cmnd *cmd)
{
/*
* Restore the SCSI command state.
}
EXPORT_SYMBOL(scsi_device_cancel);
-#ifdef CONFIG_HOTPLUG_CPU
-static int scsi_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- int cpu = (unsigned long)hcpu;
-
- switch(action) {
- case CPU_DEAD:
- /* Drain scsi_done_q. */
- local_irq_disable();
- list_splice_init(&per_cpu(scsi_done_q, cpu),
- &__get_cpu_var(scsi_done_q));
- raise_softirq_irqoff(SCSI_SOFTIRQ);
- local_irq_enable();
- break;
- default:
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __devinitdata scsi_cpu_nb = {
- .notifier_call = scsi_cpu_notify,
-};
-
-#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
-#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
-#else
-#define register_scsi_cpu()
-#define unregister_scsi_cpu()
-#endif /* CONFIG_HOTPLUG_CPU */
-
MODULE_DESCRIPTION("SCSI core");
MODULE_LICENSE("GPL");
if (error)
goto cleanup_sysctl;
- for (i = 0; i < NR_CPUS; i++)
+ for_each_cpu(i)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
- devfs_mk_dir("scsi");
- open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
- register_scsi_cpu();
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
scsi_exit_sysctl();
scsi_exit_hosts();
scsi_exit_devinfo();
- devfs_remove("scsi");
scsi_exit_procfs();
scsi_exit_queue();
- unregister_scsi_cpu();
}
subsys_initcall(init_scsi);