Commit c82dc88d authored by James Bottomley's avatar James Bottomley

[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: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent ea2151b4
...@@ -1065,10 +1065,10 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, ...@@ -1065,10 +1065,10 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
struct list_head *done_q) struct list_head *done_q)
{ {
struct scsi_cmnd *scmd, *tgtr_scmd, *next; struct scsi_cmnd *scmd, *tgtr_scmd, *next;
unsigned int id; unsigned int id = 0;
int rtn; int rtn;
for (id = 0; id <= shost->max_id; id++) { do {
tgtr_scmd = NULL; tgtr_scmd = NULL;
list_for_each_entry(scmd, work_q, eh_entry) { list_for_each_entry(scmd, work_q, eh_entry) {
if (id == scmd_id(scmd)) { if (id == scmd_id(scmd)) {
...@@ -1076,8 +1076,18 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, ...@@ -1076,8 +1076,18 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
break; break;
} }
} }
if (!tgtr_scmd) {
/* not one exactly equal; find the next highest */
list_for_each_entry(scmd, work_q, eh_entry) {
if (scmd_id(scmd) > id &&
(!tgtr_scmd ||
scmd_id(tgtr_scmd) > scmd_id(scmd)))
tgtr_scmd = scmd;
}
}
if (!tgtr_scmd) if (!tgtr_scmd)
continue; /* no more commands, that's it */
break;
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
"to target %d\n", "to target %d\n",
...@@ -1096,7 +1106,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, ...@@ -1096,7 +1106,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
" failed target: " " failed target: "
"%d\n", "%d\n",
current->comm, id)); current->comm, id));
} id++;
} while(id != 0);
return list_empty(work_q); return list_empty(work_q);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment