Commit 21af8107 authored by David S. Miller's avatar David S. Miller

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: default avatarMeelis Roos <mroos@linux.ee>
Tested-by: default avatarMeelis Roos <mroos@linux.ee>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab2abda6
...@@ -530,7 +530,7 @@ static int esp_need_to_nego_sync(struct esp_target_data *tp) ...@@ -530,7 +530,7 @@ static int esp_need_to_nego_sync(struct esp_target_data *tp)
static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
struct esp_lun_data *lp) struct esp_lun_data *lp)
{ {
if (!ent->tag[0]) { if (!ent->orig_tag[0]) {
/* Non-tagged, slot already taken? */ /* Non-tagged, slot already taken? */
if (lp->non_tagged_cmd) if (lp->non_tagged_cmd)
return -EBUSY; return -EBUSY;
...@@ -564,9 +564,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, ...@@ -564,9 +564,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
return -EBUSY; return -EBUSY;
} }
BUG_ON(lp->tagged_cmds[ent->tag[1]]); BUG_ON(lp->tagged_cmds[ent->orig_tag[1]]);
lp->tagged_cmds[ent->tag[1]] = ent; lp->tagged_cmds[ent->orig_tag[1]] = ent;
lp->num_tagged++; lp->num_tagged++;
return 0; return 0;
...@@ -575,9 +575,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, ...@@ -575,9 +575,9 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
static void esp_free_lun_tag(struct esp_cmd_entry *ent, static void esp_free_lun_tag(struct esp_cmd_entry *ent,
struct esp_lun_data *lp) struct esp_lun_data *lp)
{ {
if (ent->tag[0]) { if (ent->orig_tag[0]) {
BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent); BUG_ON(lp->tagged_cmds[ent->orig_tag[1]] != ent);
lp->tagged_cmds[ent->tag[1]] = NULL; lp->tagged_cmds[ent->orig_tag[1]] = NULL;
lp->num_tagged--; lp->num_tagged--;
} else { } else {
BUG_ON(lp->non_tagged_cmd != ent); 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,6 +667,8 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
ent->tag[0] = 0; ent->tag[0] = 0;
ent->tag[1] = 0; ent->tag[1] = 0;
} }
ent->orig_tag[0] = ent->tag[0];
ent->orig_tag[1] = ent->tag[1];
if (esp_alloc_lun_tag(ent, lp) < 0) if (esp_alloc_lun_tag(ent, lp) < 0)
continue; continue;
......
...@@ -271,6 +271,7 @@ struct esp_cmd_entry { ...@@ -271,6 +271,7 @@ struct esp_cmd_entry {
#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ #define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
u8 tag[2]; u8 tag[2];
u8 orig_tag[2];
u8 status; u8 status;
u8 message; u8 message;
......
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