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

Commit d23861ff authored by Cornelia Huck's avatar Cornelia Huck Committed by Martin Schwidefsky
Browse files

[S390] cio: Retry internal operations after vary off.



If I/O was running on a just varied off chpid, it will be terminated.
If this was a common I/O layer internal I/O, it needs to be retried.

Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 24cb5b48
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
		cc = cio_clear(sch);
		if (cc == -ENODEV)
			goto out_unreg;
		/* Request retry of internal operation. */
		device_set_intretry(sch);
		/* Call handler. */
		if (sch->driver && sch->driver->termination)
			sch->driver->termination(&sch->dev);
@@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index)
{
	int cc;

	if (!device_is_online(sch))
		/* cio could be doing I/O. */
		return 0;
	cc = stsch(sch->schid, &sch->schib);
	if (cc)
		return 0;
@@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index)
	return 0;
}

static void terminate_internal_io(struct subchannel *sch)
{
	if (cio_clear(sch)) {
		/* Recheck device in case clear failed. */
		sch->lpm = 0;
		if (device_trigger_verify(sch) != 0) {
			if(css_enqueue_subchannel_slow(sch->schid)) {
				css_clear_subchannel_slow_list();
				need_rescan = 1;
			}
		}
		return;
	}
	/* Request retry of internal operation. */
	device_set_intretry(sch);
	/* Call handler. */
	if (sch->driver && sch->driver->termination)
		sch->driver->termination(&sch->dev);
}

static inline void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
@@ -748,10 +767,14 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
		}
		sch->opm &= ~(0x80 >> chp);
		sch->lpm &= ~(0x80 >> chp);
		if (check_for_io_on_path(sch, chp))
		if (check_for_io_on_path(sch, chp)) {
			if (device_is_online(sch))
				/* Path verification is done after killing. */
				device_kill_io(sch);
		else if (!sch->lpm) {
			else
				/* Kill and retry internal I/O. */
				terminate_internal_io(sch);
		} else if (!sch->lpm) {
			if (device_trigger_verify(sch) != 0) {
				if (css_enqueue_subchannel_slow(sch->schid)) {
					css_clear_subchannel_slow_list();
+2 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ struct ccw_device_private {
		unsigned int donotify:1;    /* call notify function */
		unsigned int recog_done:1;  /* dev. recog. complete */
		unsigned int fake_irb:1;    /* deliver faked irb */
		unsigned int intretry:1;    /* retry internal operation */
	} __attribute__((packed)) flags;
	unsigned long intparm;	/* user interruption parameter */
	struct qdio_irq *qdio_data;
@@ -171,6 +172,7 @@ void device_trigger_reprobe(struct subchannel *);
/* Helper functions for vary on/off. */
int device_is_online(struct subchannel *);
void device_kill_io(struct subchannel *);
void device_set_intretry(struct subchannel *sch);
int device_trigger_verify(struct subchannel *sch);

/* Machine check helper function. */
+3 −0
Original line number Diff line number Diff line
@@ -948,6 +948,9 @@ io_subchannel_ioterm(struct device *dev)
	cdev = dev->driver_data;
	if (!cdev)
		return;
	/* Internal I/O will be retried by the interrupt handler. */
	if (cdev->private->flags.intretry)
		return;
	cdev->private->state = DEV_STATE_CLEAR_VERIFY;
	if (cdev->handler)
		cdev->handler(cdev, cdev->private->intparm,
+16 −0
Original line number Diff line number Diff line
@@ -59,6 +59,16 @@ device_set_disconnected(struct subchannel *sch)
	cdev->private->state = DEV_STATE_DISCONNECTED;
}

void device_set_intretry(struct subchannel *sch)
{
	struct ccw_device *cdev;

	cdev = sch->dev.driver_data;
	if (!cdev)
		return;
	cdev->private->flags.intretry = 1;
}

int device_trigger_verify(struct subchannel *sch)
{
	struct ccw_device *cdev;
@@ -904,6 +914,12 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
	 * had killed the original request.
	 */
	if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
		/* Retry Basic Sense if requested. */
		if (cdev->private->flags.intretry) {
			cdev->private->flags.intretry = 0;
			ccw_device_do_sense(cdev, irb);
			return;
		}
		cdev->private->flags.dosense = 0;
		memset(&cdev->private->irb, 0, sizeof(struct irb));
		ccw_device_accumulate_irb(cdev, irb);
+9 −1
Original line number Diff line number Diff line
@@ -191,6 +191,8 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
		if ((sch->opm & cdev->private->imask) != 0 &&
		    cdev->private->iretry > 0) {
			cdev->private->iretry--;
			/* Reset internal retry indication. */
			cdev->private->flags.intretry = 0;
			ret = cio_start (sch, cdev->private->iccws,
					 cdev->private->imask);
			/* ret is 0, -EBUSY, -EACCES or -ENODEV */
@@ -237,8 +239,14 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
		return 0; /* Success */
	}
	/* Check the error cases. */
	if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
	if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
		/* Retry Sense ID if requested. */
		if (cdev->private->flags.intretry) {
			cdev->private->flags.intretry = 0;
			return -EAGAIN;
		}
		return -ETIME;
	}
	if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) {
		/*
		 * if the device doesn't support the SenseID
Loading