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

📄 chsc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}void chsc_chp_online(struct chp_id chpid){	char dbf_txt[15];	sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);	CIO_TRACE_EVENT(2, dbf_txt);	if (chp_get_status(chpid) != 0)		for_each_subchannel(__chp_add, &chpid);}static void __s390_subchannel_vary_chpid(struct subchannel *sch,					 struct chp_id chpid, int on){	int chp, old_lpm;	int mask;	unsigned long flags;	spin_lock_irqsave(sch->lock, flags);	old_lpm = sch->lpm;	for (chp = 0; chp < 8; chp++) {		mask = 0x80 >> chp;		if (!(sch->ssd_info.path_mask & mask))			continue;		if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid))			continue;		if (on) {			sch->opm |= mask;			sch->lpm |= mask;			if (!old_lpm)				device_trigger_reprobe(sch);			else if (sch->driver && sch->driver->verify)				sch->driver->verify(&sch->dev);			break;		}		sch->opm &= ~mask;		sch->lpm &= ~mask;		if (check_for_io_on_path(sch, mask)) {			if (device_is_online(sch))				/* Path verification is done after killing. */				device_kill_io(sch);			else {				/* Kill and retry internal I/O. */				terminate_internal_io(sch);				/* Re-start path verification. */				if (sch->driver && sch->driver->verify)					sch->driver->verify(&sch->dev);			}		} else if (!sch->lpm) {			if (device_trigger_verify(sch) != 0)				css_schedule_eval(sch->schid);		} else if (sch->driver && sch->driver->verify)			sch->driver->verify(&sch->dev);		break;	}	spin_unlock_irqrestore(sch->lock, flags);}static int s390_subchannel_vary_chpid_off(struct device *dev, void *data){	struct subchannel *sch;	struct chp_id *chpid;	sch = to_subchannel(dev);	chpid = data;	__s390_subchannel_vary_chpid(sch, *chpid, 0);	return 0;}static int s390_subchannel_vary_chpid_on(struct device *dev, void *data){	struct subchannel *sch;	struct chp_id *chpid;	sch = to_subchannel(dev);	chpid = data;	__s390_subchannel_vary_chpid(sch, *chpid, 1);	return 0;}static int__s390_vary_chpid_on(struct subchannel_id schid, void *data){	struct schib schib;	struct subchannel *sch;	sch = get_subchannel_by_schid(schid);	if (sch) {		put_device(&sch->dev);		return 0;	}	if (stsch_err(schid, &schib))		/* We're through */		return -ENXIO;	/* Put it on the slow path. */	css_schedule_eval(schid);	return 0;}/** * chsc_chp_vary - propagate channel-path vary operation to subchannels * @chpid: channl-path ID * @on: non-zero for vary online, zero for vary offline */int chsc_chp_vary(struct chp_id chpid, int on){	/*	 * Redo PathVerification on the devices the chpid connects to	 */	bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?			 s390_subchannel_vary_chpid_on :			 s390_subchannel_vary_chpid_off);	if (on)		/* Scan for new devices on varied on path. */		for_each_subchannel(__s390_vary_chpid_on, NULL);	return 0;}static voidchsc_remove_cmg_attr(struct channel_subsystem *css){	int i;	for (i = 0; i <= __MAX_CHPID; i++) {		if (!css->chps[i])			continue;		chp_remove_cmg_attr(css->chps[i]);	}}static intchsc_add_cmg_attr(struct channel_subsystem *css){	int i, ret;	ret = 0;	for (i = 0; i <= __MAX_CHPID; i++) {		if (!css->chps[i])			continue;		ret = chp_add_cmg_attr(css->chps[i]);		if (ret)			goto cleanup;	}	return ret;cleanup:	for (--i; i >= 0; i--) {		if (!css->chps[i])			continue;		chp_remove_cmg_attr(css->chps[i]);	}	return ret;}static int__chsc_do_secm(struct channel_subsystem *css, int enable, void *page){	struct {		struct chsc_header request;		u32 operation_code : 2;		u32 : 30;		u32 key : 4;		u32 : 28;		u32 zeroes1;		u32 cub_addr1;		u32 zeroes2;		u32 cub_addr2;		u32 reserved[13];		struct chsc_header response;		u32 status : 8;		u32 : 4;		u32 fmt : 4;		u32 : 16;	} __attribute__ ((packed)) *secm_area;	int ret, ccode;	secm_area = page;	secm_area->request.length = 0x0050;	secm_area->request.code = 0x0016;	secm_area->key = PAGE_DEFAULT_KEY;	secm_area->cub_addr1 = (u64)(unsigned long)css->cub_addr1;	secm_area->cub_addr2 = (u64)(unsigned long)css->cub_addr2;	secm_area->operation_code = enable ? 0 : 1;	ccode = chsc(secm_area);	if (ccode > 0)		return (ccode == 3) ? -ENODEV : -EBUSY;	switch (secm_area->response.code) {	case 0x0001: /* Success. */		ret = 0;		break;	case 0x0003: /* Invalid block. */	case 0x0007: /* Invalid format. */	case 0x0008: /* Other invalid block. */		CIO_CRW_EVENT(2, "Error in chsc request block!\n");		ret = -EINVAL;		break;	case 0x0004: /* Command not provided in model. */		CIO_CRW_EVENT(2, "Model does not provide secm\n");		ret = -EOPNOTSUPP;		break;	case 0x0102: /* cub adresses incorrect */		CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n");		ret = -EINVAL;		break;	case 0x0103: /* key error */		CIO_CRW_EVENT(2, "Access key error in secm\n");		ret = -EINVAL;		break;	case 0x0105: /* error while starting */		CIO_CRW_EVENT(2, "Error while starting channel measurement\n");		ret = -EIO;		break;	default:		CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",			      secm_area->response.code);		ret = -EIO;	}	return ret;}intchsc_secm(struct channel_subsystem *css, int enable){	void  *secm_area;	int ret;	secm_area = (void *)get_zeroed_page(GFP_KERNEL |  GFP_DMA);	if (!secm_area)		return -ENOMEM;	mutex_lock(&css->mutex);	if (enable && !css->cm_enabled) {		css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);		css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);		if (!css->cub_addr1 || !css->cub_addr2) {			free_page((unsigned long)css->cub_addr1);			free_page((unsigned long)css->cub_addr2);			free_page((unsigned long)secm_area);			mutex_unlock(&css->mutex);			return -ENOMEM;		}	}	ret = __chsc_do_secm(css, enable, secm_area);	if (!ret) {		css->cm_enabled = enable;		if (css->cm_enabled) {			ret = chsc_add_cmg_attr(css);			if (ret) {				memset(secm_area, 0, PAGE_SIZE);				__chsc_do_secm(css, 0, secm_area);				css->cm_enabled = 0;			}		} else			chsc_remove_cmg_attr(css);	}	if (!css->cm_enabled) {		free_page((unsigned long)css->cub_addr1);		free_page((unsigned long)css->cub_addr2);	}	mutex_unlock(&css->mutex);	free_page((unsigned long)secm_area);	return ret;}int chsc_determine_channel_path_description(struct chp_id chpid,					    struct channel_path_desc *desc){	int ccode, ret;	struct {		struct chsc_header request;		u32 : 24;		u32 first_chpid : 8;		u32 : 24;		u32 last_chpid : 8;		u32 zeroes1;		struct chsc_header response;		u32 zeroes2;		struct channel_path_desc desc;	} __attribute__ ((packed)) *scpd_area;	scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!scpd_area)		return -ENOMEM;	scpd_area->request.length = 0x0010;	scpd_area->request.code = 0x0002;	scpd_area->first_chpid = chpid.id;	scpd_area->last_chpid = chpid.id;	ccode = chsc(scpd_area);	if (ccode > 0) {		ret = (ccode == 3) ? -ENODEV : -EBUSY;		goto out;	}	switch (scpd_area->response.code) {	case 0x0001: /* Success. */		memcpy(desc, &scpd_area->desc,		       sizeof(struct channel_path_desc));		ret = 0;		break;	case 0x0003: /* Invalid block. */	case 0x0007: /* Invalid format. */	case 0x0008: /* Other invalid block. */		CIO_CRW_EVENT(2, "Error in chsc request block!\n");		ret = -EINVAL;		break;	case 0x0004: /* Command not provided in model. */		CIO_CRW_EVENT(2, "Model does not provide scpd\n");		ret = -EOPNOTSUPP;		break;	default:		CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",			      scpd_area->response.code);		ret = -EIO;	}out:	free_page((unsigned long)scpd_area);	return ret;}static voidchsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,			  struct cmg_chars *chars){	switch (chp->cmg) {	case 2:	case 3:		chp->cmg_chars = kmalloc(sizeof(struct cmg_chars),					 GFP_KERNEL);		if (chp->cmg_chars) {			int i, mask;			struct cmg_chars *cmg_chars;			cmg_chars = chp->cmg_chars;			for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {				mask = 0x80 >> (i + 3);				if (cmcv & mask)					cmg_chars->values[i] = chars->values[i];				else					cmg_chars->values[i] = 0;			}		}		break;	default:		/* No cmg-dependent data. */		break;	}}int chsc_get_channel_measurement_chars(struct channel_path *chp){	int ccode, ret;	struct {		struct chsc_header request;		u32 : 24;		u32 first_chpid : 8;		u32 : 24;		u32 last_chpid : 8;		u32 zeroes1;		struct chsc_header response;		u32 zeroes2;		u32 not_valid : 1;		u32 shared : 1;		u32 : 22;		u32 chpid : 8;		u32 cmcv : 5;		u32 : 11;		u32 cmgq : 8;		u32 cmg : 8;		u32 zeroes3;		u32 data[NR_MEASUREMENT_CHARS];	} __attribute__ ((packed)) *scmc_area;	scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!scmc_area)		return -ENOMEM;	scmc_area->request.length = 0x0010;	scmc_area->request.code = 0x0022;	scmc_area->first_chpid = chp->chpid.id;	scmc_area->last_chpid = chp->chpid.id;	ccode = chsc(scmc_area);	if (ccode > 0) {		ret = (ccode == 3) ? -ENODEV : -EBUSY;		goto out;	}	switch (scmc_area->response.code) {	case 0x0001: /* Success. */		if (!scmc_area->not_valid) {			chp->cmg = scmc_area->cmg;			chp->shared = scmc_area->shared;			chsc_initialize_cmg_chars(chp, scmc_area->cmcv,						  (struct cmg_chars *)						  &scmc_area->data);		} else {			chp->cmg = -1;			chp->shared = -1;		}		ret = 0;		break;	case 0x0003: /* Invalid block. */	case 0x0007: /* Invalid format. */	case 0x0008: /* Invalid bit combination. */		CIO_CRW_EVENT(2, "Error in chsc request block!\n");		ret = -EINVAL;		break;	case 0x0004: /* Command not provided. */		CIO_CRW_EVENT(2, "Model does not provide scmc\n");		ret = -EOPNOTSUPP;		break;	default:		CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",			      scmc_area->response.code);		ret = -EIO;	}out:	free_page((unsigned long)scmc_area);	return ret;}int __init chsc_alloc_sei_area(void){	sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!sei_page)		CIO_MSG_EVENT(0, "Can't allocate page for processing of "			      "chsc machine checks!\n");	return (sei_page ? 0 : -ENOMEM);}void __init chsc_free_sei_area(void){	kfree(sei_page);}int __initchsc_enable_facility(int operation_code){	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;	sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);	if (!sda_area)		return -ENOMEM;	sda_area->request.length = 0x0400;	sda_area->request.code = 0x0031;	sda_area->operation_code = operation_code;	ret = chsc(sda_area);	if (ret > 0) {		ret = (ret == 3) ? -ENODEV : -EBUSY;		goto out;	}	switch (sda_area->response.code) {	case 0x0001: /* everything ok */		ret = 0;		break;	case 0x0003: /* invalid request block */	case 0x0007:		ret = -EINVAL;		break;	case 0x0004: /* command not provided */	case 0x0101: /* facility not provided */		ret = -EOPNOTSUPP;		break;	default: /* something went wrong */		ret = -EIO;	} out:	free_page((unsigned long)sda_area);	return ret;}struct css_general_char css_general_characteristics;struct css_chsc_char css_chsc_characteristics;int __initchsc_determine_css_characteristics(void){	int result;	struct {		struct chsc_header request;		u32 reserved1;		u32 reserved2;		u32 reserved3;		struct chsc_header response;		u32 reserved4;		u32 general_char[510];		u32 chsc_char[518];	} __attribute__ ((packed)) *scsc_area;	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!scsc_area) {		CIO_MSG_EVENT(0, "Was not able to determine available"			      "CHSCs due to no memory.\n");		return -ENOMEM;	}	scsc_area->request.length = 0x0010;	scsc_area->request.code = 0x0010;	result = chsc(scsc_area);	if (result) {		CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "			      "cc=%i.\n", result);		result = -EIO;		goto exit;	}	if (scsc_area->response.code != 1) {		CIO_MSG_EVENT(0, "Was not able to determine "			      "available CHSCs.\n");		result = -EIO;		goto exit;	}	memcpy(&css_general_characteristics, scsc_area->general_char,	       sizeof(css_general_characteristics));	memcpy(&css_chsc_characteristics, scsc_area->chsc_char,	       sizeof(css_chsc_characteristics));exit:	free_page ((unsigned long) scsc_area);	return result;}EXPORT_SYMBOL_GPL(css_general_characteristics);EXPORT_SYMBOL_GPL(css_chsc_characteristics);

⌨️ 快捷键说明

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