Commit 704c4b0d authored by Uma Krishnan's avatar Uma Krishnan Committed by Martin K. Petersen

cxlflash: Shutdown notify support for CXL Flash cards

Some CXL Flash cards need notification of device shutdown in order to
flush pending I/Os.

A PCI notification hook for shutdown has been added where the driver
notifies the card and returns. When the device is removed in the PCI
remove path, notification code will wait for shutdown processing to
complete.
Signed-off-by: default avatarUma Krishnan <ukrishn@linux.vnet.ibm.com>
Acked-by: default avatarManoj N. Kumar <manoj@linux.vnet.ibm.com>
Acked-by: default avatarMatthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 96e1b660
...@@ -764,6 +764,67 @@ static void term_afu(struct cxlflash_cfg *cfg) ...@@ -764,6 +764,67 @@ static void term_afu(struct cxlflash_cfg *cfg)
pr_debug("%s: returning\n", __func__); pr_debug("%s: returning\n", __func__);
} }
/**
* 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 = &afu->afu_map->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;
/* 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 * cxlflash_remove() - PCI entry point to tear down host
* @pdev: PCI device associated with the host. * @pdev: PCI device associated with the host.
...@@ -785,6 +846,9 @@ static void cxlflash_remove(struct pci_dev *pdev) ...@@ -785,6 +846,9 @@ static void cxlflash_remove(struct pci_dev *pdev)
cfg->tmf_slock); cfg->tmf_slock);
spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); 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; cfg->state = STATE_FAILTERM;
cxlflash_stop_term_user_contexts(cfg); cxlflash_stop_term_user_contexts(cfg);
...@@ -2336,7 +2400,7 @@ static struct scsi_host_template driver_template = { ...@@ -2336,7 +2400,7 @@ static struct scsi_host_template driver_template = {
static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS, static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS,
0ULL }; 0ULL };
static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS, static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS,
0ULL }; CXLFLASH_NOTIFY_SHUTDOWN };
/* /*
* PCI device binding table * PCI device binding table
...@@ -2613,6 +2677,7 @@ static struct pci_driver cxlflash_driver = { ...@@ -2613,6 +2677,7 @@ static struct pci_driver cxlflash_driver = {
.id_table = cxlflash_pci_table, .id_table = cxlflash_pci_table,
.probe = cxlflash_probe, .probe = cxlflash_probe,
.remove = cxlflash_remove, .remove = cxlflash_remove,
.shutdown = cxlflash_shutdown,
.err_handler = &cxlflash_err_handler, .err_handler = &cxlflash_err_handler,
}; };
......
...@@ -89,6 +89,7 @@ enum undo_level { ...@@ -89,6 +89,7 @@ enum undo_level {
struct dev_dependent_vals { struct dev_dependent_vals {
u64 max_sectors; u64 max_sectors;
u64 flags; u64 flags;
#define CXLFLASH_NOTIFY_SHUTDOWN 0x0000000000000001ULL
}; };
struct asyc_intr_info { struct asyc_intr_info {
......
...@@ -311,6 +311,12 @@ struct sisl_global_regs { ...@@ -311,6 +311,12 @@ struct sisl_global_regs {
#define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) #define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK)
#define SISL_FC_INTERNAL_SHIFT 32 #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_UNMASK 0xFFFFULL /* 1 means unmasked */
#define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ #define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment