Found during code inspection, that the following functions are not
being used outside of the file where they are defined. Make them static.

int cxlflash_send_cmd(struct afu *, struct afu_cmd *);
void cxlflash_wait_resp(struct afu *, struct afu_cmd *);
int cxlflash_afu_reset(struct cxlflash_cfg *);
struct afu_cmd *cxlflash_cmd_checkout(struct afu *);
void cxlflash_cmd_checkin(struct afu_cmd *);
void init_pcr(struct cxlflash_cfg *);
int init_global(struct cxlflash_cfg *);

Signed-off-by: Matthew R. Ochs <mro...@linux.vnet.ibm.com>
Signed-off-by: Manoj N. Kumar <ma...@linux.vnet.ibm.com>
Reviewed-by: Brian King <brk...@linux.vnet.ibm.com>
---
 drivers/scsi/cxlflash/common.h |    5 -
 drivers/scsi/cxlflash/main.c   | 1018 ++++++++++++++++++++--------------------
 2 files changed, 509 insertions(+), 514 deletions(-)

diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index 11318de..b038ac7 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -192,11 +192,6 @@ static inline u64 lun_to_lunid(u64 lun)
        return swab64(lun_id);
 }
 
-int cxlflash_send_cmd(struct afu *, struct afu_cmd *);
-void cxlflash_wait_resp(struct afu *, struct afu_cmd *);
-int cxlflash_afu_reset(struct cxlflash_cfg *);
-struct afu_cmd *cxlflash_cmd_checkout(struct afu *);
-void cxlflash_cmd_checkin(struct afu_cmd *);
 int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8);
 void cxlflash_list_init(void);
 void cxlflash_term_global_luns(void);
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 8940336..226cefe 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
 
 
 /**
- * cxlflash_cmd_checkout() - checks out an AFU command
+ * cmd_checkout() - checks out an AFU command
  * @afu:       AFU to checkout from.
  *
  * Commands are checked out in a round-robin fashion. Note that since
@@ -47,7 +47,7 @@ MODULE_LICENSE("GPL");
  *
  * Return: The checked out command or NULL when command pool is empty.
  */
-struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu)
+static struct afu_cmd *cmd_checkout(struct afu *afu)
 {
        int k, dec = CXLFLASH_NUM_CMDS;
        struct afu_cmd *cmd;
@@ -70,7 +70,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu)
 }
 
 /**
- * cxlflash_cmd_checkin() - checks in an AFU command
+ * cmd_checkin() - checks in an AFU command
  * @cmd:       AFU command to checkin.
  *
  * Safe to pass commands that have already been checked in. Several
@@ -79,7 +79,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu)
  * to avoid clobbering values in the event that the command is checked
  * out right away.
  */
-void cxlflash_cmd_checkin(struct afu_cmd *cmd)
+static void cmd_checkin(struct afu_cmd *cmd)
 {
        cmd->rcb.scp = NULL;
        cmd->rcb.timeout = 0;
@@ -238,7 +238,7 @@ static void cmd_complete(struct afu_cmd *cmd)
 
                resid = cmd->sa.resid;
                cmd_is_tmf = cmd->cmd_tmf;
-               cxlflash_cmd_checkin(cmd); /* Don't use cmd after here */
+               cmd_checkin(cmd); /* Don't use cmd after here */
 
                pr_debug("%s: calling scsi_set_resid, scp=%p "
                         "result=%X resid=%d\n", __func__,
@@ -260,6 +260,146 @@ static void cmd_complete(struct afu_cmd *cmd)
 }
 
 /**
+ * context_reset() - timeout handler for AFU commands
+ * @cmd:       AFU command that timed out.
+ *
+ * Sends a reset to the AFU.
+ */
+static void context_reset(struct afu_cmd *cmd)
+{
+       int nretry = 0;
+       u64 rrin = 0x1;
+       u64 room = 0;
+       struct afu *afu = cmd->parent;
+       ulong lock_flags;
+
+       pr_debug("%s: cmd=%p\n", __func__, cmd);
+
+       spin_lock_irqsave(&cmd->slock, lock_flags);
+
+       /* Already completed? */
+       if (cmd->sa.host_use_b[0] & B_DONE) {
+               spin_unlock_irqrestore(&cmd->slock, lock_flags);
+               return;
+       }
+
+       cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT);
+       spin_unlock_irqrestore(&cmd->slock, lock_flags);
+
+       /*
+        * We really want to send this reset at all costs, so spread
+        * out wait time on successive retries for available room.
+        */
+       do {
+               room = readq_be(&afu->host_map->cmd_room);
+               atomic64_set(&afu->room, room);
+               if (room)
+                       goto write_rrin;
+               udelay(nretry);
+       } while (nretry++ < MC_ROOM_RETRY_CNT);
+
+       pr_err("%s: no cmd_room to send reset\n", __func__);
+       return;
+
+write_rrin:
+       nretry = 0;
+       writeq_be(rrin, &afu->host_map->ioarrin);
+       do {
+               rrin = readq_be(&afu->host_map->ioarrin);
+               if (rrin != 0x1)
+                       break;
+               /* Double delay each time */
+               udelay(2 ^ nretry);
+       } while (nretry++ < MC_ROOM_RETRY_CNT);
+}
+
+/**
+ * send_cmd() - sends an AFU command
+ * @afu:       AFU associated with the host.
+ * @cmd:       AFU command to send.
+ *
+ * Return:
+ *     0 on success or SCSI_MLQUEUE_HOST_BUSY
+ */
+static int send_cmd(struct afu *afu, struct afu_cmd *cmd)
+{
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
+       int nretry = 0;
+       int rc = 0;
+       u64 room;
+       long newval;
+
+       /*
+        * This routine is used by critical users such an AFU sync and to
+        * send a task management function (TMF). Thus we want to retry a
+        * bit before returning an error. To avoid the performance penalty
+        * of MMIO, we spread the update of 'room' over multiple commands.
+        */
+retry:
+       newval = atomic64_dec_if_positive(&afu->room);
+       if (!newval) {
+               do {
+                       room = readq_be(&afu->host_map->cmd_room);
+                       atomic64_set(&afu->room, room);
+                       if (room)
+                               goto write_ioarrin;
+                       udelay(nretry);
+               } while (nretry++ < MC_ROOM_RETRY_CNT);
+
+               dev_err(dev, "%s: no cmd_room to send 0x%X\n",
+                      __func__, cmd->rcb.cdb[0]);
+
+               goto no_room;
+       } else if (unlikely(newval < 0)) {
+               /* This should be rare. i.e. Only if two threads race and
+                * decrement before the MMIO read is done. In this case
+                * just benefit from the other thread having updated
+                * afu->room.
+                */
+               if (nretry++ < MC_ROOM_RETRY_CNT) {
+                       udelay(nretry);
+                       goto retry;
+               }
+
+               goto no_room;
+       }
+
+write_ioarrin:
+       writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin);
+out:
+       pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd,
+                cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc);
+       return rc;
+
+no_room:
+       afu->read_room = true;
+       schedule_work(&cfg->work_q);
+       rc = SCSI_MLQUEUE_HOST_BUSY;
+       goto out;
+}
+
+/**
+ * wait_resp() - polls for a response or timeout to a sent AFU command
+ * @afu:       AFU associated with the host.
+ * @cmd:       AFU command that was sent.
+ */
+static void wait_resp(struct afu *afu, struct afu_cmd *cmd)
+{
+       ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000);
+
+       timeout = wait_for_completion_timeout(&cmd->cevent, timeout);
+       if (!timeout)
+               context_reset(cmd);
+
+       if (unlikely(cmd->sa.ioasc != 0))
+               pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, "
+                      "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0],
+                      cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc,
+                      cmd->sa.rc.fc_rc);
+}
+
+/**
  * send_tmf() - sends a Task Management Function (TMF)
  * @afu:       AFU to checkout from.
  * @scp:       SCSI command from stack.
@@ -280,7 +420,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, 
u64 tmfcmd)
        ulong lock_flags;
        int rc = 0;
 
-       cmd = cxlflash_cmd_checkout(afu);
+       cmd = cmd_checkout(afu);
        if (unlikely(!cmd)) {
                pr_err("%s: could not get a free command\n", __func__);
                rc = SCSI_MLQUEUE_HOST_BUSY;
@@ -313,9 +453,9 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, 
u64 tmfcmd)
        memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd));
 
        /* Send the command */
-       rc = cxlflash_send_cmd(afu, cmd);
+       rc = send_cmd(afu, cmd);
        if (unlikely(rc)) {
-               cxlflash_cmd_checkin(cmd);
+               cmd_checkin(cmd);
                spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags);
                cfg->tmf_active = false;
                spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags);
@@ -398,7 +538,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scp)
                break;
        }
 
-       cmd = cxlflash_cmd_checkout(afu);
+       cmd = cmd_checkout(afu);
        if (unlikely(!cmd)) {
                pr_err("%s: could not get a free command\n", __func__);
                rc = SCSI_MLQUEUE_HOST_BUSY;
@@ -438,9 +578,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *scp)
        memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb));
 
        /* Send the command */
-       rc = cxlflash_send_cmd(afu, cmd);
+       rc = send_cmd(afu, cmd);
        if (unlikely(rc)) {
-               cxlflash_cmd_checkin(cmd);
+               cmd_checkin(cmd);
                scsi_dma_unmap(scp);
        }
 
@@ -449,369 +589,55 @@ out:
 }
 
 /**
- * cxlflash_eh_device_reset_handler() - reset a single LUN
- * @scp:       SCSI command to send.
- *
- * Return:
- *     SUCCESS as defined in scsi/scsi.h
- *     FAILED as defined in scsi/scsi.h
+ * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe
+ * @cxlflash:  Internal structure associated with the host.
  */
-static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)
+static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg)
 {
-       int rc = SUCCESS;
-       struct Scsi_Host *host = scp->device->host;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
-       struct afu *afu = cfg->afu;
-       int rcr = 0;
-
-       pr_debug("%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]));
-
-       switch (cfg->state) {
-       case STATE_NORMAL:
-               rcr = send_tmf(afu, scp, TMF_LUN_RESET);
-               if (unlikely(rcr))
-                       rc = FAILED;
-               break;
-       case STATE_RESET:
-               wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
-               if (cfg->state == STATE_NORMAL)
-                       break;
-               /* fall through */
-       default:
-               rc = FAILED;
-               break;
-       }
+       struct pci_dev *pdev = cfg->dev;
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
-       return rc;
+       if (pci_channel_offline(pdev))
+               wait_event_timeout(cfg->reset_waitq,
+                                  !pci_channel_offline(pdev),
+                                  CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT);
 }
 
 /**
- * cxlflash_eh_host_reset_handler() - reset the host adapter
- * @scp:       SCSI command from stack identifying host.
- *
- * Return:
- *     SUCCESS as defined in scsi/scsi.h
- *     FAILED as defined in scsi/scsi.h
+ * free_mem() - free memory associated with the AFU
+ * @cxlflash:  Internal structure associated with the host.
  */
-static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
+static void free_mem(struct cxlflash_cfg *cfg)
 {
-       int rc = SUCCESS;
-       int rcr = 0;
-       struct Scsi_Host *host = scp->device->host;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       int i;
+       char *buf = NULL;
+       struct afu *afu = cfg->afu;
 
-       pr_debug("%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]));
+       if (cfg->afu) {
+               for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+                       buf = afu->cmd[i].buf;
+                       if (!((u64)buf & (PAGE_SIZE - 1)))
+                               free_page((ulong)buf);
+               }
 
-       switch (cfg->state) {
-       case STATE_NORMAL:
-               cfg->state = STATE_RESET;
-               scsi_block_requests(cfg->host);
-               cxlflash_mark_contexts_error(cfg);
-               rcr = cxlflash_afu_reset(cfg);
-               if (rcr) {
-                       rc = FAILED;
-                       cfg->state = STATE_FAILTERM;
-               } else
-                       cfg->state = STATE_NORMAL;
-               wake_up_all(&cfg->reset_waitq);
-               scsi_unblock_requests(cfg->host);
-               break;
-       case STATE_RESET:
-               wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
-               if (cfg->state == STATE_NORMAL)
-                       break;
-               /* fall through */
-       default:
-               rc = FAILED;
-               break;
+               free_pages((ulong)afu, get_order(sizeof(struct afu)));
+               cfg->afu = NULL;
        }
-
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
-       return rc;
 }
 
 /**
- * cxlflash_change_queue_depth() - change the queue depth for the device
- * @sdev:      SCSI device destined for queue depth change.
- * @qdepth:    Requested queue depth value to set.
- *
- * The requested queue depth is capped to the maximum supported value.
+ * stop_afu() - stops the AFU command timers and unmaps the MMIO space
+ * @cxlflash:  Internal structure associated with the host.
  *
- * Return: The actual queue depth set.
+ * Safe to call with AFU in a partially allocated/initialized state.
  */
-static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static void stop_afu(struct cxlflash_cfg *cfg)
 {
+       int i;
+       struct afu *afu = cfg->afu;
 
-       if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN)
-               qdepth = CXLFLASH_MAX_CMDS_PER_LUN;
-
-       scsi_change_queue_depth(sdev, qdepth);
-       return sdev->queue_depth;
-}
-
-/**
- * cxlflash_show_port_status() - queries and presents the current port status
- * @dev:       Generic device associated with the host owning the port.
- * @attr:      Device attribute representing the port.
- * @buf:       Buffer of length PAGE_SIZE to report back port status in ASCII.
- *
- * Return: The size of the ASCII string returned in @buf.
- */
-static ssize_t cxlflash_show_port_status(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
-       struct afu *afu = cfg->afu;
-
-       char *disp_status;
-       int rc;
-       u32 port;
-       u64 status;
-       u64 *fc_regs;
-
-       rc = kstrtouint((attr->attr.name + 4), 10, &port);
-       if (rc || (port >= NUM_FC_PORTS))
-               return 0;
-
-       fc_regs = &afu->afu_map->global.fc_regs[port][0];
-       status =
-           (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK);
-
-       if (status == FC_MTIP_STATUS_ONLINE)
-               disp_status = "online";
-       else if (status == FC_MTIP_STATUS_OFFLINE)
-               disp_status = "offline";
-       else
-               disp_status = "unknown";
-
-       return snprintf(buf, PAGE_SIZE, "%s\n", disp_status);
-}
-
-/**
- * cxlflash_show_lun_mode() - presents the current LUN mode of the host
- * @dev:       Generic device associated with the host.
- * @attr:      Device attribute representing the lun mode.
- * @buf:       Buffer of length PAGE_SIZE to report back the LUN mode in ASCII.
- *
- * Return: The size of the ASCII string returned in @buf.
- */
-static ssize_t cxlflash_show_lun_mode(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
-       struct afu *afu = cfg->afu;
-
-       return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun);
-}
-
-/**
- * cxlflash_store_lun_mode() - sets the LUN mode of the host
- * @dev:       Generic device associated with the host.
- * @attr:      Device attribute representing the lun mode.
- * @buf:       Buffer of length PAGE_SIZE containing the LUN mode in ASCII.
- * @count:     Length of data resizing in @buf.
- *
- * The CXL Flash AFU supports a dummy LUN mode where the external
- * links and storage are not required. Space on the FPGA is used
- * to create 1 or 2 small LUNs which are presented to the system
- * as if they were a normal storage device. This feature is useful
- * during development and also provides manufacturing with a way
- * to test the AFU without an actual device.
- *
- * 0 = external LUN[s] (default)
- * 1 = internal LUN (1 x 64K, 512B blocks, id 0)
- * 2 = internal LUN (1 x 64K, 4K blocks, id 0)
- * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1)
- * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1)
- *
- * Return: The size of the ASCII string returned in @buf.
- */
-static ssize_t cxlflash_store_lun_mode(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
-       struct afu *afu = cfg->afu;
-       int rc;
-       u32 lun_mode;
-
-       rc = kstrtouint(buf, 10, &lun_mode);
-       if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
-               afu->internal_lun = lun_mode;
-               cxlflash_afu_reset(cfg);
-               scsi_scan_host(cfg->host);
-       }
-
-       return count;
-}
-
-/**
- * cxlflash_show_ioctl_version() - presents the current ioctl version of the 
host
- * @dev:       Generic device associated with the host.
- * @attr:      Device attribute representing the ioctl version.
- * @buf:       Buffer of length PAGE_SIZE to report back the ioctl version.
- *
- * Return: The size of the ASCII string returned in @buf.
- */
-static ssize_t cxlflash_show_ioctl_version(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf)
-{
-       return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0);
-}
-
-/**
- * cxlflash_show_dev_mode() - presents the current mode of the device
- * @dev:       Generic device associated with the device.
- * @attr:      Device attribute representing the device mode.
- * @buf:       Buffer of length PAGE_SIZE to report back the dev mode in ASCII.
- *
- * Return: The size of the ASCII string returned in @buf.
- */
-static ssize_t cxlflash_show_dev_mode(struct device *dev,
-                                     struct device_attribute *attr, char *buf)
-{
-       struct scsi_device *sdev = to_scsi_device(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       sdev->hostdata ? "superpipe" : "legacy");
-}
-
-/**
- * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe
- * @cxlflash:  Internal structure associated with the host.
- */
-static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg)
-{
-       struct pci_dev *pdev = cfg->dev;
-
-       if (pci_channel_offline(pdev))
-               wait_event_timeout(cfg->reset_waitq,
-                                  !pci_channel_offline(pdev),
-                                  CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT);
-}
-
-/*
- * Host attributes
- */
-static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL);
-static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL);
-static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode,
-                  cxlflash_store_lun_mode);
-static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL);
-
-static struct device_attribute *cxlflash_host_attrs[] = {
-       &dev_attr_port0,
-       &dev_attr_port1,
-       &dev_attr_lun_mode,
-       &dev_attr_ioctl_version,
-       NULL
-};
-
-/*
- * Device attributes
- */
-static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL);
-
-static struct device_attribute *cxlflash_dev_attrs[] = {
-       &dev_attr_mode,
-       NULL
-};
-
-/*
- * Host template
- */
-static struct scsi_host_template driver_template = {
-       .module = THIS_MODULE,
-       .name = CXLFLASH_ADAPTER_NAME,
-       .info = cxlflash_driver_info,
-       .ioctl = cxlflash_ioctl,
-       .proc_name = CXLFLASH_NAME,
-       .queuecommand = cxlflash_queuecommand,
-       .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,
-       .cmd_per_lun = 16,
-       .can_queue = CXLFLASH_MAX_CMDS,
-       .this_id = -1,
-       .sg_tablesize = SG_NONE,        /* No scatter gather support. */
-       .max_sectors = CXLFLASH_MAX_SECTORS,
-       .use_clustering = ENABLE_CLUSTERING,
-       .shost_attrs = cxlflash_host_attrs,
-       .sdev_attrs = cxlflash_dev_attrs,
-};
-
-/*
- * Device dependent values
- */
-static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
-
-/*
- * PCI device binding table
- */
-static struct pci_device_id cxlflash_pci_table[] = {
-       {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
-       {}
-};
-
-MODULE_DEVICE_TABLE(pci, cxlflash_pci_table);
-
-/**
- * free_mem() - free memory associated with the AFU
- * @cxlflash:  Internal structure associated with the host.
- */
-static void free_mem(struct cxlflash_cfg *cfg)
-{
-       int i;
-       char *buf = NULL;
-       struct afu *afu = cfg->afu;
-
-       if (cfg->afu) {
-               for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
-                       buf = afu->cmd[i].buf;
-                       if (!((u64)buf & (PAGE_SIZE - 1)))
-                               free_page((ulong)buf);
-               }
-
-               free_pages((ulong)afu, get_order(sizeof(struct afu)));
-               cfg->afu = NULL;
-       }
-}
-
-/**
- * stop_afu() - stops the AFU command timers and unmaps the MMIO space
- * @cxlflash:  Internal structure associated with the host.
- *
- * Safe to call with AFU in a partially allocated/initialized state.
- */
-static void stop_afu(struct cxlflash_cfg *cfg)
-{
-       int i;
-       struct afu *afu = cfg->afu;
-
-       if (likely(afu)) {
-               for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
-                       complete(&afu->cmd[i].cevent);
+       if (likely(afu)) {
+               for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
+                       complete(&afu->cmd[i].cevent);
 
                if (likely(afu->afu_map)) {
                        cxl_psa_unmap((void *)afu->afu_map);
@@ -1631,67 +1457,13 @@ out:
 }
 
 /**
- * cxlflash_context_reset() - timeout handler for AFU commands
- * @cmd:       AFU command that timed out.
+ * init_pcr() - initialize the provisioning and control registers
+ * @cxlflash:  Internal structure associated with the host.
  *
- * Sends a reset to the AFU.
+ * Also sets up fast access to the mapped registers and initializes AFU
+ * command fields that never change.
  */
-void cxlflash_context_reset(struct afu_cmd *cmd)
-{
-       int nretry = 0;
-       u64 rrin = 0x1;
-       u64 room = 0;
-       struct afu *afu = cmd->parent;
-       ulong lock_flags;
-
-       pr_debug("%s: cmd=%p\n", __func__, cmd);
-
-       spin_lock_irqsave(&cmd->slock, lock_flags);
-
-       /* Already completed? */
-       if (cmd->sa.host_use_b[0] & B_DONE) {
-               spin_unlock_irqrestore(&cmd->slock, lock_flags);
-               return;
-       }
-
-       cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT);
-       spin_unlock_irqrestore(&cmd->slock, lock_flags);
-
-       /*
-        * We really want to send this reset at all costs, so spread
-        * out wait time on successive retries for available room.
-        */
-       do {
-               room = readq_be(&afu->host_map->cmd_room);
-               atomic64_set(&afu->room, room);
-               if (room)
-                       goto write_rrin;
-               udelay(nretry);
-       } while (nretry++ < MC_ROOM_RETRY_CNT);
-
-       pr_err("%s: no cmd_room to send reset\n", __func__);
-       return;
-
-write_rrin:
-       nretry = 0;
-       writeq_be(rrin, &afu->host_map->ioarrin);
-       do {
-               rrin = readq_be(&afu->host_map->ioarrin);
-               if (rrin != 0x1)
-                       break;
-               /* Double delay each time */
-               udelay(2 ^ nretry);
-       } while (nretry++ < MC_ROOM_RETRY_CNT);
-}
-
-/**
- * init_pcr() - initialize the provisioning and control registers
- * @cxlflash:  Internal structure associated with the host.
- *
- * Also sets up fast access to the mapped registers and initializes AFU
- * command fields that never change.
- */
-void init_pcr(struct cxlflash_cfg *cfg)
+static void init_pcr(struct cxlflash_cfg *cfg)
 {
        struct afu *afu = cfg->afu;
        struct sisl_ctrl_map *ctrl_map;
@@ -1727,7 +1499,7 @@ void init_pcr(struct cxlflash_cfg *cfg)
  * init_global() - initialize AFU global registers
  * @cxlflash:  Internal structure associated with the host.
  */
-int init_global(struct cxlflash_cfg *cfg)
+static int init_global(struct cxlflash_cfg *cfg)
 {
        struct afu *afu = cfg->afu;
        u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */
@@ -1998,92 +1770,6 @@ err1:
 }
 
 /**
- * cxlflash_send_cmd() - sends an AFU command
- * @afu:       AFU associated with the host.
- * @cmd:       AFU command to send.
- *
- * Return:
- *     0 on success
- *     -1 on failure
- */
-int cxlflash_send_cmd(struct afu *afu, struct afu_cmd *cmd)
-{
-       struct cxlflash_cfg *cfg = afu->parent;
-       int nretry = 0;
-       int rc = 0;
-       u64 room;
-       long newval;
-
-       /*
-        * This routine is used by critical users such an AFU sync and to
-        * send a task management function (TMF). Thus we want to retry a
-        * bit before returning an error. To avoid the performance penalty
-        * of MMIO, we spread the update of 'room' over multiple commands.
-        */
-retry:
-       newval = atomic64_dec_if_positive(&afu->room);
-       if (!newval) {
-               do {
-                       room = readq_be(&afu->host_map->cmd_room);
-                       atomic64_set(&afu->room, room);
-                       if (room)
-                               goto write_ioarrin;
-                       udelay(nretry);
-               } while (nretry++ < MC_ROOM_RETRY_CNT);
-
-               pr_err("%s: no cmd_room to send 0x%X\n",
-                      __func__, cmd->rcb.cdb[0]);
-
-               goto no_room;
-       } else if (unlikely(newval < 0)) {
-               /* This should be rare. i.e. Only if two threads race and
-                * decrement before the MMIO read is done. In this case
-                * just benefit from the other thread having updated
-                * afu->room.
-                */
-               if (nretry++ < MC_ROOM_RETRY_CNT) {
-                       udelay(nretry);
-                       goto retry;
-               }
-
-               goto no_room;
-       }
-
-write_ioarrin:
-       writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin);
-out:
-       pr_debug("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd,
-                cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc);
-       return rc;
-
-no_room:
-       afu->read_room = true;
-       schedule_work(&cfg->work_q);
-       rc = SCSI_MLQUEUE_HOST_BUSY;
-       goto out;
-}
-
-/**
- * cxlflash_wait_resp() - polls for a response or timeout to a sent AFU command
- * @afu:       AFU associated with the host.
- * @cmd:       AFU command that was sent.
- */
-void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd)
-{
-       ulong timeout = jiffies + (cmd->rcb.timeout * 2 * HZ);
-
-       timeout = wait_for_completion_timeout(&cmd->cevent, timeout);
-       if (!timeout)
-               cxlflash_context_reset(cmd);
-
-       if (unlikely(cmd->sa.ioasc != 0))
-               pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, "
-                      "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0],
-                      cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc,
-                      cmd->sa.rc.fc_rc);
-}
-
-/**
  * cxlflash_afu_sync() - builds and sends an AFU sync command
  * @afu:       AFU associated with the host.
  * @ctx_hndl_u:        Identifies context requesting sync.
@@ -2121,7 +1807,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t 
ctx_hndl_u,
 
        mutex_lock(&sync_active);
 retry:
-       cmd = cxlflash_cmd_checkout(afu);
+       cmd = cmd_checkout(afu);
        if (unlikely(!cmd)) {
                retry_cnt++;
                udelay(1000 * retry_cnt);
@@ -2150,11 +1836,11 @@ retry:
        *((u16 *)&cmd->rcb.cdb[2]) = swab16(ctx_hndl_u);
        *((u32 *)&cmd->rcb.cdb[4]) = swab32(res_hndl_u);
 
-       rc = cxlflash_send_cmd(afu, cmd);
+       rc = send_cmd(afu, cmd);
        if (unlikely(rc))
                goto out;
 
-       cxlflash_wait_resp(afu, cmd);
+       wait_resp(afu, cmd);
 
        /* set on timeout */
        if (unlikely((cmd->sa.ioasc != 0) ||
@@ -2163,20 +1849,20 @@ retry:
 out:
        mutex_unlock(&sync_active);
        if (cmd)
-               cxlflash_cmd_checkin(cmd);
+               cmd_checkin(cmd);
        pr_debug("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
 /**
- * cxlflash_afu_reset() - resets the AFU
- * @cxlflash:  Internal structure associated with the host.
+ * afu_reset() - resets the AFU
+ * @cfg:       Internal structure associated with the host.
  *
  * Return:
  *     0 on success
  *     A failure value from internal services.
  */
-int cxlflash_afu_reset(struct cxlflash_cfg *cfg)
+static int afu_reset(struct cxlflash_cfg *cfg)
 {
        int rc = 0;
        /* Stop the context before the reset. Since the context is
@@ -2192,6 +1878,320 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg)
 }
 
 /**
+ * cxlflash_eh_device_reset_handler() - reset a single LUN
+ * @scp:       SCSI command to send.
+ *
+ * Return:
+ *     SUCCESS as defined in scsi/scsi.h
+ *     FAILED as defined in scsi/scsi.h
+ */
+static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)
+{
+       int rc = SUCCESS;
+       struct Scsi_Host *host = scp->device->host;
+       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       struct afu *afu = cfg->afu;
+       int rcr = 0;
+
+       pr_debug("%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]));
+
+       switch (cfg->state) {
+       case STATE_NORMAL:
+               rcr = send_tmf(afu, scp, TMF_LUN_RESET);
+               if (unlikely(rcr))
+                       rc = FAILED;
+               break;
+       case STATE_RESET:
+               wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
+               if (cfg->state == STATE_NORMAL)
+                       break;
+               /* fall through */
+       default:
+               rc = FAILED;
+               break;
+       }
+
+       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       return rc;
+}
+
+/**
+ * cxlflash_eh_host_reset_handler() - reset the host adapter
+ * @scp:       SCSI command from stack identifying host.
+ *
+ * Return:
+ *     SUCCESS as defined in scsi/scsi.h
+ *     FAILED as defined in scsi/scsi.h
+ */
+static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
+{
+       int rc = SUCCESS;
+       int rcr = 0;
+       struct Scsi_Host *host = scp->device->host;
+       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+
+       pr_debug("%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]));
+
+       switch (cfg->state) {
+       case STATE_NORMAL:
+               cfg->state = STATE_RESET;
+               scsi_block_requests(cfg->host);
+               cxlflash_mark_contexts_error(cfg);
+               rcr = afu_reset(cfg);
+               if (rcr) {
+                       rc = FAILED;
+                       cfg->state = STATE_FAILTERM;
+               } else
+                       cfg->state = STATE_NORMAL;
+               wake_up_all(&cfg->reset_waitq);
+               scsi_unblock_requests(cfg->host);
+               break;
+       case STATE_RESET:
+               wait_event(cfg->reset_waitq, cfg->state != STATE_RESET);
+               if (cfg->state == STATE_NORMAL)
+                       break;
+               /* fall through */
+       default:
+               rc = FAILED;
+               break;
+       }
+
+       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       return rc;
+}
+
+/**
+ * cxlflash_change_queue_depth() - change the queue depth for the device
+ * @sdev:      SCSI device destined for queue depth change.
+ * @qdepth:    Requested queue depth value to set.
+ *
+ * The requested queue depth is capped to the maximum supported value.
+ *
+ * Return: The actual queue depth set.
+ */
+static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+
+       if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN)
+               qdepth = CXLFLASH_MAX_CMDS_PER_LUN;
+
+       scsi_change_queue_depth(sdev, qdepth);
+       return sdev->queue_depth;
+}
+
+/**
+ * cxlflash_show_port_status() - queries and presents the current port status
+ * @dev:       Generic device associated with the host owning the port.
+ * @attr:      Device attribute representing the port.
+ * @buf:       Buffer of length PAGE_SIZE to report back port status in ASCII.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t cxlflash_show_port_status(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct afu *afu = cfg->afu;
+
+       char *disp_status;
+       int rc;
+       u32 port;
+       u64 status;
+       u64 *fc_regs;
+
+       rc = kstrtouint((attr->attr.name + 4), 10, &port);
+       if (rc || (port >= NUM_FC_PORTS))
+               return 0;
+
+       fc_regs = &afu->afu_map->global.fc_regs[port][0];
+       status =
+           (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK);
+
+       if (status == FC_MTIP_STATUS_ONLINE)
+               disp_status = "online";
+       else if (status == FC_MTIP_STATUS_OFFLINE)
+               disp_status = "offline";
+       else
+               disp_status = "unknown";
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", disp_status);
+}
+
+/**
+ * cxlflash_show_lun_mode() - presents the current LUN mode of the host
+ * @dev:       Generic device associated with the host.
+ * @attr:      Device attribute representing the lun mode.
+ * @buf:       Buffer of length PAGE_SIZE to report back the LUN mode in ASCII.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t cxlflash_show_lun_mode(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct afu *afu = cfg->afu;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun);
+}
+
+/**
+ * cxlflash_store_lun_mode() - sets the LUN mode of the host
+ * @dev:       Generic device associated with the host.
+ * @attr:      Device attribute representing the lun mode.
+ * @buf:       Buffer of length PAGE_SIZE containing the LUN mode in ASCII.
+ * @count:     Length of data resizing in @buf.
+ *
+ * The CXL Flash AFU supports a dummy LUN mode where the external
+ * links and storage are not required. Space on the FPGA is used
+ * to create 1 or 2 small LUNs which are presented to the system
+ * as if they were a normal storage device. This feature is useful
+ * during development and also provides manufacturing with a way
+ * to test the AFU without an actual device.
+ *
+ * 0 = external LUN[s] (default)
+ * 1 = internal LUN (1 x 64K, 512B blocks, id 0)
+ * 2 = internal LUN (1 x 64K, 4K blocks, id 0)
+ * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1)
+ * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1)
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t cxlflash_store_lun_mode(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct afu *afu = cfg->afu;
+       int rc;
+       u32 lun_mode;
+
+       rc = kstrtouint(buf, 10, &lun_mode);
+       if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
+               afu->internal_lun = lun_mode;
+               afu_reset(cfg);
+               scsi_scan_host(cfg->host);
+       }
+
+       return count;
+}
+
+/**
+ * cxlflash_show_ioctl_version() - presents the hosts current ioctl version
+ * @dev:       Generic device associated with the host.
+ * @attr:      Device attribute representing the ioctl version.
+ * @buf:       Buffer of length PAGE_SIZE to report back the ioctl version.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t cxlflash_show_ioctl_version(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0);
+}
+
+/**
+ * cxlflash_show_dev_mode() - presents the current mode of the device
+ * @dev:       Generic device associated with the device.
+ * @attr:      Device attribute representing the device mode.
+ * @buf:       Buffer of length PAGE_SIZE to report back the dev mode in ASCII.
+ *
+ * Return: The size of the ASCII string returned in @buf.
+ */
+static ssize_t cxlflash_show_dev_mode(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       sdev->hostdata ? "superpipe" : "legacy");
+}
+
+/*
+ * Host attributes
+ */
+static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL);
+static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL);
+static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode,
+                  cxlflash_store_lun_mode);
+static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL);
+
+static struct device_attribute *cxlflash_host_attrs[] = {
+       &dev_attr_port0,
+       &dev_attr_port1,
+       &dev_attr_lun_mode,
+       &dev_attr_ioctl_version,
+       NULL
+};
+
+/*
+ * Device attributes
+ */
+static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL);
+
+static struct device_attribute *cxlflash_dev_attrs[] = {
+       &dev_attr_mode,
+       NULL
+};
+
+/*
+ * Host template
+ */
+static struct scsi_host_template driver_template = {
+       .module = THIS_MODULE,
+       .name = CXLFLASH_ADAPTER_NAME,
+       .info = cxlflash_driver_info,
+       .ioctl = cxlflash_ioctl,
+       .proc_name = CXLFLASH_NAME,
+       .queuecommand = cxlflash_queuecommand,
+       .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,
+       .cmd_per_lun = 16,
+       .can_queue = CXLFLASH_MAX_CMDS,
+       .this_id = -1,
+       .sg_tablesize = SG_NONE,        /* No scatter gather support. */
+       .max_sectors = CXLFLASH_MAX_SECTORS,
+       .use_clustering = ENABLE_CLUSTERING,
+       .shost_attrs = cxlflash_host_attrs,
+       .sdev_attrs = cxlflash_dev_attrs,
+};
+
+/*
+ * Device dependent values
+ */
+static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+
+/*
+ * PCI device binding table
+ */
+static struct pci_device_id cxlflash_pci_table[] = {
+       {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+       {}
+};
+
+MODULE_DEVICE_TABLE(pci, cxlflash_pci_table);
+
+/**
  * cxlflash_worker_thread() - work thread handler for the AFU
  * @work:      Work structure contained within cxlflash associated with host.
  *
-- 
2.1.0

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to