|
@@ -195,6 +195,10 @@ static struct board_type products[] = {
|
|
|
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
|
|
|
};
|
|
|
|
|
|
+#define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy)
|
|
|
+static const struct scsi_cmnd hpsa_cmd_busy;
|
|
|
+#define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle)
|
|
|
+static const struct scsi_cmnd hpsa_cmd_idle;
|
|
|
static int number_of_controllers;
|
|
|
|
|
|
static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
|
|
@@ -270,6 +274,11 @@ static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
|
|
|
return (struct ctlr_info *) *priv;
|
|
|
}
|
|
|
|
|
|
+static inline bool hpsa_is_cmd_idle(struct CommandList *c)
|
|
|
+{
|
|
|
+ return c->scsi_cmd == SCSI_CMD_IDLE;
|
|
|
+}
|
|
|
+
|
|
|
/* extract sense key, asc, and ascq from sense data. -1 means invalid. */
|
|
|
static void decode_sense_data(const u8 *sense_data, int sense_data_len,
|
|
|
u8 *sense_key, u8 *asc, u8 *ascq)
|
|
@@ -959,9 +968,11 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void enqueue_cmd_and_start_io(struct ctlr_info *h,
|
|
|
- struct CommandList *c)
|
|
|
+static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
|
|
|
{
|
|
|
+ if (unlikely(c->abort_pending))
|
|
|
+ return finish_cmd(c);
|
|
|
+
|
|
|
__enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
|
|
|
}
|
|
|
|
|
@@ -1973,9 +1984,36 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,
|
|
|
return retry; /* retry on raid path? */
|
|
|
}
|
|
|
|
|
|
+static void hpsa_cmd_resolve_events(struct ctlr_info *h,
|
|
|
+ struct CommandList *c)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Prevent the following race in the abort handler:
|
|
|
+ *
|
|
|
+ * 1. LLD is requested to abort a SCSI command
|
|
|
+ * 2. The SCSI command completes
|
|
|
+ * 3. The struct CommandList associated with step 2 is made available
|
|
|
+ * 4. New I/O request to LLD to another LUN re-uses struct CommandList
|
|
|
+ * 5. Abort handler follows scsi_cmnd->host_scribble and
|
|
|
+ * finds struct CommandList and tries to aborts it
|
|
|
+ * Now we have aborted the wrong command.
|
|
|
+ *
|
|
|
+ * Clear c->scsi_cmd here so that the abort handler will know this
|
|
|
+ * command has completed. Then, check to see if the abort handler is
|
|
|
+ * waiting for this command, and, if so, wake it.
|
|
|
+ */
|
|
|
+ c->scsi_cmd = SCSI_CMD_IDLE;
|
|
|
+ mb(); /* Ensure c->scsi_cmd is set to SCSI_CMD_IDLE */
|
|
|
+ if (c->abort_pending) {
|
|
|
+ c->abort_pending = false;
|
|
|
+ wake_up_all(&h->abort_sync_wait_queue);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void hpsa_cmd_free_and_done(struct ctlr_info *h,
|
|
|
struct CommandList *c, struct scsi_cmnd *cmd)
|
|
|
{
|
|
|
+ hpsa_cmd_resolve_events(h, c);
|
|
|
cmd_free(h, c);
|
|
|
cmd->scsi_done(cmd);
|
|
|
}
|
|
@@ -1986,6 +2024,21 @@ static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c)
|
|
|
queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
|
|
|
}
|
|
|
|
|
|
+static void hpsa_set_scsi_cmd_aborted(struct scsi_cmnd *cmd)
|
|
|
+{
|
|
|
+ cmd->result = DID_ABORT << 16;
|
|
|
+}
|
|
|
+
|
|
|
+static void hpsa_cmd_abort_and_free(struct ctlr_info *h, struct CommandList *c,
|
|
|
+ struct scsi_cmnd *cmd)
|
|
|
+{
|
|
|
+ hpsa_set_scsi_cmd_aborted(cmd);
|
|
|
+ dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n",
|
|
|
+ c->Request.CDB, c->err_info->ScsiStatus);
|
|
|
+ hpsa_cmd_resolve_events(h, c);
|
|
|
+ cmd_free(h, c); /* FIX-ME: change to cmd_tagged_free(h, c) */
|
|
|
+}
|
|
|
+
|
|
|
static void process_ioaccel2_completion(struct ctlr_info *h,
|
|
|
struct CommandList *c, struct scsi_cmnd *cmd,
|
|
|
struct hpsa_scsi_dev_t *dev)
|
|
@@ -1997,6 +2050,10 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
|
|
|
c2->error_data.status == 0))
|
|
|
return hpsa_cmd_free_and_done(h, c, cmd);
|
|
|
|
|
|
+ /* don't requeue a command which is being aborted */
|
|
|
+ if (unlikely(c->abort_pending))
|
|
|
+ return hpsa_cmd_abort_and_free(h, c, cmd);
|
|
|
+
|
|
|
/*
|
|
|
* Any RAID offload error results in retry which will use
|
|
|
* the normal I/O path so the controller can handle whatever's
|
|
@@ -2118,10 +2175,14 @@ static void complete_scsi_command(struct CommandList *cp)
|
|
|
if (is_logical_dev_addr_mode(dev->scsi3addr)) {
|
|
|
if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
|
|
|
dev->offload_enabled = 0;
|
|
|
- return hpsa_retry_cmd(h, cp);
|
|
|
+ if (!cp->abort_pending)
|
|
|
+ return hpsa_retry_cmd(h, cp);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (cp->abort_pending)
|
|
|
+ ei->CommandStatus = CMD_ABORTED;
|
|
|
+
|
|
|
/* an error has occurred */
|
|
|
switch (ei->CommandStatus) {
|
|
|
|
|
@@ -2209,10 +2270,8 @@ static void complete_scsi_command(struct CommandList *cp)
|
|
|
cp->Request.CDB);
|
|
|
break;
|
|
|
case CMD_ABORTED:
|
|
|
- cmd->result = DID_ABORT << 16;
|
|
|
- dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n",
|
|
|
- cp->Request.CDB, ei->ScsiStatus);
|
|
|
- break;
|
|
|
+ /* Return now to avoid calling scsi_done(). */
|
|
|
+ return hpsa_cmd_abort_and_free(h, cp, cmd);
|
|
|
case CMD_ABORT_FAILED:
|
|
|
cmd->result = DID_ERROR << 16;
|
|
|
dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n",
|
|
@@ -4450,6 +4509,7 @@ static void hpsa_cmd_init(struct ctlr_info *h, int index,
|
|
|
c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle);
|
|
|
c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info));
|
|
|
c->h = h;
|
|
|
+ c->scsi_cmd = SCSI_CMD_IDLE;
|
|
|
}
|
|
|
|
|
|
static void hpsa_preinitialize_commands(struct ctlr_info *h)
|
|
@@ -4513,6 +4573,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
|
|
|
cmd->result = DID_NO_CONNECT << 16;
|
|
|
return hpsa_cmd_free_and_done(c->h, c, cmd);
|
|
|
}
|
|
|
+ if (c->abort_pending)
|
|
|
+ return hpsa_cmd_abort_and_free(c->h, c, cmd);
|
|
|
if (c->cmd_type == CMD_IOACCEL2) {
|
|
|
struct ctlr_info *h = c->h;
|
|
|
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
|
|
@@ -4928,8 +4990,7 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h,
|
|
|
struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *) c2;
|
|
|
struct io_accel2_cmd *c2a =
|
|
|
&h->ioaccel2_cmd_pool[command_to_abort->cmdindex];
|
|
|
- struct scsi_cmnd *scmd =
|
|
|
- (struct scsi_cmnd *) command_to_abort->scsi_cmd;
|
|
|
+ struct scsi_cmnd *scmd = command_to_abort->scsi_cmd;
|
|
|
struct hpsa_scsi_dev_t *dev = scmd->device->hostdata;
|
|
|
|
|
|
/*
|
|
@@ -4944,6 +5005,8 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h,
|
|
|
sizeof(ac->error_len));
|
|
|
|
|
|
c->cmd_type = IOACCEL2_TMF;
|
|
|
+ c->scsi_cmd = SCSI_CMD_BUSY;
|
|
|
+
|
|
|
/* Adjust the DMA address to point to the accelerated command buffer */
|
|
|
c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
|
|
|
(c->cmdindex * sizeof(struct io_accel2_cmd));
|
|
@@ -5137,7 +5200,7 @@ static inline int wait_for_available_abort_cmd(struct ctlr_info *h)
|
|
|
static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
|
|
|
{
|
|
|
|
|
|
- int i, rc;
|
|
|
+ int rc;
|
|
|
struct ctlr_info *h;
|
|
|
struct hpsa_scsi_dev_t *dev;
|
|
|
struct CommandList *abort; /* pointer to command to be aborted */
|
|
@@ -5210,6 +5273,16 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
|
|
|
return FAILED;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Check that we're aborting the right command.
|
|
|
+ * It's possible the CommandList already completed and got re-used.
|
|
|
+ */
|
|
|
+ if (abort->scsi_cmd != sc) {
|
|
|
+ cmd_free(h, abort);
|
|
|
+ return SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ abort->abort_pending = true;
|
|
|
hpsa_get_tag(h, abort, &taglower, &tagupper);
|
|
|
reply_queue = hpsa_extract_reply_queue(h, abort);
|
|
|
ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
|
|
@@ -5245,27 +5318,10 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
|
|
|
return FAILED;
|
|
|
}
|
|
|
dev_info(&h->pdev->dev, "%s SENT, SUCCESS\n", msg);
|
|
|
-
|
|
|
- /*
|
|
|
- * If the abort(s) above completed and actually aborted the
|
|
|
- * command, then the command to be aborted should already be
|
|
|
- * completed. If not, wait around a bit more to see if they
|
|
|
- * manage to complete normally.
|
|
|
- */
|
|
|
-#define ABORT_COMPLETE_WAIT_SECS 30
|
|
|
- for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
|
|
|
- refcount = atomic_read(&abort->refcount);
|
|
|
- if (refcount < 2) {
|
|
|
- cmd_free(h, abort);
|
|
|
- return SUCCESS;
|
|
|
- } else {
|
|
|
- msleep(100);
|
|
|
- }
|
|
|
- }
|
|
|
- dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
|
|
|
- msg, ABORT_COMPLETE_WAIT_SECS);
|
|
|
+ wait_event(h->abort_sync_wait_queue,
|
|
|
+ abort->scsi_cmd != sc || lockup_detected(h));
|
|
|
cmd_free(h, abort);
|
|
|
- return FAILED;
|
|
|
+ return !lockup_detected(h) ? SUCCESS : FAILED;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -5511,6 +5567,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
|
|
|
|
|
/* Fill in the command type */
|
|
|
c->cmd_type = CMD_IOCTL_PEND;
|
|
|
+ c->scsi_cmd = SCSI_CMD_BUSY;
|
|
|
/* Fill in Command Header */
|
|
|
c->Header.ReplyQueue = 0; /* unused in simple mode */
|
|
|
if (iocommand.buf_size > 0) { /* buffer to fill */
|
|
@@ -5646,6 +5703,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
|
|
c = cmd_alloc(h);
|
|
|
|
|
|
c->cmd_type = CMD_IOCTL_PEND;
|
|
|
+ c->scsi_cmd = SCSI_CMD_BUSY;
|
|
|
c->Header.ReplyQueue = 0;
|
|
|
c->Header.SGList = (u8) sg_used;
|
|
|
c->Header.SGTotal = cpu_to_le16(sg_used);
|
|
@@ -5789,6 +5847,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
|
|
u64 tag; /* for commands to be aborted */
|
|
|
|
|
|
c->cmd_type = CMD_IOCTL_PEND;
|
|
|
+ c->scsi_cmd = SCSI_CMD_BUSY;
|
|
|
c->Header.ReplyQueue = 0;
|
|
|
if (buff != NULL && size > 0) {
|
|
|
c->Header.SGList = 1;
|
|
@@ -7582,6 +7641,7 @@ reinit_after_soft_reset:
|
|
|
goto clean5; /* cmd, irq, pci, lockup, wq/aer/h */
|
|
|
init_waitqueue_head(&h->scan_wait_queue);
|
|
|
init_waitqueue_head(&h->abort_cmd_wait_queue);
|
|
|
+ init_waitqueue_head(&h->abort_sync_wait_queue);
|
|
|
h->scan_finished = 1; /* no scan currently in progress */
|
|
|
|
|
|
pci_set_drvdata(pdev, h);
|