aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <jbottomley@parallels.com>2013-11-11 07:44:53 -0500
committerJames Bottomley <JBottomley@Parallels.com>2013-12-19 10:39:02 -0500
commit2451079bc2ae1334058be8babd44be03ecfa7041 (patch)
tree6c1e7c36d47108fb094a8e97062b56fe573e16e8
parent1a4049ddfdaa75db7c9927dbc4d991bd73f923a0 (diff)
[SCSI] Fix erratic device offline during EH
Commit 18a4d0a22ed6c54b67af7718c305cd010f09ddf8 (Handle disk devices which can not process medium access commands) was introduced to offline any device which cannot process medium access commands. However, commit 3eef6257de48ff84a5d98ca533685df8a3beaeb8 (Reduce error recovery time by reducing use of TURs) reduced the number of TURs by sending it only on the first failing command, which might or might not be a medium access command. So in combination this results in an erratic device offlining during EH; if the command where the TUR was sent upon happens to be a medium access command the device will be set offline, if not everything proceeds as normal. This patch moves the check to the final test, eliminating this problem. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/scsi_error.c26
-rw-r--r--drivers/scsi/sd.c26
-rw-r--r--include/scsi/scsi_driver.h2
3 files changed, 30 insertions, 24 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e8bee9f0ad0f..67c001457cb8 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -941,12 +941,6 @@ retry:
941 941
942 scsi_eh_restore_cmnd(scmd, &ses); 942 scsi_eh_restore_cmnd(scmd, &ses);
943 943
944 if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
945 struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
946 if (sdrv->eh_action)
947 rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn);
948 }
949
950 return rtn; 944 return rtn;
951} 945}
952 946
@@ -964,6 +958,16 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
964 return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0); 958 return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0);
965} 959}
966 960
961static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn)
962{
963 if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
964 struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
965 if (sdrv->eh_action)
966 rtn = sdrv->eh_action(scmd, rtn);
967 }
968 return rtn;
969}
970
967/** 971/**
968 * scsi_eh_finish_cmd - Handle a cmd that eh is finished with. 972 * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
969 * @scmd: Original SCSI cmd that eh has finished. 973 * @scmd: Original SCSI cmd that eh has finished.
@@ -1142,7 +1146,9 @@ static int scsi_eh_test_devices(struct list_head *cmd_list,
1142 1146
1143 list_for_each_entry_safe(scmd, next, cmd_list, eh_entry) 1147 list_for_each_entry_safe(scmd, next, cmd_list, eh_entry)
1144 if (scmd->device == sdev) { 1148 if (scmd->device == sdev) {
1145 if (finish_cmds) 1149 if (finish_cmds &&
1150 (try_stu ||
1151 scsi_eh_action(scmd, SUCCESS) == SUCCESS))
1146 scsi_eh_finish_cmd(scmd, done_q); 1152 scsi_eh_finish_cmd(scmd, done_q);
1147 else 1153 else
1148 list_move_tail(&scmd->eh_entry, work_q); 1154 list_move_tail(&scmd->eh_entry, work_q);
@@ -1283,7 +1289,8 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
1283 !scsi_eh_tur(stu_scmd)) { 1289 !scsi_eh_tur(stu_scmd)) {
1284 list_for_each_entry_safe(scmd, next, 1290 list_for_each_entry_safe(scmd, next,
1285 work_q, eh_entry) { 1291 work_q, eh_entry) {
1286 if (scmd->device == sdev) 1292 if (scmd->device == sdev &&
1293 scsi_eh_action(scmd, SUCCESS) == SUCCESS)
1287 scsi_eh_finish_cmd(scmd, done_q); 1294 scsi_eh_finish_cmd(scmd, done_q);
1288 } 1295 }
1289 } 1296 }
@@ -1350,7 +1357,8 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
1350 !scsi_eh_tur(bdr_scmd)) { 1357 !scsi_eh_tur(bdr_scmd)) {
1351 list_for_each_entry_safe(scmd, next, 1358 list_for_each_entry_safe(scmd, next,
1352 work_q, eh_entry) { 1359 work_q, eh_entry) {
1353 if (scmd->device == sdev) 1360 if (scmd->device == sdev &&
1361 scsi_eh_action(scmd, rtn) != FAILED)
1354 scsi_eh_finish_cmd(scmd, 1362 scsi_eh_finish_cmd(scmd,
1355 done_q); 1363 done_q);
1356 } 1364 }
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 69725f7c32c1..35a785609364 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -110,7 +110,7 @@ static int sd_suspend_runtime(struct device *);
110static int sd_resume(struct device *); 110static int sd_resume(struct device *);
111static void sd_rescan(struct device *); 111static void sd_rescan(struct device *);
112static int sd_done(struct scsi_cmnd *); 112static int sd_done(struct scsi_cmnd *);
113static int sd_eh_action(struct scsi_cmnd *, unsigned char *, int, int); 113static int sd_eh_action(struct scsi_cmnd *, int);
114static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); 114static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
115static void scsi_disk_release(struct device *cdev); 115static void scsi_disk_release(struct device *cdev);
116static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); 116static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
@@ -1551,23 +1551,23 @@ static const struct block_device_operations sd_fops = {
1551/** 1551/**
1552 * sd_eh_action - error handling callback 1552 * sd_eh_action - error handling callback
1553 * @scmd: sd-issued command that has failed 1553 * @scmd: sd-issued command that has failed
1554 * @eh_cmnd: The command that was sent during error handling
1555 * @eh_cmnd_len: Length of eh_cmnd in bytes
1556 * @eh_disp: The recovery disposition suggested by the midlayer 1554 * @eh_disp: The recovery disposition suggested by the midlayer
1557 * 1555 *
1558 * This function is called by the SCSI midlayer upon completion of 1556 * This function is called by the SCSI midlayer upon completion of an
1559 * an error handling command (TEST UNIT READY, START STOP UNIT, 1557 * error test command (currently TEST UNIT READY). The result of sending
1560 * etc.) The command sent to the device by the error handler is 1558 * the eh command is passed in eh_disp. We're looking for devices that
1561 * stored in eh_cmnd. The result of sending the eh command is 1559 * fail medium access commands but are OK with non access commands like
1562 * passed in eh_disp. 1560 * test unit ready (so wrongly see the device as having a successful
1561 * recovery)
1563 **/ 1562 **/
1564static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd, 1563static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp)
1565 int eh_cmnd_len, int eh_disp)
1566{ 1564{
1567 struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk); 1565 struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk);
1568 1566
1569 if (!scsi_device_online(scmd->device) || 1567 if (!scsi_device_online(scmd->device) ||
1570 !scsi_medium_access_command(scmd)) 1568 !scsi_medium_access_command(scmd) ||
1569 host_byte(scmd->result) != DID_TIME_OUT ||
1570 eh_disp != SUCCESS)
1571 return eh_disp; 1571 return eh_disp;
1572 1572
1573 /* 1573 /*
@@ -1577,9 +1577,7 @@ static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd,
1577 * process of recovering or has it suffered an internal failure 1577 * process of recovering or has it suffered an internal failure
1578 * that prevents access to the storage medium. 1578 * that prevents access to the storage medium.
1579 */ 1579 */
1580 if (host_byte(scmd->result) == DID_TIME_OUT && eh_disp == SUCCESS && 1580 sdkp->medium_access_timed_out++;
1581 eh_cmnd_len && eh_cmnd[0] == TEST_UNIT_READY)
1582 sdkp->medium_access_timed_out++;
1583 1581
1584 /* 1582 /*
1585 * If the device keeps failing read/write commands but TEST UNIT 1583 * If the device keeps failing read/write commands but TEST UNIT
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index d443aa06a722..20fdfc2526ad 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -16,7 +16,7 @@ struct scsi_driver {
16 16
17 void (*rescan)(struct device *); 17 void (*rescan)(struct device *);
18 int (*done)(struct scsi_cmnd *); 18 int (*done)(struct scsi_cmnd *);
19 int (*eh_action)(struct scsi_cmnd *, unsigned char *, int, int); 19 int (*eh_action)(struct scsi_cmnd *, int);
20}; 20};
21#define to_scsi_driver(drv) \ 21#define to_scsi_driver(drv) \
22 container_of((drv), struct scsi_driver, gendrv) 22 container_of((drv), struct scsi_driver, gendrv)