diff options
author | David S. Miller <davem@davemloft.net> | 2013-08-01 21:08:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-01 21:08:34 -0400 |
commit | 21af8107f27878813d0364733c0b08813c2c192a (patch) | |
tree | 5a5f4867228e9e394ef9dc75f59878eba268eaf7 | |
parent | ab2abda6377723e0d5fbbfe5f5aa16a5523344d1 (diff) |
esp_scsi: Fix tag state corruption when autosensing.
Meelis Roos reports a crash in esp_free_lun_tag() in the presense
of a disk which has died.
The issue is that when we issue an autosense command, we do so by
hijacking the original command that caused the check-condition.
When we do so we clear out the ent->tag[] array when we issue it via
find_and_prep_issuable_command(). This is so that the autosense
command is forced to be issued non-tagged.
That is problematic, because it is the value of ent->tag[] which
determines whether we issued the original scsi command as tagged
vs. non-tagged (see esp_alloc_lun_tag()).
And that, in turn, is what trips up the sanity checks in
esp_free_lun_tag(). That function needs the original ->tag[] values
in order to free up the tag slot properly.
Fix this by remembering the original command's tag values, and
having esp_alloc_lun_tag() and esp_free_lun_tag() use them.
Reported-by: Meelis Roos <mroos@linux.ee>
Tested-by: Meelis Roos <mroos@linux.ee>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/scsi/esp_scsi.c | 14 | ||||
-rw-r--r-- | drivers/scsi/esp_scsi.h | 1 |
2 files changed, 9 insertions, 6 deletions
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 34552bf1c023..55548dc5cec3 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c | |||
@@ -530,7 +530,7 @@ static int esp_need_to_nego_sync(struct esp_target_data *tp) | |||
530 | static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, | 530 | static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, |
531 | struct esp_lun_data *lp) | 531 | struct esp_lun_data *lp) |
532 | { | 532 | { |
533 | if (!ent->tag[0]) { | 533 | if (!ent->orig_tag[0]) { |
534 | /* Non-tagged, slot already taken? */ | 534 | /* Non-tagged, slot already taken? */ |
535 | if (lp->non_tagged_cmd) | 535 | if (lp->non_tagged_cmd) |
536 | return -EBUSY; | 536 | return -EBUSY; |
@@ -564,9 +564,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, | |||
564 | return -EBUSY; | 564 | return -EBUSY; |
565 | } | 565 | } |
566 | 566 | ||
567 | BUG_ON(lp->tagged_cmds[ent->tag[1]]); | 567 | BUG_ON(lp->tagged_cmds[ent->orig_tag[1]]); |
568 | 568 | ||
569 | lp->tagged_cmds[ent->tag[1]] = ent; | 569 | lp->tagged_cmds[ent->orig_tag[1]] = ent; |
570 | lp->num_tagged++; | 570 | lp->num_tagged++; |
571 | 571 | ||
572 | return 0; | 572 | return 0; |
@@ -575,9 +575,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, | |||
575 | static void esp_free_lun_tag(struct esp_cmd_entry *ent, | 575 | static void esp_free_lun_tag(struct esp_cmd_entry *ent, |
576 | struct esp_lun_data *lp) | 576 | struct esp_lun_data *lp) |
577 | { | 577 | { |
578 | if (ent->tag[0]) { | 578 | if (ent->orig_tag[0]) { |
579 | BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent); | 579 | BUG_ON(lp->tagged_cmds[ent->orig_tag[1]] != ent); |
580 | lp->tagged_cmds[ent->tag[1]] = NULL; | 580 | lp->tagged_cmds[ent->orig_tag[1]] = NULL; |
581 | lp->num_tagged--; | 581 | lp->num_tagged--; |
582 | } else { | 582 | } else { |
583 | BUG_ON(lp->non_tagged_cmd != ent); | 583 | BUG_ON(lp->non_tagged_cmd != ent); |
@@ -667,6 +667,8 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) | |||
667 | ent->tag[0] = 0; | 667 | ent->tag[0] = 0; |
668 | ent->tag[1] = 0; | 668 | ent->tag[1] = 0; |
669 | } | 669 | } |
670 | ent->orig_tag[0] = ent->tag[0]; | ||
671 | ent->orig_tag[1] = ent->tag[1]; | ||
670 | 672 | ||
671 | if (esp_alloc_lun_tag(ent, lp) < 0) | 673 | if (esp_alloc_lun_tag(ent, lp) < 0) |
672 | continue; | 674 | continue; |
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index 28e22acf87ea..cd68805e8d78 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h | |||
@@ -271,6 +271,7 @@ struct esp_cmd_entry { | |||
271 | #define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ | 271 | #define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ |
272 | 272 | ||
273 | u8 tag[2]; | 273 | u8 tag[2]; |
274 | u8 orig_tag[2]; | ||
274 | 275 | ||
275 | u8 status; | 276 | u8 status; |
276 | u8 message; | 277 | u8 message; |