mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 17:30:53 +07:00
s390: add support for ipl devices in subchannel sets > 0
Allow to ipl from CCW based devices residing in any subchannel set. Reviewed-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
e0bedada3a
commit
18e22a1772
@ -312,6 +312,7 @@ extern void css_schedule_reprobe(void);
|
|||||||
extern void reipl_ccw_dev(struct ccw_dev_id *id);
|
extern void reipl_ccw_dev(struct ccw_dev_id *id);
|
||||||
|
|
||||||
struct cio_iplinfo {
|
struct cio_iplinfo {
|
||||||
|
u8 ssid;
|
||||||
u16 devno;
|
u16 devno;
|
||||||
int is_qdio;
|
int is_qdio;
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,8 @@ struct ipl_block_fcp {
|
|||||||
|
|
||||||
struct ipl_block_ccw {
|
struct ipl_block_ccw {
|
||||||
u8 reserved1[84];
|
u8 reserved1[84];
|
||||||
u8 reserved2[2];
|
u16 reserved2 : 13;
|
||||||
|
u8 ssid : 3;
|
||||||
u16 devno;
|
u16 devno;
|
||||||
u8 vm_flags;
|
u8 vm_flags;
|
||||||
u8 reserved3[3];
|
u8 reserved3[3];
|
||||||
|
@ -121,6 +121,7 @@ static char *dump_type_str(enum dump_type type)
|
|||||||
* Must be in data section since the bss section
|
* Must be in data section since the bss section
|
||||||
* is not cleared when these are accessed.
|
* is not cleared when these are accessed.
|
||||||
*/
|
*/
|
||||||
|
static u8 ipl_ssid __attribute__((__section__(".data"))) = 0;
|
||||||
static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
|
static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
|
||||||
u32 ipl_flags __attribute__((__section__(".data"))) = 0;
|
u32 ipl_flags __attribute__((__section__(".data"))) = 0;
|
||||||
|
|
||||||
@ -197,6 +198,33 @@ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
|
|||||||
return snprintf(page, PAGE_SIZE, _format, ##args); \
|
return snprintf(page, PAGE_SIZE, _format, ##args); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk) \
|
||||||
|
static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
|
||||||
|
struct kobj_attribute *attr, \
|
||||||
|
const char *buf, size_t len) \
|
||||||
|
{ \
|
||||||
|
unsigned long long ssid, devno; \
|
||||||
|
\
|
||||||
|
if (sscanf(buf, "0.%llx.%llx\n", &ssid, &devno) != 2) \
|
||||||
|
return -EINVAL; \
|
||||||
|
\
|
||||||
|
if (ssid > __MAX_SSID || devno > __MAX_SUBCHANNEL) \
|
||||||
|
return -EINVAL; \
|
||||||
|
\
|
||||||
|
_ipl_blk.ssid = ssid; \
|
||||||
|
_ipl_blk.devno = devno; \
|
||||||
|
return len; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_IPL_CCW_ATTR_RW(_prefix, _name, _ipl_blk) \
|
||||||
|
IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n", \
|
||||||
|
_ipl_blk.ssid, _ipl_blk.devno); \
|
||||||
|
IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk); \
|
||||||
|
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
|
||||||
|
__ATTR(_name, (S_IRUGO | S_IWUSR), \
|
||||||
|
sys_##_prefix##_##_name##_show, \
|
||||||
|
sys_##_prefix##_##_name##_store) \
|
||||||
|
|
||||||
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
|
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
|
||||||
IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
|
IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
|
||||||
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
|
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
|
||||||
@ -395,7 +423,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
|
|||||||
|
|
||||||
switch (ipl_info.type) {
|
switch (ipl_info.type) {
|
||||||
case IPL_TYPE_CCW:
|
case IPL_TYPE_CCW:
|
||||||
return sprintf(page, "0.0.%04x\n", ipl_devno);
|
return sprintf(page, "0.%x.%04x\n", ipl_ssid, ipl_devno);
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
case IPL_TYPE_FCP_DUMP:
|
case IPL_TYPE_FCP_DUMP:
|
||||||
return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
|
return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
|
||||||
@ -807,9 +835,7 @@ static struct attribute_group reipl_fcp_attr_group = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* CCW reipl device attributes */
|
/* CCW reipl device attributes */
|
||||||
|
DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ipl_info.ccw);
|
||||||
DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
|
|
||||||
reipl_block_ccw->ipl_info.ccw.devno);
|
|
||||||
|
|
||||||
/* NSS wrapper */
|
/* NSS wrapper */
|
||||||
static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
|
static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
|
||||||
@ -1049,8 +1075,8 @@ static void __reipl_run(void *unused)
|
|||||||
|
|
||||||
switch (reipl_method) {
|
switch (reipl_method) {
|
||||||
case REIPL_METHOD_CCW_CIO:
|
case REIPL_METHOD_CCW_CIO:
|
||||||
|
devid.ssid = reipl_block_ccw->ipl_info.ccw.ssid;
|
||||||
devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
|
devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
|
||||||
devid.ssid = 0;
|
|
||||||
reipl_ccw_dev(&devid);
|
reipl_ccw_dev(&devid);
|
||||||
break;
|
break;
|
||||||
case REIPL_METHOD_CCW_VM:
|
case REIPL_METHOD_CCW_VM:
|
||||||
@ -1185,6 +1211,7 @@ static int __init reipl_ccw_init(void)
|
|||||||
|
|
||||||
reipl_block_ccw_init(reipl_block_ccw);
|
reipl_block_ccw_init(reipl_block_ccw);
|
||||||
if (ipl_info.type == IPL_TYPE_CCW) {
|
if (ipl_info.type == IPL_TYPE_CCW) {
|
||||||
|
reipl_block_ccw->ipl_info.ccw.ssid = ipl_ssid;
|
||||||
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
|
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
|
||||||
reipl_block_ccw_fill_parms(reipl_block_ccw);
|
reipl_block_ccw_fill_parms(reipl_block_ccw);
|
||||||
}
|
}
|
||||||
@ -1329,9 +1356,7 @@ static struct attribute_group dump_fcp_attr_group = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* CCW dump device attributes */
|
/* CCW dump device attributes */
|
||||||
|
DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ipl_info.ccw);
|
||||||
DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
|
|
||||||
dump_block_ccw->ipl_info.ccw.devno);
|
|
||||||
|
|
||||||
static struct attribute *dump_ccw_attrs[] = {
|
static struct attribute *dump_ccw_attrs[] = {
|
||||||
&sys_dump_ccw_device_attr.attr,
|
&sys_dump_ccw_device_attr.attr,
|
||||||
@ -1411,8 +1436,8 @@ static void __dump_run(void *unused)
|
|||||||
|
|
||||||
switch (dump_method) {
|
switch (dump_method) {
|
||||||
case DUMP_METHOD_CCW_CIO:
|
case DUMP_METHOD_CCW_CIO:
|
||||||
|
devid.ssid = dump_block_ccw->ipl_info.ccw.ssid;
|
||||||
devid.devno = dump_block_ccw->ipl_info.ccw.devno;
|
devid.devno = dump_block_ccw->ipl_info.ccw.devno;
|
||||||
devid.ssid = 0;
|
|
||||||
reipl_ccw_dev(&devid);
|
reipl_ccw_dev(&devid);
|
||||||
break;
|
break;
|
||||||
case DUMP_METHOD_CCW_VM:
|
case DUMP_METHOD_CCW_VM:
|
||||||
@ -1932,14 +1957,14 @@ void __init setup_ipl(void)
|
|||||||
ipl_info.type = get_ipl_type();
|
ipl_info.type = get_ipl_type();
|
||||||
switch (ipl_info.type) {
|
switch (ipl_info.type) {
|
||||||
case IPL_TYPE_CCW:
|
case IPL_TYPE_CCW:
|
||||||
|
ipl_info.data.ccw.dev_id.ssid = ipl_ssid;
|
||||||
ipl_info.data.ccw.dev_id.devno = ipl_devno;
|
ipl_info.data.ccw.dev_id.devno = ipl_devno;
|
||||||
ipl_info.data.ccw.dev_id.ssid = 0;
|
|
||||||
break;
|
break;
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
case IPL_TYPE_FCP_DUMP:
|
case IPL_TYPE_FCP_DUMP:
|
||||||
|
ipl_info.data.fcp.dev_id.ssid = 0;
|
||||||
ipl_info.data.fcp.dev_id.devno =
|
ipl_info.data.fcp.dev_id.devno =
|
||||||
IPL_PARMBLOCK_START->ipl_info.fcp.devno;
|
IPL_PARMBLOCK_START->ipl_info.fcp.devno;
|
||||||
ipl_info.data.fcp.dev_id.ssid = 0;
|
|
||||||
ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
|
ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
|
||||||
ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
|
ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
|
||||||
break;
|
break;
|
||||||
@ -1971,6 +1996,7 @@ void __init ipl_save_parameters(void)
|
|||||||
if (cio_get_iplinfo(&iplinfo))
|
if (cio_get_iplinfo(&iplinfo))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ipl_ssid = iplinfo.ssid;
|
||||||
ipl_devno = iplinfo.devno;
|
ipl_devno = iplinfo.devno;
|
||||||
ipl_flags |= IPL_DEVNO_VALID;
|
ipl_flags |= IPL_DEVNO_VALID;
|
||||||
if (!iplinfo.is_qdio)
|
if (!iplinfo.is_qdio)
|
||||||
|
@ -1080,28 +1080,10 @@ void __init chsc_init_cleanup(void)
|
|||||||
free_page((unsigned long)sei_page);
|
free_page((unsigned long)sei_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
int chsc_enable_facility(int operation_code)
|
int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
int ret;
|
||||||
struct {
|
|
||||||
struct chsc_header request;
|
|
||||||
u8 reserved1:4;
|
|
||||||
u8 format:4;
|
|
||||||
u8 reserved2;
|
|
||||||
u16 operation_code;
|
|
||||||
u32 reserved3;
|
|
||||||
u32 reserved4;
|
|
||||||
u32 operation_data_area[252];
|
|
||||||
struct chsc_header response;
|
|
||||||
u32 reserved5:4;
|
|
||||||
u32 format2:4;
|
|
||||||
u32 reserved6:24;
|
|
||||||
} __attribute__ ((packed)) *sda_area;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&chsc_page_lock, flags);
|
|
||||||
memset(chsc_page, 0, PAGE_SIZE);
|
|
||||||
sda_area = chsc_page;
|
|
||||||
sda_area->request.length = 0x0400;
|
sda_area->request.length = 0x0400;
|
||||||
sda_area->request.code = 0x0031;
|
sda_area->request.code = 0x0031;
|
||||||
sda_area->operation_code = operation_code;
|
sda_area->operation_code = operation_code;
|
||||||
@ -1119,10 +1101,25 @@ int chsc_enable_facility(int operation_code)
|
|||||||
default:
|
default:
|
||||||
ret = chsc_error_from_response(sda_area->response.code);
|
ret = chsc_error_from_response(sda_area->response.code);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chsc_enable_facility(int operation_code)
|
||||||
|
{
|
||||||
|
struct chsc_sda_area *sda_area;
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&chsc_page_lock, flags);
|
||||||
|
memset(chsc_page, 0, PAGE_SIZE);
|
||||||
|
sda_area = chsc_page;
|
||||||
|
|
||||||
|
ret = __chsc_enable_facility(sda_area, operation_code);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
|
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
|
||||||
operation_code, sda_area->response.code);
|
operation_code, sda_area->response.code);
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&chsc_page_lock, flags);
|
spin_unlock_irqrestore(&chsc_page_lock, flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,20 @@ struct chsc_scpd {
|
|||||||
u8 data[PAGE_SIZE - 20];
|
u8 data[PAGE_SIZE - 20];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct chsc_sda_area {
|
||||||
|
struct chsc_header request;
|
||||||
|
u8 :4;
|
||||||
|
u8 format:4;
|
||||||
|
u8 :8;
|
||||||
|
u16 operation_code;
|
||||||
|
u32 :32;
|
||||||
|
u32 :32;
|
||||||
|
u32 operation_data_area[252];
|
||||||
|
struct chsc_header response;
|
||||||
|
u32 :4;
|
||||||
|
u32 format2:4;
|
||||||
|
u32 :24;
|
||||||
|
} __packed __aligned(PAGE_SIZE);
|
||||||
|
|
||||||
extern int chsc_get_ssd_info(struct subchannel_id schid,
|
extern int chsc_get_ssd_info(struct subchannel_id schid,
|
||||||
struct chsc_ssd_info *ssd);
|
struct chsc_ssd_info *ssd);
|
||||||
@ -122,6 +136,7 @@ extern int chsc_determine_css_characteristics(void);
|
|||||||
extern int chsc_init(void);
|
extern int chsc_init(void);
|
||||||
extern void chsc_init_cleanup(void);
|
extern void chsc_init_cleanup(void);
|
||||||
|
|
||||||
|
int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code);
|
||||||
extern int chsc_enable_facility(int);
|
extern int chsc_enable_facility(int);
|
||||||
struct channel_subsystem;
|
struct channel_subsystem;
|
||||||
extern int chsc_secm(struct channel_subsystem *, int);
|
extern int chsc_secm(struct channel_subsystem *, int);
|
||||||
|
@ -925,18 +925,32 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
|
|||||||
|
|
||||||
int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
|
int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
|
||||||
{
|
{
|
||||||
|
static struct chsc_sda_area sda_area __initdata;
|
||||||
struct subchannel_id schid;
|
struct subchannel_id schid;
|
||||||
struct schib schib;
|
struct schib schib;
|
||||||
|
|
||||||
schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
|
schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
|
||||||
if (!schid.one)
|
if (!schid.one)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (schid.ssid) {
|
||||||
|
/*
|
||||||
|
* Firmware should have already enabled MSS but whoever started
|
||||||
|
* the kernel might have initiated a channel subsystem reset.
|
||||||
|
* Ensure that MSS is enabled.
|
||||||
|
*/
|
||||||
|
memset(&sda_area, 0, sizeof(sda_area));
|
||||||
|
if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
if (stsch_err(schid, &schib))
|
if (stsch_err(schid, &schib))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
|
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (!schib.pmcw.dnv)
|
if (!schib.pmcw.dnv)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
iplinfo->ssid = schid.ssid;
|
||||||
iplinfo->devno = schib.pmcw.dev;
|
iplinfo->devno = schib.pmcw.dev;
|
||||||
iplinfo->is_qdio = schib.pmcw.qf;
|
iplinfo->is_qdio = schib.pmcw.qf;
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user