⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipl.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  arch/s390/kernel/ipl.c *    ipl/reipl/dump support for Linux on s390. * *    Copyright (C) IBM Corp. 2005,2006 *    Author(s): Michael Holzheu <holzheu@de.ibm.com> *		 Heiko Carstens <heiko.carstens@de.ibm.com> *		 Volker Sameske <sameske@de.ibm.com> */#include <linux/types.h>#include <linux/module.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/reboot.h>#include <linux/ctype.h>#include <asm/ipl.h>#include <asm/smp.h>#include <asm/setup.h>#include <asm/cpcmd.h>#include <asm/cio.h>#include <asm/ebcdic.h>#include <asm/reset.h>#include <asm/sclp.h>#define IPL_PARM_BLOCK_VERSION 0#define IPL_UNKNOWN_STR		"unknown"#define IPL_CCW_STR		"ccw"#define IPL_FCP_STR		"fcp"#define IPL_FCP_DUMP_STR	"fcp_dump"#define IPL_NSS_STR		"nss"static char *ipl_type_str(enum ipl_type type){	switch (type) {	case IPL_TYPE_CCW:		return IPL_CCW_STR;	case IPL_TYPE_FCP:		return IPL_FCP_STR;	case IPL_TYPE_FCP_DUMP:		return IPL_FCP_DUMP_STR;	case IPL_TYPE_NSS:		return IPL_NSS_STR;	case IPL_TYPE_UNKNOWN:	default:		return IPL_UNKNOWN_STR;	}}enum dump_type {	DUMP_TYPE_NONE	= 1,	DUMP_TYPE_CCW	= 2,	DUMP_TYPE_FCP	= 4,};#define DUMP_NONE_STR	 "none"#define DUMP_CCW_STR	 "ccw"#define DUMP_FCP_STR	 "fcp"static char *dump_type_str(enum dump_type type){	switch (type) {	case DUMP_TYPE_NONE:		return DUMP_NONE_STR;	case DUMP_TYPE_CCW:		return DUMP_CCW_STR;	case DUMP_TYPE_FCP:		return DUMP_FCP_STR;	default:		return NULL;	}}/* * Must be in data section since the bss section * is not cleared when these are accessed. */static u16 ipl_devno __attribute__((__section__(".data"))) = 0;u32 ipl_flags __attribute__((__section__(".data"))) = 0;enum ipl_method {	REIPL_METHOD_CCW_CIO,	REIPL_METHOD_CCW_DIAG,	REIPL_METHOD_CCW_VM,	REIPL_METHOD_FCP_RO_DIAG,	REIPL_METHOD_FCP_RW_DIAG,	REIPL_METHOD_FCP_RO_VM,	REIPL_METHOD_FCP_DUMP,	REIPL_METHOD_NSS,	REIPL_METHOD_DEFAULT,};enum dump_method {	DUMP_METHOD_NONE,	DUMP_METHOD_CCW_CIO,	DUMP_METHOD_CCW_DIAG,	DUMP_METHOD_CCW_VM,	DUMP_METHOD_FCP_DIAG,};enum shutdown_action {	SHUTDOWN_REIPL,	SHUTDOWN_DUMP,	SHUTDOWN_STOP,};#define SHUTDOWN_REIPL_STR "reipl"#define SHUTDOWN_DUMP_STR  "dump"#define SHUTDOWN_STOP_STR  "stop"static char *shutdown_action_str(enum shutdown_action action){	switch (action) {	case SHUTDOWN_REIPL:		return SHUTDOWN_REIPL_STR;	case SHUTDOWN_DUMP:		return SHUTDOWN_DUMP_STR;	case SHUTDOWN_STOP:		return SHUTDOWN_STOP_STR;	default:		return NULL;	}}static int diag308_set_works = 0;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 int dump_capabilities = DUMP_TYPE_NONE;static enum dump_type dump_type = DUMP_TYPE_NONE;static enum dump_method dump_method = DUMP_METHOD_NONE;static struct ipl_parameter_block *dump_block_fcp;static struct ipl_parameter_block *dump_block_ccw;static enum shutdown_action on_panic_action = SHUTDOWN_STOP;static struct sclp_ipl_info sclp_ipl_info;int diag308(unsigned long subcode, void *addr){	register unsigned long _addr asm("0") = (unsigned long) addr;	register unsigned long _rc asm("1") = 0;	asm volatile(		"	diag	%0,%2,0x308\n"		"0:\n"		EX_TABLE(0b,0b)		: "+d" (_addr), "+d" (_rc)		: "d" (subcode) : "cc", "memory");	return _rc;}EXPORT_SYMBOL_GPL(diag308);/* SYSFS */#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)		\static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\		char *page)						\{									\	return sprintf(page, _format, _value);				\}									\static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\	__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)	\static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\		char *page)						\{									\	return sprintf(page, _fmt_out,					\			(unsigned long long) _value);			\}									\static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\		const char *buf, size_t len)				\{									\	unsigned long long value;					\	if (sscanf(buf, _fmt_in, &value) != 1)				\		return -EINVAL;						\	_value = value;							\	return len;							\}									\static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\	__ATTR(_name,(S_IRUGO | S_IWUSR),				\			sys_##_prefix##_##_name##_show,			\			sys_##_prefix##_##_name##_store);#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\		char *page)						\{									\	return sprintf(page, _fmt_out, _value);				\}									\static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\		const char *buf, size_t len)				\{									\	if (sscanf(buf, _fmt_in, _value) != 1)				\		return -EINVAL;						\	return len;							\}									\static struct subsys_attribute sys_##_prefix##_##_name##_attr =		\	__ATTR(_name,(S_IRUGO | S_IWUSR),				\			sys_##_prefix##_##_name##_show,			\			sys_##_prefix##_##_name##_store);static void make_attrs_ro(struct attribute **attrs){	while (*attrs) {		(*attrs)->mode = S_IRUGO;		attrs++;	}}/* * ipl section */static __init enum ipl_type get_ipl_type(void){	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;	if (ipl_flags & IPL_NSS_VALID)		return IPL_TYPE_NSS;	if (!(ipl_flags & IPL_DEVNO_VALID))		return IPL_TYPE_UNKNOWN;	if (!(ipl_flags & IPL_PARMBLOCK_VALID))		return IPL_TYPE_CCW;	if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)		return IPL_TYPE_UNKNOWN;	if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)		return IPL_TYPE_UNKNOWN;	if (ipl->ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP)		return IPL_TYPE_FCP_DUMP;	return IPL_TYPE_FCP;}void __init setup_ipl_info(void){	ipl_info.type = get_ipl_type();	switch (ipl_info.type) {	case IPL_TYPE_CCW:		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.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;	case IPL_TYPE_NSS:		strncpy(ipl_info.data.nss.name, kernel_nss_name,			sizeof(ipl_info.data.nss.name));		break;	case IPL_TYPE_UNKNOWN:	default:		/* We have no info to copy */		break;	}}struct ipl_info ipl_info;EXPORT_SYMBOL_GPL(ipl_info);static ssize_t ipl_type_show(struct kset *kset, char *page){	return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));}static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);static ssize_t sys_ipl_device_show(struct kset *kset, char *page){	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;	switch (ipl_info.type) {	case IPL_TYPE_CCW:		return sprintf(page, "0.0.%04x\n", ipl_devno);	case IPL_TYPE_FCP:	case IPL_TYPE_FCP_DUMP:		return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);	default:		return 0;	}}static struct subsys_attribute sys_ipl_device_attr =	__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,				  char *buf, loff_t off, size_t count){	unsigned int size = IPL_PARMBLOCK_SIZE;	if (off > size)		return 0;	if (off + count > size)		count = size - off;	memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);	return count;}static struct bin_attribute ipl_parameter_attr = {	.attr = {		.name = "binary_parameter",		.mode = S_IRUGO,	},	.size = PAGE_SIZE,	.read = &ipl_parameter_read,};static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr,				 char *buf, loff_t off, size_t count){	unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;	void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;	if (off > size)		return 0;	if (off + count > size)		count = size - off;	memcpy(buf, scp_data + off, count);	return count;}static struct bin_attribute ipl_scp_data_attr = {	.attr = {		.name = "scp_data",		.mode = S_IRUGO,	},	.size = PAGE_SIZE,	.read = ipl_scp_data_read,};/* FCP ipl device attributes */DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)		   IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)		   IPL_PARMBLOCK_START->ipl_info.fcp.lun);DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)		   IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)		   IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);static struct attribute *ipl_fcp_attrs[] = {	&sys_ipl_type_attr.attr,	&sys_ipl_device_attr.attr,	&sys_ipl_fcp_wwpn_attr.attr,	&sys_ipl_fcp_lun_attr.attr,	&sys_ipl_fcp_bootprog_attr.attr,	&sys_ipl_fcp_br_lba_attr.attr,	NULL,};static struct attribute_group ipl_fcp_attr_group = {	.attrs = ipl_fcp_attrs,};/* CCW ipl device attributes */static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page){	char loadparm[LOADPARM_LEN + 1] = {};	if (!sclp_ipl_info.is_valid)		return sprintf(page, "#unknown#\n");	memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);	EBCASC(loadparm, LOADPARM_LEN);	strstrip(loadparm);	return sprintf(page, "%s\n", loadparm);}static struct subsys_attribute sys_ipl_ccw_loadparm_attr =	__ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);static struct attribute *ipl_ccw_attrs[] = {	&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,};/* NSS ipl device attributes */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,	NULL,};static struct attribute_group ipl_nss_attr_group = {	.attrs = ipl_nss_attrs,};/* UNKNOWN ipl device attributes */static struct attribute *ipl_unknown_attrs[] = {	&sys_ipl_type_attr.attr,	NULL,};static struct attribute_group ipl_unknown_attr_group = {	.attrs = ipl_unknown_attrs,};static decl_subsys(ipl, NULL, NULL);/* * reipl section *//* FCP reipl device attributes */DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",		   reipl_block_fcp->ipl_info.fcp.wwpn);DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",		   reipl_block_fcp->ipl_info.fcp.lun);DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",		   reipl_block_fcp->ipl_info.fcp.bootprog);DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",		   reipl_block_fcp->ipl_info.fcp.br_lba);DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",		   reipl_block_fcp->ipl_info.fcp.devno);static struct attribute *reipl_fcp_attrs[] = {	&sys_reipl_fcp_device_attr.attr,	&sys_reipl_fcp_wwpn_attr.attr,	&sys_reipl_fcp_lun_attr.attr,	&sys_reipl_fcp_bootprog_attr.attr,	&sys_reipl_fcp_br_lba_attr.attr,	NULL,};static struct attribute_group reipl_fcp_attr_group = {	.name  = IPL_FCP_STR,	.attrs = reipl_fcp_attrs,};/* 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);static void reipl_get_ascii_loadparm(char *loadparm){	memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,	       LOADPARM_LEN);	EBCASC(loadparm, LOADPARM_LEN);	loadparm[LOADPARM_LEN] = 0;	strstrip(loadparm);}static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page){	char buf[LOADPARM_LEN + 1];	reipl_get_ascii_loadparm(buf);	return sprintf(page, "%s\n", buf);}static ssize_t reipl_ccw_loadparm_store(struct kset *kset,					const char *buf, size_t len){	int i, lp_len;	/* ignore trailing newline */	lp_len = len;	if ((len > 0) && (buf[len - 1] == '\n'))		lp_len--;	/* loadparm can have max 8 characters and must not start with a blank */	if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))		return -EINVAL;	/* loadparm can only contain "a-z,A-Z,0-9,SP,." */	for (i = 0; i < lp_len; i++) {		if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||		    (buf[i] == '.'))			continue;		return -EINVAL;	}	/* initialize loadparm with blanks */	memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', 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);	return len;}static struct subsys_attribute sys_reipl_ccw_loadparm_attr =	__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,	       reipl_ccw_loadparm_store);static struct attribute *reipl_ccw_attrs[] = {	&sys_reipl_ccw_device_attr.attr,	&sys_reipl_ccw_loadparm_attr.attr,	NULL,};static struct attribute_group reipl_ccw_attr_group = {	.name  = IPL_CCW_STR,	.attrs = reipl_ccw_attrs,};/* NSS reipl device attributes */DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);static struct attribute *reipl_nss_attrs[] = {	&sys_reipl_nss_name_attr.attr,	NULL,};static struct attribute_group reipl_nss_attr_group = {	.name  = IPL_NSS_STR,	.attrs = reipl_nss_attrs,};/* reipl type */static int reipl_set_type(enum ipl_type type){	if (!(reipl_capabilities & type))		return -EINVAL;	switch(type) {	case IPL_TYPE_CCW:		if (MACHINE_IS_VM)			reipl_method = REIPL_METHOD_CCW_VM;		else			reipl_method = REIPL_METHOD_CCW_CIO;		break;	case IPL_TYPE_FCP:		if (diag308_set_works)			reipl_method = REIPL_METHOD_FCP_RW_DIAG;		else if (MACHINE_IS_VM)			reipl_method = REIPL_METHOD_FCP_RO_VM;		else			reipl_method = REIPL_METHOD_FCP_RO_DIAG;		break;	case IPL_TYPE_FCP_DUMP:		reipl_method = REIPL_METHOD_FCP_DUMP;		break;	case IPL_TYPE_NSS:		reipl_method = REIPL_METHOD_NSS;		break;	case IPL_TYPE_UNKNOWN:		reipl_method = REIPL_METHOD_DEFAULT;		break;	default:		BUG();	}	reipl_type = type;	return 0;}static ssize_t reipl_type_show(struct kset *kset, char *page){	return sprintf(page, "%s\n", ipl_type_str(reipl_type));}static ssize_t reipl_type_store(struct kset *kset, const char *buf,				size_t len){	int rc = -EINVAL;	if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)		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_NSS_STR, strlen(IPL_NSS_STR)) == 0)		rc = reipl_set_type(IPL_TYPE_NSS);	return (rc != 0) ? rc : len;}static struct subsys_attribute reipl_type_attr =		__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);static decl_subsys(reipl, NULL, NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -