summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDon Brace <don.brace@microsemi.com>2019-05-07 14:32:13 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2019-06-18 19:46:18 -0400
commit4770e68d162634b2134741d08c49185f858c90ee (patch)
treeafa72eabc55f9f63e8bea9b5a1fe0d3fd7822db5
parent0119208885b3faf2459de6d3fcc6d090580b906f (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.c21
-rw-r--r--drivers/scsi/hpsa.h1
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