1312 lines · 34.1 KB · C
RawDownload
// 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.