Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18e22a17 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

s390: add support for ipl devices in subchannel sets > 0



Allow to ipl from CCW based devices residing in any subchannel set.

Reviewed-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent e0bedada
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -312,6 +312,7 @@ extern void css_schedule_reprobe(void);
extern void reipl_ccw_dev(struct ccw_dev_id *id);

struct cio_iplinfo {
	u8 ssid;
	u16 devno;
	int is_qdio;
};
+2 −1
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ struct ipl_block_fcp {

struct ipl_block_ccw {
	u8  reserved1[84];
	u8  reserved2[2];
	u16 reserved2 : 13;
	u8  ssid : 3;
	u16 devno;
	u8  vm_flags;
	u8  reserved3[3];
+37 −11
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ static char *dump_type_str(enum dump_type type)
 * Must be in data section since the bss section
 * is not cleared when these are accessed.
 */
static u8 ipl_ssid __attribute__((__section__(".data"))) = 0;
static u16 ipl_devno __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);		\
}

#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)		\
IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value)			\
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) {
	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_DUMP:
		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 */

DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
	reipl_block_ccw->ipl_info.ccw.devno);
DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ipl_info.ccw);

/* NSS wrapper */
static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
@@ -1049,8 +1075,8 @@ static void __reipl_run(void *unused)

	switch (reipl_method) {
	case REIPL_METHOD_CCW_CIO:
		devid.ssid  = reipl_block_ccw->ipl_info.ccw.ssid;
		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
		devid.ssid  = 0;
		reipl_ccw_dev(&devid);
		break;
	case REIPL_METHOD_CCW_VM:
@@ -1185,6 +1211,7 @@ static int __init reipl_ccw_init(void)

	reipl_block_ccw_init(reipl_block_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_fill_parms(reipl_block_ccw);
	}
@@ -1329,9 +1356,7 @@ static struct attribute_group dump_fcp_attr_group = {
};

/* CCW dump device attributes */

DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
		   dump_block_ccw->ipl_info.ccw.devno);
DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ipl_info.ccw);

static struct attribute *dump_ccw_attrs[] = {
	&sys_dump_ccw_device_attr.attr,
@@ -1411,8 +1436,8 @@ static void __dump_run(void *unused)

	switch (dump_method) {
	case DUMP_METHOD_CCW_CIO:
		devid.ssid  = dump_block_ccw->ipl_info.ccw.ssid;
		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
		devid.ssid  = 0;
		reipl_ccw_dev(&devid);
		break;
	case DUMP_METHOD_CCW_VM:
@@ -1932,14 +1957,14 @@ void __init setup_ipl(void)
	ipl_info.type = get_ipl_type();
	switch (ipl_info.type) {
	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.ssid = 0;
		break;
	case IPL_TYPE_FCP:
	case IPL_TYPE_FCP_DUMP:
		ipl_info.data.fcp.dev_id.ssid = 0;
		ipl_info.data.fcp.dev_id.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.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
		break;
@@ -1971,6 +1996,7 @@ void __init ipl_save_parameters(void)
	if (cio_get_iplinfo(&iplinfo))
		return;

	ipl_ssid = iplinfo.ssid;
	ipl_devno = iplinfo.devno;
	ipl_flags |= IPL_DEVNO_VALID;
	if (!iplinfo.is_qdio)
+17 −20
Original line number Diff line number Diff line
@@ -1080,28 +1080,10 @@ void __init chsc_init_cleanup(void)
	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;
	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.code = 0x0031;
	sda_area->operation_code = operation_code;
@@ -1119,10 +1101,25 @@ int chsc_enable_facility(int operation_code)
	default:
		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)
		CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
			      operation_code, sda_area->response.code);
out:

	spin_unlock_irqrestore(&chsc_page_lock, flags);
	return ret;
}
+15 −0
Original line number Diff line number Diff line
@@ -115,6 +115,20 @@ struct chsc_scpd {
	u8 data[PAGE_SIZE - 20];
} __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,
			     struct chsc_ssd_info *ssd);
@@ -122,6 +136,7 @@ extern int chsc_determine_css_characteristics(void);
extern int chsc_init(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);
struct channel_subsystem;
extern int chsc_secm(struct channel_subsystem *, int);
Loading