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

📄 chsc.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* Check if we might have lost some information. */		if (sei_area->flags & 0x40)			CIO_CRW_EVENT(2, "chsc_process_crw: Event information "				       "has been lost due to overflow!\n");		if (sei_area->rs != 4) {			CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "				      "(%04X) isn't a chpid!\n",				      sei_area->rsid);			continue;		}		/* which kind of information was stored? */		switch (sei_area->cc) {		case 1: /* link incident*/			CIO_CRW_EVENT(4, "chsc_process_crw: "				      "channel subsystem reports link incident,"				      " reporting source is chpid %x\n",				      sei_area->rsid);			chpid = __get_chpid_from_lir(sei_area->ccdf);			if (chpid < 0)				CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",					      __FUNCTION__);			else				s390_set_chpid_offline(chpid);			break;					case 2: /* i/o resource accessibiliy */			CIO_CRW_EVENT(4, "chsc_process_crw: "				      "channel subsystem reports some I/O "				      "devices may have become accessible\n");			pr_debug("Data received after sei: \n");			pr_debug("Validity flags: %x\n", sei_area->vf);						/* allocate a new channel path structure, if needed */			status = get_chp_status(sei_area->rsid);			if (status < 0)				new_channel_path(sei_area->rsid);			else if (!status)				break;			dev = get_device(&css[0]->chps[sei_area->rsid]->dev);			res_data.chp = to_channelpath(dev);			pr_debug("chpid: %x", sei_area->rsid);			if ((sei_area->vf & 0xc0) != 0) {				res_data.fla = sei_area->fla;				if ((sei_area->vf & 0xc0) == 0xc0) {					pr_debug(" full link addr: %x",						 sei_area->fla);					res_data.fla_mask = 0xffff;				} else {					pr_debug(" link addr: %x",						 sei_area->fla);					res_data.fla_mask = 0xff00;				}			}			ret = s390_process_res_acc(&res_data);			pr_debug("\n\n");			put_device(dev);			break;					default: /* other stuff */			CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",				      sei_area->cc);			break;		}	} while (sei_area->flags & 0x80);	return ret;}static inline int__chp_add_new_sch(struct subchannel_id schid){	struct schib schib;	int ret;	if (stsch(schid, &schib))		/* We're through */		return need_rescan ? -EAGAIN : -ENXIO;	/* Put it on the slow path. */	ret = css_enqueue_subchannel_slow(schid);	if (ret) {		css_clear_subchannel_slow_list();		need_rescan = 1;		return -EAGAIN;	}	return 0;}static int__chp_add(struct subchannel_id schid, void *data){	int i;	struct channel_path *chp;	struct subchannel *sch;	chp = (struct channel_path *)data;	sch = get_subchannel_by_schid(schid);	if (!sch)		/* Check if the subchannel is now available. */		return __chp_add_new_sch(schid);	spin_lock_irq(&sch->lock);	for (i=0; i<8; i++)		if (sch->schib.pmcw.chpid[i] == chp->id) {			if (stsch(sch->schid, &sch->schib) != 0) {				/* Endgame. */				spin_unlock_irq(&sch->lock);				return -ENXIO;			}			break;		}	if (i==8) {		spin_unlock_irq(&sch->lock);		return 0;	}	sch->lpm = ((sch->schib.pmcw.pim &		     sch->schib.pmcw.pam &		     sch->schib.pmcw.pom)		    | 0x80 >> i) & sch->opm;	if (sch->driver && sch->driver->verify)		sch->driver->verify(&sch->dev);	spin_unlock_irq(&sch->lock);	put_device(&sch->dev);	return 0;}static intchp_add(int chpid){	int rc;	char dbf_txt[15];	struct device *dev;	if (!get_chp_status(chpid))		return 0; /* no need to do the rest */		sprintf(dbf_txt, "cadd%x", chpid);	CIO_TRACE_EVENT(2, dbf_txt);	dev = get_device(&css[0]->chps[chpid]->dev);	rc = for_each_subchannel(__chp_add, to_channelpath(dev));	if (css_slow_subchannels_exist())		rc = -EAGAIN;	if (rc != -EAGAIN)		rc = 0;	put_device(dev);	return rc;}/*  * Handling of crw machine checks with channel path source. */intchp_process_crw(int chpid, int on){	if (on == 0) {		/* Path has gone. We use the link incident routine.*/		s390_set_chpid_offline(chpid);		return 0; /* De-register is async anyway. */	}	/*	 * Path has come. Allocate a new channel path structure,	 * if needed.	 */	if (get_chp_status(chpid) < 0)		new_channel_path(chpid);	/* Avoid the extra overhead in process_rec_acc. */	return chp_add(chpid);}static inline int__check_for_io_and_kill(struct subchannel *sch, int index){	int cc;	if (!device_is_online(sch))		/* cio could be doing I/O. */		return 0;	cc = stsch(sch->schid, &sch->schib);	if (cc)		return 0;	if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) {		device_set_waiting(sch);		return 1;	}	return 0;}static inline void__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on){	int chp, old_lpm;	unsigned long flags;	if (!sch->ssd_info.valid)		return;		spin_lock_irqsave(&sch->lock, flags);	old_lpm = sch->lpm;	for (chp = 0; chp < 8; chp++) {		if (sch->ssd_info.chpid[chp] != chpid)			continue;		if (on) {			sch->opm |= (0x80 >> chp);			sch->lpm |= (0x80 >> chp);			if (!old_lpm)				device_trigger_reprobe(sch);			else if (sch->driver && sch->driver->verify)				sch->driver->verify(&sch->dev);		} else {			sch->opm &= ~(0x80 >> chp);			sch->lpm &= ~(0x80 >> chp);			/*			 * Give running I/O a grace period in which it			 * can successfully terminate, even using the			 * just varied off path. Then kill it.			 */			if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {				if (css_enqueue_subchannel_slow(sch->schid)) {					css_clear_subchannel_slow_list();					need_rescan = 1;				}			} else if (sch->driver && sch->driver->verify)				sch->driver->verify(&sch->dev);		}		break;	}	spin_unlock_irqrestore(&sch->lock, flags);}static ints390_subchannel_vary_chpid_off(struct device *dev, void *data){	struct subchannel *sch;	__u8 *chpid;	sch = to_subchannel(dev);	chpid = data;	__s390_subchannel_vary_chpid(sch, *chpid, 0);	return 0;}static ints390_subchannel_vary_chpid_on(struct device *dev, void *data){	struct subchannel *sch;	__u8 *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. */	if (css_enqueue_subchannel_slow(schid)) {		css_clear_subchannel_slow_list();		need_rescan = 1;		return -EAGAIN;	}	return 0;}/* * Function: s390_vary_chpid * Varies the specified chpid online or offline */static ints390_vary_chpid( __u8 chpid, int on){	char dbf_text[15];	int status;	sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);	CIO_TRACE_EVENT( 2, dbf_text);	status = get_chp_status(chpid);	if (status < 0) {		printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid);		return -EINVAL;	}	if (!on && !status) {		printk(KERN_ERR "chpid %x is already offline\n", chpid);		return -EINVAL;	}	set_chp_logically_online(chpid, 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);	if (need_rescan || css_slow_subchannels_exist())		queue_work(slow_path_wq, &slow_path_work);	return 0;}/* * Channel measurement related functions */static ssize_tchp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off,			   size_t count){	struct channel_path *chp;	unsigned int size;	chp = to_channelpath(container_of(kobj, struct device, kobj));	if (!chp->cmg_chars)		return 0;	size = sizeof(struct cmg_chars);	if (off > size)		return 0;	if (off + count > size)		count = size - off;	memcpy(buf, chp->cmg_chars + off, count);	return count;}static struct bin_attribute chp_measurement_chars_attr = {	.attr = {		.name = "measurement_chars",		.mode = S_IRUSR,		.owner = THIS_MODULE,	},	.size = sizeof(struct cmg_chars),	.read = chp_measurement_chars_read,};static voidchp_measurement_copy_block(struct cmg_entry *buf,			   struct channel_subsystem *css, int chpid){	void *area;	struct cmg_entry *entry, reference_buf;	int idx;	if (chpid < 128) {		area = css->cub_addr1;		idx = chpid;	} else {		area = css->cub_addr2;		idx = chpid - 128;	}	entry = area + (idx * sizeof(struct cmg_entry));	do {		memcpy(buf, entry, sizeof(*entry));		memcpy(&reference_buf, entry, sizeof(*entry));	} while (reference_buf.values[0] != buf->values[0]);}static ssize_tchp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count){	struct channel_path *chp;	struct channel_subsystem *css;	unsigned int size;	chp = to_channelpath(container_of(kobj, struct device, kobj));	css = to_css(chp->dev.parent);	size = sizeof(struct cmg_chars);	/* Only allow single reads. */	if (off || count < size)		return 0;	chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);	return count;}static struct bin_attribute chp_measurement_attr = {	.attr = {		.name = "measurement",		.mode = S_IRUSR,		.owner = THIS_MODULE,	},	.size = sizeof(struct cmg_entry),	.read = chp_measurement_read,};static voidchsc_remove_chp_cmg_attr(struct channel_path *chp){	sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);	sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);}static intchsc_add_chp_cmg_attr(struct channel_path *chp){	int ret;	ret = sysfs_create_bin_file(&chp->dev.kobj,				    &chp_measurement_chars_attr);	if (ret)		return ret;	ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);	if (ret)		sysfs_remove_bin_file(&chp->dev.kobj,				      &chp_measurement_chars_attr);	return ret;}static voidchsc_remove_cmg_attr(struct channel_subsystem *css){	int i;	for (i = 0; i <= __MAX_CHPID; i++) {		if (!css->chps[i])			continue;		chsc_remove_chp_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 = chsc_add_chp_cmg_attr(css->chps[i]);		if (ret)			goto cleanup;	}	return ret;cleanup:	for (--i; i >= 0; i--) {		if (!css->chps[i])			continue;		chsc_remove_chp_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;	} *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");

⌨️ 快捷键说明

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