scsi: cxlflash: Add scsi command abort handler
authorUma Krishnan <ukrishn@linux.vnet.ibm.com>
Thu, 22 Jun 2017 02:15:06 +0000 (21:15 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 26 Jun 2017 19:01:10 +0000 (15:01 -0400)
To date, CXL flash devices do not support a single command abort operation.
Instead, the SISLite specification provides a context reset operation to
cleanup all pending commands for a given context.

When a context reset is successful, it is guaranteed that the AFU has
aborted all currently pending I/O. This sequence is less invasive than a
device or host reset and can be executed to support scsi command abort
requests. Add eh_abort_handler callback support to process command timeouts
and abort requests.

Signed-off-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com>
Acked-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/cxlflash/main.c

index 0a3de42310eccbd16a1a275ca1123d9a4d53edff..ceb247b5d1f209c350b6c67f5baa3c9a6e525fa4 100644 (file)
@@ -228,6 +228,10 @@ static void flush_pending_cmds(struct hwq *hwq)
  * @hwq:       Hardware queue owning the context to be reset.
  * @reset_reg: MMIO register to perform reset.
  *
+ * When the reset is successful, the SISLite specification guarantees that
+ * the AFU has aborted all currently pending I/O. Accordingly, these commands
+ * must be flushed.
+ *
  * Return: 0 on success, -errno on failure
  */
 static int context_reset(struct hwq *hwq, __be64 __iomem *reset_reg)
@@ -237,9 +241,12 @@ static int context_reset(struct hwq *hwq, __be64 __iomem *reset_reg)
        int rc = -ETIMEDOUT;
        int nretry = 0;
        u64 val = 0x1;
+       ulong lock_flags;
 
        dev_dbg(dev, "%s: hwq=%p\n", __func__, hwq);
 
+       spin_lock_irqsave(&hwq->hsq_slock, lock_flags);
+
        writeq_be(val, reset_reg);
        do {
                val = readq_be(reset_reg);
@@ -252,6 +259,11 @@ static int context_reset(struct hwq *hwq, __be64 __iomem *reset_reg)
                udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 
+       if (!rc)
+               flush_pending_cmds(hwq);
+
+       spin_unlock_irqrestore(&hwq->hsq_slock, lock_flags);
+
        dev_dbg(dev, "%s: returning rc=%d, val=%016llx nretry=%d\n",
                __func__, rc, val, nretry);
        return rc;
@@ -2255,6 +2267,54 @@ out:
        return rc;
 }
 
+/**
+ * cxlflash_eh_abort_handler() - abort a SCSI command
+ * @scp:       SCSI command to abort.
+ *
+ * CXL Flash devices do not support a single command abort. Reset the context
+ * as per SISLite specification. Flush any pending commands in the hardware
+ * queue before the reset.
+ *
+ * Return: SUCCESS/FAILED as defined in scsi/scsi.h
+ */
+static int cxlflash_eh_abort_handler(struct scsi_cmnd *scp)
+{
+       int rc = FAILED;
+       struct Scsi_Host *host = scp->device->host;
+       struct cxlflash_cfg *cfg = shost_priv(host);
+       struct afu_cmd *cmd = sc_to_afuc(scp);
+       struct device *dev = &cfg->dev->dev;
+       struct afu *afu = cfg->afu;
+       struct hwq *hwq = get_hwq(afu, cmd->hwq_index);
+
+       dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu "
+               "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no,
+               scp->device->channel, scp->device->id, scp->device->lun,
+               get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
+
+       /* When the state is not normal, another reset/reload is in progress.
+        * Return failed and the mid-layer will invoke host reset handler.
+        */
+       if (cfg->state != STATE_NORMAL) {
+               dev_dbg(dev, "%s: Invalid state for abort, state=%d\n",
+                       __func__, cfg->state);
+               goto out;
+       }
+
+       rc = afu->context_reset(hwq);
+       if (unlikely(rc))
+               goto out;
+
+       rc = SUCCESS;
+
+out:
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
+       return rc;
+}
+
 /**
  * cxlflash_eh_device_reset_handler() - reset a single LUN
  * @scp:       SCSI command to send.
@@ -2969,6 +3029,7 @@ static struct scsi_host_template driver_template = {
        .ioctl = cxlflash_ioctl,
        .proc_name = CXLFLASH_NAME,
        .queuecommand = cxlflash_queuecommand,
+       .eh_abort_handler = cxlflash_eh_abort_handler,
        .eh_device_reset_handler = cxlflash_eh_device_reset_handler,
        .eh_host_reset_handler = cxlflash_eh_host_reset_handler,
        .change_queue_depth = cxlflash_change_queue_depth,