diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
commit | d635711daa98be86d4c7fd01499c34f566b54ccb (patch) | |
tree | aa5cc3760a27c3d57146498cb82fa549547de06c /drivers/scsi/cxlflash | |
parent | c91265cd0efb83778f015b4d4b1129bd2cfd075e (diff) |
Linux-libre 4.6.2-gnu
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r-- | drivers/scsi/cxlflash/common.h | 9 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 224 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.h | 5 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/superpipe.c | 195 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/superpipe.h | 1 |
5 files changed, 228 insertions, 206 deletions
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 5ada9268a..6e6815545 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -34,7 +34,6 @@ extern const struct file_operations cxlflash_cxl_fops; sectors */ -#define NUM_RRQ_ENTRY 16 /* for master issued cmds */ #define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry)) /* AFU command retry limit */ @@ -48,9 +47,12 @@ extern const struct file_operations cxlflash_cxl_fops; index derivation */ -#define CXLFLASH_MAX_CMDS 16 +#define CXLFLASH_MAX_CMDS 256 #define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS +/* RRQ for master issued cmds */ +#define NUM_RRQ_ENTRY CXLFLASH_MAX_CMDS + static inline void check_sizes(void) { @@ -106,7 +108,6 @@ struct cxlflash_cfg { atomic_t scan_host_needed; struct cxl_afu *cxl_afu; - struct pci_dev *parent_dev; atomic_t recovery_threads; struct mutex ctx_recovery_mutex; @@ -149,7 +150,7 @@ struct afu_cmd { struct afu { /* Stuff requiring alignment go first. */ - u64 rrq_entry[NUM_RRQ_ENTRY]; /* 128B RRQ */ + u64 rrq_entry[NUM_RRQ_ENTRY]; /* 2K RRQ */ /* * Command & data for AFU commands. */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index f6d90ce8f..8fb9643fe 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -289,7 +289,7 @@ static void context_reset(struct afu_cmd *cmd) atomic64_set(&afu->room, room); if (room) goto write_rrin; - udelay(nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); pr_err("%s: no cmd_room to send reset\n", __func__); @@ -303,7 +303,7 @@ write_rrin: if (rrin != 0x1) break; /* Double delay each time */ - udelay(2 << nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); } @@ -338,7 +338,7 @@ retry: atomic64_set(&afu->room, room); if (room) goto write_ioarrin; - udelay(nretry); + udelay(1 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); dev_err(dev, "%s: no cmd_room to send 0x%X\n", @@ -352,7 +352,7 @@ retry: * afu->room. */ if (nretry++ < MC_ROOM_RETRY_CNT) { - udelay(nretry); + udelay(1 << nretry); goto retry; } @@ -683,28 +683,23 @@ static void stop_afu(struct cxlflash_cfg *cfg) } /** - * term_mc() - terminates the master context + * term_intr() - disables all AFU interrupts * @cfg: Internal structure associated with the host. * @level: Depth of allocation, where to begin waterfall tear down. * * Safe to call with AFU/MC in partially allocated/initialized state. */ -static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) +static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level) { - int rc = 0; struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; if (!afu || !cfg->mcctx) { - dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n", - __func__); + dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); return; } switch (level) { - case UNDO_START: - rc = cxl_stop_context(cfg->mcctx); - BUG_ON(rc); case UNMAP_THREE: cxl_unmap_afu_irq(cfg->mcctx, 3, afu); case UNMAP_TWO: @@ -713,9 +708,34 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) cxl_unmap_afu_irq(cfg->mcctx, 1, afu); case FREE_IRQ: cxl_free_afu_irqs(cfg->mcctx); - case RELEASE_CONTEXT: - cfg->mcctx = NULL; + /* fall through */ + case UNDO_NOOP: + /* No action required */ + break; + } +} + +/** + * term_mc() - terminates the master context + * @cfg: Internal structure associated with the host. + * @level: Depth of allocation, where to begin waterfall tear down. + * + * Safe to call with AFU/MC in partially allocated/initialized state. + */ +static void term_mc(struct cxlflash_cfg *cfg) +{ + int rc = 0; + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + + if (!afu || !cfg->mcctx) { + dev_err(dev, "%s: returning with NULL afu or MC\n", __func__); + return; } + + rc = cxl_stop_context(cfg->mcctx); + WARN_ON(rc); + cfg->mcctx = NULL; } /** @@ -726,11 +746,21 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) */ static void term_afu(struct cxlflash_cfg *cfg) { - term_mc(cfg, UNDO_START); - + /* + * Tear down is carefully orchestrated to ensure + * no interrupts can come in when the problem state + * area is unmapped. + * + * 1) Disable all AFU interrupts + * 2) Unmap the problem state area + * 3) Stop the master context + */ + term_intr(cfg, UNMAP_THREE); if (cfg->afu) stop_afu(cfg); + term_mc(cfg); + pr_debug("%s: returning\n", __func__); } @@ -767,7 +797,6 @@ static void cxlflash_remove(struct pci_dev *pdev) cancel_work_sync(&cfg->work_q); term_afu(cfg); case INIT_STATE_PCI: - pci_release_regions(cfg->dev); pci_disable_device(pdev); case INIT_STATE_NONE: free_mem(cfg); @@ -840,15 +869,6 @@ static int init_pci(struct cxlflash_cfg *cfg) struct pci_dev *pdev = cfg->dev; int rc = 0; - cfg->cxlflash_regs_pci = pci_resource_start(pdev, 0); - rc = pci_request_regions(pdev, CXLFLASH_NAME); - if (rc < 0) { - dev_err(&pdev->dev, - "%s: Couldn't register memory range of registers\n", - __func__); - goto out; - } - rc = pci_enable_device(pdev); if (rc || pci_channel_offline(pdev)) { if (pci_channel_offline(pdev)) { @@ -860,55 +880,13 @@ static int init_pci(struct cxlflash_cfg *cfg) dev_err(&pdev->dev, "%s: Cannot enable adapter\n", __func__); cxlflash_wait_for_pci_err_recovery(cfg); - goto out_release_regions; - } - } - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc < 0) { - dev_dbg(&pdev->dev, "%s: Failed to set 64 bit PCI DMA mask\n", - __func__); - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - if (rc < 0) { - dev_err(&pdev->dev, "%s: Failed to set PCI DMA mask\n", - __func__); - goto out_disable; - } - - pci_set_master(pdev); - - if (pci_channel_offline(pdev)) { - cxlflash_wait_for_pci_err_recovery(cfg); - if (pci_channel_offline(pdev)) { - rc = -EIO; - goto out_msi_disable; + goto out; } } - rc = pci_save_state(pdev); - - if (rc != PCIBIOS_SUCCESSFUL) { - dev_err(&pdev->dev, "%s: Failed to save PCI config space\n", - __func__); - rc = -EIO; - goto cleanup_nolog; - } - out: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; - -cleanup_nolog: -out_msi_disable: - cxlflash_wait_for_pci_err_recovery(cfg); -out_disable: - pci_disable_device(pdev); -out_release_regions: - pci_release_regions(pdev); - goto out; - } /** @@ -1407,7 +1385,7 @@ static int start_context(struct cxlflash_cfg *cfg) */ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) { - struct pci_dev *dev = cfg->parent_dev; + struct pci_dev *dev = cfg->dev; int rc = 0; int ro_start, ro_size, i, j, k; ssize_t vpd_size; @@ -1416,7 +1394,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" }; /* Get the VPD data from the device */ - vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data); + vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data)); if (unlikely(vpd_size <= 0)) { dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n", __func__, vpd_size); @@ -1649,41 +1627,24 @@ static int start_afu(struct cxlflash_cfg *cfg) } /** - * init_mc() - create and register as the master context + * init_intr() - setup interrupt handlers for the master context * @cfg: Internal structure associated with the host. * * Return: 0 on success, -errno on failure */ -static int init_mc(struct cxlflash_cfg *cfg) +static enum undo_level init_intr(struct cxlflash_cfg *cfg, + struct cxl_context *ctx) { - struct cxl_context *ctx; - struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int rc = 0; - enum undo_level level; - - ctx = cxl_get_context(cfg->dev); - if (unlikely(!ctx)) - return -ENOMEM; - cfg->mcctx = ctx; - - /* Set it up as a master with the CXL */ - cxl_set_master(ctx); - - /* During initialization reset the AFU to start from a clean slate */ - rc = cxl_afu_reset(cfg->mcctx); - if (unlikely(rc)) { - dev_err(dev, "%s: initial AFU reset failed rc=%d\n", - __func__, rc); - level = RELEASE_CONTEXT; - goto out; - } + enum undo_level level = UNDO_NOOP; rc = cxl_allocate_afu_irqs(ctx, 3); if (unlikely(rc)) { dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n", __func__, rc); - level = RELEASE_CONTEXT; + level = UNDO_NOOP; goto out; } @@ -1713,8 +1674,47 @@ static int init_mc(struct cxlflash_cfg *cfg) level = UNMAP_TWO; goto out; } +out: + return level; +} - rc = 0; +/** + * init_mc() - create and register as the master context + * @cfg: Internal structure associated with the host. + * + * Return: 0 on success, -errno on failure + */ +static int init_mc(struct cxlflash_cfg *cfg) +{ + struct cxl_context *ctx; + struct device *dev = &cfg->dev->dev; + int rc = 0; + enum undo_level level; + + ctx = cxl_get_context(cfg->dev); + if (unlikely(!ctx)) { + rc = -ENOMEM; + goto ret; + } + cfg->mcctx = ctx; + + /* Set it up as a master with the CXL */ + cxl_set_master(ctx); + + /* During initialization reset the AFU to start from a clean slate */ + rc = cxl_afu_reset(cfg->mcctx); + if (unlikely(rc)) { + dev_err(dev, "%s: initial AFU reset failed rc=%d\n", + __func__, rc); + goto ret; + } + + level = init_intr(cfg, ctx); + if (unlikely(level)) { + dev_err(dev, "%s: setting up interrupts failed rc=%d\n", + __func__, rc); + goto out; + } /* This performs the equivalent of the CXL_IOCTL_START_WORK. * The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process @@ -1730,7 +1730,7 @@ ret: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; out: - term_mc(cfg, level); + term_intr(cfg, level); goto ret; } @@ -1803,7 +1803,8 @@ out: err2: kref_put(&afu->mapcount, afu_unmap); err1: - term_mc(cfg, UNDO_START); + term_intr(cfg, UNMAP_THREE); + term_mc(cfg); goto out; } @@ -2149,6 +2150,16 @@ static ssize_t lun_mode_store(struct device *dev, rc = kstrtouint(buf, 10, &lun_mode); if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { afu->internal_lun = lun_mode; + + /* + * When configured for internal LUN, there is only one channel, + * channel number 0, else there will be 2 (default). + */ + if (afu->internal_lun) + shost->max_channel = 0; + else + shost->max_channel = NUM_FC_PORTS - 1; + afu_reset(cfg); scsi_scan_host(cfg->host); } @@ -2295,7 +2306,7 @@ static struct scsi_host_template driver_template = { .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, + .cmd_per_lun = CXLFLASH_MAX_CMDS_PER_LUN, .can_queue = CXLFLASH_MAX_CMDS, .this_id = -1, .sg_tablesize = SG_NONE, /* No scatter gather support */ @@ -2392,7 +2403,6 @@ static int cxlflash_probe(struct pci_dev *pdev, { struct Scsi_Host *host; struct cxlflash_cfg *cfg = NULL; - struct device *phys_dev; struct dev_dependent_vals *ddv; int rc = 0; @@ -2458,19 +2468,6 @@ static int cxlflash_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, cfg); - /* - * Use the special service provided to look up the physical - * PCI device, since we are called on the probe of the virtual - * PCI host bus (vphb) - */ - phys_dev = cxl_get_phys_dev(pdev); - if (!dev_is_pci(phys_dev)) { - dev_err(&pdev->dev, "%s: not a pci dev\n", __func__); - rc = -ENODEV; - goto out_remove; - } - cfg->parent_dev = to_pci_dev(phys_dev); - cfg->cxl_afu = cxl_pci_to_afu(pdev); rc = init_pci(cfg); @@ -2544,8 +2541,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, if (unlikely(rc)) dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", __func__, rc); - term_mc(cfg, UNDO_START); - stop_afu(cfg); + term_afu(cfg); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: cfg->state = STATE_FAILTERM; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 0faed422c..eb9d8f730 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -79,12 +79,11 @@ #define WWPN_BUF_LEN (WWPN_LEN + 1) enum undo_level { - RELEASE_CONTEXT = 0, + UNDO_NOOP = 0, FREE_IRQ, UNMAP_ONE, UNMAP_TWO, - UNMAP_THREE, - UNDO_START + UNMAP_THREE }; struct dev_dependent_vals { diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index f4020dbb5..d8a5cb3cd 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -709,27 +709,32 @@ int cxlflash_disk_release(struct scsi_device *sdev, * @cfg: Internal structure associated with the host. * @ctxi: Context to release. * - * Note that the rht_lun member of the context was cut from a single - * allocation when the context was created and therefore does not need - * to be explicitly freed. Also note that we conditionally check for the - * existence of the context control map before clearing the RHT registers - * and context capabilities because it is possible to destroy a context - * while the context is in the error state (previous mapping was removed - * [so we don't have to worry about clearing] and context is waiting for - * a new mapping). + * This routine is safe to be called with a a non-initialized context + * and is tolerant of being called with the context's mutex held (it + * will be unlocked if necessary before freeing). Also note that the + * routine conditionally checks for the existence of the context control + * map before clearing the RHT registers and context capabilities because + * it is possible to destroy a context while the context is in the error + * state (previous mapping was removed [so there is no need to worry about + * clearing] and context is waiting for a new mapping). */ static void destroy_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) { struct afu *afu = cfg->afu; - WARN_ON(!list_empty(&ctxi->luns)); + if (ctxi->initialized) { + WARN_ON(!list_empty(&ctxi->luns)); - /* Clear RHT registers and drop all capabilities for this context */ - if (afu->afu_map && ctxi->ctrl_map) { - writeq_be(0, &ctxi->ctrl_map->rht_start); - writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); - writeq_be(0, &ctxi->ctrl_map->ctx_cap); + /* Clear RHT registers and drop all capabilities for context */ + if (afu->afu_map && ctxi->ctrl_map) { + writeq_be(0, &ctxi->ctrl_map->rht_start); + writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); + writeq_be(0, &ctxi->ctrl_map->ctx_cap); + } + + if (mutex_is_locked(&ctxi->mutex)) + mutex_unlock(&ctxi->mutex); } /* Free memory associated with context */ @@ -742,23 +747,12 @@ static void destroy_context(struct cxlflash_cfg *cfg, /** * create_context() - allocates and initializes a context * @cfg: Internal structure associated with the host. - * @ctx: Previously obtained CXL context reference. - * @ctxid: Previously obtained process element associated with CXL context. - * @adap_fd: Previously obtained adapter fd associated with CXL context. - * @file: Previously obtained file associated with CXL context. - * @perms: User-specified permissions. - * - * The context's mutex is locked when an allocated context is returned. * * Return: Allocated context on success, NULL on failure */ -static struct ctx_info *create_context(struct cxlflash_cfg *cfg, - struct cxl_context *ctx, int ctxid, - int adap_fd, struct file *file, - u32 perms) +static struct ctx_info *create_context(struct cxlflash_cfg *cfg) { struct device *dev = &cfg->dev->dev; - struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct llun_info **lli = NULL; u8 *ws = NULL; @@ -781,28 +775,49 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, ctxi->rht_lun = lli; ctxi->rht_needs_ws = ws; ctxi->rht_start = rhte; - ctxi->rht_perms = perms; +out: + return ctxi; + +err: + kfree(ws); + kfree(lli); + kfree(ctxi); + ctxi = NULL; + goto out; +} + +/** + * init_context() - initializes a previously allocated context + * @ctxi: Previously allocated context + * @cfg: Internal structure associated with the host. + * @ctx: Previously obtained CXL context reference. + * @ctxid: Previously obtained process element associated with CXL context. + * @adap_fd: Previously obtained adapter fd associated with CXL context. + * @file: Previously obtained file associated with CXL context. + * @perms: User-specified permissions. + * + * Upon return, the context is marked as initialized and the context's mutex + * is locked. + */ +static void init_context(struct ctx_info *ctxi, struct cxlflash_cfg *cfg, + struct cxl_context *ctx, int ctxid, int adap_fd, + struct file *file, u32 perms) +{ + struct afu *afu = cfg->afu; + ctxi->rht_perms = perms; ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); ctxi->lfd = adap_fd; ctxi->pid = current->tgid; /* tgid = pid */ ctxi->ctx = ctx; ctxi->file = file; + ctxi->initialized = true; mutex_init(&ctxi->mutex); INIT_LIST_HEAD(&ctxi->luns); INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ mutex_lock(&ctxi->mutex); -out: - return ctxi; - -err: - kfree(ws); - kfree(lli); - kfree(ctxi); - ctxi = NULL; - goto out; } /** @@ -1300,9 +1315,9 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, u32 perms; int ctxid = -1; u64 rctxid = 0UL; - struct file *file; + struct file *file = NULL; - struct cxl_context *ctx; + struct cxl_context *ctx = NULL; int fd = -1; @@ -1356,7 +1371,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, if (unlikely(!lun_access)) { dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); rc = -ENOMEM; - goto err0; + goto err; } lun_access->lli = lli; @@ -1371,53 +1386,56 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, goto out_attach; } + ctxi = create_context(cfg); + if (unlikely(!ctxi)) { + dev_err(dev, "%s: Failed to create context! (%d)\n", + __func__, ctxid); + goto err; + } + ctx = cxl_dev_context_init(cfg->dev); if (IS_ERR_OR_NULL(ctx)) { dev_err(dev, "%s: Could not initialize context %p\n", __func__, ctx); rc = -ENODEV; - goto err1; + goto err; + } + + work = &ctxi->work; + work->num_interrupts = attach->num_interrupts; + work->flags = CXL_START_WORK_NUM_IRQS; + + rc = cxl_start_work(ctx, work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err; } ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); rc = -EPERM; - goto err2; + goto err; } file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); if (unlikely(fd < 0)) { rc = -ENODEV; dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err2; + goto err; } /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ perms = SISL_RHT_PERM(attach->hdr.flags + 1); - ctxi = create_context(cfg, ctx, ctxid, fd, file, perms); - if (unlikely(!ctxi)) { - dev_err(dev, "%s: Failed to create context! (%d)\n", - __func__, ctxid); - goto err3; - } - - work = &ctxi->work; - work->num_interrupts = attach->num_interrupts; - work->flags = CXL_START_WORK_NUM_IRQS; - - rc = cxl_start_work(ctx, work); - if (unlikely(rc)) { - dev_dbg(dev, "%s: Could not start context rc=%d\n", - __func__, rc); - goto err4; - } + /* Context mutex is locked upon return */ + init_context(ctxi, cfg, ctx, ctxid, fd, file, perms); rc = afu_attach(cfg, ctxi); if (unlikely(rc)) { dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); - goto err5; + goto err; } /* @@ -1453,13 +1471,14 @@ out: __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); return rc; -err5: - cxl_stop_context(ctx); -err4: - put_context(ctxi); - destroy_context(cfg, ctxi); - ctxi = NULL; -err3: +err: + /* Cleanup CXL context; okay to 'stop' even if it was not started */ + if (!IS_ERR_OR_NULL(ctx)) { + cxl_stop_context(ctx); + cxl_release_context(ctx); + ctx = NULL; + } + /* * Here, we're overriding the fops with a dummy all-NULL fops because * fput() calls the release fop, which will cause us to mistakenly @@ -1467,15 +1486,21 @@ err3: * to that routine (cxlflash_cxl_release) we should try to fix the * issue here. */ - file->f_op = &null_fops; - fput(file); - put_unused_fd(fd); - fd = -1; -err2: - cxl_release_context(ctx); -err1: + if (fd > 0) { + file->f_op = &null_fops; + fput(file); + put_unused_fd(fd); + fd = -1; + file = NULL; + } + + /* Cleanup our context; safe to call even with mutex locked */ + if (ctxi) { + destroy_context(cfg, ctxi); + ctxi = NULL; + } + kfree(lun_access); -err0: scsi_device_put(sdev); goto out; } @@ -1507,24 +1532,24 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) goto out; } + rc = cxl_start_work(ctx, &ctxi->work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err1; + } + ctxid = cxl_process_element(ctx); if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) { dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); rc = -EPERM; - goto err1; + goto err2; } file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); if (unlikely(fd < 0)) { rc = -ENODEV; dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err1; - } - - rc = cxl_start_work(ctx, &ctxi->work); - if (unlikely(rc)) { - dev_dbg(dev, "%s: Could not start context rc=%d\n", - __func__, rc); goto err2; } @@ -1569,10 +1594,10 @@ out: return rc; err3: - cxl_stop_context(ctx); -err2: fput(file); put_unused_fd(fd); +err2: + cxl_stop_context(ctx); err1: cxl_release_context(ctx); goto out; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index bede574bc..5f9a091fd 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -102,6 +102,7 @@ struct ctx_info { u64 ctxid; int lfd; pid_t pid; + bool initialized; bool unavail; bool err_recovery_active; struct mutex mutex; /* Context protection */ |