diff options
author | Don Brace <don.brace@microsemi.com> | 2019-05-07 13:32:13 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2019-06-18 19:46:18 -0400 |
commit | 4770e68d162634b2134741d08c49185f858c90ee (patch) | |
tree | afa72eabc55f9f63e8bea9b5a1fe0d3fd7822db5 | |
parent | 0119208885b3faf2459de6d3fcc6d090580b906f (diff) | |
download | linux-4770e68d162634b2134741d08c49185f858c90ee.tar.bz2 |
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) 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; } 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 { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_collision_tag; /* tags are global */ atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 |