aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/hosts.c14
-rw-r--r--drivers/scsi/scsi.c3
-rw-r--r--drivers/scsi/scsi_error.c151
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--include/scsi/scsi_cmnd.h1
-rw-r--r--include/scsi/scsi_host.h10
6 files changed, 167 insertions, 14 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index f2c5005f312a..c3ab093dd8a7 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -169,6 +169,7 @@ void scsi_remove_host(struct Scsi_Host *shost)
169 spin_unlock_irqrestore(shost->host_lock, flags); 169 spin_unlock_irqrestore(shost->host_lock, flags);
170 170
171 scsi_autopm_get_host(shost); 171 scsi_autopm_get_host(shost);
172 flush_workqueue(shost->tmf_work_q);
172 scsi_forget_host(shost); 173 scsi_forget_host(shost);
173 mutex_unlock(&shost->scan_mutex); 174 mutex_unlock(&shost->scan_mutex);
174 scsi_proc_host_rm(shost); 175 scsi_proc_host_rm(shost);
@@ -294,6 +295,8 @@ static void scsi_host_dev_release(struct device *dev)
294 295
295 scsi_proc_hostdir_rm(shost->hostt); 296 scsi_proc_hostdir_rm(shost->hostt);
296 297
298 if (shost->tmf_work_q)
299 destroy_workqueue(shost->tmf_work_q);
297 if (shost->ehandler) 300 if (shost->ehandler)
298 kthread_stop(shost->ehandler); 301 kthread_stop(shost->ehandler);
299 if (shost->work_q) 302 if (shost->work_q)
@@ -360,7 +363,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
360 INIT_LIST_HEAD(&shost->eh_cmd_q); 363 INIT_LIST_HEAD(&shost->eh_cmd_q);
361 INIT_LIST_HEAD(&shost->starved_list); 364 INIT_LIST_HEAD(&shost->starved_list);
362 init_waitqueue_head(&shost->host_wait); 365 init_waitqueue_head(&shost->host_wait);
363
364 mutex_init(&shost->scan_mutex); 366 mutex_init(&shost->scan_mutex);
365 367
366 /* 368 /*
@@ -444,9 +446,19 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
444 goto fail_kfree; 446 goto fail_kfree;
445 } 447 }
446 448
449 shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
450 WQ_UNBOUND | WQ_MEM_RECLAIM,
451 1, shost->host_no);
452 if (!shost->tmf_work_q) {
453 printk(KERN_WARNING "scsi%d: failed to create tmf workq\n",
454 shost->host_no);
455 goto fail_kthread;
456 }
447 scsi_proc_hostdir_add(shost->hostt); 457 scsi_proc_hostdir_add(shost->hostt);
448 return shost; 458 return shost;
449 459
460 fail_kthread:
461 kthread_stop(shost->ehandler);
450 fail_kfree: 462 fail_kfree:
451 kfree(shost); 463 kfree(shost);
452 return NULL; 464 return NULL;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index fe0bcb18fb26..2b04a57e0f4f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -297,6 +297,7 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
297 297
298 cmd->device = dev; 298 cmd->device = dev;
299 INIT_LIST_HEAD(&cmd->list); 299 INIT_LIST_HEAD(&cmd->list);
300 INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
300 spin_lock_irqsave(&dev->list_lock, flags); 301 spin_lock_irqsave(&dev->list_lock, flags);
301 list_add_tail(&cmd->list, &dev->cmd_list); 302 list_add_tail(&cmd->list, &dev->cmd_list);
302 spin_unlock_irqrestore(&dev->list_lock, flags); 303 spin_unlock_irqrestore(&dev->list_lock, flags);
@@ -353,6 +354,8 @@ void scsi_put_command(struct scsi_cmnd *cmd)
353 list_del_init(&cmd->list); 354 list_del_init(&cmd->list);
354 spin_unlock_irqrestore(&cmd->device->list_lock, flags); 355 spin_unlock_irqrestore(&cmd->device->list_lock, flags);
355 356
357 cancel_delayed_work(&cmd->abort_work);
358
356 __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev); 359 __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
357} 360}
358EXPORT_SYMBOL(scsi_put_command); 361EXPORT_SYMBOL(scsi_put_command);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 67c001457cb8..3dd04026d466 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -53,6 +53,8 @@ static void scsi_eh_done(struct scsi_cmnd *scmd);
53#define HOST_RESET_SETTLE_TIME (10) 53#define HOST_RESET_SETTLE_TIME (10)
54 54
55static int scsi_eh_try_stu(struct scsi_cmnd *scmd); 55static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
56static int scsi_try_to_abort_cmd(struct scsi_host_template *,
57 struct scsi_cmnd *);
56 58
57/* called with shost->host_lock held */ 59/* called with shost->host_lock held */
58void scsi_eh_wakeup(struct Scsi_Host *shost) 60void scsi_eh_wakeup(struct Scsi_Host *shost)
@@ -100,6 +102,116 @@ static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
100} 102}
101 103
102/** 104/**
105 * scmd_eh_abort_handler - Handle command aborts
106 * @work: command to be aborted.
107 */
108void
109scmd_eh_abort_handler(struct work_struct *work)
110{
111 struct scsi_cmnd *scmd =
112 container_of(work, struct scsi_cmnd, abort_work.work);
113 struct scsi_device *sdev = scmd->device;
114 unsigned long flags;
115 int rtn;
116
117 spin_lock_irqsave(sdev->host->host_lock, flags);
118 if (scsi_host_eh_past_deadline(sdev->host)) {
119 spin_unlock_irqrestore(sdev->host->host_lock, flags);
120 SCSI_LOG_ERROR_RECOVERY(3,
121 scmd_printk(KERN_INFO, scmd,
122 "scmd %p eh timeout, not aborting\n",
123 scmd));
124 } else {
125 spin_unlock_irqrestore(sdev->host->host_lock, flags);
126 SCSI_LOG_ERROR_RECOVERY(3,
127 scmd_printk(KERN_INFO, scmd,
128 "aborting command %p\n", scmd));
129 rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
130 if (rtn == SUCCESS) {
131 scmd->result |= DID_TIME_OUT << 16;
132 if (!scsi_noretry_cmd(scmd) &&
133 (++scmd->retries <= scmd->allowed)) {
134 SCSI_LOG_ERROR_RECOVERY(3,
135 scmd_printk(KERN_WARNING, scmd,
136 "scmd %p retry "
137 "aborted command\n", scmd));
138 scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
139 } else {
140 SCSI_LOG_ERROR_RECOVERY(3,
141 scmd_printk(KERN_WARNING, scmd,
142 "scmd %p finish "
143 "aborted command\n", scmd));
144 scsi_finish_command(scmd);
145 }
146 return;
147 }
148 SCSI_LOG_ERROR_RECOVERY(3,
149 scmd_printk(KERN_INFO, scmd,
150 "scmd %p abort failed, rtn %d\n",
151 scmd, rtn));
152 }
153
154 if (!scsi_eh_scmd_add(scmd, 0)) {
155 SCSI_LOG_ERROR_RECOVERY(3,
156 scmd_printk(KERN_WARNING, scmd,
157 "scmd %p terminate "
158 "aborted command\n", scmd));
159 scmd->result |= DID_TIME_OUT << 16;
160 scsi_finish_command(scmd);
161 }
162}
163
164/**
165 * scsi_abort_command - schedule a command abort
166 * @scmd: scmd to abort.
167 *
168 * We only need to abort commands after a command timeout
169 */
170static int
171scsi_abort_command(struct scsi_cmnd *scmd)
172{
173 struct scsi_device *sdev = scmd->device;
174 struct Scsi_Host *shost = sdev->host;
175 unsigned long flags;
176
177 if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
178 /*
179 * Retry after abort failed, escalate to next level.
180 */
181 SCSI_LOG_ERROR_RECOVERY(3,
182 scmd_printk(KERN_INFO, scmd,
183 "scmd %p previous abort failed\n", scmd));
184 cancel_delayed_work(&scmd->abort_work);
185 return FAILED;
186 }
187
188 /*
189 * Do not try a command abort if
190 * SCSI EH has already started.
191 */
192 spin_lock_irqsave(shost->host_lock, flags);
193 if (scsi_host_in_recovery(shost)) {
194 spin_unlock_irqrestore(shost->host_lock, flags);
195 SCSI_LOG_ERROR_RECOVERY(3,
196 scmd_printk(KERN_INFO, scmd,
197 "scmd %p not aborting, host in recovery\n",
198 scmd));
199 return FAILED;
200 }
201
202 if (shost->eh_deadline && !shost->last_reset)
203 shost->last_reset = jiffies;
204 spin_unlock_irqrestore(shost->host_lock, flags);
205
206 scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
207 SCSI_LOG_ERROR_RECOVERY(3,
208 scmd_printk(KERN_INFO, scmd,
209 "scmd %p abort scheduled\n", scmd));
210 queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
211 return SUCCESS;
212}
213
214/**
103 * scsi_eh_scmd_add - add scsi cmd to error handling. 215 * scsi_eh_scmd_add - add scsi cmd to error handling.
104 * @scmd: scmd to run eh on. 216 * @scmd: scmd to run eh on.
105 * @eh_flag: optional SCSI_EH flag. 217 * @eh_flag: optional SCSI_EH flag.
@@ -125,6 +237,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
125 shost->last_reset = jiffies; 237 shost->last_reset = jiffies;
126 238
127 ret = 1; 239 ret = 1;
240 if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
241 eh_flag &= ~SCSI_EH_CANCEL_CMD;
128 scmd->eh_eflags |= eh_flag; 242 scmd->eh_eflags |= eh_flag;
129 list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); 243 list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
130 shost->host_failed++; 244 shost->host_failed++;
@@ -161,6 +275,10 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
161 else if (host->hostt->eh_timed_out) 275 else if (host->hostt->eh_timed_out)
162 rtn = host->hostt->eh_timed_out(scmd); 276 rtn = host->hostt->eh_timed_out(scmd);
163 277
278 if (rtn == BLK_EH_NOT_HANDLED && !host->hostt->no_async_abort)
279 if (scsi_abort_command(scmd) == SUCCESS)
280 return BLK_EH_NOT_HANDLED;
281
164 scmd->result |= DID_TIME_OUT << 16; 282 scmd->result |= DID_TIME_OUT << 16;
165 283
166 if (unlikely(rtn == BLK_EH_NOT_HANDLED && 284 if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
@@ -1577,7 +1695,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
1577} 1695}
1578 1696
1579/** 1697/**
1580 * scsi_noretry_cmd - determinte if command should be failed fast 1698 * scsi_noretry_cmd - determine if command should be failed fast
1581 * @scmd: SCSI cmd to examine. 1699 * @scmd: SCSI cmd to examine.
1582 */ 1700 */
1583int scsi_noretry_cmd(struct scsi_cmnd *scmd) 1701int scsi_noretry_cmd(struct scsi_cmnd *scmd)
@@ -1585,6 +1703,8 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
1585 switch (host_byte(scmd->result)) { 1703 switch (host_byte(scmd->result)) {
1586 case DID_OK: 1704 case DID_OK:
1587 break; 1705 break;
1706 case DID_TIME_OUT:
1707 goto check_type;
1588 case DID_BUS_BUSY: 1708 case DID_BUS_BUSY:
1589 return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT); 1709 return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT);
1590 case DID_PARITY: 1710 case DID_PARITY:
@@ -1598,18 +1718,19 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
1598 return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER); 1718 return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
1599 } 1719 }
1600 1720
1601 switch (status_byte(scmd->result)) { 1721 if (status_byte(scmd->result) != CHECK_CONDITION)
1602 case CHECK_CONDITION: 1722 return 0;
1603 /*
1604 * assume caller has checked sense and determinted
1605 * the check condition was retryable.
1606 */
1607 if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
1608 scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
1609 return 1;
1610 }
1611 1723
1612 return 0; 1724check_type:
1725 /*
1726 * assume caller has checked sense and determined
1727 * the check condition was retryable.
1728 */
1729 if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
1730 scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
1731 return 1;
1732 else
1733 return 0;
1613} 1734}
1614 1735
1615/** 1736/**
@@ -1659,9 +1780,13 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
1659 * looks good. drop through, and check the next byte. 1780 * looks good. drop through, and check the next byte.
1660 */ 1781 */
1661 break; 1782 break;
1783 case DID_ABORT:
1784 if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
1785 scmd->result |= DID_TIME_OUT << 16;
1786 return SUCCESS;
1787 }
1662 case DID_NO_CONNECT: 1788 case DID_NO_CONNECT:
1663 case DID_BAD_TARGET: 1789 case DID_BAD_TARGET:
1664 case DID_ABORT:
1665 /* 1790 /*
1666 * note - this means that we just report the status back 1791 * note - this means that we just report the status back
1667 * to the top level driver, not that we actually think 1792 * to the top level driver, not that we actually think
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 8f9a0cadc296..f079a598bed4 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -19,6 +19,7 @@ struct scsi_nl_hdr;
19 * Scsi Error Handler Flags 19 * Scsi Error Handler Flags
20 */ 20 */
21#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */ 21#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */
22#define SCSI_EH_ABORT_SCHEDULED 0x0002 /* Abort has been scheduled */
22 23
23#define SCSI_SENSE_VALID(scmd) \ 24#define SCSI_SENSE_VALID(scmd) \
24 (((scmd)->sense_buffer[0] & 0x70) == 0x70) 25 (((scmd)->sense_buffer[0] & 0x70) == 0x70)
@@ -66,6 +67,7 @@ extern int __init scsi_init_devinfo(void);
66extern void scsi_exit_devinfo(void); 67extern void scsi_exit_devinfo(void);
67 68
68/* scsi_error.c */ 69/* scsi_error.c */
70extern void scmd_eh_abort_handler(struct work_struct *work);
69extern enum blk_eh_timer_return scsi_times_out(struct request *req); 71extern enum blk_eh_timer_return scsi_times_out(struct request *req);
70extern int scsi_error_handler(void *host); 72extern int scsi_error_handler(void *host);
71extern int scsi_decide_disposition(struct scsi_cmnd *cmd); 73extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index de5f5d8f1f8a..91558a1f97f4 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -55,6 +55,7 @@ struct scsi_cmnd {
55 struct scsi_device *device; 55 struct scsi_device *device;
56 struct list_head list; /* scsi_cmnd participates in queue lists */ 56 struct list_head list; /* scsi_cmnd participates in queue lists */
57 struct list_head eh_entry; /* entry for the host eh_cmd_q */ 57 struct list_head eh_entry; /* entry for the host eh_cmd_q */
58 struct delayed_work abort_work;
58 int eh_eflags; /* Used by error handlr */ 59 int eh_eflags; /* Used by error handlr */
59 60
60 /* 61 /*
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index fe3b58e836c8..53075e5039e6 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -479,6 +479,11 @@ struct scsi_host_template {
479 unsigned no_write_same:1; 479 unsigned no_write_same:1;
480 480
481 /* 481 /*
482 * True if asynchronous aborts are not supported
483 */
484 unsigned no_async_abort:1;
485
486 /*
482 * Countdown for host blocking with no commands outstanding. 487 * Countdown for host blocking with no commands outstanding.
483 */ 488 */
484 unsigned int max_host_blocked; 489 unsigned int max_host_blocked;
@@ -690,6 +695,11 @@ struct Scsi_Host {
690 struct workqueue_struct *work_q; 695 struct workqueue_struct *work_q;
691 696
692 /* 697 /*
698 * Task management function work queue
699 */
700 struct workqueue_struct *tmf_work_q;
701
702 /*
693 * Host has rejected a command because it was busy. 703 * Host has rejected a command because it was busy.
694 */ 704 */
695 unsigned int host_blocked; 705 unsigned int host_blocked;