summaryrefslogtreecommitdiff
path: root/drivers/scsi/cxlflash
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r--drivers/scsi/cxlflash/main.c106
-rw-r--r--drivers/scsi/cxlflash/main.h6
-rw-r--r--drivers/scsi/cxlflash/sislite.h6
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 */