Commit 23a457b8 authored by Jason J. Herne's avatar Jason J. Herne Committed by Vasily Gorbik

s390: nvme reipl

Populate sysfs and structs with reipl entries for nvme ipl type.
This allows specifying a target nvme device when rebooting/reipling.
Signed-off-by: default avatarJason J. Herne <jjherne@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 3737e8ee
......@@ -136,6 +136,7 @@ static int reipl_capabilities = IPL_TYPE_UNKNOWN;
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
static struct ipl_parameter_block *reipl_block_fcp;
static struct ipl_parameter_block *reipl_block_nvme;
static struct ipl_parameter_block *reipl_block_ccw;
static struct ipl_parameter_block *reipl_block_nss;
static struct ipl_parameter_block *reipl_block_actual;
......@@ -785,6 +786,93 @@ static struct attribute_group reipl_fcp_attr_group = {
static struct kobj_attribute sys_reipl_fcp_clear_attr =
__ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store);
/* NVME reipl device attributes */
static ssize_t reipl_nvme_scpdata_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t size = reipl_block_nvme->nvme.scp_data_len;
void *scp_data = reipl_block_nvme->nvme.scp_data;
return memory_read_from_buffer(buf, count, &off, scp_data, size);
}
static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t scpdata_len = count;
size_t padding;
if (off)
return -EINVAL;
memcpy(reipl_block_nvme->nvme.scp_data, buf, count);
if (scpdata_len % 8) {
padding = 8 - (scpdata_len % 8);
memset(reipl_block_nvme->nvme.scp_data + scpdata_len,
0, padding);
scpdata_len += padding;
}
reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len;
reipl_block_nvme->nvme.scp_data_len = scpdata_len;
return count;
}
static struct bin_attribute sys_reipl_nvme_scp_data_attr =
__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_nvme_scpdata_read,
reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_nvme_bin_attrs[] = {
&sys_reipl_nvme_scp_data_attr,
NULL,
};
DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n",
reipl_block_nvme->nvme.fid);
DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n",
reipl_block_nvme->nvme.nsid);
DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
reipl_block_nvme->nvme.bootprog);
DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n",
reipl_block_nvme->nvme.br_lba);
/* nvme wrapper */
static ssize_t reipl_nvme_loadparm_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
return reipl_generic_loadparm_show(reipl_block_nvme, page);
}
static ssize_t reipl_nvme_loadparm_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
return reipl_generic_loadparm_store(reipl_block_nvme, buf, len);
}
static struct kobj_attribute sys_reipl_nvme_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nvme_loadparm_show,
reipl_nvme_loadparm_store);
static struct attribute *reipl_nvme_attrs[] = {
&sys_reipl_nvme_fid_attr.attr,
&sys_reipl_nvme_nsid_attr.attr,
&sys_reipl_nvme_bootprog_attr.attr,
&sys_reipl_nvme_br_lba_attr.attr,
&sys_reipl_nvme_loadparm_attr.attr,
NULL,
};
static struct attribute_group reipl_nvme_attr_group = {
.attrs = reipl_nvme_attrs,
.bin_attrs = reipl_nvme_bin_attrs
};
/* CCW reipl device attributes */
DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
......@@ -949,6 +1037,9 @@ static int reipl_set_type(enum ipl_type type)
case IPL_TYPE_FCP:
reipl_block_actual = reipl_block_fcp;
break;
case IPL_TYPE_NVME:
reipl_block_actual = reipl_block_nvme;
break;
case IPL_TYPE_NSS:
reipl_block_actual = reipl_block_nss;
break;
......@@ -975,6 +1066,8 @@ static ssize_t reipl_type_store(struct kobject *kobj,
rc = reipl_set_type(IPL_TYPE_CCW);
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_FCP);
else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_NVME);
else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_NSS);
return (rc != 0) ? rc : len;
......@@ -985,6 +1078,7 @@ static struct kobj_attribute reipl_type_attr =
static struct kset *reipl_kset;
static struct kset *reipl_fcp_kset;
static struct kset *reipl_nvme_kset;
static void __reipl_run(void *unused)
{
......@@ -1003,11 +1097,14 @@ static void __reipl_run(void *unused)
else
diag308(DIAG308_LOAD_NORMAL, NULL);
break;
case IPL_TYPE_NVME:
diag308(DIAG308_SET, reipl_block_nvme);
diag308(DIAG308_LOAD_CLEAR, NULL);
break;
case IPL_TYPE_NSS:
diag308(DIAG308_SET, reipl_block_nss);
diag308(DIAG308_LOAD_CLEAR, NULL);
break;
case IPL_TYPE_NVME:
case IPL_TYPE_UNKNOWN:
diag308(DIAG308_LOAD_CLEAR, NULL);
break;
......@@ -1152,6 +1249,49 @@ static int __init reipl_fcp_init(void)
return rc;
}
static int __init reipl_nvme_init(void)
{
int rc;
reipl_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_nvme)
return -ENOMEM;
/* sysfs: create kset for mixing attr group and bin attrs */
reipl_nvme_kset = kset_create_and_add(IPL_NVME_STR, NULL,
&reipl_kset->kobj);
if (!reipl_nvme_kset) {
free_page((unsigned long) reipl_block_nvme);
return -ENOMEM;
}
rc = sysfs_create_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
if (rc) {
kset_unregister(reipl_nvme_kset);
free_page((unsigned long) reipl_block_nvme);
return rc;
}
if (ipl_info.type == IPL_TYPE_NVME) {
memcpy(reipl_block_nvme, &ipl_block, sizeof(ipl_block));
/*
* Fix loadparm: There are systems where the (SCSI) LOADPARM
* is invalid in the IPL parameter block, so take it
* always from sclp_ipl_info.
*/
memcpy(reipl_block_nvme->nvme.loadparm, sclp_ipl_info.loadparm,
LOADPARM_LEN);
} else {
reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN;
reipl_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
reipl_block_nvme->nvme.pbt = IPL_PBT_NVME;
reipl_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_IPL;
}
reipl_capabilities |= IPL_TYPE_NVME;
return 0;
}
static int __init reipl_type_init(void)
{
enum ipl_type reipl_type = ipl_info.type;
......@@ -1167,6 +1307,9 @@ static int __init reipl_type_init(void)
if (reipl_block->pb0_hdr.pbt == IPL_PBT_FCP) {
memcpy(reipl_block_fcp, reipl_block, size);
reipl_type = IPL_TYPE_FCP;
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_NVME) {
memcpy(reipl_block_nvme, reipl_block, size);
reipl_type = IPL_TYPE_NVME;
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
memcpy(reipl_block_ccw, reipl_block, size);
reipl_type = IPL_TYPE_CCW;
......@@ -1191,6 +1334,9 @@ static int __init reipl_init(void)
if (rc)
return rc;
rc = reipl_fcp_init();
if (rc)
return rc;
rc = reipl_nvme_init();
if (rc)
return rc;
rc = reipl_nss_init();
......
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