aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-09-12 17:46:51 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:57 -0400
commitc82dc88ddaf17112841dd3a6b08352968555ee08 (patch)
tree6be63f298247641ccec9766e68a5d3a727d8a87d /drivers/scsi
parentea2151b4e142fa2de0319d9dd80413a997bf435a (diff)
[SCSI] scsi_error: fix target reset handling
There's a target reset bug. This loop: for (id = 0; id <= shost->max_id; id++) { Never terminates if shost->max_id is set to ~0, like aic94xx does. It's also pretty inefficient since you mostly have compact target numbers, but the max_id can be very high. The best way would be to sort the recovery list by target id and skip them if they're equal, but even a worst case O(N^2) traversal is probably OK here, so fix it by finding the next highest target number (assuming n+1) and terminating when there isn't one. Cc: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_error.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index ad019ece2139..94ed262bdf0c 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1065,10 +1065,10 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
1065 struct list_head *done_q) 1065 struct list_head *done_q)
1066{ 1066{
1067 struct scsi_cmnd *scmd, *tgtr_scmd, *next; 1067 struct scsi_cmnd *scmd, *tgtr_scmd, *next;
1068 unsigned int id; 1068 unsigned int id = 0;
1069 int rtn; 1069 int rtn;
1070 1070
1071 for (id = 0; id <= shost->max_id; id++) { 1071 do {
1072 tgtr_scmd = NULL; 1072 tgtr_scmd = NULL;
1073 list_for_each_entry(scmd, work_q, eh_entry) { 1073 list_for_each_entry(scmd, work_q, eh_entry) {
1074 if (id == scmd_id(scmd)) { 1074 if (id == scmd_id(scmd)) {
@@ -1076,8 +1076,18 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
1076 break; 1076 break;
1077 } 1077 }
1078 } 1078 }
1079 if (!tgtr_scmd) {
1080 /* not one exactly equal; find the next highest */
1081 list_for_each_entry(scmd, work_q, eh_entry) {
1082 if (scmd_id(scmd) > id &&
1083 (!tgtr_scmd ||
1084 scmd_id(tgtr_scmd) > scmd_id(scmd)))
1085 tgtr_scmd = scmd;
1086 }
1087 }
1079 if (!tgtr_scmd) 1088 if (!tgtr_scmd)
1080 continue; 1089 /* no more commands, that's it */
1090 break;
1081 1091
1082 SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " 1092 SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
1083 "to target %d\n", 1093 "to target %d\n",
@@ -1096,7 +1106,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
1096 " failed target: " 1106 " failed target: "
1097 "%d\n", 1107 "%d\n",
1098 current->comm, id)); 1108 current->comm, id));
1099 } 1109 id++;
1110 } while(id != 0);
1100 1111
1101 return list_empty(work_q); 1112 return list_empty(work_q);
1102} 1113}