- 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 <[email protected]>
Reviewed-by: David Carroll <[email protected]>
Reviewed-by: Scott Teel <[email protected]>
Signed-off-by: Don Brace <[email protected]>
---
 drivers/scsi/hpsa.c |   21 ++++++++++++++-------
 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 ade0d505a32c..a315d108fdcb 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -5620,6 +5620,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.
@@ -6026,7 +6028,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
@@ -6034,14 +6035,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

Reply via email to