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

📄 cio.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  drivers/s390/cio/cio.c *   S/390 common I/O routines -- low level i/o calls *   $Revision: 1.123 $ * *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, *			      IBM Corporation *    Author(s): Ingo Adlung (adlung@de.ibm.com) *		 Cornelia Huck (cohuck@de.ibm.com) *		 Arnd Bergmann (arndb@de.ibm.com) *		 Martin Schwidefsky (schwidefsky@de.ibm.com) */#include <linux/module.h>#include <linux/config.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/kernel_stat.h>#include <asm/hardirq.h>#include <asm/cio.h>#include <asm/delay.h>#include <asm/irq.h>#include "airq.h"#include "cio.h"#include "css.h"#include "chsc.h"#include "ioasm.h"#include "blacklist.h"#include "cio_debug.h"debug_info_t *cio_debug_msg_id;debug_info_t *cio_debug_trace_id;debug_info_t *cio_debug_crw_id;int cio_show_msg;static int __initcio_setup (char *parm){	if (!strcmp (parm, "yes"))		cio_show_msg = 1;	else if (!strcmp (parm, "no"))		cio_show_msg = 0;	else		printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",			parm);	return 1;}__setup ("cio_msg=", cio_setup);/* * Function: cio_debug_init * Initializes three debug logs (under /proc/s390dbf) for common I/O: * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on * - cio_trace logs the calling of different functions * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW */static int __initcio_debug_init (void){	cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long));	if (!cio_debug_msg_id)		goto out_unregister;	debug_register_view (cio_debug_msg_id, &debug_sprintf_view);	debug_set_level (cio_debug_msg_id, 2);	cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);	if (!cio_debug_trace_id)		goto out_unregister;	debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);	debug_set_level (cio_debug_trace_id, 2);	cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long));	if (!cio_debug_crw_id)		goto out_unregister;	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);	debug_set_level (cio_debug_crw_id, 2);	pr_debug("debugging initialized\n");	return 0;out_unregister:	if (cio_debug_msg_id)		debug_unregister (cio_debug_msg_id);	if (cio_debug_trace_id)		debug_unregister (cio_debug_trace_id);	if (cio_debug_crw_id)		debug_unregister (cio_debug_crw_id);	pr_debug("could not initialize debugging\n");	return -1;}arch_initcall (cio_debug_init);intcio_set_options (struct subchannel *sch, int flags){       sch->options.suspend = (flags & DOIO_ALLOW_SUSPEND) != 0;       sch->options.prefetch = (flags & DOIO_DENY_PREFETCH) != 0;       sch->options.inter = (flags & DOIO_SUPPRESS_INTER) != 0;       return 0;}/* FIXME: who wants to use this? */intcio_get_options (struct subchannel *sch){       int flags;       flags = 0;       if (sch->options.suspend)		flags |= DOIO_ALLOW_SUSPEND;       if (sch->options.prefetch)		flags |= DOIO_DENY_PREFETCH;       if (sch->options.inter)		flags |= DOIO_SUPPRESS_INTER;       return flags;}/* * Use tpi to get a pending interrupt, call the interrupt handler and * return a pointer to the subchannel structure. */static inline intcio_tpi(void){	struct tpi_info *tpi_info;	struct subchannel *sch;	struct irb *irb;	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;	if (tpi (NULL) != 1)		return 0;	irb = (struct irb *) __LC_IRB;	/* Store interrupt response block to lowcore. */	if (tsch (tpi_info->irq, irb) != 0)		/* Not status pending or not operational. */		return 1;	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;	if (!sch)		return 1;	irq_enter ();	spin_lock(&sch->lock);	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));	if (sch->driver && sch->driver->irq)		sch->driver->irq(&sch->dev);	spin_unlock(&sch->lock);	irq_exit ();	return 1;}static inline intcio_start_handle_notoper(struct subchannel *sch, __u8 lpm){	char dbf_text[15];	if (lpm != 0)		sch->lpm &= ~lpm;	else		sch->lpm = 0;	stsch (sch->irq, &sch->schib);	CIO_MSG_EVENT(0, "cio_start: 'not oper' status for "		      "subchannel %04x!\n", sch->irq);	sprintf(dbf_text, "no%s", sch->dev.bus_id);	CIO_TRACE_EVENT(0, dbf_text);	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));	return (sch->lpm ? -EACCES : -ENODEV);}intcio_start (struct subchannel *sch,	/* subchannel structure */	   struct ccw1 * cpa,		/* logical channel prog addr */	   __u8 lpm)			/* logical path mask */{	char dbf_txt[15];	int ccode;	CIO_TRACE_EVENT (4, "stIO");	CIO_TRACE_EVENT (4, sch->dev.bus_id);	/* sch is always under 2G. */	sch->orb.intparm = (__u32)(unsigned long)sch;	sch->orb.fmt = 1;	sch->orb.pfch = sch->options.prefetch == 0;	sch->orb.spnd = sch->options.suspend;	sch->orb.ssic = sch->options.suspend && sch->options.inter;	sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm;#ifdef CONFIG_ARCH_S390X	/*	 * for 64 bit we always support 64 bit IDAWs with 4k page size only	 */	sch->orb.c64 = 1;	sch->orb.i2k = 0;#endif	sch->orb.cpa = (__u32) __pa (cpa);	/*	 * Issue "Start subchannel" and process condition code	 */	ccode = ssch (sch->irq, &sch->orb);	sprintf (dbf_txt, "ccode:%d", ccode);	CIO_TRACE_EVENT (4, dbf_txt);	switch (ccode) {	case 0:		/*		 * initialize device status information		 */		sch->schib.scsw.actl |= SCSW_ACTL_START_PEND;		return 0;	case 1:		/* status pending */	case 2:		/* busy */		return -EBUSY;	default:		/* device/path not operational */		return cio_start_handle_notoper(sch, lpm);	}}/* * resume suspended I/O operation */intcio_resume (struct subchannel *sch){	char dbf_txt[15];	int ccode;	CIO_TRACE_EVENT (4, "resIO");	CIO_TRACE_EVENT (4, sch->dev.bus_id);	ccode = rsch (sch->irq);	sprintf (dbf_txt, "ccode:%d", ccode);	CIO_TRACE_EVENT (4, dbf_txt);	switch (ccode) {	case 0:		sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND;		return 0;	case 1:		return -EBUSY;	case 2:		return -EINVAL;	default:		/*		 * useless to wait for request completion		 *  as device is no longer operational !		 */		return -ENODEV;	}}/* * halt I/O operation */intcio_halt(struct subchannel *sch){	char dbf_txt[15];	int ccode;	if (!sch)		return -ENODEV;	CIO_TRACE_EVENT (2, "haltIO");	CIO_TRACE_EVENT (2, sch->dev.bus_id);	/*	 * Issue "Halt subchannel" and process condition code	 */	ccode = hsch (sch->irq);	sprintf (dbf_txt, "ccode:%d", ccode);	CIO_TRACE_EVENT (2, dbf_txt);	switch (ccode) {	case 0:		sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND;		return 0;	case 1:		/* status pending */	case 2:		/* busy */		return -EBUSY;	default:		/* device not operational */		return -ENODEV;	}}/* * Clear I/O operation */intcio_clear(struct subchannel *sch){	char dbf_txt[15];	int ccode;	if (!sch)		return -ENODEV;	CIO_TRACE_EVENT (2, "clearIO");	CIO_TRACE_EVENT (2, sch->dev.bus_id);	/*	 * Issue "Clear subchannel" and process condition code	 */	ccode = csch (sch->irq);	sprintf (dbf_txt, "ccode:%d", ccode);	CIO_TRACE_EVENT (2, dbf_txt);	switch (ccode) {	case 0:		sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND;		return 0;	default:		/* device not operational */		return -ENODEV;	}}/* * Function: cio_cancel * Issues a "Cancel Subchannel" on the specified subchannel * Note: We don't need any fancy intparms and flags here *	 since xsch is executed synchronously. * Only for common I/O internal use as for now. */intcio_cancel (struct subchannel *sch){	char dbf_txt[15];	int ccode;	if (!sch)		return -ENODEV;	CIO_TRACE_EVENT (2, "cancelIO");	CIO_TRACE_EVENT (2, sch->dev.bus_id);	ccode = xsch (sch->irq);	sprintf (dbf_txt, "ccode:%d", ccode);	CIO_TRACE_EVENT (2, dbf_txt);	switch (ccode) {	case 0:		/* success */		/* Update information in scsw. */		stsch (sch->irq, &sch->schib);		return 0;	case 1:		/* status pending */		return -EBUSY;	case 2:		/* not applicable */		return -EINVAL;	default:	/* not oper */		return -ENODEV;	}}/* * Function: cio_modify * Issues a "Modify Subchannel" on the specified subchannel */intcio_modify (struct subchannel *sch){	int ccode, retry, ret;	ret = 0;	for (retry = 0; retry < 5; retry++) {		ccode = msch_err (sch->irq, &sch->schib);		if (ccode < 0)	/* -EIO if msch gets a program check. */			return ccode;		switch (ccode) {		case 0: /* successfull */			return 0;		case 1:	/* status pending */			return -EBUSY;		case 2:	/* busy */			udelay (100);	/* allow for recovery */			ret = -EBUSY;			break;		case 3:	/* not operational */			return -ENODEV;		}	}	return ret;}/* * Enable subchannel. */intcio_enable_subchannel (struct subchannel *sch, unsigned int isc){	char dbf_txt[15];	int ccode;	int retry;	int ret;	CIO_TRACE_EVENT (2, "ensch");	CIO_TRACE_EVENT (2, sch->dev.bus_id);	ccode = stsch (sch->irq, &sch->schib);	if (ccode)		return -ENODEV;	sch->schib.pmcw.ena = 1;	sch->schib.pmcw.isc = isc;	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;	for (retry = 5, ret = 0; retry > 0; retry--) {		ret = cio_modify(sch);		if (ret == -ENODEV)			break;		if (ret == -EIO)			/*			 * Got a program check in cio_modify. Try without

⌨️ 快捷键说明

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