Пример #1
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)
{
	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;
	}
}
Пример #2
0
/*
 * 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;
	}
}
Пример #3
0
/**
 * cio_disable_subchannel - disable a subchannel.
 * @sch: subchannel to disable
 */
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;
}
Пример #4
0
/*
 * 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;
	}
}
Пример #5
0
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;
	}
}
Пример #6
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;
}
Пример #7
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)
{
	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;
}
Пример #8
0
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;
	}
}
Пример #9
0
/*
 * 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;
	}
}
Пример #10
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 */
{
	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));
	/* sch is always under 2G. */
	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
	/*
	 * 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 */
	CIO_HEX_EVENT(5, &ccode, sizeof(ccode));

	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;
	}
}
Пример #11
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;
	}
}
Пример #12
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;
}
Пример #13
0
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;
	}
Пример #14
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;
	}
Пример #15
0
static inline int
cio_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);
}
Пример #16
0
static int
cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
{
	char dbf_text[15];

	if (lpm != 0)
		sch->lpm &= ~lpm;
	else
		sch->lpm = 0;

	stsch (sch->schid, &sch->schib);

	CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
		      "subchannel 0.%x.%04x!\n", sch->schid.ssid,
		      sch->schid.sch_no);
	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
	CIO_TRACE_EVENT(0, dbf_text);
	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));

	return (sch->lpm ? -EACCES : -ENODEV);
}
Пример #17
0
/*
 * Check for any kind of channel or interface control check but don't
 * issue the message for the console device
 */
static inline void
ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
{
	if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
				 SCHN_STAT_CHN_CTRL_CHK |
				 SCHN_STAT_INTF_CTRL_CHK)))
		return;
	CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
		      "received"
		      " ... device %04x on subchannel 0.%x.%04x, dev_stat "
		      ": %02X sch_stat : %02X\n",
		      cdev->private->dev_id.devno, cdev->private->schid.ssid,
		      cdev->private->schid.sch_no,
		      irb->scsw.dstat, irb->scsw.cstat);

	if (irb->scsw.cc != 3) {
		char dbf_text[15];

		sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no);
		CIO_TRACE_EVENT(0, dbf_text);
		CIO_HEX_EVENT(0, irb, sizeof (struct irb));
	}
Пример #18
0
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));

	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:		
		return -ENODEV;
	}
}
Пример #19
0
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:
		return -ENODEV;
	}
}