b718ae835b
Report the legacy fallback behavior for uuid attributes just once instead of logging repeated warnings for the same condition every time the attribute is read. The old behavior is too spamy on the kernel logs. Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reported-by: Breno Leitao <leitao@debian.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Keith Busch <kbusch@kernel.org>
669 lines
18 KiB
C
669 lines
18 KiB
C
// 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 "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 inline struct nvme_ns_head *dev_to_ns_head(struct device *dev)
|
|
{
|
|
struct gendisk *disk = dev_to_disk(dev);
|
|
|
|
if (disk->fops == &nvme_bdev_ops)
|
|
return nvme_get_ns_from_dev(dev)->head;
|
|
else
|
|
return disk->private_data;
|
|
}
|
|
|
|
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, "%d\n", dev_to_ns_head(dev)->ns_id);
|
|
}
|
|
static DEVICE_ATTR_RO(nsid);
|
|
|
|
static struct attribute *nvme_ns_id_attrs[] = {
|
|
&dev_attr_wwid.attr,
|
|
&dev_attr_uuid.attr,
|
|
&dev_attr_nguid.attr,
|
|
&dev_attr_eui.attr,
|
|
&dev_attr_nsid.attr,
|
|
#ifdef CONFIG_NVME_MULTIPATH
|
|
&dev_attr_ana_grpid.attr,
|
|
&dev_attr_ana_state.attr,
|
|
#endif
|
|
NULL,
|
|
};
|
|
|
|
static umode_t nvme_ns_id_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) {
|
|
if (dev_to_disk(dev)->fops != &nvme_bdev_ops) /* per-path attr */
|
|
return 0;
|
|
if (!nvme_ctrl_use_ana(nvme_get_ns_from_dev(dev)->ctrl))
|
|
return 0;
|
|
}
|
|
#endif
|
|
return a->mode;
|
|
}
|
|
|
|
static const struct attribute_group nvme_ns_id_attr_group = {
|
|
.attrs = nvme_ns_id_attrs,
|
|
.is_visible = nvme_ns_id_attrs_are_visible,
|
|
};
|
|
|
|
const struct attribute_group *nvme_ns_id_attr_groups[] = {
|
|
&nvme_ns_id_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);
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(delete_controller, S_IWUSR, NULL, nvme_sysfs_delete);
|
|
|
|
static ssize_t nvme_sysfs_show_transport(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%s\n", ctrl->ops->name);
|
|
}
|
|
static DEVICE_ATTR(transport, S_IRUGO, nvme_sysfs_show_transport, NULL);
|
|
|
|
static ssize_t nvme_sysfs_show_state(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
static const char *const state_name[] = {
|
|
[NVME_CTRL_NEW] = "new",
|
|
[NVME_CTRL_LIVE] = "live",
|
|
[NVME_CTRL_RESETTING] = "resetting",
|
|
[NVME_CTRL_CONNECTING] = "connecting",
|
|
[NVME_CTRL_DELETING] = "deleting",
|
|
[NVME_CTRL_DELETING_NOIO]= "deleting (no IO)",
|
|
[NVME_CTRL_DEAD] = "dead",
|
|
};
|
|
|
|
if ((unsigned)ctrl->state < ARRAY_SIZE(state_name) &&
|
|
state_name[ctrl->state])
|
|
return sysfs_emit(buf, "%s\n", state_name[ctrl->state]);
|
|
|
|
return sysfs_emit(buf, "unknown state\n");
|
|
}
|
|
|
|
static DEVICE_ATTR(state, S_IRUGO, nvme_sysfs_show_state, NULL);
|
|
|
|
static ssize_t nvme_sysfs_show_subsysnqn(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%s\n", ctrl->subsys->subnqn);
|
|
}
|
|
static DEVICE_ATTR(subsysnqn, S_IRUGO, nvme_sysfs_show_subsysnqn, NULL);
|
|
|
|
static ssize_t nvme_sysfs_show_hostnqn(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%s\n", ctrl->opts->host->nqn);
|
|
}
|
|
static DEVICE_ATTR(hostnqn, S_IRUGO, nvme_sysfs_show_hostnqn, NULL);
|
|
|
|
static ssize_t nvme_sysfs_show_hostid(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%pU\n", &ctrl->opts->host->id);
|
|
}
|
|
static DEVICE_ATTR(hostid, S_IRUGO, nvme_sysfs_show_hostid, NULL);
|
|
|
|
static ssize_t nvme_sysfs_show_address(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
return ctrl->ops->get_address(ctrl, buf, PAGE_SIZE);
|
|
}
|
|
static DEVICE_ATTR(address, S_IRUGO, nvme_sysfs_show_address, NULL);
|
|
|
|
static ssize_t nvme_ctrl_loss_tmo_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
|
|
if (ctrl->opts->max_reconnects == -1)
|
|
return sysfs_emit(buf, "off\n");
|
|
return sysfs_emit(buf, "%d\n",
|
|
opts->max_reconnects * opts->reconnect_delay);
|
|
}
|
|
|
|
static ssize_t nvme_ctrl_loss_tmo_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
int ctrl_loss_tmo, err;
|
|
|
|
err = kstrtoint(buf, 10, &ctrl_loss_tmo);
|
|
if (err)
|
|
return -EINVAL;
|
|
|
|
if (ctrl_loss_tmo < 0)
|
|
opts->max_reconnects = -1;
|
|
else
|
|
opts->max_reconnects = DIV_ROUND_UP(ctrl_loss_tmo,
|
|
opts->reconnect_delay);
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(ctrl_loss_tmo, S_IRUGO | S_IWUSR,
|
|
nvme_ctrl_loss_tmo_show, nvme_ctrl_loss_tmo_store);
|
|
|
|
static ssize_t nvme_ctrl_reconnect_delay_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
if (ctrl->opts->reconnect_delay == -1)
|
|
return sysfs_emit(buf, "off\n");
|
|
return sysfs_emit(buf, "%d\n", ctrl->opts->reconnect_delay);
|
|
}
|
|
|
|
static ssize_t nvme_ctrl_reconnect_delay_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
unsigned int v;
|
|
int err;
|
|
|
|
err = kstrtou32(buf, 10, &v);
|
|
if (err)
|
|
return err;
|
|
|
|
ctrl->opts->reconnect_delay = v;
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(reconnect_delay, S_IRUGO | S_IWUSR,
|
|
nvme_ctrl_reconnect_delay_show, nvme_ctrl_reconnect_delay_store);
|
|
|
|
static ssize_t nvme_ctrl_fast_io_fail_tmo_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
if (ctrl->opts->fast_io_fail_tmo == -1)
|
|
return sysfs_emit(buf, "off\n");
|
|
return sysfs_emit(buf, "%d\n", ctrl->opts->fast_io_fail_tmo);
|
|
}
|
|
|
|
static ssize_t nvme_ctrl_fast_io_fail_tmo_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
int fast_io_fail_tmo, err;
|
|
|
|
err = kstrtoint(buf, 10, &fast_io_fail_tmo);
|
|
if (err)
|
|
return -EINVAL;
|
|
|
|
if (fast_io_fail_tmo < 0)
|
|
opts->fast_io_fail_tmo = -1;
|
|
else
|
|
opts->fast_io_fail_tmo = fast_io_fail_tmo;
|
|
return count;
|
|
}
|
|
static DEVICE_ATTR(fast_io_fail_tmo, S_IRUGO | S_IWUSR,
|
|
nvme_ctrl_fast_io_fail_tmo_show, nvme_ctrl_fast_io_fail_tmo_store);
|
|
|
|
static ssize_t cntrltype_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
static const char * const type[] = {
|
|
[NVME_CTRL_IO] = "io\n",
|
|
[NVME_CTRL_DISC] = "discovery\n",
|
|
[NVME_CTRL_ADMIN] = "admin\n",
|
|
};
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
if (ctrl->cntrltype > NVME_CTRL_ADMIN || !type[ctrl->cntrltype])
|
|
return sysfs_emit(buf, "reserved\n");
|
|
|
|
return sysfs_emit(buf, type[ctrl->cntrltype]);
|
|
}
|
|
static DEVICE_ATTR_RO(cntrltype);
|
|
|
|
static ssize_t dctype_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
static const char * const type[] = {
|
|
[NVME_DCTYPE_NOT_REPORTED] = "none\n",
|
|
[NVME_DCTYPE_DDC] = "ddc\n",
|
|
[NVME_DCTYPE_CDC] = "cdc\n",
|
|
};
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
if (ctrl->dctype > NVME_DCTYPE_CDC || !type[ctrl->dctype])
|
|
return sysfs_emit(buf, "reserved\n");
|
|
|
|
return sysfs_emit(buf, type[ctrl->dctype]);
|
|
}
|
|
static DEVICE_ATTR_RO(dctype);
|
|
|
|
#ifdef CONFIG_NVME_AUTH
|
|
static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
|
|
if (!opts->dhchap_secret)
|
|
return sysfs_emit(buf, "none\n");
|
|
return sysfs_emit(buf, "%s\n", opts->dhchap_secret);
|
|
}
|
|
|
|
static ssize_t nvme_ctrl_dhchap_secret_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
char *dhchap_secret;
|
|
|
|
if (!ctrl->opts->dhchap_secret)
|
|
return -EINVAL;
|
|
if (count < 7)
|
|
return -EINVAL;
|
|
if (memcmp(buf, "DHHC-1:", 7))
|
|
return -EINVAL;
|
|
|
|
dhchap_secret = kzalloc(count + 1, GFP_KERNEL);
|
|
if (!dhchap_secret)
|
|
return -ENOMEM;
|
|
memcpy(dhchap_secret, buf, count);
|
|
nvme_auth_stop(ctrl);
|
|
if (strcmp(dhchap_secret, opts->dhchap_secret)) {
|
|
struct nvme_dhchap_key *key, *host_key;
|
|
int ret;
|
|
|
|
ret = nvme_auth_generate_key(dhchap_secret, &key);
|
|
if (ret) {
|
|
kfree(dhchap_secret);
|
|
return ret;
|
|
}
|
|
kfree(opts->dhchap_secret);
|
|
opts->dhchap_secret = dhchap_secret;
|
|
host_key = ctrl->host_key;
|
|
mutex_lock(&ctrl->dhchap_auth_mutex);
|
|
ctrl->host_key = key;
|
|
mutex_unlock(&ctrl->dhchap_auth_mutex);
|
|
nvme_auth_free_key(host_key);
|
|
} else
|
|
kfree(dhchap_secret);
|
|
/* Start re-authentication */
|
|
dev_info(ctrl->device, "re-authenticating controller\n");
|
|
queue_work(nvme_wq, &ctrl->dhchap_auth_work);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(dhchap_secret, S_IRUGO | S_IWUSR,
|
|
nvme_ctrl_dhchap_secret_show, nvme_ctrl_dhchap_secret_store);
|
|
|
|
static ssize_t nvme_ctrl_dhchap_ctrl_secret_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
|
|
if (!opts->dhchap_ctrl_secret)
|
|
return sysfs_emit(buf, "none\n");
|
|
return sysfs_emit(buf, "%s\n", opts->dhchap_ctrl_secret);
|
|
}
|
|
|
|
static ssize_t nvme_ctrl_dhchap_ctrl_secret_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
struct nvmf_ctrl_options *opts = ctrl->opts;
|
|
char *dhchap_secret;
|
|
|
|
if (!ctrl->opts->dhchap_ctrl_secret)
|
|
return -EINVAL;
|
|
if (count < 7)
|
|
return -EINVAL;
|
|
if (memcmp(buf, "DHHC-1:", 7))
|
|
return -EINVAL;
|
|
|
|
dhchap_secret = kzalloc(count + 1, GFP_KERNEL);
|
|
if (!dhchap_secret)
|
|
return -ENOMEM;
|
|
memcpy(dhchap_secret, buf, count);
|
|
nvme_auth_stop(ctrl);
|
|
if (strcmp(dhchap_secret, opts->dhchap_ctrl_secret)) {
|
|
struct nvme_dhchap_key *key, *ctrl_key;
|
|
int ret;
|
|
|
|
ret = nvme_auth_generate_key(dhchap_secret, &key);
|
|
if (ret) {
|
|
kfree(dhchap_secret);
|
|
return ret;
|
|
}
|
|
kfree(opts->dhchap_ctrl_secret);
|
|
opts->dhchap_ctrl_secret = dhchap_secret;
|
|
ctrl_key = ctrl->ctrl_key;
|
|
mutex_lock(&ctrl->dhchap_auth_mutex);
|
|
ctrl->ctrl_key = key;
|
|
mutex_unlock(&ctrl->dhchap_auth_mutex);
|
|
nvme_auth_free_key(ctrl_key);
|
|
} else
|
|
kfree(dhchap_secret);
|
|
/* Start re-authentication */
|
|
dev_info(ctrl->device, "re-authenticating controller\n");
|
|
queue_work(nvme_wq, &ctrl->dhchap_auth_work);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(dhchap_ctrl_secret, S_IRUGO | S_IWUSR,
|
|
nvme_ctrl_dhchap_ctrl_secret_show, nvme_ctrl_dhchap_ctrl_secret_store);
|
|
#endif
|
|
|
|
static struct attribute *nvme_dev_attrs[] = {
|
|
&dev_attr_reset_controller.attr,
|
|
&dev_attr_rescan_controller.attr,
|
|
&dev_attr_model.attr,
|
|
&dev_attr_serial.attr,
|
|
&dev_attr_firmware_rev.attr,
|
|
&dev_attr_cntlid.attr,
|
|
&dev_attr_delete_controller.attr,
|
|
&dev_attr_transport.attr,
|
|
&dev_attr_subsysnqn.attr,
|
|
&dev_attr_address.attr,
|
|
&dev_attr_state.attr,
|
|
&dev_attr_numa_node.attr,
|
|
&dev_attr_queue_count.attr,
|
|
&dev_attr_sqsize.attr,
|
|
&dev_attr_hostnqn.attr,
|
|
&dev_attr_hostid.attr,
|
|
&dev_attr_ctrl_loss_tmo.attr,
|
|
&dev_attr_reconnect_delay.attr,
|
|
&dev_attr_fast_io_fail_tmo.attr,
|
|
&dev_attr_kato.attr,
|
|
&dev_attr_cntrltype.attr,
|
|
&dev_attr_dctype.attr,
|
|
#ifdef CONFIG_NVME_AUTH
|
|
&dev_attr_dhchap_secret.attr,
|
|
&dev_attr_dhchap_ctrl_secret.attr,
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
|
|
struct attribute *a, int n)
|
|
{
|
|
struct device *dev = container_of(kobj, struct device, kobj);
|
|
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
|
|
|
if (a == &dev_attr_delete_controller.attr && !ctrl->ops->delete_ctrl)
|
|
return 0;
|
|
if (a == &dev_attr_address.attr && !ctrl->ops->get_address)
|
|
return 0;
|
|
if (a == &dev_attr_hostnqn.attr && !ctrl->opts)
|
|
return 0;
|
|
if (a == &dev_attr_hostid.attr && !ctrl->opts)
|
|
return 0;
|
|
if (a == &dev_attr_ctrl_loss_tmo.attr && !ctrl->opts)
|
|
return 0;
|
|
if (a == &dev_attr_reconnect_delay.attr && !ctrl->opts)
|
|
return 0;
|
|
if (a == &dev_attr_fast_io_fail_tmo.attr && !ctrl->opts)
|
|
return 0;
|
|
#ifdef CONFIG_NVME_AUTH
|
|
if (a == &dev_attr_dhchap_secret.attr && !ctrl->opts)
|
|
return 0;
|
|
if (a == &dev_attr_dhchap_ctrl_secret.attr && !ctrl->opts)
|
|
return 0;
|
|
#endif
|
|
|
|
return a->mode;
|
|
}
|
|
|
|
const struct attribute_group nvme_dev_attrs_group = {
|
|
.attrs = nvme_dev_attrs,
|
|
.is_visible = nvme_dev_attrs_are_visible,
|
|
};
|
|
EXPORT_SYMBOL_GPL(nvme_dev_attrs_group);
|
|
|
|
const struct attribute_group *nvme_dev_attr_groups[] = {
|
|
&nvme_dev_attrs_group,
|
|
NULL,
|
|
};
|
|
|
|
#define SUBSYS_ATTR_RO(_name, _mode, _show) \
|
|
struct device_attribute subsys_attr_##_name = \
|
|
__ATTR(_name, _mode, _show, NULL)
|
|
|
|
static ssize_t nvme_subsys_show_nqn(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_subsystem *subsys =
|
|
container_of(dev, struct nvme_subsystem, dev);
|
|
|
|
return sysfs_emit(buf, "%s\n", subsys->subnqn);
|
|
}
|
|
static SUBSYS_ATTR_RO(subsysnqn, S_IRUGO, nvme_subsys_show_nqn);
|
|
|
|
static ssize_t nvme_subsys_show_type(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct nvme_subsystem *subsys =
|
|
container_of(dev, struct nvme_subsystem, dev);
|
|
|
|
switch (subsys->subtype) {
|
|
case NVME_NQN_DISC:
|
|
return sysfs_emit(buf, "discovery\n");
|
|
case NVME_NQN_NVME:
|
|
return sysfs_emit(buf, "nvm\n");
|
|
default:
|
|
return sysfs_emit(buf, "reserved\n");
|
|
}
|
|
}
|
|
static SUBSYS_ATTR_RO(subsystype, S_IRUGO, nvme_subsys_show_type);
|
|
|
|
#define nvme_subsys_show_str_function(field) \
|
|
static ssize_t subsys_##field##_show(struct device *dev, \
|
|
struct device_attribute *attr, char *buf) \
|
|
{ \
|
|
struct nvme_subsystem *subsys = \
|
|
container_of(dev, struct nvme_subsystem, dev); \
|
|
return sysfs_emit(buf, "%.*s\n", \
|
|
(int)sizeof(subsys->field), subsys->field); \
|
|
} \
|
|
static SUBSYS_ATTR_RO(field, S_IRUGO, subsys_##field##_show);
|
|
|
|
nvme_subsys_show_str_function(model);
|
|
nvme_subsys_show_str_function(serial);
|
|
nvme_subsys_show_str_function(firmware_rev);
|
|
|
|
static struct attribute *nvme_subsys_attrs[] = {
|
|
&subsys_attr_model.attr,
|
|
&subsys_attr_serial.attr,
|
|
&subsys_attr_firmware_rev.attr,
|
|
&subsys_attr_subsysnqn.attr,
|
|
&subsys_attr_subsystype.attr,
|
|
#ifdef CONFIG_NVME_MULTIPATH
|
|
&subsys_attr_iopolicy.attr,
|
|
#endif
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group nvme_subsys_attrs_group = {
|
|
.attrs = nvme_subsys_attrs,
|
|
};
|
|
|
|
const struct attribute_group *nvme_subsys_attrs_groups[] = {
|
|
&nvme_subsys_attrs_group,
|
|
NULL,
|
|
};
|