int
cio_cancel (struct subchannel *sch)
{
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT(2, "cancelIO");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	ccode = xsch (sch->schid);

	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:		
		
		if (cio_update_schib(sch))
			return -ENODEV;
		return 0;
	case 1:		
		return -EBUSY;
	case 2:		
		return -EINVAL;
	default:	
		return -ENODEV;
	}
}
int cio_disable_subchannel(struct subchannel *sch)
{
	int retry;
	int ret;

	CIO_TRACE_EVENT(2, "dissch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return 0;
	if (cio_update_schib(sch))
		return -ENODEV;

	sch->config.ena = 0;

	for (retry = 0; retry < 3; retry++) {
		ret = cio_commit_config(sch);
		if (ret == -EBUSY) {
			struct irb irb;
			if (tsch(sch->schid, &irb) != 0)
				break;
		} else
			break;
	}
	CIO_HEX_EVENT(2, &ret, sizeof(ret));
	return ret;
}
int
cio_halt(struct subchannel *sch)
{
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT(2, "haltIO");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	ccode = hsch (sch->schid);

	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
		return 0;
	case 1:		
	case 2:		
		return -EBUSY;
	default:		
		return -ENODEV;
	}
}
Example #4
0
/*
 * resume suspended I/O operation
 */
int
cio_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;
	}
}
Example #5
0
File: cio.c Project: IDM350/linux
/**
 * cio_enable_subchannel - enable a subchannel.
 * @sch: subchannel to be enabled
 * @intparm: interruption parameter to set
 */
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
	int ret;

	CIO_TRACE_EVENT(2, "ensch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return -EINVAL;
	if (cio_update_schib(sch))
		return -ENODEV;

	sch->config.ena = 1;
	sch->config.isc = sch->isc;
	sch->config.intparm = intparm;

	ret = cio_commit_config(sch);
	if (ret == -EIO) {
		/*
		 * Got a program check in msch. Try without
		 * the concurrent sense bit the next time.
		 */
		sch->config.csense = 0;
		ret = cio_commit_config(sch);
	}
	CIO_HEX_EVENT(2, &ret, sizeof(ret));
	return ret;
}
Example #6
0
/*
 * halt I/O operation
 */
int
cio_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;
	}
}
Example #7
0
File: cio.c Project: IDM350/linux
/*
 * Clear I/O operation
 */
int
cio_clear(struct subchannel *sch)
{
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT(2, "clearIO");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	/*
	 * Issue "Clear subchannel" and process condition code
	 */
	ccode = csch (sch->schid);

	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
		return 0;
	default:		/* device not operational */
		return -ENODEV;
	}
}
Example #8
0
File: cio.c Project: IDM350/linux
/*
 * 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.
 */
int
cio_cancel (struct subchannel *sch)
{
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT(2, "cancelIO");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	ccode = xsch (sch->schid);

	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:		/* success */
		/* Update information in scsw. */
		if (cio_update_schib(sch))
			return -ENODEV;
		return 0;
	case 1:		/* status pending */
		return -EBUSY;
	case 2:		/* not applicable */
		return -EINVAL;
	default:	/* not oper */
		return -ENODEV;
	}
}
Example #9
0
File: cio.c Project: IDM350/linux
/*
 * halt I/O operation
 */
int
cio_halt(struct subchannel *sch)
{
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT(2, "haltIO");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	/*
	 * Issue "Halt subchannel" and process condition code
	 */
	ccode = hsch (sch->schid);

	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
		return 0;
	case 1:		/* status pending */
	case 2:		/* busy */
		return -EBUSY;
	default:		/* device not operational */
		return -ENODEV;
	}
}
Example #10
0
File: cio.c Project: IDM350/linux
/*
 * resume suspended I/O operation
 */
int
cio_resume (struct subchannel *sch)
{
	int ccode;

	CIO_TRACE_EVENT(4, "resIO");
	CIO_TRACE_EVENT(4, dev_name(&sch->dev));

	ccode = rsch (sch->schid);

	CIO_HEX_EVENT(4, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:
		sch->schib.scsw.cmd.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;
	}
}
Example #11
0
/*
 * 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.
 */
int
cio_cancel (struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	if (!sch)
		return -ENODEV;

	sprintf (dbf_txt, "cancelIO%x", sch->irq);
	CIO_TRACE_EVENT (2, dbf_txt);

	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;
	}
}
Example #12
0
/*
 * Clear I/O operation
 */
int
cio_clear(struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	if (!sch)
		return -ENODEV;

	sprintf (dbf_txt, "clearIO%x", sch->irq);
	CIO_TRACE_EVENT (2, dbf_txt);

	/*
	 * 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;
	}
}
Example #13
0
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
	int retry;
	int ret;

	CIO_TRACE_EVENT(2, "ensch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return -EINVAL;
	if (cio_update_schib(sch))
		return -ENODEV;

	sch->config.ena = 1;
	sch->config.isc = sch->isc;
	sch->config.intparm = intparm;

	for (retry = 0; retry < 3; retry++) {
		ret = cio_commit_config(sch);
		if (ret == -EIO) {
			sch->config.csense = 0;
		} else if (ret == -EBUSY) {
			struct irb irb;
			if (tsch(sch->schid, &irb) != 0)
				break;
		} else
			break;
	}
	CIO_HEX_EVENT(2, &ret, sizeof(ret));
	return ret;
}
Example #14
0
int
cio_start_key (struct subchannel *sch,	/* subchannel structure */
	       struct ccw1 * cpa,	/* logical channel prog addr */
	       __u8 lpm,		/* logical path mask */
	       __u8 key)                /* storage key */
{
	char dbf_txt[15];
	int ccode;
	union orb *orb;

	CIO_TRACE_EVENT(4, "stIO");
	CIO_TRACE_EVENT(4, dev_name(&sch->dev));

	orb = &to_io_private(sch)->orb;
	memset(orb, 0, sizeof(union orb));
	/* sch is always under 2G. */
	orb->cmd.intparm = (u32)(addr_t)sch;
	orb->cmd.fmt = 1;

	orb->cmd.pfch = sch->options.prefetch == 0;
	orb->cmd.spnd = sch->options.suspend;
	orb->cmd.ssic = sch->options.suspend && sch->options.inter;
	orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
	/*
	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
	 */
	orb->cmd.c64 = 1;
	orb->cmd.i2k = 0;
#endif
	orb->cmd.key = key >> 4;
	/* issue "Start Subchannel" */
	orb->cmd.cpa = (__u32) __pa(cpa);
	ccode = ssch(sch->schid, orb);

	/* process condition code */
	sprintf(dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT(4, dbf_txt);

	switch (ccode) {
	case 0:
		/*
		 * initialize device status information
		 */
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
		return 0;
	case 1:		/* status pending */
	case 2:		/* busy */
		return -EBUSY;
	case 3:		/* device/path not operational */
		return cio_start_handle_notoper(sch, lpm);
	default:
		return ccode;
	}
}
Example #15
0
int
cio_start_key (struct subchannel *sch,	/* subchannel structure */
	       struct ccw1 * cpa,	/* logical channel prog addr */
	       __u8 lpm,		/* logical path mask */
	       __u8 key)                /* storage key */
{
	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.key = key >> 4;
	/* issue "Start Subchannel" */
	sch->orb.cpa = (__u32) __pa (cpa);
	ccode = ssch (sch->irq, &sch->orb);

	/* process condition code */
	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);
	}
}
Example #16
0
/**
 * s390_register_adapter_interrupt() - register adapter interrupt handler
 * @handler: adapter handler to be registered
 * @drv_data: driver data passed with each call to the handler
 * @isc: isc for which the handler should be called
 *
 * Returns:
 *  Pointer to the indicator to be used on success
 *  ERR_PTR() if registration failed
 */
void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
				      void *drv_data, u8 isc)
{
	struct airq_t *airq;
	char dbf_txt[16];
	int ret;

	if (isc > MAX_ISC)
		return ERR_PTR(-EINVAL);
	airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
	if (!airq) {
		ret = -ENOMEM;
		goto out;
	}
	airq->handler = handler;
	airq->drv_data = drv_data;

	ret = register_airq(airq, isc);
out:
	snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
	CIO_TRACE_EVENT(4, dbf_txt);
	if (ret < 0) {
		kfree(airq);
		return ERR_PTR(ret);
	} else
		return &indicators[isc].byte[ret];
}
/*
 * Function: s390_redo_validation
 * Look for no longer blacklisted devices
 * FIXME: there must be a better way to do this */
static inline void
s390_redo_validation (void)
{
	unsigned int irq;

	CIO_TRACE_EVENT (0, "redoval");
	for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) {
		int ret;
		struct subchannel *sch;

		sch = get_subchannel_by_schid(irq);
		if (sch) {
			/* Already known. */
			put_device(&sch->dev);
			continue;
		}
		ret = css_probe_device(irq);
		if (ret == -ENXIO)
			break; /* We're through. */
		if (ret == -ENOMEM)
			/*
			 * Stop validation for now. Bad, but no need for a
			 * panic.
			 */
			break;
	}
}
Example #18
0
/*
 * Function: s390_vary_chpid
 * Varies the specified chpid online or offline
 */
static int s390_vary_chpid(struct chp_id chpid, int on)
{
	char dbf_text[15];
	int status;

	sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
		chpid.id);
	CIO_TRACE_EVENT(2, dbf_text);

	status = chp_get_status(chpid);
	if (status < 0) {
		printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
		       chpid.cssid, chpid.id);
		return -EINVAL;
	}

	if (!on && !status) {
		printk(KERN_ERR "chpid %x.%02x is already offline\n",
		       chpid.cssid, chpid.id);
		return -EINVAL;
	}

	set_chp_logically_online(chpid, on);
	chsc_chp_vary(chpid, on);
	return 0;
}
Example #19
0
int
cio_start_key (struct subchannel *sch,	
	       struct ccw1 * cpa,	
	       __u8 lpm,		
	       __u8 key)                
{
	struct io_subchannel_private *priv = to_io_private(sch);
	union orb *orb = &priv->orb;
	int ccode;

	CIO_TRACE_EVENT(5, "stIO");
	CIO_TRACE_EVENT(5, dev_name(&sch->dev));

	memset(orb, 0, sizeof(union orb));
	
	orb->cmd.intparm = (u32)(addr_t)sch;
	orb->cmd.fmt = 1;

	orb->cmd.pfch = priv->options.prefetch == 0;
	orb->cmd.spnd = priv->options.suspend;
	orb->cmd.ssic = priv->options.suspend && priv->options.inter;
	orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
	orb->cmd.c64 = 1;
	orb->cmd.i2k = 0;
#endif
	orb->cmd.key = key >> 4;
	
	orb->cmd.cpa = (__u32) __pa(cpa);
	ccode = ssch(sch->schid, orb);

	
	CIO_HEX_EVENT(5, &ccode, sizeof(ccode));

	switch (ccode) {
	case 0:
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
		return 0;
	case 1:		
	case 2:		
		return -EBUSY;
	case 3:		
		return cio_start_handle_notoper(sch, lpm);
	default:
		return ccode;
	}
}
Example #20
0
void
do_adapter_IO (void)
{
	CIO_TRACE_EVENT (6, "doaio");

	if (adapter_handler)
		(*adapter_handler) ();
}
Example #21
0
File: cio.c Project: AllenDou/linux
/**
 * cio_validate_subchannel - basic validation of subchannel
 * @sch: subchannel structure to be filled out
 * @schid: subchannel id
 *
 * Find out subchannel type and initialize struct subchannel.
 * Return codes:
 *   0 on success
 *   -ENXIO for non-defined subchannels
 *   -ENODEV for invalid subchannels or blacklisted devices
 *   -EIO for subchannels in an invalid subchannel set
 */
int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
{
	char dbf_txt[15];
	int ccode;
	int err;

	sprintf(dbf_txt, "valsch%x", schid.sch_no);
	CIO_TRACE_EVENT(4, dbf_txt);

	/* Nuke all fields. */
	memset(sch, 0, sizeof(struct subchannel));

	sch->schid = schid;
	if (cio_is_console(schid)) {
		sch->lock = cio_get_console_lock();
	} else {
		err = cio_create_sch_lock(sch);
		if (err)
			goto out;
	}
	mutex_init(&sch->reg_mutex);

	/*
	 * The first subchannel that is not-operational (ccode==3)
	 *  indicates that there aren't any more devices available.
	 * If stsch gets an exception, it means the current subchannel set
	 *  is not valid.
	 */
	ccode = stsch_err (schid, &sch->schib);
	if (ccode) {
		err = (ccode == 3) ? -ENXIO : ccode;
		goto out;
	}
	/* Copy subchannel type from path management control word. */
	sch->st = sch->schib.pmcw.st;

	switch (sch->st) {
	case SUBCHANNEL_TYPE_IO:
		err = cio_validate_io_subchannel(sch);
		break;
	case SUBCHANNEL_TYPE_MSG:
		err = cio_validate_msg_subchannel(sch);
		break;
	default:
		err = 0;
	}
	if (err)
		goto out;

	CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
		      sch->schid.ssid, sch->schid.sch_no, sch->st);
	return 0;
out:
	if (!cio_is_console(schid))
		kfree(sch->lock);
	sch->lock = NULL;
	return err;
}
Example #22
0
/**
 * cio_disable_subchannel - disable a subchannel.
 * @sch: subchannel to disable
 */
int cio_disable_subchannel(struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

	CIO_TRACE_EVENT (2, "dissch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return 0;
	ccode = stsch (sch->schid, &sch->schib);
	if (ccode == 3)		/* Not operational. */
		return -ENODEV;

	if (scsw_actl(&sch->schib.scsw) != 0)
		/*
		 * the disable function must not be called while there are
		 *  requests pending for completion !
		 */
		return -EBUSY;

	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 0;
		ret = cio_modify(sch);
		if (ret == -ENODEV)
			break;
		if (ret == -EBUSY)
			/*
			 * The subchannel is busy or status pending.
			 * We'll disable when the next interrupt was delivered
			 * via the state machine.
			 */
			break;
		if (ret == 0) {
			stsch (sch->schid, &sch->schib);
			if (!sch->schib.pmcw.ena)
				break;
		}
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (2, dbf_txt);
	return ret;
}
Example #23
0
/**
 * cio_disable_subchannel - disable a subchannel.
 * @sch: subchannel to disable
 */
int cio_disable_subchannel(struct subchannel *sch)
{
	int ret;

	CIO_TRACE_EVENT(2, "dissch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return 0;
	if (cio_update_schib(sch))
		return -ENODEV;

	sch->config.ena = 0;
	ret = cio_commit_config(sch);

	CIO_HEX_EVENT(2, &ret, sizeof(ret));
	return ret;
}
Example #24
0
/**
 * cio_enable_subchannel - enable a subchannel.
 * @sch: subchannel to be enabled
 * @intparm: interruption parameter to set
 */
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

	CIO_TRACE_EVENT (2, "ensch");
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));

	if (sch_is_pseudo_sch(sch))
		return -EINVAL;
	ccode = stsch (sch->schid, &sch->schib);
	if (ccode)
		return -ENODEV;

	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 1;
		sch->schib.pmcw.isc = sch->isc;
		sch->schib.pmcw.intparm = intparm;
		ret = cio_modify(sch);
		if (ret == -ENODEV)
			break;
		if (ret == -EIO)
			/*
			 * Got a program check in cio_modify. Try without
			 * the concurrent sense bit the next time.
			 */
			sch->schib.pmcw.csense = 0;
		if (ret == 0) {
			stsch (sch->schid, &sch->schib);
			if (sch->schib.pmcw.ena)
				break;
		}
		if (ret == -EBUSY) {
			struct irb irb;
			if (tsch(sch->schid, &irb) != 0)
				break;
		}
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (2, dbf_txt);
	return ret;
}
Example #25
0
/*
 * Enable subchannel.
 */
int
cio_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;

	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 1;
		sch->schib.pmcw.isc = isc;
		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
		ret = cio_modify(sch);
		if (ret == -ENODEV)
			break;
		if (ret == -EIO)
			/*
			 * Got a program check in cio_modify. Try without
			 * the concurrent sense bit the next time.
			 */
			sch->schib.pmcw.csense = 0;
		if (ret == 0) {
			stsch (sch->irq, &sch->schib);
			if (sch->schib.pmcw.ena)
				break;
		}
		if (ret == -EBUSY) {
			struct irb irb;
			if (tsch(sch->irq, &irb) != 0)
				break;
		}
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (2, dbf_txt);
	return ret;
}
static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
{
	struct irb *irb = &cdev->private->irb;
	struct cmd_scsw *scsw = &irb->scsw.cmd;
	enum uc_todo todo;

	
	if (ccw_device_accumulate_and_sense(cdev, lcirb))
		return IO_RUNNING;
	
	if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
		return IO_KILLED;
	
	if (scsw->cc == 3 || scsw->pno)
		return IO_PATH_ERROR;
	
	if (irb->esw.esw0.erw.cons) {
		CIO_TRACE_EVENT(2, "sensedata");
		CIO_HEX_EVENT(2, &cdev->private->dev_id,
			      sizeof(struct ccw_dev_id));
		CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
		
		if (irb->ecw[0] & SNS0_CMD_REJECT)
			return IO_REJECTED;
		
		if (cdev->drv && cdev->drv->uc_handler) {
			todo = cdev->drv->uc_handler(cdev, lcirb);
			CIO_TRACE_EVENT(2, "uc_response");
			CIO_HEX_EVENT(2, &todo, sizeof(todo));
			switch (todo) {
			case UC_TODO_RETRY:
				return IO_STATUS_ERROR;
			case UC_TODO_RETRY_ON_NEW_PATH:
				return IO_PATH_ERROR;
			case UC_TODO_STOP:
				return IO_REJECTED;
			default:
				return IO_STATUS_ERROR;
			}
		}
		
		return IO_STATUS_ERROR;
	}
Example #27
0
/*
 * Return the status of the internal I/O started on the specified ccw device.
 * Perform BASIC SENSE if required.
 */
static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
{
	struct irb *irb = &cdev->private->irb;
	struct cmd_scsw *scsw = &irb->scsw.cmd;
	enum uc_todo todo;

	/* Perform BASIC SENSE if needed. */
	if (ccw_device_accumulate_and_sense(cdev, lcirb))
		return IO_RUNNING;
	/* Check for halt/clear interrupt. */
	if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
		return IO_KILLED;
	/* Check for path error. */
	if (scsw->cc == 3 || scsw->pno)
		return IO_PATH_ERROR;
	/* Handle BASIC SENSE data. */
	if (irb->esw.esw0.erw.cons) {
		CIO_TRACE_EVENT(2, "sensedata");
		CIO_HEX_EVENT(2, &cdev->private->dev_id,
			      sizeof(struct ccw_dev_id));
		CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
		/* Check for command reject. */
		if (irb->ecw[0] & SNS0_CMD_REJECT)
			return IO_REJECTED;
		/* Ask the driver what to do */
		if (cdev->drv && cdev->drv->uc_handler) {
			todo = cdev->drv->uc_handler(cdev, lcirb);
			CIO_TRACE_EVENT(2, "uc_response");
			CIO_HEX_EVENT(2, &todo, sizeof(todo));
			switch (todo) {
			case UC_TODO_RETRY:
				return IO_STATUS_ERROR;
			case UC_TODO_RETRY_ON_NEW_PATH:
				return IO_PATH_ERROR;
			case UC_TODO_STOP:
				return IO_REJECTED;
			default:
				return IO_STATUS_ERROR;
			}
		}
		/* Assume that unexpected SENSE data implies an error. */
		return IO_STATUS_ERROR;
	}
Example #28
0
int
s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
{
	int ret;
	char dbf_txt[15];

	CIO_TRACE_EVENT (4, "urgaint");

	if (handler == NULL)
		ret = -EINVAL;
	else {
		adapter_handler = NULL;
		synchronize_sched();  /* Allow interrupts to complete. */
		ret = 0;
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (4, dbf_txt);

	return ret;
}
Example #29
0
/*
 * register for adapter interrupts
 *
 * With HiperSockets the zSeries architecture provides for
 *  means of adapter interrups, pseudo I/O interrupts that are
 *  not tied to an I/O subchannel, but to an adapter. However,
 *  it doesn't disclose the info how to enable/disable them, but
 *  to recognize them only. Perhaps we should consider them
 *  being shared interrupts, and thus build a linked list
 *  of adapter handlers ... to be evaluated ...
 */
int
s390_register_adapter_interrupt (adapter_int_handler_t handler)
{
	int ret;
	char dbf_txt[15];

	CIO_TRACE_EVENT (4, "rgaint");

	if (handler == NULL)
		ret = -EINVAL;
	else
		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
	if (!ret)
		synchronize_sched();  /* Allow interrupts to complete. */

	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (4, dbf_txt);

	return ret;
}
Example #30
0
int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
{
	char dbf_txt[15];
	int ccode;
	int err;

	sprintf(dbf_txt, "valsch%x", schid.sch_no);
	CIO_TRACE_EVENT(4, dbf_txt);

	
	memset(sch, 0, sizeof(struct subchannel));

	sch->schid = schid;
	if (cio_is_console(schid)) {
		sch->lock = cio_get_console_lock();
	} else {
		err = cio_create_sch_lock(sch);
		if (err)
			goto out;
	}
	mutex_init(&sch->reg_mutex);

	ccode = stsch_err (schid, &sch->schib);
	if (ccode) {
		err = (ccode == 3) ? -ENXIO : ccode;
		goto out;
	}
	
	sch->st = sch->schib.pmcw.st;

	switch (sch->st) {
	case SUBCHANNEL_TYPE_IO:
		err = cio_validate_io_subchannel(sch);
		break;
	case SUBCHANNEL_TYPE_MSG:
		err = cio_validate_msg_subchannel(sch);
		break;
	default:
		err = 0;
	}
	if (err)
		goto out;

	CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
		      sch->schid.ssid, sch->schid.sch_no, sch->st);
	return 0;
out:
	if (!cio_is_console(schid))
		kfree(sch->lock);
	sch->lock = NULL;
	return err;
}