diff options
author | Don Brace <don.brace@microsemi.com> | 2019-05-07 21:32:13 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2019-06-19 02:46:18 +0300 |
commit | 4770e68d162634b2134741d08c49185f858c90ee (patch) | |
tree | afa72eabc55f9f63e8bea9b5a1fe0d3fd7822db5 /drivers/scsi/hpsa.c | |
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>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 21 |
1 files changed, 14 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) return 0; } c = cmd_tagged_alloc(h, cmd); + if (c == NULL) + return SCSI_MLQUEUE_DEVICE_BUSY; /* * Call alternate submit routine for I/O accelerated commands. @@ -6041,7 +6043,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, BUG(); } - atomic_inc(&c->refcount); if (unlikely(!hpsa_is_cmd_idle(c))) { /* * 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, * two requests...because if the selected command isn't idle * then someone is going to be very disappointed. */ - dev_err(&h->pdev->dev, - "tag collision (tag=%d) in cmd_tagged_alloc().\n", - idx); - if (c->scsi_cmd != NULL) - scsi_print_command(c->scsi_cmd); - scsi_print_command(scmd); + if (idx != h->last_collision_tag) { /* Print once per tag */ + dev_warn(&h->pdev->dev, + "%s: tag collision (tag=%d)\n", __func__, idx); + if (c->scsi_cmd != NULL) + scsi_print_command(c->scsi_cmd); + if (scmd) + scsi_print_command(scmd); + h->last_collision_tag = idx; + } + return NULL; } + atomic_inc(&c->refcount); + hpsa_cmd_partial_init(h, idx, c); return c; } |