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

Commit cdb912a4 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

[S390] cio: introduce cio_update_schib



There is the chance that we get condition code 0 for a stsch but
the resulting schib is not vaild. In the current code there are
2 cases:
* we do a check for validity of the schib after stsch, but at this
  time we have already stored the invaild schib in the subchannel
  structure. This may lead to problems.
* we don't do a check for validity, which is not that good either.

The patch addresses both issues by introducing the stsch wrapper
cio_update_schib which performs stsch on a local schib. This schib
is only written back to the subchannel if it's valid.

side note: For some functions (chp_events) the return codes are
different now (-ENXIO vs -ENODEV) but this shouldn't do harm
since the caller doesn't check for _specific_ errors.

Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent d6a30761
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ static void chsc_subchannel_irq(struct subchannel *sch)
	}
	private->request = NULL;
	memcpy(&request->irb, irb, sizeof(*irb));
	stsch(sch->schid, &sch->schib);
	cio_update_schib(sch);
	complete(&request->completion);
	put_device(&sch->dev);
}
+35 −12
Original line number Diff line number Diff line
@@ -114,11 +114,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 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);

	if (cio_update_schib(sch))
		return -ENODEV;

	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
	CIO_TRACE_EVENT(0, dbf_text);
	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
@@ -316,7 +318,8 @@ cio_cancel (struct subchannel *sch)
	switch (ccode) {
	case 0:		/* success */
		/* Update information in scsw. */
		stsch (sch->schid, &sch->schib);
		if (cio_update_schib(sch))
			return -ENODEV;
		return 0;
	case 1:		/* status pending */
		return -EBUSY;
@@ -357,6 +360,23 @@ cio_modify (struct subchannel *sch)
	return ret;
}

/**
 * cio_update_schib - Perform stsch and update schib if subchannel is valid.
 * @sch: subchannel on which to perform stsch
 * Return zero on success, -ENODEV otherwise.
 */
int cio_update_schib(struct subchannel *sch)
{
	struct schib schib;

	if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
		return -ENODEV;

	memcpy(&sch->schib, &schib, sizeof(schib));
	return 0;
}
EXPORT_SYMBOL_GPL(cio_update_schib);

/**
 * cio_enable_subchannel - enable a subchannel.
 * @sch: subchannel to be enabled
@@ -365,7 +385,6 @@ cio_modify (struct subchannel *sch)
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

@@ -374,8 +393,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)

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

	for (retry = 5, ret = 0; retry > 0; retry--) {
@@ -392,7 +410,10 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
			 */
			sch->schib.pmcw.csense = 0;
		if (ret == 0) {
			stsch (sch->schid, &sch->schib);
			if (cio_update_schib(sch)) {
				ret = -ENODEV;
				break;
			}
			if (sch->schib.pmcw.ena)
				break;
		}
@@ -415,7 +436,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
int cio_disable_subchannel(struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

@@ -424,8 +444,7 @@ int cio_disable_subchannel(struct subchannel *sch)

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

	if (scsw_actl(&sch->schib.scsw) != 0)
@@ -448,7 +467,10 @@ int cio_disable_subchannel(struct subchannel *sch)
			 */
			break;
		if (ret == 0) {
			stsch (sch->schid, &sch->schib);
			if (cio_update_schib(sch)) {
				ret = -ENODEV;
				break;
			}
			if (!sch->schib.pmcw.ena)
				break;
		}
@@ -851,7 +873,8 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
		cc = msch(schid, schib);
		if (cc)
			return (cc==3?-ENODEV:-EBUSY);
		stsch(schid, schib);
		if (stsch(schid, schib) || !css_sch_is_valid(schib))
			return -ENODEV;
		if (!schib->pmcw.ena)
			return 0;
	}
+1 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ extern int cio_cancel (struct subchannel *);
extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *);
extern int cio_modify (struct subchannel *);
extern int cio_update_schib(struct subchannel *sch);

int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
int cio_tm_intrg(struct subchannel *sch);
+5 −3
Original line number Diff line number Diff line
@@ -195,7 +195,8 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
	/* msch can silently fail, so do it again if necessary */
	for (retry = 0; retry < 3; retry++) {
		/* prepare schib */
		stsch(sch->schid, schib);
		if (cio_update_schib(sch))
			return -ENODEV;
		schib->pmcw.mme  = mme;
		schib->pmcw.mbfc = mbfc;
		/* address can be either a block address or a block index */
@@ -219,7 +220,8 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
				ret = -EINVAL;
				break;
		}
		stsch(sch->schid, schib); /* restore the schib */
		if (cio_update_schib(sch))
			return -ENODEV;

		if (ret)
			break;
@@ -338,7 +340,7 @@ static int cmf_copy_block(struct ccw_device *cdev)

	sch = to_subchannel(cdev->dev.parent);

	if (stsch(sch->schid, &sch->schib))
	if (cio_update_schib(sch))
		return -ENODEV;

	if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
+4 −9
Original line number Diff line number Diff line
@@ -1350,10 +1350,7 @@ static void io_subchannel_verify(struct subchannel *sch)

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

	cc = stsch(sch->schid, &sch->schib);
	if (cc)
	if (cio_update_schib(sch))
		return 0;
	if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
		return 1;
@@ -1422,15 +1419,13 @@ static int io_subchannel_chp_event(struct subchannel *sch,
		io_subchannel_verify(sch);
		break;
	case CHP_OFFLINE:
		if (stsch(sch->schid, &sch->schib))
			return -ENXIO;
		if (!css_sch_is_valid(&sch->schib))
		if (cio_update_schib(sch))
			return -ENODEV;
		io_subchannel_terminate_path(sch, mask);
		break;
	case CHP_ONLINE:
		if (stsch(sch->schid, &sch->schib))
			return -ENXIO;
		if (cio_update_schib(sch))
			return -ENODEV;
		sch->lpm |= mask & sch->opm;
		io_subchannel_verify(sch);
		break;
Loading