// SPDX-License-Identifier: GPL-2.0/* * Sysfs interface for the NVMe core driver. * * Copyright (c) 2011-2014, Intel Corporation. */ #include <linux/nvme-auth.h>#include <linux/blkdev.h> #include "nvme.h"#include "fabrics.h" static ssize_t nvme_sysfs_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); int ret; ret = nvme_reset_ctrl_sync(ctrl); if (ret < 0) return ret; return count;}static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset); static ssize_t nvme_sysfs_rescan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); nvme_queue_scan(ctrl); return count;}static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan); static ssize_t nvme_adm_passthru_err_log_enabled_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); return sysfs_emit(buf, ctrl->passthru_err_log_enabled ? "on\n" : "off\n");} static ssize_t nvme_adm_passthru_err_log_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); bool passthru_err_log_enabled; int err; err = kstrtobool(buf, &passthru_err_log_enabled); if (err) return -EINVAL; ctrl->passthru_err_log_enabled = passthru_err_log_enabled; return count;} static inline struct nvme_ns_head *dev_to_ns_head(struct device *dev){ struct gendisk *disk = dev_to_disk(dev); if (nvme_disk_is_ns_head(disk)) return disk->private_data; return nvme_get_ns_from_dev(dev)->head;} static ssize_t nvme_io_passthru_err_log_enabled_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns_head *head = dev_to_ns_head(dev); return sysfs_emit(buf, head->passthru_err_log_enabled ? "on\n" : "off\n");} static ssize_t nvme_io_passthru_err_log_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct nvme_ns_head *head = dev_to_ns_head(dev); bool passthru_err_log_enabled; int err; err = kstrtobool(buf, &passthru_err_log_enabled); if (err) return -EINVAL; head->passthru_err_log_enabled = passthru_err_log_enabled; return count;} static struct device_attribute dev_attr_adm_passthru_err_log_enabled = \ __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \ nvme_adm_passthru_err_log_enabled_show, nvme_adm_passthru_err_log_enabled_store); static struct device_attribute dev_attr_io_passthru_err_log_enabled = \ __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \ nvme_io_passthru_err_log_enabled_show, nvme_io_passthru_err_log_enabled_store); static ssize_t wwid_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns_head *head = dev_to_ns_head(dev); struct nvme_ns_ids *ids = &head->ids; struct nvme_subsystem *subsys = head->subsys; int serial_len = sizeof(subsys->serial); int model_len = sizeof(subsys->model); if (!uuid_is_null(&ids->uuid)) return sysfs_emit(buf, "uuid.%pU\n", &ids->uuid); if (memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return sysfs_emit(buf, "eui.%16phN\n", ids->nguid); if (memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) return sysfs_emit(buf, "eui.%8phN\n", ids->eui64); while (serial_len > 0 && (subsys->serial[serial_len - 1] == ' ' || subsys->serial[serial_len - 1] == '\0')) serial_len--; while (model_len > 0 && (subsys->model[model_len - 1] == ' ' || subsys->model[model_len - 1] == '\0')) model_len--; return sysfs_emit(buf, "nvme.%04x-%*phN-%*phN-%08x\n", subsys->vendor_id, serial_len, subsys->serial, model_len, subsys->model, head->ns_id);}static DEVICE_ATTR_RO(wwid); static ssize_t nguid_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%pU\n", dev_to_ns_head(dev)->ids.nguid);}static DEVICE_ATTR_RO(nguid); static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns_ids *ids = &dev_to_ns_head(dev)->ids; /* For backward compatibility expose the NGUID to userspace if * we have no UUID set */ if (uuid_is_null(&ids->uuid)) { dev_warn_once(dev, "No UUID available providing old NGUID\n"); return sysfs_emit(buf, "%pU\n", ids->nguid); } return sysfs_emit(buf, "%pU\n", &ids->uuid);}static DEVICE_ATTR_RO(uuid); static ssize_t eui_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%8ph\n", dev_to_ns_head(dev)->ids.eui64);}static DEVICE_ATTR_RO(eui); static ssize_t nsid_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ns_id);}static DEVICE_ATTR_RO(nsid); static ssize_t csi_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ids.csi);}static DEVICE_ATTR_RO(csi); static ssize_t metadata_bytes_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ms);}static DEVICE_ATTR_RO(metadata_bytes); static int ns_head_update_nuse(struct nvme_ns_head *head){ struct nvme_id_ns *id; struct nvme_ns *ns; int srcu_idx, ret = -EWOULDBLOCK; /* Avoid issuing commands too often by rate limiting the update */ if (!__ratelimit(&head->rs_nuse)) return 0; srcu_idx = srcu_read_lock(&head->srcu); ns = nvme_find_path(head); if (!ns) goto out_unlock; ret = nvme_identify_ns(ns->ctrl, head->ns_id, &id); if (ret) goto out_unlock; head->nuse = le64_to_cpu(id->nuse); kfree(id); out_unlock: srcu_read_unlock(&head->srcu, srcu_idx); return ret;} static int ns_update_nuse(struct nvme_ns *ns){ struct nvme_id_ns *id; int ret; /* Avoid issuing commands too often by rate limiting the update. */ if (!__ratelimit(&ns->head->rs_nuse)) return 0; ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, &id); if (ret) return ret; ns->head->nuse = le64_to_cpu(id->nuse); kfree(id); return 0;} static ssize_t nuse_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns_head *head = dev_to_ns_head(dev); struct gendisk *disk = dev_to_disk(dev); int ret; if (nvme_disk_is_ns_head(disk)) ret = ns_head_update_nuse(head); else ret = ns_update_nuse(disk->private_data); if (ret < 0) return ret; else if (ret > 0) return -EIO; return sysfs_emit(buf, "%llu\n", head->nuse);}static DEVICE_ATTR_RO(nuse); static struct attribute *nvme_ns_attrs[] = { &dev_attr_wwid.attr, &dev_attr_uuid.attr, &dev_attr_nguid.attr, &dev_attr_eui.attr, &dev_attr_csi.attr, &dev_attr_nsid.attr, &dev_attr_metadata_bytes.attr, &dev_attr_nuse.attr,#ifdef CONFIG_NVME_MULTIPATH &dev_attr_ana_grpid.attr, &dev_attr_ana_state.attr, &dev_attr_queue_depth.attr, &dev_attr_numa_nodes.attr, &dev_attr_delayed_removal_secs.attr,#endif &dev_attr_io_passthru_err_log_enabled.attr, NULL,}; static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n){ struct device *dev = container_of(kobj, struct device, kobj); struct nvme_ns_ids *ids = &dev_to_ns_head(dev)->ids; if (a == &dev_attr_uuid.attr) { if (uuid_is_null(&ids->uuid) && !memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return 0; } if (a == &dev_attr_nguid.attr) { if (!memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return 0; } if (a == &dev_attr_eui.attr) { if (!memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) return 0; }#ifdef CONFIG_NVME_MULTIPATH if (a == &dev_attr_ana_grpid.attr || a == &dev_attr_ana_state.attr) { /* per-path attr */ if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; if (!nvme_ctrl_use_ana(nvme_get_ns_from_dev(dev)->ctrl)) return 0; } if (a == &dev_attr_queue_depth.attr || a == &dev_attr_numa_nodes.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_delayed_removal_secs.attr) { struct gendisk *disk = dev_to_disk(dev); if (!nvme_disk_is_ns_head(disk)) return 0; }#endif return a->mode;} static const struct attribute_group nvme_ns_attr_group = { .attrs = nvme_ns_attrs, .is_visible = nvme_ns_attrs_are_visible,}; #ifdef CONFIG_NVME_MULTIPATH/* * NOTE: The dummy attribute does not appear in sysfs. It exists solely to allow * control over the visibility of the multipath sysfs node. Without at least one * attribute defined in nvme_ns_mpath_attrs[], the sysfs implementation does not * invoke the multipath_sysfs_group_visible() method. As a result, we would not * be able to control the visibility of the multipath sysfs node. */static struct attribute dummy_attr = { .name = "dummy",}; static struct attribute *nvme_ns_mpath_attrs[] = { &dummy_attr, NULL,}; static bool multipath_sysfs_group_visible(struct kobject *kobj){ struct device *dev = container_of(kobj, struct device, kobj); return nvme_disk_is_ns_head(dev_to_disk(dev));}DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(multipath_sysfs) const struct attribute_group nvme_ns_mpath_attr_group = { .name = "multipath", .attrs = nvme_ns_mpath_attrs, .is_visible = SYSFS_GROUP_VISIBLE(multipath_sysfs),};#endif static ssize_t command_retries_count_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns *ns = nvme_get_ns_from_dev(dev); return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->retries));} static ssize_t command_retries_count_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned long retries; int err; struct nvme_ns *ns = nvme_get_ns_from_dev(dev); err = kstrtoul(buf, 0, &retries); if (err) return -EINVAL; atomic_long_set(&ns->retries, retries); return count;}static DEVICE_ATTR_RW(command_retries_count); static ssize_t nvme_io_errors_show(struct device *dev, struct device_attribute *attr, char *buf){ struct nvme_ns *ns = nvme_get_ns_from_dev(dev); return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->errors));} static ssize_t nvme_io_errors_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned long errors; int err; struct nvme_ns *ns = nvme_get_ns_from_dev(dev); err = kstrtoul(buf, 0, &errors); if (err) return -EINVAL; atomic_long_set(&ns->errors, errors); return count;} static struct device_attribute dev_attr_io_errors = __ATTR(command_error_count, 0644, nvme_io_errors_show, nvme_io_errors_store); static struct attribute *nvme_ns_diag_attrs[] = { &dev_attr_command_retries_count.attr, &dev_attr_io_errors.attr,#ifdef CONFIG_NVME_MULTIPATH &dev_attr_multipath_failover_count.attr, &dev_attr_io_requeue_no_usable_path_count.attr, &dev_attr_io_fail_no_available_path_count.attr,#endif NULL,}; static umode_t nvme_ns_diag_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n){ struct device *dev = container_of(kobj, struct device, kobj); if (a == &dev_attr_command_retries_count.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_errors.attr) { struct gendisk *disk = dev_to_disk(dev); if (nvme_disk_is_ns_head(disk)) return 0; }#ifdef CONFIG_NVME_MULTIPATH if (a == &dev_attr_multipath_failover_count.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_requeue_no_usable_path_count.attr) { if (!nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_fail_no_available_path_count.attr) { if (!nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; }#endif return a->mode;} static const struct attribute_group nvme_ns_diag_attr_group = { .name = "diag", .attrs = nvme_ns_diag_attrs, .is_visible = nvme_ns_diag_attrs_are_visible,}; const struct attribute_group *nvme_ns_attr_groups[] = { &nvme_ns_attr_group,#ifdef CONFIG_NVME_MULTIPATH &nvme_ns_mpath_attr_group,#endif &nvme_ns_diag_attr_group, NULL,}; #define nvme_show_str_function(field) \static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \{ \ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); \ return sysfs_emit(buf, "%.*s\n", \ (int)sizeof(ctrl->subsys->field), ctrl->subsys->field); \} \static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL); nvme_show_str_function(model);nvme_show_str_function(serial);nvme_show_str_function(firmware_rev); #define nvme_show_int_function(field) \static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \{ \ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); \ return sysfs_emit(buf, "%d\n", ctrl->field); \} \static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL); nvme_show_int_function(cntlid);nvme_show_int_function(numa_node);nvme_show_int_function(queue_count);nvme_show_int_function(sqsize);nvme_show_int_function(kato); static ssize_t nvme_sysfs_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); if (!test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags)) return -EBUSY; if (device_remove_file_self(dev, attr)) nvme_delete_ctrl_sync(ctrl);Lines 1–500 of 1312. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Sysfs interface for the NVMe core driver. * * Copyright (c) 2011-2014, Intel Corporation. */ #include <linux/nvme-auth.h> #include <linux/blkdev.h> #include "nvme.h" #include "fabrics.h" static ssize_t nvme_sysfs_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); int ret; ret = nvme_reset_ctrl_sync(ctrl); if (ret < 0) return ret; return count; } static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset); static ssize_t nvme_sysfs_rescan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); nvme_queue_scan(ctrl); return count; } static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan); static ssize_t nvme_adm_passthru_err_log_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); return sysfs_emit(buf, ctrl->passthru_err_log_enabled ? "on\n" : "off\n"); } static ssize_t nvme_adm_passthru_err_log_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); bool passthru_err_log_enabled; int err; err = kstrtobool(buf, &passthru_err_log_enabled); if (err) return -EINVAL; ctrl->passthru_err_log_enabled = passthru_err_log_enabled; return count; } static inline struct nvme_ns_head *dev_to_ns_head(struct device *dev) { struct gendisk *disk = dev_to_disk(dev); if (nvme_disk_is_ns_head(disk)) return disk->private_data; return nvme_get_ns_from_dev(dev)->head; } static ssize_t nvme_io_passthru_err_log_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns_head *head = dev_to_ns_head(dev); return sysfs_emit(buf, head->passthru_err_log_enabled ? "on\n" : "off\n"); } static ssize_t nvme_io_passthru_err_log_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ns_head *head = dev_to_ns_head(dev); bool passthru_err_log_enabled; int err; err = kstrtobool(buf, &passthru_err_log_enabled); if (err) return -EINVAL; head->passthru_err_log_enabled = passthru_err_log_enabled; return count; } static struct device_attribute dev_attr_adm_passthru_err_log_enabled = \ __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \ nvme_adm_passthru_err_log_enabled_show, nvme_adm_passthru_err_log_enabled_store); static struct device_attribute dev_attr_io_passthru_err_log_enabled = \ __ATTR(passthru_err_log_enabled, S_IRUGO | S_IWUSR, \ nvme_io_passthru_err_log_enabled_show, nvme_io_passthru_err_log_enabled_store); static ssize_t wwid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns_head *head = dev_to_ns_head(dev); struct nvme_ns_ids *ids = &head->ids; struct nvme_subsystem *subsys = head->subsys; int serial_len = sizeof(subsys->serial); int model_len = sizeof(subsys->model); if (!uuid_is_null(&ids->uuid)) return sysfs_emit(buf, "uuid.%pU\n", &ids->uuid); if (memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return sysfs_emit(buf, "eui.%16phN\n", ids->nguid); if (memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) return sysfs_emit(buf, "eui.%8phN\n", ids->eui64); while (serial_len > 0 && (subsys->serial[serial_len - 1] == ' ' || subsys->serial[serial_len - 1] == '\0')) serial_len--; while (model_len > 0 && (subsys->model[model_len - 1] == ' ' || subsys->model[model_len - 1] == '\0')) model_len--; return sysfs_emit(buf, "nvme.%04x-%*phN-%*phN-%08x\n", subsys->vendor_id, serial_len, subsys->serial, model_len, subsys->model, head->ns_id); } static DEVICE_ATTR_RO(wwid); static ssize_t nguid_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%pU\n", dev_to_ns_head(dev)->ids.nguid); } static DEVICE_ATTR_RO(nguid); static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns_ids *ids = &dev_to_ns_head(dev)->ids; /* For backward compatibility expose the NGUID to userspace if * we have no UUID set */ if (uuid_is_null(&ids->uuid)) { dev_warn_once(dev, "No UUID available providing old NGUID\n"); return sysfs_emit(buf, "%pU\n", ids->nguid); } return sysfs_emit(buf, "%pU\n", &ids->uuid); } static DEVICE_ATTR_RO(uuid); static ssize_t eui_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%8ph\n", dev_to_ns_head(dev)->ids.eui64); } static DEVICE_ATTR_RO(eui); static ssize_t nsid_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ns_id); } static DEVICE_ATTR_RO(nsid); static ssize_t csi_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ids.csi); } static DEVICE_ATTR_RO(csi); static ssize_t metadata_bytes_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ms); } static DEVICE_ATTR_RO(metadata_bytes); static int ns_head_update_nuse(struct nvme_ns_head *head) { struct nvme_id_ns *id; struct nvme_ns *ns; int srcu_idx, ret = -EWOULDBLOCK; /* Avoid issuing commands too often by rate limiting the update */ if (!__ratelimit(&head->rs_nuse)) return 0; srcu_idx = srcu_read_lock(&head->srcu); ns = nvme_find_path(head); if (!ns) goto out_unlock; ret = nvme_identify_ns(ns->ctrl, head->ns_id, &id); if (ret) goto out_unlock; head->nuse = le64_to_cpu(id->nuse); kfree(id); out_unlock: srcu_read_unlock(&head->srcu, srcu_idx); return ret; } static int ns_update_nuse(struct nvme_ns *ns) { struct nvme_id_ns *id; int ret; /* Avoid issuing commands too often by rate limiting the update. */ if (!__ratelimit(&ns->head->rs_nuse)) return 0; ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, &id); if (ret) return ret; ns->head->nuse = le64_to_cpu(id->nuse); kfree(id); return 0; } static ssize_t nuse_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns_head *head = dev_to_ns_head(dev); struct gendisk *disk = dev_to_disk(dev); int ret; if (nvme_disk_is_ns_head(disk)) ret = ns_head_update_nuse(head); else ret = ns_update_nuse(disk->private_data); if (ret < 0) return ret; else if (ret > 0) return -EIO; return sysfs_emit(buf, "%llu\n", head->nuse); } static DEVICE_ATTR_RO(nuse); static struct attribute *nvme_ns_attrs[] = { &dev_attr_wwid.attr, &dev_attr_uuid.attr, &dev_attr_nguid.attr, &dev_attr_eui.attr, &dev_attr_csi.attr, &dev_attr_nsid.attr, &dev_attr_metadata_bytes.attr, &dev_attr_nuse.attr, #ifdef CONFIG_NVME_MULTIPATH &dev_attr_ana_grpid.attr, &dev_attr_ana_state.attr, &dev_attr_queue_depth.attr, &dev_attr_numa_nodes.attr, &dev_attr_delayed_removal_secs.attr, #endif &dev_attr_io_passthru_err_log_enabled.attr, NULL, }; static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); struct nvme_ns_ids *ids = &dev_to_ns_head(dev)->ids; if (a == &dev_attr_uuid.attr) { if (uuid_is_null(&ids->uuid) && !memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return 0; } if (a == &dev_attr_nguid.attr) { if (!memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) return 0; } if (a == &dev_attr_eui.attr) { if (!memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) return 0; } #ifdef CONFIG_NVME_MULTIPATH if (a == &dev_attr_ana_grpid.attr || a == &dev_attr_ana_state.attr) { /* per-path attr */ if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; if (!nvme_ctrl_use_ana(nvme_get_ns_from_dev(dev)->ctrl)) return 0; } if (a == &dev_attr_queue_depth.attr || a == &dev_attr_numa_nodes.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_delayed_removal_secs.attr) { struct gendisk *disk = dev_to_disk(dev); if (!nvme_disk_is_ns_head(disk)) return 0; } #endif return a->mode; } static const struct attribute_group nvme_ns_attr_group = { .attrs = nvme_ns_attrs, .is_visible = nvme_ns_attrs_are_visible, }; #ifdef CONFIG_NVME_MULTIPATH /* * NOTE: The dummy attribute does not appear in sysfs. It exists solely to allow * control over the visibility of the multipath sysfs node. Without at least one * attribute defined in nvme_ns_mpath_attrs[], the sysfs implementation does not * invoke the multipath_sysfs_group_visible() method. As a result, we would not * be able to control the visibility of the multipath sysfs node. */ static struct attribute dummy_attr = { .name = "dummy", }; static struct attribute *nvme_ns_mpath_attrs[] = { &dummy_attr, NULL, }; static bool multipath_sysfs_group_visible(struct kobject *kobj) { struct device *dev = container_of(kobj, struct device, kobj); return nvme_disk_is_ns_head(dev_to_disk(dev)); } DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(multipath_sysfs) const struct attribute_group nvme_ns_mpath_attr_group = { .name = "multipath", .attrs = nvme_ns_mpath_attrs, .is_visible = SYSFS_GROUP_VISIBLE(multipath_sysfs), }; #endif static ssize_t command_retries_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns *ns = nvme_get_ns_from_dev(dev); return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->retries)); } static ssize_t command_retries_count_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long retries; int err; struct nvme_ns *ns = nvme_get_ns_from_dev(dev); err = kstrtoul(buf, 0, &retries); if (err) return -EINVAL; atomic_long_set(&ns->retries, retries); return count; } static DEVICE_ATTR_RW(command_retries_count); static ssize_t nvme_io_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nvme_ns *ns = nvme_get_ns_from_dev(dev); return sysfs_emit(buf, "%lu\n", atomic_long_read(&ns->errors)); } static ssize_t nvme_io_errors_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long errors; int err; struct nvme_ns *ns = nvme_get_ns_from_dev(dev); err = kstrtoul(buf, 0, &errors); if (err) return -EINVAL; atomic_long_set(&ns->errors, errors); return count; } static struct device_attribute dev_attr_io_errors = __ATTR(command_error_count, 0644, nvme_io_errors_show, nvme_io_errors_store); static struct attribute *nvme_ns_diag_attrs[] = { &dev_attr_command_retries_count.attr, &dev_attr_io_errors.attr, #ifdef CONFIG_NVME_MULTIPATH &dev_attr_multipath_failover_count.attr, &dev_attr_io_requeue_no_usable_path_count.attr, &dev_attr_io_fail_no_available_path_count.attr, #endif NULL, }; static umode_t nvme_ns_diag_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { struct device *dev = container_of(kobj, struct device, kobj); if (a == &dev_attr_command_retries_count.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_errors.attr) { struct gendisk *disk = dev_to_disk(dev); if (nvme_disk_is_ns_head(disk)) return 0; } #ifdef CONFIG_NVME_MULTIPATH if (a == &dev_attr_multipath_failover_count.attr) { if (nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_requeue_no_usable_path_count.attr) { if (!nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } if (a == &dev_attr_io_fail_no_available_path_count.attr) { if (!nvme_disk_is_ns_head(dev_to_disk(dev))) return 0; } #endif return a->mode; } static const struct attribute_group nvme_ns_diag_attr_group = { .name = "diag", .attrs = nvme_ns_diag_attrs, .is_visible = nvme_ns_diag_attrs_are_visible, }; const struct attribute_group *nvme_ns_attr_groups[] = { &nvme_ns_attr_group, #ifdef CONFIG_NVME_MULTIPATH &nvme_ns_mpath_attr_group, #endif &nvme_ns_diag_attr_group, NULL, }; #define nvme_show_str_function(field) \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); \ return sysfs_emit(buf, "%.*s\n", \ (int)sizeof(ctrl->subsys->field), ctrl->subsys->field); \ } \ static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL); nvme_show_str_function(model); nvme_show_str_function(serial); nvme_show_str_function(firmware_rev); #define nvme_show_int_function(field) \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct nvme_ctrl *ctrl = dev_get_drvdata(dev); \ return sysfs_emit(buf, "%d\n", ctrl->field); \ } \ static DEVICE_ATTR(field, S_IRUGO, field##_show, NULL); nvme_show_int_function(cntlid); nvme_show_int_function(numa_node); nvme_show_int_function(queue_count); nvme_show_int_function(sqsize); nvme_show_int_function(kato); static ssize_t nvme_sysfs_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nvme_ctrl *ctrl = dev_get_drvdata(dev); if (!test_bit(NVME_CTRL_STARTED_ONCE, &ctrl->flags)) return -EBUSY; if (device_remove_file_self(dev, attr)) nvme_delete_ctrl_sync(ctrl);