mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 17:59:32 +00:00
nvme: support for multiple Command Sets Supported and Effects log pages
The Commands Supported and Effects log page was extended with a CSI field that enables the host to query the log page for each command set supported. Retrieve this log page for each command set that an attached namespace supports, and save a pointer to that log in the namespace head. Reviewed-by: Matias Bjørling <matias.bjorling@wdc.com> Reviewed-by: Javier González <javier.gonz@samsung.com> Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Keith Busch <keith.busch@wdc.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
71010c3094
commit
be93e87e78
6 changed files with 76 additions and 25 deletions
|
@ -1370,8 +1370,8 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
|
||||||
u32 effects = 0;
|
u32 effects = 0;
|
||||||
|
|
||||||
if (ns) {
|
if (ns) {
|
||||||
if (ctrl->effects)
|
if (ns->head->effects)
|
||||||
effects = le32_to_cpu(ctrl->effects->iocs[opcode]);
|
effects = le32_to_cpu(ns->head->effects->iocs[opcode]);
|
||||||
if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))
|
if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))
|
||||||
dev_warn(ctrl->device,
|
dev_warn(ctrl->device,
|
||||||
"IO command:%02x has unhandled effects:%08x\n",
|
"IO command:%02x has unhandled effects:%08x\n",
|
||||||
|
@ -2851,7 +2851,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
|
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
|
||||||
void *log, size_t size, u64 offset)
|
void *log, size_t size, u64 offset)
|
||||||
{
|
{
|
||||||
struct nvme_command c = { };
|
struct nvme_command c = { };
|
||||||
|
@ -2865,29 +2865,57 @@ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
|
||||||
c.get_log_page.numdu = cpu_to_le16(dwlen >> 16);
|
c.get_log_page.numdu = cpu_to_le16(dwlen >> 16);
|
||||||
c.get_log_page.lpol = cpu_to_le32(lower_32_bits(offset));
|
c.get_log_page.lpol = cpu_to_le32(lower_32_bits(offset));
|
||||||
c.get_log_page.lpou = cpu_to_le32(upper_32_bits(offset));
|
c.get_log_page.lpou = cpu_to_le32(upper_32_bits(offset));
|
||||||
|
c.get_log_page.csi = csi;
|
||||||
|
|
||||||
return nvme_submit_sync_cmd(ctrl->admin_q, &c, log, size);
|
return nvme_submit_sync_cmd(ctrl->admin_q, &c, log, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_get_effects_log(struct nvme_ctrl *ctrl)
|
static struct nvme_cel *nvme_find_cel(struct nvme_ctrl *ctrl, u8 csi)
|
||||||
{
|
{
|
||||||
|
struct nvme_cel *cel, *ret = NULL;
|
||||||
|
|
||||||
|
spin_lock(&ctrl->lock);
|
||||||
|
list_for_each_entry(cel, &ctrl->cels, entry) {
|
||||||
|
if (cel->csi == csi) {
|
||||||
|
ret = cel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&ctrl->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_get_effects_log(struct nvme_ctrl *ctrl, u8 csi,
|
||||||
|
struct nvme_effects_log **log)
|
||||||
|
{
|
||||||
|
struct nvme_cel *cel = nvme_find_cel(ctrl, csi);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!ctrl->effects)
|
if (cel)
|
||||||
ctrl->effects = kzalloc(sizeof(*ctrl->effects), GFP_KERNEL);
|
goto out;
|
||||||
|
|
||||||
if (!ctrl->effects)
|
cel = kzalloc(sizeof(*cel), GFP_KERNEL);
|
||||||
return 0;
|
if (!cel)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, 0,
|
ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, 0, csi,
|
||||||
ctrl->effects, sizeof(*ctrl->effects), 0);
|
&cel->log, sizeof(cel->log), 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(ctrl->effects);
|
kfree(cel);
|
||||||
ctrl->effects = NULL;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cel->csi = csi;
|
||||||
|
|
||||||
|
spin_lock(&ctrl->lock);
|
||||||
|
list_add_tail(&cel->entry, &ctrl->cels);
|
||||||
|
spin_unlock(&ctrl->lock);
|
||||||
|
out:
|
||||||
|
*log = &cel->log;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the cached copies of the Identify data and various controller
|
* Initialize the cached copies of the Identify data and various controller
|
||||||
* register in our nvme_ctrl structure. This should be called as soon as
|
* register in our nvme_ctrl structure. This should be called as soon as
|
||||||
|
@ -2918,7 +2946,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id->lpa & NVME_CTRL_LPA_CMD_EFFECTS_LOG) {
|
if (id->lpa & NVME_CTRL_LPA_CMD_EFFECTS_LOG) {
|
||||||
ret = nvme_get_effects_log(ctrl);
|
ret = nvme_get_effects_log(ctrl, NVME_CSI_NVM, &ctrl->effects);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
@ -3551,6 +3579,13 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
|
||||||
goto out_cleanup_srcu;
|
goto out_cleanup_srcu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (head->ids.csi) {
|
||||||
|
ret = nvme_get_effects_log(ctrl, head->ids.csi, &head->effects);
|
||||||
|
if (ret)
|
||||||
|
goto out_cleanup_srcu;
|
||||||
|
} else
|
||||||
|
head->effects = ctrl->effects;
|
||||||
|
|
||||||
ret = nvme_mpath_alloc_disk(ctrl, head);
|
ret = nvme_mpath_alloc_disk(ctrl, head);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_cleanup_srcu;
|
goto out_cleanup_srcu;
|
||||||
|
@ -3891,8 +3926,8 @@ static void nvme_clear_changed_ns_log(struct nvme_ctrl *ctrl)
|
||||||
* raced with us in reading the log page, which could cause us to miss
|
* raced with us in reading the log page, which could cause us to miss
|
||||||
* updates.
|
* updates.
|
||||||
*/
|
*/
|
||||||
error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CHANGED_NS, 0, log,
|
error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CHANGED_NS, 0,
|
||||||
log_size, 0);
|
NVME_CSI_NVM, log, log_size, 0);
|
||||||
if (error)
|
if (error)
|
||||||
dev_warn(ctrl->device,
|
dev_warn(ctrl->device,
|
||||||
"reading changed ns log failed: %d\n", error);
|
"reading changed ns log failed: %d\n", error);
|
||||||
|
@ -4036,8 +4071,8 @@ static void nvme_get_fw_slot_info(struct nvme_ctrl *ctrl)
|
||||||
if (!log)
|
if (!log)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_FW_SLOT, 0, log,
|
if (nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_FW_SLOT, 0, NVME_CSI_NVM,
|
||||||
sizeof(*log), 0))
|
log, sizeof(*log), 0))
|
||||||
dev_warn(ctrl->device, "Get FW SLOT INFO log error\n");
|
dev_warn(ctrl->device, "Get FW SLOT INFO log error\n");
|
||||||
kfree(log);
|
kfree(log);
|
||||||
}
|
}
|
||||||
|
@ -4174,11 +4209,16 @@ static void nvme_free_ctrl(struct device *dev)
|
||||||
struct nvme_ctrl *ctrl =
|
struct nvme_ctrl *ctrl =
|
||||||
container_of(dev, struct nvme_ctrl, ctrl_device);
|
container_of(dev, struct nvme_ctrl, ctrl_device);
|
||||||
struct nvme_subsystem *subsys = ctrl->subsys;
|
struct nvme_subsystem *subsys = ctrl->subsys;
|
||||||
|
struct nvme_cel *cel, *next;
|
||||||
|
|
||||||
if (subsys && ctrl->instance != subsys->instance)
|
if (subsys && ctrl->instance != subsys->instance)
|
||||||
ida_simple_remove(&nvme_instance_ida, ctrl->instance);
|
ida_simple_remove(&nvme_instance_ida, ctrl->instance);
|
||||||
|
|
||||||
kfree(ctrl->effects);
|
list_for_each_entry_safe(cel, next, &ctrl->cels, entry) {
|
||||||
|
list_del(&cel->entry);
|
||||||
|
kfree(cel);
|
||||||
|
}
|
||||||
|
|
||||||
nvme_mpath_uninit(ctrl);
|
nvme_mpath_uninit(ctrl);
|
||||||
__free_page(ctrl->discard_page);
|
__free_page(ctrl->discard_page);
|
||||||
|
|
||||||
|
@ -4209,6 +4249,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
|
||||||
spin_lock_init(&ctrl->lock);
|
spin_lock_init(&ctrl->lock);
|
||||||
mutex_init(&ctrl->scan_lock);
|
mutex_init(&ctrl->scan_lock);
|
||||||
INIT_LIST_HEAD(&ctrl->namespaces);
|
INIT_LIST_HEAD(&ctrl->namespaces);
|
||||||
|
INIT_LIST_HEAD(&ctrl->cels);
|
||||||
init_rwsem(&ctrl->namespaces_rwsem);
|
init_rwsem(&ctrl->namespaces_rwsem);
|
||||||
ctrl->dev = dev;
|
ctrl->dev = dev;
|
||||||
ctrl->ops = ops;
|
ctrl->ops = ops;
|
||||||
|
|
|
@ -62,7 +62,7 @@ static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
|
ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0,
|
||||||
&data->log, sizeof(data->log), 0);
|
NVME_CSI_NVM, &data->log, sizeof(data->log), 0);
|
||||||
|
|
||||||
return ret <= 0 ? ret : -EIO;
|
return ret <= 0 ? ret : -EIO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -593,8 +593,8 @@ static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
|
||||||
dev_meta_off = dev_meta;
|
dev_meta_off = dev_meta;
|
||||||
|
|
||||||
ret = nvme_get_log(ctrl, ns->head->ns_id,
|
ret = nvme_get_log(ctrl, ns->head->ns_id,
|
||||||
NVME_NVM_LOG_REPORT_CHUNK, 0, dev_meta, len,
|
NVME_NVM_LOG_REPORT_CHUNK, 0, NVME_CSI_NVM,
|
||||||
offset);
|
dev_meta, len, offset);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(ctrl->device, "Get REPORT CHUNK log error\n");
|
dev_err(ctrl->device, "Get REPORT CHUNK log error\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -527,7 +527,7 @@ static int nvme_read_ana_log(struct nvme_ctrl *ctrl)
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
mutex_lock(&ctrl->ana_lock);
|
mutex_lock(&ctrl->ana_lock);
|
||||||
error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_ANA, 0,
|
error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_ANA, 0, NVME_CSI_NVM,
|
||||||
ctrl->ana_log_buf, ctrl->ana_log_size, 0);
|
ctrl->ana_log_buf, ctrl->ana_log_size, 0);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(ctrl->device, "Failed to get ANA log: %d\n", error);
|
dev_warn(ctrl->device, "Failed to get ANA log: %d\n", error);
|
||||||
|
|
|
@ -191,6 +191,12 @@ struct nvme_fault_inject {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nvme_cel {
|
||||||
|
struct list_head entry;
|
||||||
|
struct nvme_effects_log log;
|
||||||
|
u8 csi;
|
||||||
|
};
|
||||||
|
|
||||||
struct nvme_ctrl {
|
struct nvme_ctrl {
|
||||||
bool comp_seen;
|
bool comp_seen;
|
||||||
enum nvme_ctrl_state state;
|
enum nvme_ctrl_state state;
|
||||||
|
@ -257,6 +263,7 @@ struct nvme_ctrl {
|
||||||
unsigned long quirks;
|
unsigned long quirks;
|
||||||
struct nvme_id_power_state psd[32];
|
struct nvme_id_power_state psd[32];
|
||||||
struct nvme_effects_log *effects;
|
struct nvme_effects_log *effects;
|
||||||
|
struct list_head cels;
|
||||||
struct work_struct scan_work;
|
struct work_struct scan_work;
|
||||||
struct work_struct async_event_work;
|
struct work_struct async_event_work;
|
||||||
struct delayed_work ka_work;
|
struct delayed_work ka_work;
|
||||||
|
@ -359,6 +366,7 @@ struct nvme_ns_head {
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
bool shared;
|
bool shared;
|
||||||
int instance;
|
int instance;
|
||||||
|
struct nvme_effects_log *effects;
|
||||||
#ifdef CONFIG_NVME_MULTIPATH
|
#ifdef CONFIG_NVME_MULTIPATH
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
struct bio_list requeue_list;
|
struct bio_list requeue_list;
|
||||||
|
@ -561,7 +569,7 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl);
|
||||||
int nvme_try_sched_reset(struct nvme_ctrl *ctrl);
|
int nvme_try_sched_reset(struct nvme_ctrl *ctrl);
|
||||||
int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
|
int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
|
||||||
|
|
||||||
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
|
int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
|
||||||
void *log, size_t size, u64 offset);
|
void *log, size_t size, u64 offset);
|
||||||
|
|
||||||
extern const struct attribute_group *nvme_ns_id_attr_groups[];
|
extern const struct attribute_group *nvme_ns_id_attr_groups[];
|
||||||
|
|
|
@ -1101,7 +1101,9 @@ struct nvme_get_log_page_command {
|
||||||
};
|
};
|
||||||
__le64 lpo;
|
__le64 lpo;
|
||||||
};
|
};
|
||||||
__u32 rsvd14[2];
|
__u8 rsvd14[3];
|
||||||
|
__u8 csi;
|
||||||
|
__u32 rsvd15;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvme_directive_cmd {
|
struct nvme_directive_cmd {
|
||||||
|
|
Loading…
Reference in a new issue