Commit 68c5444c authored by Aleksandr Miloserdov's avatar Aleksandr Miloserdov Committed by Christoph Hellwig
Browse files

nvmet: expose firmware revision to configfs



Allow user to set currently active firmware revision

Reviewed-by: default avatarKonstantin Shelekhin <k.shelekhin@yadro.com>
Reviewed-by: default avatarDmitriy Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: default avatarAleksandr Miloserdov <a.miloserdov@yadro.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 23855abd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -370,7 +370,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
	memcpy_and_pad(id->mn, sizeof(id->mn), subsys->model_number,
		       strlen(subsys->model_number), ' ');
	memcpy_and_pad(id->fr, sizeof(id->fr),
		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
		       subsys->firmware_rev, strlen(subsys->firmware_rev), ' ');

	put_unaligned_le24(subsys->ieee_oui, id->ieee);

+63 −0
Original line number Diff line number Diff line
@@ -1307,6 +1307,68 @@ static ssize_t nvmet_subsys_attr_ieee_oui_store(struct config_item *item,
}
CONFIGFS_ATTR(nvmet_subsys_, attr_ieee_oui);

static ssize_t nvmet_subsys_attr_firmware_show(struct config_item *item,
					    char *page)
{
	struct nvmet_subsys *subsys = to_subsys(item);

	return sysfs_emit(page, "%s\n", subsys->firmware_rev);
}

static ssize_t nvmet_subsys_attr_firmware_store_locked(struct nvmet_subsys *subsys,
		const char *page, size_t count)
{
	int pos = 0, len;
	char *val;

	if (subsys->subsys_discovered) {
		pr_err("Can't set firmware revision. %s is already assigned\n",
		       subsys->firmware_rev);
		return -EINVAL;
	}

	len = strcspn(page, "\n");
	if (!len)
		return -EINVAL;

	if (len > NVMET_FR_MAX_SIZE) {
		pr_err("Firmware revision size can not exceed %d Bytes\n",
		       NVMET_FR_MAX_SIZE);
		return -EINVAL;
	}

	for (pos = 0; pos < len; pos++) {
		if (!nvmet_is_ascii(page[pos]))
			return -EINVAL;
	}

	val = kmemdup_nul(page, len, GFP_KERNEL);
	if (!val)
		return -ENOMEM;

	kfree(subsys->firmware_rev);

	subsys->firmware_rev = val;

	return count;
}

static ssize_t nvmet_subsys_attr_firmware_store(struct config_item *item,
					     const char *page, size_t count)
{
	struct nvmet_subsys *subsys = to_subsys(item);
	ssize_t ret;

	down_write(&nvmet_config_sem);
	mutex_lock(&subsys->lock);
	ret = nvmet_subsys_attr_firmware_store_locked(subsys, page, count);
	mutex_unlock(&subsys->lock);
	up_write(&nvmet_config_sem);

	return ret;
}
CONFIGFS_ATTR(nvmet_subsys_, attr_firmware);

#ifdef CONFIG_BLK_DEV_INTEGRITY
static ssize_t nvmet_subsys_attr_pi_enable_show(struct config_item *item,
						char *page)
@@ -1369,6 +1431,7 @@ static struct configfs_attribute *nvmet_subsys_attrs[] = {
	&nvmet_subsys_attr_attr_model,
	&nvmet_subsys_attr_attr_qid_max,
	&nvmet_subsys_attr_attr_ieee_oui,
	&nvmet_subsys_attr_attr_firmware,
#ifdef CONFIG_BLK_DEV_INTEGRITY
	&nvmet_subsys_attr_attr_pi_enable,
#endif
+13 −2
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@
#include <linux/pci-p2pdma.h>
#include <linux/scatterlist.h>

#include <generated/utsrelease.h>

#define CREATE_TRACE_POINTS
#include "trace.h"

@@ -1563,6 +1565,12 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,

	subsys->ieee_oui = 0;

	subsys->firmware_rev = kstrndup(UTS_RELEASE, NVMET_FR_MAX_SIZE, GFP_KERNEL);
	if (!subsys->firmware_rev) {
		ret = -ENOMEM;
		goto free_mn;
	}

	switch (type) {
	case NVME_NQN_NVME:
		subsys->max_qid = NVMET_NR_QUEUES;
@@ -1574,14 +1582,14 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
	default:
		pr_err("%s: Unknown Subsystem type - %d\n", __func__, type);
		ret = -EINVAL;
		goto free_mn;
		goto free_fr;
	}
	subsys->type = type;
	subsys->subsysnqn = kstrndup(subsysnqn, NVMF_NQN_SIZE,
			GFP_KERNEL);
	if (!subsys->subsysnqn) {
		ret = -ENOMEM;
		goto free_mn;
		goto free_fr;
	}
	subsys->cntlid_min = NVME_CNTLID_MIN;
	subsys->cntlid_max = NVME_CNTLID_MAX;
@@ -1594,6 +1602,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,

	return subsys;

free_fr:
	kfree(subsys->firmware_rev);
free_mn:
	kfree(subsys->model_number);
free_subsys:
@@ -1613,6 +1623,7 @@ static void nvmet_subsys_free(struct kref *ref)

	kfree(subsys->subsysnqn);
	kfree(subsys->model_number);
	kfree(subsys->firmware_rev);
	kfree(subsys);
}

+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#define NVMET_DEFAULT_CTRL_MODEL	"Linux"
#define NVMET_MN_MAX_SIZE		40
#define NVMET_SN_MAX_SIZE		20
#define NVMET_FR_MAX_SIZE		8

/*
 * Supported optional AENs:
@@ -264,6 +265,7 @@ struct nvmet_subsys {

	char			*model_number;
	u32			ieee_oui;
	char			*firmware_rev;

#ifdef CONFIG_NVME_TARGET_PASSTHRU
	struct nvme_ctrl	*passthru_ctrl;