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

📄 chsc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	ret = 0;	do {		int ccode, status;		memset(sei_area, 0, sizeof(*sei_area));		sei_area->request = (struct chsc_header) {			.length = 0x0010,			.code   = 0x000e,		};		ccode = chsc(sei_area);		if (ccode > 0)			return 0;		switch (sei_area->response.code) {			/* for debug purposes, check for problems */		case 0x0001:			CIO_CRW_EVENT(4, "chsc_process_crw: event information "					"successfully stored\n");			break; /* everything ok */		case 0x0002:			CIO_CRW_EVENT(2,				      "chsc_process_crw: invalid command!\n");			return 0;		case 0x0003:			CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "				      "request block!\n");			return 0;		case 0x0005:			CIO_CRW_EVENT(2, "chsc_process_crw: no event "				      "information stored\n");			return 0;		default:			CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",				      sei_area->response.code);			return 0;		}		/* 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)				return 0;			if ((sei_area->vf & 0x80) == 0) {				pr_debug("chpid: %x\n", sei_area->rsid);				ret = s390_process_res_acc(sei_area->rsid,							   0, 0);			} else if ((sei_area->vf & 0xc0) == 0x80) {				pr_debug("chpid: %x link addr: %x\n",					 sei_area->rsid, sei_area->fla);				ret = s390_process_res_acc(sei_area->rsid,							   sei_area->fla,							   0xff00);			} else if ((sei_area->vf & 0xc0) == 0xc0) {				pr_debug("chpid: %x full link addr: %x\n",					 sei_area->rsid, sei_area->fla);				ret = s390_process_res_acc(sei_area->rsid,							   sei_area->fla,							   0xffff);			}			pr_debug("\n");						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 intchp_add(int chpid){	struct subchannel *sch;	int irq, ret, rc;	char dbf_txt[15];	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);	rc = 0;	for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {		int i;		sch = get_subchannel_by_schid(irq);		if (!sch) {			struct schib schib;			if (stsch(irq, &schib)) {				/* We're through */				if (need_rescan)					rc = -EAGAIN;				break;			}			if (need_rescan) {				rc = -EAGAIN;				continue;			}			/* Put it on the slow path. */			ret = css_enqueue_subchannel_slow(irq);			if (ret) {				css_clear_subchannel_slow_list();				need_rescan = 1;			}			rc = -EAGAIN;			continue;		}			spin_lock(&sch->lock);		for (i=0; i<8; i++)			if (sch->schib.pmcw.chpid[i] == chpid) {				if (stsch(sch->irq, &sch->schib) != 0) {					/* Endgame. */					spin_unlock(&sch->lock);					return rc;				}				break;			}		if (i==8) {			spin_unlock(&sch->lock);			return rc;		}		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(&sch->lock);		put_device(&sch->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;	cc = stsch(sch->irq, &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;	if (!sch->ssd_info.valid)		return;		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->irq)) {					css_clear_subchannel_slow_list();					need_rescan = 1;				}			} else if (sch->driver && sch->driver->verify)				sch->driver->verify(&sch->dev);		}		break;	}}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;}/* * 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, irq, ret;	struct subchannel *sch;	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)		goto out;	/* Scan for new devices on varied on path. */	for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {		struct schib schib;		if (need_rescan)			break;		sch = get_subchannel_by_schid(irq);		if (sch) {			put_device(&sch->dev);			continue;		}		if (stsch(irq, &schib))			/* We're through */			break;		/* Put it on the slow path. */		ret = css_enqueue_subchannel_slow(irq);		if (ret) {			css_clear_subchannel_slow_list();			need_rescan = 1;		}	}out:	if (need_rescan || css_slow_subchannels_exist())		queue_work(slow_path_wq, &slow_path_work);	return 0;}/* * Files for the channel path entries. */static ssize_tchp_status_show(struct device *dev, char *buf){	struct channel_path *chp = container_of(dev, struct channel_path, dev);	if (!chp)		return 0;	return (get_chp_status(chp->id) ? sprintf(buf, "online\n") :		sprintf(buf, "offline\n"));}static ssize_tchp_status_write(struct device *dev, const char *buf, size_t count){	struct channel_path *cp = container_of(dev, struct channel_path, dev);	char cmd[10];	int num_args;	int error;	num_args = sscanf(buf, "%5s", cmd);	if (!num_args)		return count;	if (!strnicmp(cmd, "on", 2))		error = s390_vary_chpid(cp->id, 1);	else if (!strnicmp(cmd, "off", 3))		error = s390_vary_chpid(cp->id, 0);	else		error = -EINVAL;	return error < 0 ? error : count;}static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);static voidchp_release(struct device *dev){	struct channel_path *cp;		cp = container_of(dev, struct channel_path, dev);	kfree(cp);}/* * Entries for chpids on the system bus. * This replaces /proc/chpids. */static intnew_channel_path(int chpid){	struct channel_path *chp;	int ret;	chp = kmalloc(sizeof(struct channel_path), GFP_KERNEL);	if (!chp)		return -ENOMEM;	memset(chp, 0, sizeof(struct channel_path));	/* fill in status, etc. */	chp->id = chpid;	chp->state = 1;	chp->dev = (struct device) {		.parent  = &css_bus_device,		.release = chp_release,	};	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);	/* make it known to the system */	ret = device_register(&chp->dev);	if (ret) {		printk(KERN_WARNING "%s: could not register %02x\n",		       __func__, chpid);		goto out_free;	}	ret = device_create_file(&chp->dev, &dev_attr_status);	if (ret) {		device_unregister(&chp->dev);		goto out_free;	} else		chps[chpid] = chp;	return ret;out_free:	kfree(chp);	return ret;}static int __initchsc_alloc_sei_area(void){	sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!sei_page)		printk(KERN_WARNING"Can't allocate page for processing of " \		       "chsc machine checks!\n");	return (sei_page ? 0 : -ENOMEM);}subsys_initcall(chsc_alloc_sei_area);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];	} *scsc_area;	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);	if (!scsc_area) {	        printk(KERN_WARNING"cio: Was not able to determine available" \		       "CHSCs due to no memory.\n");		return -ENOMEM;	}	scsc_area->request = (struct chsc_header) {		.length = 0x0010,		.code   = 0x0010,	};	result = chsc(scsc_area);	if (result) {		printk(KERN_WARNING"cio: Was not able to determine " \		       "available CHSCs, cc=%i.\n", result);		result = -EIO;		goto exit;	}	if (scsc_area->response.code != 1) {		printk(KERN_WARNING"cio: 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 + -