diff options
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 106 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.h | 6 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/sislite.h | 6 |
3 files changed, 99 insertions, 19 deletions
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 8fb9643fe..661bb94e2 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -765,6 +765,75 @@ static void term_afu(struct cxlflash_cfg *cfg) } /** + * notify_shutdown() - notifies device of pending shutdown + * @cfg: Internal structure associated with the host. + * @wait: Whether to wait for shutdown processing to complete. + * + * This function will notify the AFU that the adapter is being shutdown + * and will wait for shutdown processing to complete if wait is true. + * This notification should flush pending I/Os to the device and halt + * further I/Os until the next AFU reset is issued and device restarted. + */ +static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + struct sisl_global_map __iomem *global; + struct dev_dependent_vals *ddv; + u64 reg, status; + int i, retry_cnt = 0; + + ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data; + if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN)) + return; + + if (!afu || !afu->afu_map) { + dev_dbg(dev, "%s: The problem state area is not mapped\n", + __func__); + return; + } + + global = &afu->afu_map->global; + + /* Notify AFU */ + for (i = 0; i < NUM_FC_PORTS; i++) { + reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]); + reg |= SISL_FC_SHUTDOWN_NORMAL; + writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]); + } + + if (!wait) + return; + + /* Wait up to 1.5 seconds for shutdown processing to complete */ + for (i = 0; i < NUM_FC_PORTS; i++) { + retry_cnt = 0; + while (true) { + status = readq_be(&global->fc_regs[i][FC_STATUS / 8]); + if (status & SISL_STATUS_SHUTDOWN_COMPLETE) + break; + if (++retry_cnt >= MC_RETRY_CNT) { + dev_dbg(dev, "%s: port %d shutdown processing " + "not yet completed\n", __func__, i); + break; + } + msleep(100 * retry_cnt); + } + } +} + +/** + * cxlflash_shutdown() - shutdown handler + * @pdev: PCI device associated with the host. + */ +static void cxlflash_shutdown(struct pci_dev *pdev) +{ + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + + notify_shutdown(cfg, false); +} + +/** * cxlflash_remove() - PCI entry point to tear down host * @pdev: PCI device associated with the host. * @@ -785,6 +854,9 @@ static void cxlflash_remove(struct pci_dev *pdev) cfg->tmf_slock); spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); + /* Notify AFU and wait for shutdown processing to complete */ + notify_shutdown(cfg, true); + cfg->state = STATE_FAILTERM; cxlflash_stop_term_user_contexts(cfg); @@ -1916,6 +1988,19 @@ static int afu_reset(struct cxlflash_cfg *cfg) } /** + * drain_ioctls() - wait until all currently executing ioctls have completed + * @cfg: Internal structure associated with the host. + * + * Obtain write access to read/write semaphore that wraps ioctl + * handling to 'drain' ioctls currently executing. + */ +static void drain_ioctls(struct cxlflash_cfg *cfg) +{ + down_write(&cfg->ioctl_rwsem); + up_write(&cfg->ioctl_rwsem); +} + +/** * cxlflash_eh_device_reset_handler() - reset a single LUN * @scp: SCSI command to send. * @@ -1986,6 +2071,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) switch (cfg->state) { case STATE_NORMAL: cfg->state = STATE_RESET; + drain_ioctls(cfg); cxlflash_mark_contexts_error(cfg); rcr = afu_reset(cfg); if (rcr) { @@ -2319,8 +2405,10 @@ static struct scsi_host_template driver_template = { /* * Device dependent values */ -static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; -static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS }; +static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, + 0ULL }; +static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, + CXLFLASH_NOTIFY_SHUTDOWN }; /* * PCI device binding table @@ -2504,19 +2592,6 @@ out_remove: } /** - * drain_ioctls() - wait until all currently executing ioctls have completed - * @cfg: Internal structure associated with the host. - * - * Obtain write access to read/write semaphore that wraps ioctl - * handling to 'drain' ioctls currently executing. - */ -static void drain_ioctls(struct cxlflash_cfg *cfg) -{ - down_write(&cfg->ioctl_rwsem); - up_write(&cfg->ioctl_rwsem); -} - -/** * cxlflash_pci_error_detected() - called when a PCI error is detected * @pdev: PCI device struct. * @state: PCI channel state. @@ -2610,6 +2685,7 @@ static struct pci_driver cxlflash_driver = { .id_table = cxlflash_pci_table, .probe = cxlflash_probe, .remove = cxlflash_remove, + .shutdown = cxlflash_shutdown, .err_handler = &cxlflash_err_handler, }; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index eb9d8f730..e43545c86 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -88,6 +88,8 @@ enum undo_level { struct dev_dependent_vals { u64 max_sectors; + u64 flags; +#define CXLFLASH_NOTIFY_SHUTDOWN 0x0000000000000001ULL }; struct asyc_intr_info { @@ -100,8 +102,4 @@ struct asyc_intr_info { #define SCAN_HOST 0x04 }; -#ifndef CONFIG_CXL_EEH -#define cxl_perst_reloads_same_image(_a, _b) do { } while (0) -#endif - #endif /* _CXLFLASH_MAIN_H */ diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 0b3366f5e..347fc1671 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -311,6 +311,12 @@ struct sisl_global_regs { #define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) #define SISL_FC_INTERNAL_SHIFT 32 +#define SISL_FC_SHUTDOWN_NORMAL 0x0000000000000010ULL +#define SISL_FC_SHUTDOWN_ABRUPT 0x0000000000000020ULL + +#define SISL_STATUS_SHUTDOWN_ACTIVE 0x0000000000000010ULL +#define SISL_STATUS_SHUTDOWN_COMPLETE 0x0000000000000020ULL + #define SISL_ASTATUS_UNMASK 0xFFFFULL /* 1 means unmasked */ #define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ |