aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-08-01 21:08:34 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-01 21:08:34 -0400
commit21af8107f27878813d0364733c0b08813c2c192a (patch)
tree5a5f4867228e9e394ef9dc75f59878eba268eaf7
parentab2abda6377723e0d5fbbfe5f5aa16a5523344d1 (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.c14
-rw-r--r--drivers/scsi/esp_scsi.h1
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)
530static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, 530static 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,
575static void esp_free_lun_tag(struct esp_cmd_entry *ent, 575static 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;