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

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
......@@ -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);
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment