diff options
author | Don Brace <don.brace@microsemi.com> | 2019-05-07 14:32:13 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2019-06-18 19:46:18 -0400 |
commit | 4770e68d162634b2134741d08c49185f858c90ee (patch) | |
tree | afa72eabc55f9f63e8bea9b5a1fe0d3fd7822db5 | |
parent | 0119208885b3faf2459de6d3fcc6d090580b906f (diff) |
scsi: hpsa: check for tag collision
Correct rare multipath issue where a device is deleted with an
outstanding cmd which results in a tag collision.
The cmd eventually completes. If a collision is detected wait until
the command slot is cleared.
Reviewed-by: Justin Lindley <justin.lindley@microsemi.com>
Reviewed-by: David Carroll <david.carroll@microsemi.com>
Reviewed-by: Scott Teel <scott.teel@microsemi.com>
Signed-off-by: Don Brace <don.brace@microsemi.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/hpsa.c | 21 | ||||
-rw-r--r-- | drivers/scsi/hpsa.h | 1 |
2 files changed, 15 insertions, 7 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 61365fc87786..283fd603624b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
@@ -5635,6 +5635,8 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) | |||
5635 | return 0; | 5635 | return 0; |
5636 | } | 5636 | } |
5637 | c = cmd_tagged_alloc(h, cmd); | 5637 | c = cmd_tagged_alloc(h, cmd); |
5638 | if (c == NULL) | ||
5639 | return SCSI_MLQUEUE_DEVICE_BUSY; | ||
5638 | 5640 | ||
5639 | /* | 5641 | /* |
5640 | * Call alternate submit routine for I/O accelerated commands. | 5642 | * Call alternate submit routine for I/O accelerated commands. |
@@ -6041,7 +6043,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, | |||
6041 | BUG(); | 6043 | BUG(); |
6042 | } | 6044 | } |
6043 | 6045 | ||
6044 | atomic_inc(&c->refcount); | ||
6045 | if (unlikely(!hpsa_is_cmd_idle(c))) { | 6046 | if (unlikely(!hpsa_is_cmd_idle(c))) { |
6046 | /* | 6047 | /* |
6047 | * We expect that the SCSI layer will hand us a unique tag | 6048 | * We expect that the SCSI layer will hand us a unique tag |
@@ -6049,14 +6050,20 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, | |||
6049 | * two requests...because if the selected command isn't idle | 6050 | * two requests...because if the selected command isn't idle |
6050 | * then someone is going to be very disappointed. | 6051 | * then someone is going to be very disappointed. |
6051 | */ | 6052 | */ |
6052 | dev_err(&h->pdev->dev, | 6053 | if (idx != h->last_collision_tag) { /* Print once per tag */ |
6053 | "tag collision (tag=%d) in cmd_tagged_alloc().\n", | 6054 | dev_warn(&h->pdev->dev, |
6054 | idx); | 6055 | "%s: tag collision (tag=%d)\n", __func__, idx); |
6055 | if (c->scsi_cmd != NULL) | 6056 | if (c->scsi_cmd != NULL) |
6056 | scsi_print_command(c->scsi_cmd); | 6057 | scsi_print_command(c->scsi_cmd); |
6057 | scsi_print_command(scmd); | 6058 | if (scmd) |
6059 | scsi_print_command(scmd); | ||
6060 | h->last_collision_tag = idx; | ||
6061 | } | ||
6062 | return NULL; | ||
6058 | } | 6063 | } |
6059 | 6064 | ||
6065 | atomic_inc(&c->refcount); | ||
6066 | |||
6060 | hpsa_cmd_partial_init(h, idx, c); | 6067 | hpsa_cmd_partial_init(h, idx, c); |
6061 | return c; | 6068 | return c; |
6062 | } | 6069 | } |
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7aa7378f70dd..75210de71917 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
@@ -174,6 +174,7 @@ struct ctlr_info { | |||
174 | struct CfgTable __iomem *cfgtable; | 174 | struct CfgTable __iomem *cfgtable; |
175 | int interrupts_enabled; | 175 | int interrupts_enabled; |
176 | int max_commands; | 176 | int max_commands; |
177 | int last_collision_tag; /* tags are global */ | ||
177 | atomic_t commands_outstanding; | 178 | atomic_t commands_outstanding; |
178 | # define PERF_MODE_INT 0 | 179 | # define PERF_MODE_INT 0 |
179 | # define DOORBELL_INT 1 | 180 | # define DOORBELL_INT 1 |