|
@@ -22,6 +22,7 @@
|
|
|
#include <asm/ebcdic.h>
|
|
|
#include <asm/reset.h>
|
|
|
#include <asm/sclp.h>
|
|
|
+#include <asm/setup.h>
|
|
|
|
|
|
#define IPL_PARM_BLOCK_VERSION 0
|
|
|
|
|
@@ -121,6 +122,7 @@ enum ipl_method {
|
|
|
REIPL_METHOD_FCP_RO_VM,
|
|
|
REIPL_METHOD_FCP_DUMP,
|
|
|
REIPL_METHOD_NSS,
|
|
|
+ REIPL_METHOD_NSS_DIAG,
|
|
|
REIPL_METHOD_DEFAULT,
|
|
|
};
|
|
|
|
|
@@ -134,14 +136,15 @@ enum dump_method {
|
|
|
|
|
|
static int diag308_set_works = 0;
|
|
|
|
|
|
+static struct ipl_parameter_block ipl_block;
|
|
|
+
|
|
|
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
|
|
|
|
|
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
|
|
static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
|
|
|
static struct ipl_parameter_block *reipl_block_fcp;
|
|
|
static struct ipl_parameter_block *reipl_block_ccw;
|
|
|
-
|
|
|
-static char reipl_nss_name[NSS_NAME_SIZE + 1];
|
|
|
+static struct ipl_parameter_block *reipl_block_nss;
|
|
|
|
|
|
static int dump_capabilities = DUMP_TYPE_NONE;
|
|
|
static enum dump_type dump_type = DUMP_TYPE_NONE;
|
|
@@ -263,6 +266,56 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
|
|
|
static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
|
|
|
|
|
|
+/* VM IPL PARM routines */
|
|
|
+static void reipl_get_ascii_vmparm(char *dest,
|
|
|
+ const struct ipl_parameter_block *ipb)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int len = 0;
|
|
|
+ char has_lowercase = 0;
|
|
|
+
|
|
|
+ if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
|
|
|
+ (ipb->ipl_info.ccw.vm_parm_len > 0)) {
|
|
|
+
|
|
|
+ len = ipb->ipl_info.ccw.vm_parm_len;
|
|
|
+ memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
|
|
|
+ /* If at least one character is lowercase, we assume mixed
|
|
|
+ * case; otherwise we convert everything to lowercase.
|
|
|
+ */
|
|
|
+ for (i = 0; i < len; i++)
|
|
|
+ if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
|
|
|
+ (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
|
|
|
+ (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
|
|
|
+ has_lowercase = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!has_lowercase)
|
|
|
+ EBC_TOLOWER(dest, len);
|
|
|
+ EBCASC(dest, len);
|
|
|
+ }
|
|
|
+ dest[len] = 0;
|
|
|
+}
|
|
|
+
|
|
|
+void get_ipl_vmparm(char *dest)
|
|
|
+{
|
|
|
+ if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
|
|
|
+ reipl_get_ascii_vmparm(dest, &ipl_block);
|
|
|
+ else
|
|
|
+ dest[0] = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ipl_vm_parm_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ char parm[DIAG308_VMPARM_SIZE + 1] = {};
|
|
|
+
|
|
|
+ get_ipl_vmparm(parm);
|
|
|
+ return sprintf(page, "%s\n", parm);
|
|
|
+}
|
|
|
+
|
|
|
+static struct kobj_attribute sys_ipl_vm_parm_attr =
|
|
|
+ __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
|
|
|
+
|
|
|
static ssize_t sys_ipl_device_show(struct kobject *kobj,
|
|
|
struct kobj_attribute *attr, char *page)
|
|
|
{
|
|
@@ -370,15 +423,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
|
|
|
static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
|
|
|
__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
|
|
|
|
|
|
-static struct attribute *ipl_ccw_attrs[] = {
|
|
|
+static struct attribute *ipl_ccw_attrs_vm[] = {
|
|
|
+ &sys_ipl_type_attr.attr,
|
|
|
+ &sys_ipl_device_attr.attr,
|
|
|
+ &sys_ipl_ccw_loadparm_attr.attr,
|
|
|
+ &sys_ipl_vm_parm_attr.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute *ipl_ccw_attrs_lpar[] = {
|
|
|
&sys_ipl_type_attr.attr,
|
|
|
&sys_ipl_device_attr.attr,
|
|
|
&sys_ipl_ccw_loadparm_attr.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
|
-static struct attribute_group ipl_ccw_attr_group = {
|
|
|
- .attrs = ipl_ccw_attrs,
|
|
|
+static struct attribute_group ipl_ccw_attr_group_vm = {
|
|
|
+ .attrs = ipl_ccw_attrs_vm,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group ipl_ccw_attr_group_lpar = {
|
|
|
+ .attrs = ipl_ccw_attrs_lpar
|
|
|
};
|
|
|
|
|
|
/* NSS ipl device attributes */
|
|
@@ -388,6 +453,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
|
|
|
static struct attribute *ipl_nss_attrs[] = {
|
|
|
&sys_ipl_type_attr.attr,
|
|
|
&sys_ipl_nss_name_attr.attr,
|
|
|
+ &sys_ipl_ccw_loadparm_attr.attr,
|
|
|
+ &sys_ipl_vm_parm_attr.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
@@ -450,7 +517,12 @@ static int __init ipl_init(void)
|
|
|
}
|
|
|
switch (ipl_info.type) {
|
|
|
case IPL_TYPE_CCW:
|
|
|
- rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
|
|
|
+ if (MACHINE_IS_VM)
|
|
|
+ rc = sysfs_create_group(&ipl_kset->kobj,
|
|
|
+ &ipl_ccw_attr_group_vm);
|
|
|
+ else
|
|
|
+ rc = sysfs_create_group(&ipl_kset->kobj,
|
|
|
+ &ipl_ccw_attr_group_lpar);
|
|
|
break;
|
|
|
case IPL_TYPE_FCP:
|
|
|
case IPL_TYPE_FCP_DUMP:
|
|
@@ -481,6 +553,83 @@ static struct shutdown_action __refdata ipl_action = {
|
|
|
* reipl shutdown action: Reboot Linux on shutdown.
|
|
|
*/
|
|
|
|
|
|
+/* VM IPL PARM attributes */
|
|
|
+static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
|
|
|
+ char *page)
|
|
|
+{
|
|
|
+ char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
|
|
|
+
|
|
|
+ reipl_get_ascii_vmparm(vmparm, ipb);
|
|
|
+ return sprintf(page, "%s\n", vmparm);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
|
|
|
+ size_t vmparm_max,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ int i, ip_len;
|
|
|
+
|
|
|
+ /* ignore trailing newline */
|
|
|
+ ip_len = len;
|
|
|
+ if ((len > 0) && (buf[len - 1] == '\n'))
|
|
|
+ ip_len--;
|
|
|
+
|
|
|
+ if (ip_len > vmparm_max)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* parm is used to store kernel options, check for common chars */
|
|
|
+ for (i = 0; i < ip_len; i++)
|
|
|
+ if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
|
|
|
+ ipb->ipl_info.ccw.vm_parm_len = ip_len;
|
|
|
+ if (ip_len > 0) {
|
|
|
+ ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
|
|
|
+ memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len);
|
|
|
+ ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len);
|
|
|
+ } else {
|
|
|
+ ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID;
|
|
|
+ }
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+/* NSS wrapper */
|
|
|
+static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ return reipl_generic_vmparm_show(reipl_block_nss, page);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+/* CCW wrapper */
|
|
|
+static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ return reipl_generic_vmparm_show(reipl_block_ccw, page);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+static struct kobj_attribute sys_reipl_nss_vmparm_attr =
|
|
|
+ __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
|
|
|
+ reipl_nss_vmparm_store);
|
|
|
+static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
|
|
|
+ __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
|
|
|
+ reipl_ccw_vmparm_store);
|
|
|
+
|
|
|
/* FCP reipl device attributes */
|
|
|
|
|
|
DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
|
|
@@ -513,27 +662,26 @@ static struct attribute_group reipl_fcp_attr_group = {
|
|
|
DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
|
|
|
reipl_block_ccw->ipl_info.ccw.devno);
|
|
|
|
|
|
-static void reipl_get_ascii_loadparm(char *loadparm)
|
|
|
+static void reipl_get_ascii_loadparm(char *loadparm,
|
|
|
+ struct ipl_parameter_block *ibp)
|
|
|
{
|
|
|
- memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
|
|
|
- LOADPARM_LEN);
|
|
|
+ memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN);
|
|
|
EBCASC(loadparm, LOADPARM_LEN);
|
|
|
loadparm[LOADPARM_LEN] = 0;
|
|
|
strstrip(loadparm);
|
|
|
}
|
|
|
|
|
|
-static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
|
|
|
- struct kobj_attribute *attr, char *page)
|
|
|
+static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
|
|
|
+ char *page)
|
|
|
{
|
|
|
char buf[LOADPARM_LEN + 1];
|
|
|
|
|
|
- reipl_get_ascii_loadparm(buf);
|
|
|
+ reipl_get_ascii_loadparm(buf, ipb);
|
|
|
return sprintf(page, "%s\n", buf);
|
|
|
}
|
|
|
|
|
|
-static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
|
|
|
- struct kobj_attribute *attr,
|
|
|
- const char *buf, size_t len)
|
|
|
+static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
|
|
|
+ const char *buf, size_t len)
|
|
|
{
|
|
|
int i, lp_len;
|
|
|
|
|
@@ -552,35 +700,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
/* initialize loadparm with blanks */
|
|
|
- memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
|
|
|
+ memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN);
|
|
|
/* copy and convert to ebcdic */
|
|
|
- memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
|
|
|
- ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
|
|
|
+ memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len);
|
|
|
+ ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN);
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
+/* NSS wrapper */
|
|
|
+static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ return reipl_generic_loadparm_show(reipl_block_nss, page);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_nss_loadparm_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return reipl_generic_loadparm_store(reipl_block_nss, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+/* CCW wrapper */
|
|
|
+static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ return reipl_generic_loadparm_show(reipl_block_ccw, page);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return reipl_generic_loadparm_store(reipl_block_ccw, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
|
|
|
- __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
|
|
|
- reipl_ccw_loadparm_store);
|
|
|
+ __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
|
|
|
+ reipl_ccw_loadparm_store);
|
|
|
+
|
|
|
+static struct attribute *reipl_ccw_attrs_vm[] = {
|
|
|
+ &sys_reipl_ccw_device_attr.attr,
|
|
|
+ &sys_reipl_ccw_loadparm_attr.attr,
|
|
|
+ &sys_reipl_ccw_vmparm_attr.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
|
|
|
-static struct attribute *reipl_ccw_attrs[] = {
|
|
|
+static struct attribute *reipl_ccw_attrs_lpar[] = {
|
|
|
&sys_reipl_ccw_device_attr.attr,
|
|
|
&sys_reipl_ccw_loadparm_attr.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
|
-static struct attribute_group reipl_ccw_attr_group = {
|
|
|
+static struct attribute_group reipl_ccw_attr_group_vm = {
|
|
|
.name = IPL_CCW_STR,
|
|
|
- .attrs = reipl_ccw_attrs,
|
|
|
+ .attrs = reipl_ccw_attrs_vm,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group reipl_ccw_attr_group_lpar = {
|
|
|
+ .name = IPL_CCW_STR,
|
|
|
+ .attrs = reipl_ccw_attrs_lpar,
|
|
|
};
|
|
|
|
|
|
|
|
|
/* NSS reipl device attributes */
|
|
|
+static void reipl_get_ascii_nss_name(char *dst,
|
|
|
+ struct ipl_parameter_block *ipb)
|
|
|
+{
|
|
|
+ memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
|
|
|
+ EBCASC(dst, NSS_NAME_SIZE);
|
|
|
+ dst[NSS_NAME_SIZE] = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_nss_name_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *page)
|
|
|
+{
|
|
|
+ char nss_name[NSS_NAME_SIZE + 1] = {};
|
|
|
+
|
|
|
+ reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
|
|
|
+ return sprintf(page, "%s\n", nss_name);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t reipl_nss_name_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
+{
|
|
|
+ int nss_len;
|
|
|
+
|
|
|
+ /* ignore trailing newline */
|
|
|
+ nss_len = len;
|
|
|
+ if ((len > 0) && (buf[len - 1] == '\n'))
|
|
|
+ nss_len--;
|
|
|
|
|
|
-DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
|
|
|
+ if (nss_len > NSS_NAME_SIZE)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE);
|
|
|
+ if (nss_len > 0) {
|
|
|
+ reipl_block_nss->ipl_info.ccw.vm_flags |=
|
|
|
+ DIAG308_VM_FLAGS_NSS_VALID;
|
|
|
+ memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len);
|
|
|
+ ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
|
|
|
+ EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
|
|
|
+ } else {
|
|
|
+ reipl_block_nss->ipl_info.ccw.vm_flags &=
|
|
|
+ ~DIAG308_VM_FLAGS_NSS_VALID;
|
|
|
+ }
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static struct kobj_attribute sys_reipl_nss_name_attr =
|
|
|
+ __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
|
|
|
+ reipl_nss_name_store);
|
|
|
+
|
|
|
+static struct kobj_attribute sys_reipl_nss_loadparm_attr =
|
|
|
+ __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
|
|
|
+ reipl_nss_loadparm_store);
|
|
|
|
|
|
static struct attribute *reipl_nss_attrs[] = {
|
|
|
&sys_reipl_nss_name_attr.attr,
|
|
|
+ &sys_reipl_nss_loadparm_attr.attr,
|
|
|
+ &sys_reipl_nss_vmparm_attr.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
@@ -617,7 +858,10 @@ static int reipl_set_type(enum ipl_type type)
|
|
|
reipl_method = REIPL_METHOD_FCP_DUMP;
|
|
|
break;
|
|
|
case IPL_TYPE_NSS:
|
|
|
- reipl_method = REIPL_METHOD_NSS;
|
|
|
+ if (diag308_set_works)
|
|
|
+ reipl_method = REIPL_METHOD_NSS_DIAG;
|
|
|
+ else
|
|
|
+ reipl_method = REIPL_METHOD_NSS;
|
|
|
break;
|
|
|
case IPL_TYPE_UNKNOWN:
|
|
|
reipl_method = REIPL_METHOD_DEFAULT;
|
|
@@ -655,11 +899,38 @@ static struct kobj_attribute reipl_type_attr =
|
|
|
|
|
|
static struct kset *reipl_kset;
|
|
|
|
|
|
+static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
|
|
|
+ const enum ipl_method m)
|
|
|
+{
|
|
|
+ char loadparm[LOADPARM_LEN + 1] = {};
|
|
|
+ char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
|
|
|
+ char nss_name[NSS_NAME_SIZE + 1] = {};
|
|
|
+ size_t pos = 0;
|
|
|
+
|
|
|
+ reipl_get_ascii_loadparm(loadparm, ipb);
|
|
|
+ reipl_get_ascii_nss_name(nss_name, ipb);
|
|
|
+ reipl_get_ascii_vmparm(vmparm, ipb);
|
|
|
+
|
|
|
+ switch (m) {
|
|
|
+ case REIPL_METHOD_CCW_VM:
|
|
|
+ pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno);
|
|
|
+ break;
|
|
|
+ case REIPL_METHOD_NSS:
|
|
|
+ pos = sprintf(dst, "IPL %s", nss_name);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (strlen(loadparm) > 0)
|
|
|
+ pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm);
|
|
|
+ if (strlen(vmparm) > 0)
|
|
|
+ sprintf(dst + pos, " PARM %s", vmparm);
|
|
|
+}
|
|
|
+
|
|
|
static void reipl_run(struct shutdown_trigger *trigger)
|
|
|
{
|
|
|
struct ccw_dev_id devid;
|
|
|
- static char buf[100];
|
|
|
- char loadparm[LOADPARM_LEN + 1];
|
|
|
+ static char buf[128];
|
|
|
|
|
|
switch (reipl_method) {
|
|
|
case REIPL_METHOD_CCW_CIO:
|
|
@@ -668,13 +939,7 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
|
|
reipl_ccw_dev(&devid);
|
|
|
break;
|
|
|
case REIPL_METHOD_CCW_VM:
|
|
|
- reipl_get_ascii_loadparm(loadparm);
|
|
|
- if (strlen(loadparm) == 0)
|
|
|
- sprintf(buf, "IPL %X CLEAR",
|
|
|
- reipl_block_ccw->ipl_info.ccw.devno);
|
|
|
- else
|
|
|
- sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
|
|
|
- reipl_block_ccw->ipl_info.ccw.devno, loadparm);
|
|
|
+ get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM);
|
|
|
__cpcmd(buf, NULL, 0, NULL);
|
|
|
break;
|
|
|
case REIPL_METHOD_CCW_DIAG:
|
|
@@ -691,8 +956,12 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
|
|
case REIPL_METHOD_FCP_RO_VM:
|
|
|
__cpcmd("IPL", NULL, 0, NULL);
|
|
|
break;
|
|
|
+ case REIPL_METHOD_NSS_DIAG:
|
|
|
+ diag308(DIAG308_SET, reipl_block_nss);
|
|
|
+ diag308(DIAG308_IPL, NULL);
|
|
|
+ break;
|
|
|
case REIPL_METHOD_NSS:
|
|
|
- sprintf(buf, "IPL %s", reipl_nss_name);
|
|
|
+ get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS);
|
|
|
__cpcmd(buf, NULL, 0, NULL);
|
|
|
break;
|
|
|
case REIPL_METHOD_DEFAULT:
|
|
@@ -707,16 +976,36 @@ static void reipl_run(struct shutdown_trigger *trigger)
|
|
|
disabled_wait((unsigned long) __builtin_return_address(0));
|
|
|
}
|
|
|
|
|
|
-static void __init reipl_probe(void)
|
|
|
+static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
|
|
|
{
|
|
|
- void *buffer;
|
|
|
+ ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
|
|
|
+ ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
|
|
|
+ ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
|
|
|
+ ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW;
|
|
|
+}
|
|
|
|
|
|
- buffer = (void *) get_zeroed_page(GFP_KERNEL);
|
|
|
- if (!buffer)
|
|
|
- return;
|
|
|
- if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
|
|
|
- diag308_set_works = 1;
|
|
|
- free_page((unsigned long)buffer);
|
|
|
+static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
|
|
|
+{
|
|
|
+ /* LOADPARM */
|
|
|
+ /* check if read scp info worked and set loadparm */
|
|
|
+ if (sclp_ipl_info.is_valid)
|
|
|
+ memcpy(ipb->ipl_info.ccw.load_parm,
|
|
|
+ &sclp_ipl_info.loadparm, LOADPARM_LEN);
|
|
|
+ else
|
|
|
+ /* read scp info failed: set empty loadparm (EBCDIC blanks) */
|
|
|
+ memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN);
|
|
|
+ ipb->hdr.flags = DIAG308_FLAGS_LP_VALID;
|
|
|
+
|
|
|
+ /* VM PARM */
|
|
|
+ if (MACHINE_IS_VM && diag308_set_works &&
|
|
|
+ (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) {
|
|
|
+
|
|
|
+ ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
|
|
|
+ ipb->ipl_info.ccw.vm_parm_len =
|
|
|
+ ipl_block.ipl_info.ccw.vm_parm_len;
|
|
|
+ memcpy(ipb->ipl_info.ccw.vm_parm,
|
|
|
+ ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int __init reipl_nss_init(void)
|
|
@@ -725,10 +1014,31 @@ static int __init reipl_nss_init(void)
|
|
|
|
|
|
if (!MACHINE_IS_VM)
|
|
|
return 0;
|
|
|
+
|
|
|
+ reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
|
|
|
+ if (!reipl_block_nss)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (!diag308_set_works)
|
|
|
+ sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO;
|
|
|
+
|
|
|
rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
- strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
|
|
|
+
|
|
|
+ reipl_block_ccw_init(reipl_block_nss);
|
|
|
+ if (ipl_info.type == IPL_TYPE_NSS) {
|
|
|
+ memset(reipl_block_nss->ipl_info.ccw.nss_name,
|
|
|
+ ' ', NSS_NAME_SIZE);
|
|
|
+ memcpy(reipl_block_nss->ipl_info.ccw.nss_name,
|
|
|
+ kernel_nss_name, strlen(kernel_nss_name));
|
|
|
+ ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
|
|
|
+ reipl_block_nss->ipl_info.ccw.vm_flags |=
|
|
|
+ DIAG308_VM_FLAGS_NSS_VALID;
|
|
|
+
|
|
|
+ reipl_block_ccw_fill_parms(reipl_block_nss);
|
|
|
+ }
|
|
|
+
|
|
|
reipl_capabilities |= IPL_TYPE_NSS;
|
|
|
return 0;
|
|
|
}
|
|
@@ -740,28 +1050,27 @@ static int __init reipl_ccw_init(void)
|
|
|
reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
|
|
|
if (!reipl_block_ccw)
|
|
|
return -ENOMEM;
|
|
|
- rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
|
|
|
- if (rc) {
|
|
|
- free_page((unsigned long)reipl_block_ccw);
|
|
|
- return rc;
|
|
|
+
|
|
|
+ if (MACHINE_IS_VM) {
|
|
|
+ if (!diag308_set_works)
|
|
|
+ sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO;
|
|
|
+ rc = sysfs_create_group(&reipl_kset->kobj,
|
|
|
+ &reipl_ccw_attr_group_vm);
|
|
|
+ } else {
|
|
|
+ if(!diag308_set_works)
|
|
|
+ sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
|
|
|
+ rc = sysfs_create_group(&reipl_kset->kobj,
|
|
|
+ &reipl_ccw_attr_group_lpar);
|
|
|
}
|
|
|
- reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
|
|
|
- reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
|
|
|
- reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
|
|
|
- reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
|
|
|
- reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
|
|
|
- /* check if read scp info worked and set loadparm */
|
|
|
- if (sclp_ipl_info.is_valid)
|
|
|
- memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
|
|
|
- &sclp_ipl_info.loadparm, LOADPARM_LEN);
|
|
|
- else
|
|
|
- /* read scp info failed: set empty loadparm (EBCDIC blanks) */
|
|
|
- memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
|
|
|
- LOADPARM_LEN);
|
|
|
- if (!MACHINE_IS_VM && !diag308_set_works)
|
|
|
- sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
|
|
|
- if (ipl_info.type == IPL_TYPE_CCW)
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ reipl_block_ccw_init(reipl_block_ccw);
|
|
|
+ if (ipl_info.type == IPL_TYPE_CCW) {
|
|
|
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
|
|
|
+ reipl_block_ccw_fill_parms(reipl_block_ccw);
|
|
|
+ }
|
|
|
+
|
|
|
reipl_capabilities |= IPL_TYPE_CCW;
|
|
|
return 0;
|
|
|
}
|
|
@@ -1298,7 +1607,6 @@ static void __init shutdown_actions_init(void)
|
|
|
|
|
|
static int __init s390_ipl_init(void)
|
|
|
{
|
|
|
- reipl_probe();
|
|
|
sclp_get_ipl_info(&sclp_ipl_info);
|
|
|
shutdown_actions_init();
|
|
|
shutdown_triggers_init();
|
|
@@ -1405,6 +1713,12 @@ void __init setup_ipl(void)
|
|
|
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
|
|
|
}
|
|
|
|
|
|
+void __init ipl_update_parameters(void)
|
|
|
+{
|
|
|
+ if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK)
|
|
|
+ diag308_set_works = 1;
|
|
|
+}
|
|
|
+
|
|
|
void __init ipl_save_parameters(void)
|
|
|
{
|
|
|
struct cio_iplinfo iplinfo;
|