On 16.9.2015 23:28, Matthew R. Ochs wrote: > 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 <mrochs@xxxxxxxxxxxxxxxxxx> > Signed-off-by: Manoj N. Kumar <manoj@xxxxxxxxxxxxxxxxxx> > --- > 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 6e0be53..2855b09 100644 > --- a/drivers/scsi/cxlflash/common.h > +++ b/drivers/scsi/cxlflash/common.h > @@ -194,11 +194,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 01b7f3e..f2f41a7 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); Double delay - isn't another operator needed? If so, pleas add a new patch for this. --tm > + } 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); > @@ -1640,67 +1466,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; > @@ -1736,7 +1508,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 */ > @@ -2007,92 +1779,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. > @@ -2130,7 +1816,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); > @@ -2159,11 +1845,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) || > @@ -2172,20 +1858,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 > @@ -2201,6 +1887,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. > * -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html