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

Commit 387b734f authored by Stefan Bader's avatar Stefan Bader Committed by Martin Schwidefsky
Browse files

[S390] cio: Re-start path verification after aborting internal I/O.



Path verification triggered by changes to the available CHPIDs will be
interrupted by another change but not re-started. This results in an
invalid path mask.
To solve this make sure to completely re-start path verification when
changing the available paths.

Signed-off-by: default avatarStefan Bader <shbader@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent cfbe9bb2
Loading
Loading
Loading
Loading
+54 −54
Original line number Original line Diff line number Diff line
@@ -178,6 +178,38 @@ css_get_ssd_info(struct subchannel *sch)
	return ret;
	return ret;
}
}


static int check_for_io_on_path(struct subchannel *sch, int mask)
{
	int cc;

	cc = stsch(sch->schid, &sch->schib);
	if (cc)
		return 0;
	if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask)
		return 1;
	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 int
static int
s390_subchannel_remove_chpid(struct device *dev, void *data)
s390_subchannel_remove_chpid(struct device *dev, void *data)
{
{
@@ -208,37 +240,33 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
	if (sch->schib.pmcw.pim == 0x80)
	if (sch->schib.pmcw.pim == 0x80)
		goto out_unreg;
		goto out_unreg;


	if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
	if (check_for_io_on_path(sch, mask)) {
	    (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
		if (device_is_online(sch))
	    (sch->schib.pmcw.lpum == mask)) {
			device_kill_io(sch);
		int cc;
		else {

			terminate_internal_io(sch);
		cc = cio_clear(sch);
			/* Re-start path verification. */
		if (cc == -ENODEV)
			if (sch->driver && sch->driver->verify)
			goto out_unreg;
				sch->driver->verify(&sch->dev);
		/* Request retry of internal operation. */
		device_set_intretry(sch);
		/* Call handler. */
		if (sch->driver && sch->driver->termination)
			sch->driver->termination(&sch->dev);
		goto out_unlock;
		}
		}

	} else {
		/* trigger path verification. */
		/* trigger path verification. */
		if (sch->driver && sch->driver->verify)
		if (sch->driver && sch->driver->verify)
			sch->driver->verify(&sch->dev);
			sch->driver->verify(&sch->dev);
		else if (sch->lpm == mask)
		else if (sch->lpm == mask)
			goto out_unreg;
			goto out_unreg;
out_unlock:
	}

	spin_unlock_irq(sch->lock);
	spin_unlock_irq(sch->lock);
	return 0;
	return 0;

out_unreg:
out_unreg:
	spin_unlock_irq(sch->lock);
	sch->lpm = 0;
	sch->lpm = 0;
	if (css_enqueue_subchannel_slow(sch->schid)) {
	if (css_enqueue_subchannel_slow(sch->schid)) {
		css_clear_subchannel_slow_list();
		css_clear_subchannel_slow_list();
		need_rescan = 1;
		need_rescan = 1;
	}
	}
	spin_unlock_irq(sch->lock);
	return 0;
	return 0;
}
}


@@ -683,38 +711,6 @@ int chsc_chp_online(struct chp_id chpid)
	return rc;
	return rc;
}
}


static int check_for_io_on_path(struct subchannel *sch, int index)
{
	int cc;

	cc = stsch(sch->schid, &sch->schib);
	if (cc)
		return 0;
	if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index))
		return 1;
	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 void __s390_subchannel_vary_chpid(struct subchannel *sch,
static void __s390_subchannel_vary_chpid(struct subchannel *sch,
					 struct chp_id chpid, int on)
					 struct chp_id chpid, int on)
{
{
@@ -741,13 +737,17 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
		}
		}
		sch->opm &= ~(0x80 >> chp);
		sch->opm &= ~(0x80 >> chp);
		sch->lpm &= ~(0x80 >> chp);
		sch->lpm &= ~(0x80 >> chp);
		if (check_for_io_on_path(sch, chp)) {
		if (check_for_io_on_path(sch, (0x80 >> chp))) {
			if (device_is_online(sch))
			if (device_is_online(sch))
				/* Path verification is done after killing. */
				/* Path verification is done after killing. */
				device_kill_io(sch);
				device_kill_io(sch);
			else
			else {
				/* Kill and retry internal I/O. */
				/* Kill and retry internal I/O. */
				terminate_internal_io(sch);
				terminate_internal_io(sch);
				/* Re-start path verification. */
				if (sch->driver && sch->driver->verify)
					sch->driver->verify(&sch->dev);
			}
		} else if (!sch->lpm) {
		} else if (!sch->lpm) {
			if (device_trigger_verify(sch) != 0) {
			if (device_trigger_verify(sch) != 0) {
				if (css_enqueue_subchannel_slow(sch->schid)) {
				if (css_enqueue_subchannel_slow(sch->schid)) {