diff options
| -rw-r--r-- | drivers/scsi/scsi.c | 109 | ||||
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 36 | ||||
| -rw-r--r-- | drivers/scsi/scsi_priv.h | 1 | ||||
| -rw-r--r-- | include/linux/interrupt.h | 1 |
4 files changed, 45 insertions, 102 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 180676d7115a..ee5f4dfdab14 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -69,7 +69,6 @@ | |||
| 69 | #include "scsi_logging.h" | 69 | #include "scsi_logging.h" |
| 70 | 70 | ||
| 71 | static void scsi_done(struct scsi_cmnd *cmd); | 71 | static void scsi_done(struct scsi_cmnd *cmd); |
| 72 | static int scsi_retry_command(struct scsi_cmnd *cmd); | ||
| 73 | 72 | ||
| 74 | /* | 73 | /* |
| 75 | * Definitions and constants. | 74 | * Definitions and constants. |
| @@ -752,7 +751,7 @@ static void scsi_done(struct scsi_cmnd *cmd) | |||
| 752 | * isn't running --- used by scsi_times_out */ | 751 | * isn't running --- used by scsi_times_out */ |
| 753 | void __scsi_done(struct scsi_cmnd *cmd) | 752 | void __scsi_done(struct scsi_cmnd *cmd) |
| 754 | { | 753 | { |
| 755 | unsigned long flags; | 754 | struct request *rq = cmd->request; |
| 756 | 755 | ||
| 757 | /* | 756 | /* |
| 758 | * Set the serial numbers back to zero | 757 | * Set the serial numbers back to zero |
| @@ -763,71 +762,14 @@ void __scsi_done(struct scsi_cmnd *cmd) | |||
| 763 | if (cmd->result) | 762 | if (cmd->result) |
| 764 | atomic_inc(&cmd->device->ioerr_cnt); | 763 | atomic_inc(&cmd->device->ioerr_cnt); |
| 765 | 764 | ||
| 765 | BUG_ON(!rq); | ||
| 766 | |||
| 766 | /* | 767 | /* |
| 767 | * Next, enqueue the command into the done queue. | 768 | * The uptodate/nbytes values don't matter, as we allow partial |
| 768 | * It is a per-CPU queue, so we just disable local interrupts | 769 | * completes and thus will check this in the softirq callback |
| 769 | * and need no spinlock. | ||
| 770 | */ | 770 | */ |
| 771 | local_irq_save(flags); | 771 | rq->completion_data = cmd; |
| 772 | list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q)); | 772 | blk_complete_request(rq); |
| 773 | raise_softirq_irqoff(SCSI_SOFTIRQ); | ||
| 774 | local_irq_restore(flags); | ||
| 775 | } | ||
| 776 | |||
| 777 | /** | ||
| 778 | * scsi_softirq - Perform post-interrupt processing of finished SCSI commands. | ||
| 779 | * | ||
| 780 | * This is the consumer of the done queue. | ||
| 781 | * | ||
| 782 | * This is called with all interrupts enabled. This should reduce | ||
| 783 | * interrupt latency, stack depth, and reentrancy of the low-level | ||
| 784 | * drivers. | ||
| 785 | */ | ||
| 786 | static void scsi_softirq(struct softirq_action *h) | ||
| 787 | { | ||
| 788 | int disposition; | ||
| 789 | LIST_HEAD(local_q); | ||
| 790 | |||
| 791 | local_irq_disable(); | ||
| 792 | list_splice_init(&__get_cpu_var(scsi_done_q), &local_q); | ||
| 793 | local_irq_enable(); | ||
| 794 | |||
| 795 | while (!list_empty(&local_q)) { | ||
| 796 | struct scsi_cmnd *cmd = list_entry(local_q.next, | ||
| 797 | struct scsi_cmnd, eh_entry); | ||
| 798 | /* The longest time any command should be outstanding is the | ||
| 799 | * per command timeout multiplied by the number of retries. | ||
| 800 | * | ||
| 801 | * For a typical command, this is 2.5 minutes */ | ||
| 802 | unsigned long wait_for | ||
| 803 | = cmd->allowed * cmd->timeout_per_command; | ||
| 804 | list_del_init(&cmd->eh_entry); | ||
| 805 | |||
| 806 | disposition = scsi_decide_disposition(cmd); | ||
| 807 | if (disposition != SUCCESS && | ||
| 808 | time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { | ||
| 809 | sdev_printk(KERN_ERR, cmd->device, | ||
| 810 | "timing out command, waited %lus\n", | ||
| 811 | wait_for/HZ); | ||
| 812 | disposition = SUCCESS; | ||
| 813 | } | ||
| 814 | |||
| 815 | scsi_log_completion(cmd, disposition); | ||
| 816 | switch (disposition) { | ||
| 817 | case SUCCESS: | ||
| 818 | scsi_finish_command(cmd); | ||
| 819 | break; | ||
| 820 | case NEEDS_RETRY: | ||
| 821 | scsi_retry_command(cmd); | ||
| 822 | break; | ||
| 823 | case ADD_TO_MLQUEUE: | ||
| 824 | scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); | ||
| 825 | break; | ||
| 826 | default: | ||
| 827 | if (!scsi_eh_scmd_add(cmd, 0)) | ||
| 828 | scsi_finish_command(cmd); | ||
| 829 | } | ||
| 830 | } | ||
| 831 | } | 773 | } |
| 832 | 774 | ||
| 833 | /* | 775 | /* |
| @@ -840,7 +782,7 @@ static void scsi_softirq(struct softirq_action *h) | |||
| 840 | * level drivers should not become re-entrant as a result of | 782 | * level drivers should not become re-entrant as a result of |
| 841 | * this. | 783 | * this. |
| 842 | */ | 784 | */ |
| 843 | static int scsi_retry_command(struct scsi_cmnd *cmd) | 785 | int scsi_retry_command(struct scsi_cmnd *cmd) |
| 844 | { | 786 | { |
| 845 | /* | 787 | /* |
| 846 | * Restore the SCSI command state. | 788 | * Restore the SCSI command state. |
| @@ -1273,38 +1215,6 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) | |||
| 1273 | } | 1215 | } |
| 1274 | EXPORT_SYMBOL(scsi_device_cancel); | 1216 | EXPORT_SYMBOL(scsi_device_cancel); |
| 1275 | 1217 | ||
| 1276 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 1277 | static int scsi_cpu_notify(struct notifier_block *self, | ||
| 1278 | unsigned long action, void *hcpu) | ||
| 1279 | { | ||
| 1280 | int cpu = (unsigned long)hcpu; | ||
| 1281 | |||
| 1282 | switch(action) { | ||
| 1283 | case CPU_DEAD: | ||
| 1284 | /* Drain scsi_done_q. */ | ||
| 1285 | local_irq_disable(); | ||
| 1286 | list_splice_init(&per_cpu(scsi_done_q, cpu), | ||
| 1287 | &__get_cpu_var(scsi_done_q)); | ||
| 1288 | raise_softirq_irqoff(SCSI_SOFTIRQ); | ||
| 1289 | local_irq_enable(); | ||
| 1290 | break; | ||
| 1291 | default: | ||
| 1292 | break; | ||
| 1293 | } | ||
| 1294 | return NOTIFY_OK; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | static struct notifier_block __devinitdata scsi_cpu_nb = { | ||
| 1298 | .notifier_call = scsi_cpu_notify, | ||
| 1299 | }; | ||
| 1300 | |||
| 1301 | #define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb) | ||
| 1302 | #define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb) | ||
| 1303 | #else | ||
| 1304 | #define register_scsi_cpu() | ||
| 1305 | #define unregister_scsi_cpu() | ||
| 1306 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
| 1307 | |||
| 1308 | MODULE_DESCRIPTION("SCSI core"); | 1218 | MODULE_DESCRIPTION("SCSI core"); |
| 1309 | MODULE_LICENSE("GPL"); | 1219 | MODULE_LICENSE("GPL"); |
| 1310 | 1220 | ||
| @@ -1338,8 +1248,6 @@ static int __init init_scsi(void) | |||
| 1338 | INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); | 1248 | INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); |
| 1339 | 1249 | ||
| 1340 | devfs_mk_dir("scsi"); | 1250 | devfs_mk_dir("scsi"); |
| 1341 | open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); | ||
| 1342 | register_scsi_cpu(); | ||
| 1343 | printk(KERN_NOTICE "SCSI subsystem initialized\n"); | 1251 | printk(KERN_NOTICE "SCSI subsystem initialized\n"); |
| 1344 | return 0; | 1252 | return 0; |
| 1345 | 1253 | ||
| @@ -1367,7 +1275,6 @@ static void __exit exit_scsi(void) | |||
| 1367 | devfs_remove("scsi"); | 1275 | devfs_remove("scsi"); |
| 1368 | scsi_exit_procfs(); | 1276 | scsi_exit_procfs(); |
| 1369 | scsi_exit_queue(); | 1277 | scsi_exit_queue(); |
| 1370 | unregister_scsi_cpu(); | ||
| 1371 | } | 1278 | } |
| 1372 | 1279 | ||
| 1373 | subsys_initcall(init_scsi); | 1280 | subsys_initcall(init_scsi); |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba93d6e66d48..00c9bf383e23 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -1493,6 +1493,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) | |||
| 1493 | __scsi_done(cmd); | 1493 | __scsi_done(cmd); |
| 1494 | } | 1494 | } |
| 1495 | 1495 | ||
| 1496 | static void scsi_softirq_done(struct request *rq) | ||
| 1497 | { | ||
| 1498 | struct scsi_cmnd *cmd = rq->completion_data; | ||
| 1499 | unsigned long wait_for = cmd->allowed * cmd->timeout_per_command; | ||
| 1500 | int disposition; | ||
| 1501 | |||
| 1502 | INIT_LIST_HEAD(&cmd->eh_entry); | ||
| 1503 | |||
| 1504 | disposition = scsi_decide_disposition(cmd); | ||
| 1505 | if (disposition != SUCCESS && | ||
| 1506 | time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { | ||
| 1507 | sdev_printk(KERN_ERR, cmd->device, | ||
| 1508 | "timing out command, waited %lus\n", | ||
| 1509 | wait_for/HZ); | ||
| 1510 | disposition = SUCCESS; | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | scsi_log_completion(cmd, disposition); | ||
| 1514 | |||
| 1515 | switch (disposition) { | ||
| 1516 | case SUCCESS: | ||
| 1517 | scsi_finish_command(cmd); | ||
| 1518 | break; | ||
| 1519 | case NEEDS_RETRY: | ||
| 1520 | scsi_retry_command(cmd); | ||
| 1521 | break; | ||
| 1522 | case ADD_TO_MLQUEUE: | ||
| 1523 | scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); | ||
| 1524 | break; | ||
| 1525 | default: | ||
| 1526 | if (!scsi_eh_scmd_add(cmd, 0)) | ||
| 1527 | scsi_finish_command(cmd); | ||
| 1528 | } | ||
| 1529 | } | ||
| 1530 | |||
| 1496 | /* | 1531 | /* |
| 1497 | * Function: scsi_request_fn() | 1532 | * Function: scsi_request_fn() |
| 1498 | * | 1533 | * |
| @@ -1667,6 +1702,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) | |||
| 1667 | blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); | 1702 | blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); |
| 1668 | blk_queue_segment_boundary(q, shost->dma_boundary); | 1703 | blk_queue_segment_boundary(q, shost->dma_boundary); |
| 1669 | blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); | 1704 | blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); |
| 1705 | blk_queue_softirq_done(q, scsi_softirq_done); | ||
| 1670 | 1706 | ||
| 1671 | if (!shost->use_clustering) | 1707 | if (!shost->use_clustering) |
| 1672 | clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); | 1708 | clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); |
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index f04e7e11f57a..14a6198cb8d2 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
| @@ -44,6 +44,7 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, | |||
| 44 | struct scsi_request *sreq); | 44 | struct scsi_request *sreq); |
| 45 | extern void __scsi_release_request(struct scsi_request *sreq); | 45 | extern void __scsi_release_request(struct scsi_request *sreq); |
| 46 | extern void __scsi_done(struct scsi_cmnd *cmd); | 46 | extern void __scsi_done(struct scsi_cmnd *cmd); |
| 47 | extern int scsi_retry_command(struct scsi_cmnd *cmd); | ||
| 47 | #ifdef CONFIG_SCSI_LOGGING | 48 | #ifdef CONFIG_SCSI_LOGGING |
| 48 | void scsi_log_send(struct scsi_cmnd *cmd); | 49 | void scsi_log_send(struct scsi_cmnd *cmd); |
| 49 | void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); | 50 | void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f02204706984..2c08fdc2bdf7 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
| @@ -113,7 +113,6 @@ enum | |||
| 113 | NET_TX_SOFTIRQ, | 113 | NET_TX_SOFTIRQ, |
| 114 | NET_RX_SOFTIRQ, | 114 | NET_RX_SOFTIRQ, |
| 115 | BLOCK_SOFTIRQ, | 115 | BLOCK_SOFTIRQ, |
| 116 | SCSI_SOFTIRQ, | ||
| 117 | TASKLET_SOFTIRQ | 116 | TASKLET_SOFTIRQ |
| 118 | }; | 117 | }; |
| 119 | 118 | ||
