[PATCH] nvme: allow lightnvm to have visibility over AER events
Javier González
javier at javigon.com
Fri Apr 13 04:43:00 PDT 2018
---
drivers/nvme/host/core.c | 37 +++++++++++++++++++++----
drivers/nvme/host/lightnvm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++
drivers/nvme/host/nvme.h | 3 ++
include/linux/lightnvm.h | 24 ++++++++++++++++
include/linux/nvme.h | 1 +
5 files changed, 125 insertions(+), 5 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f81e3b323366..e08cd59e6049 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3263,15 +3263,31 @@ static void nvme_aen_uevent(struct nvme_ctrl *ctrl)
kfree(envp[0]);
}
-static void nvme_async_event_work(struct work_struct *work)
+static void nvme_async_event(struct nvme_ctrl *ctrl)
{
- struct nvme_ctrl *ctrl =
- container_of(work, struct nvme_ctrl, async_event_work);
-
nvme_aen_uevent(ctrl);
ctrl->ops->submit_async_event(ctrl);
}
+static void nvme_async_event_work(struct work_struct *work)
+{
+ struct nvme_ctrl *ctrl =
+ container_of(work, struct nvme_ctrl, async_event_work);
+
+ nvme_async_event(ctrl);
+}
+
+static void nvme_aer_handle_work(struct work_struct *work)
+{
+ struct nvme_ctrl *ctrl =
+ container_of(work, struct nvme_ctrl, aer_handle_work);
+
+ if (ctrl->aen_result & NVME_AER_NOTICE_LNVM_CHUNK)
+ nvme_nvm_aer_handle(ctrl);
+
+ nvme_async_event(ctrl);
+}
+
static bool nvme_ctrl_pp_status(struct nvme_ctrl *ctrl)
{
@@ -3362,7 +3378,16 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
default:
dev_warn(ctrl->device, "async event result %08x\n", result);
}
- queue_work(nvme_wq, &ctrl->async_event_work);
+
+ /* TODO: Create a flag signaling the events that require kernel handling
+ * to make this treatment generic
+ */
+ if (result & NVME_AER_NOTICE_LNVM_CHUNK) {
+ ctrl->aen_result = result;
+ queue_work(nvme_wq, &ctrl->aer_handle_work);
+ } else {
+ queue_work(nvme_wq, &ctrl->async_event_work);
+ }
}
EXPORT_SYMBOL_GPL(nvme_complete_async_event);
@@ -3370,6 +3395,7 @@ void nvme_stop_ctrl(struct nvme_ctrl *ctrl)
{
nvme_stop_keep_alive(ctrl);
flush_work(&ctrl->async_event_work);
+ flush_work(&ctrl->aer_handle_work);
flush_work(&ctrl->scan_work);
cancel_work_sync(&ctrl->fw_act_work);
if (ctrl->ops->stop_ctrl)
@@ -3437,6 +3463,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
ctrl->quirks = quirks;
INIT_WORK(&ctrl->scan_work, nvme_scan_work);
INIT_WORK(&ctrl->async_event_work, nvme_async_event_work);
+ INIT_WORK(&ctrl->aer_handle_work, nvme_aer_handle_work);
INIT_WORK(&ctrl->fw_act_work, nvme_fw_act_work);
INIT_WORK(&ctrl->delete_work, nvme_delete_ctrl_work);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 41279da799ed..f51200447503 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -250,6 +250,17 @@ struct nvme_nvm_chk_meta {
__le64 wp;
};
+struct nvme_ocssd_log {
+ __le64 notification_count;
+ __le64 lba;
+ __le32 nsid;
+ __le16 state :5;
+ __le16 rsvd_state :11;
+ __u8 lba_mask :3;
+ __u8 lba_state :5;
+ __u8 rsvd_23_63[41];
+};
+
/*
* Check we didn't inadvertently grow the command struct
*/
@@ -950,6 +961,60 @@ static int nvme_nvm_user_vcmd(struct nvme_ns *ns, int admin,
return ret;
}
+void nvm_print_log_page(struct nvme_ocssd_log *log)
+{
+ printk(KERN_CRIT "cnt(%llu), ppa(0x%llx), nsid(%u), st(0x%05x), msk(0x%03x)\n",
+ log->notification_count, log->lba, log->nsid, log->state,
+ log->lba_mask);
+}
+
+void nvme_nvm_aer_handle(struct nvme_ctrl *ctrl)
+{
+ struct nvme_ns *iter, *ns = NULL;
+ struct nvm_dev *nvmdev;
+ struct nvme_command c = {};
+ struct nvme_ocssd_log log;
+ struct nvm_log_page log_page;
+ int ret;
+
+ c.common.opcode = nvme_admin_get_log_page;
+ c.common.command_id = NVME_AQ_BLK_MQ_DEPTH;
+ c.common.cdw10[0] = cpu_to_le32(
+ (((sizeof(struct nvme_ocssd_log) / 4) - 1) << 16) |
+ 0xd0);
+
+ memset(&log, 0, sizeof(struct nvme_ocssd_log));
+
+ ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, &log,
+ sizeof(struct nvme_ocssd_log));
+ if (ret)
+ return;
+
+ log_page.ppa.ppa = log.lba;
+ log_page.scope = log.lba_mask & NVM_LOGPAGE_STATE_MASK;
+ log_page.severity = log.state & NVM_LOGPAGE_SEVERITY_MASK;
+
+ down_read(&ctrl->namespaces_rwsem);
+ list_for_each_entry(iter, &ctrl->namespaces, list) {
+ if (iter->head->ns_id == log.nsid) {
+ ns = iter;
+ break;
+ }
+ }
+ up_read(&ctrl->namespaces_rwsem);
+
+ if (!ns)
+ return;
+
+ nvmdev = ns->ndev;
+
+ /* TODO: TOGO */
+ nvm_print_log_page(&log);
+
+ /* nvm_notify_log_page(nvmdev, log_page); */
+
+}
+
int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index aa10842a6709..7d760f54b175 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -183,6 +183,7 @@ struct nvme_ctrl {
struct nvme_effects_log *effects;
struct work_struct scan_work;
struct work_struct async_event_work;
+ struct work_struct aer_handle_work;
struct delayed_work ka_work;
struct nvme_command ka_cmd;
struct work_struct fw_act_work;
@@ -506,6 +507,7 @@ void nvme_nvm_unregister(struct nvme_ns *ns);
int nvme_nvm_register_sysfs(struct nvme_ns *ns);
void nvme_nvm_unregister_sysfs(struct nvme_ns *ns);
int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg);
+void nvme_nvm_aer_handle(struct nvme_ctrl *ctrl);
#else
static inline void nvme_nvm_update_nvm_info(struct nvme_ns *ns) {};
static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
@@ -525,6 +527,7 @@ static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd,
{
return -ENOTTY;
}
+static inline void nvme_nvm_aer_handle(struct nvme_ctrl *ctrl) {};
#endif /* CONFIG_NVM */
static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 6e0859b9d4d2..001c64690125 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -233,6 +233,30 @@ struct nvm_addrf {
};
enum {
+ /* valid bit mask */
+ NVM_LOGPAGE_STATE_MASK = 0x3,
+ NVM_LOGPAGE_SEVERITY_MASK = 0x5,
+
+ /* scope */
+ NVM_LOGPAGE_SCOPE_SECTOR = 1,
+ NVM_LOGPAGE_SCOPE_CHUNK = 2,
+ NVM_LOGPAGE_SCOPE_LUN = 4,
+
+ /* severity */
+ NVM_LOGPAGE_SEVERITY_LOW = 1,
+ NVM_LOGPAGE_SEVERITY_MID = 2,
+ NVM_LOGPAGE_SEVERITY_HIGH = 4,
+ NVM_LOGPAGE_SEVERITY_UNREC = 8,
+ NVM_LOGPAGE_SEVERITY_DEV = 16,
+};
+
+struct nvm_log_page {
+ struct ppa_addr ppa;
+ u16 scope;
+ u8 severity;
+};
+
+enum {
/* Chunk states */
NVM_CHK_ST_FREE = 1 << 0,
NVM_CHK_ST_CLOSED = 1 << 1,
diff --git a/include/linux/nvme.h b/include/linux/nvme.h
index 4112e2bd747f..f85053601c5b 100644
--- a/include/linux/nvme.h
+++ b/include/linux/nvme.h
@@ -440,6 +440,7 @@ enum {
NVME_AER_VS = 7,
NVME_AER_NOTICE_NS_CHANGED = 0x0002,
NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102,
+ NVME_AER_NOTICE_LNVM_CHUNK = 0xd00007,
};
struct nvme_lba_range_type {
--
2.7.4
More information about the Linux-nvme
mailing list