Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5434da4d authored by Dong Jia Shi's avatar Dong Jia Shi Committed by Cornelia Huck
Browse files

s390: cio: introduce cio_cancel_halt_clear



For future code reuse purpose, this decouples the cio code with
the ccw device specific parts from ccw_device_cancel_halt_clear,
and makes a new common I/O interface named cio_cancel_halt_clear.

Reviewed-by: default avatarPierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: default avatarDong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
Cc: Sebastian Ott <sebott@linux.vnet.ibm.com>
Cc: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Acked-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Message-Id: <20170317031743.40128-2-bjsdjshi@linux.vnet.ibm.com>
[CH: Fix typo]
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
parent 97da3854
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -309,6 +309,65 @@ cio_cancel (struct subchannel *sch)
	}
}

/**
 * cio_cancel_halt_clear - Cancel running I/O by performing cancel, halt
 * and clear ordinally if subchannel is valid.
 * @sch: subchannel on which to perform the cancel_halt_clear operation
 * @iretry: the number of the times remained to retry the next operation
 *
 * This should be called repeatedly since halt/clear are asynchronous
 * operations. We do one try with cio_cancel, three tries with cio_halt,
 * 255 tries with cio_clear. The caller should initialize @iretry with
 * the value 255 for its first call to this, and keep using the same
 * @iretry in the subsequent calls until it gets a non -EBUSY return.
 *
 * Returns 0 if device now idle, -ENODEV for device not operational,
 * -EBUSY if an interrupt is expected (either from halt/clear or from a
 * status pending), and -EIO if out of retries.
 */
int cio_cancel_halt_clear(struct subchannel *sch, int *iretry)
{
	int ret;

	if (cio_update_schib(sch))
		return -ENODEV;
	if (!sch->schib.pmcw.ena)
		/* Not operational -> done. */
		return 0;
	/* Stage 1: cancel io. */
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) &&
	    !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
		if (!scsw_is_tm(&sch->schib.scsw)) {
			ret = cio_cancel(sch);
			if (ret != -EINVAL)
				return ret;
		}
		/*
		 * Cancel io unsuccessful or not applicable (transport mode).
		 * Continue with asynchronous instructions.
		 */
		*iretry = 3;	/* 3 halt retries. */
	}
	/* Stage 2: halt io. */
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
		if (*iretry) {
			*iretry -= 1;
			ret = cio_halt(sch);
			if (ret != -EBUSY)
				return (ret == 0) ? -EBUSY : ret;
		}
		/* Halt io unsuccessful. */
		*iretry = 255;	/* 255 clear retries. */
	}
	/* Stage 3: clear io. */
	if (*iretry) {
		*iretry -= 1;
		ret = cio_clear(sch);
		return (ret == 0) ? -EBUSY : ret;
	}
	/* Function was unsuccessful */
	return -EIO;
}

static void cio_apply_config(struct subchannel *sch, struct schib *schib)
{
+1 −0
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *);
extern int cio_cancel_halt_clear(struct subchannel *, int *);
extern int cio_resume (struct subchannel *);
extern int cio_halt (struct subchannel *);
extern int cio_start (struct subchannel *, struct ccw1 *, __u8);
+8 −46
Original line number Diff line number Diff line
@@ -124,14 +124,6 @@ ccw_device_set_timeout(struct ccw_device *cdev, int expires)
	add_timer(&cdev->private->timer);
}

/*
 * Cancel running i/o. This is called repeatedly since halt/clear are
 * asynchronous operations. We do one try with cio_cancel, two tries
 * with cio_halt, 255 tries with cio_clear. If everythings fails panic.
 * Returns 0 if device now idle, -ENODEV for device not operational and
 * -EBUSY if an interrupt is expected (either from halt/clear or from a
 * status pending).
 */
int
ccw_device_cancel_halt_clear(struct ccw_device *cdev)
{
@@ -139,44 +131,14 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
	int ret;

	sch = to_subchannel(cdev->dev.parent);
	if (cio_update_schib(sch))
		return -ENODEV; 
	if (!sch->schib.pmcw.ena)
		/* Not operational -> done. */
		return 0;
	/* Stage 1: cancel io. */
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) &&
	    !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
		if (!scsw_is_tm(&sch->schib.scsw)) {
			ret = cio_cancel(sch);
			if (ret != -EINVAL)
				return ret;
		}
		/* cancel io unsuccessful or not applicable (transport mode).
		 * Continue with asynchronous instructions. */
		cdev->private->iretry = 3;	/* 3 halt retries. */
	}
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
		/* Stage 2: halt io. */
		if (cdev->private->iretry) {
			cdev->private->iretry--;
			ret = cio_halt(sch);
			if (ret != -EBUSY)
				return (ret == 0) ? -EBUSY : ret;
		}
		/* halt io unsuccessful. */
		cdev->private->iretry = 255;	/* 255 clear retries. */
	}
	/* Stage 3: clear io. */
	if (cdev->private->iretry) {
		cdev->private->iretry--;
		ret = cio_clear (sch);
		return (ret == 0) ? -EBUSY : ret;
	}
	/* Function was unsuccessful */
	ret = cio_cancel_halt_clear(sch, &cdev->private->iretry);

	if (ret == -EIO)
		CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n",
		      cdev->private->dev_id.ssid, cdev->private->dev_id.devno);
	return -EIO;
			      cdev->private->dev_id.ssid,
			      cdev->private->dev_id.devno);

	return ret;
}

void ccw_device_update_sense_data(struct ccw_device *cdev)