* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
*
- * Copyright (C) IBM Corp. 1999,2006
+ * Copyright IBM Corp. 1999,2008
* Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com)
return 0;
}
-/*
- * cio_validate_subchannel()
+static int cio_validate_io_subchannel(struct subchannel *sch)
+{
+ /* Initialization for io subchannels. */
+ if (!css_sch_is_valid(&sch->schib))
+ return -ENODEV;
+
+ /* Devno is valid. */
+ if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
+ /*
+ * This device must not be known to Linux. So we simply
+ * say that there is no device and return ENODEV.
+ */
+ CIO_MSG_EVENT(6, "Blacklisted device detected "
+ "at devno %04X, subchannel set %x\n",
+ sch->schib.pmcw.dev, sch->schid.ssid);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * cio_validate_subchannel - basic validation of subchannel
+ * @sch: subchannel structure to be filled out
+ * @schid: subchannel id
*
* Find out subchannel type and initialize struct subchannel.
* Return codes:
- * SUBCHANNEL_TYPE_IO for a normal io subchannel
- * SUBCHANNEL_TYPE_CHSC for a chsc subchannel
- * SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel
- * SUBCHANNEL_TYPE_ADM for a adm(?) subchannel
+ * 0 on success
* -ENXIO for non-defined subchannels
- * -ENODEV for subchannels with invalid device number or blacklisted devices
+ * -ENODEV for invalid subchannels or blacklisted devices
+ * -EIO for subchannels in an invalid subchannel set
*/
-int
-cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
+int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
{
char dbf_txt[15];
int ccode;
int err;
- sprintf (dbf_txt, "valsch%x", schid.sch_no);
- CIO_TRACE_EVENT (4, dbf_txt);
+ sprintf(dbf_txt, "valsch%x", schid.sch_no);
+ CIO_TRACE_EVENT(4, dbf_txt);
/* Nuke all fields. */
memset(sch, 0, sizeof(struct subchannel));
}
/* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st;
-
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if (sch->st != 0) {
- CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports "
- "non-I/O subchannel type %04X\n",
- sch->schid.ssid, sch->schid.sch_no, sch->st);
- /* We stop here for non-io subchannels. */
- err = sch->st;
- goto out;
+ switch (sch->st) {
+ case SUBCHANNEL_TYPE_IO:
+ err = cio_validate_io_subchannel(sch);
+ break;
+ default:
+ err = 0;
}
-
- /* Initialization for io subchannels. */
- if (!css_sch_is_valid(&sch->schib)) {
- err = -ENODEV;
+ if (err)
goto out;
- }
- /* Devno is valid. */
- if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
- /*
- * This device must not be known to Linux. So we simply
- * say that there is no device and return ENODEV.
- */
- CIO_MSG_EVENT(6, "Blacklisted device detected "
- "at devno %04X, subchannel set %x\n",
- sch->schib.pmcw.dev, sch->schid.ssid);
- err = -ENODEV;
- goto out;
- }
- if (cio_is_console(sch->schid)) {
- sch->opm = 0xff;
- sch->isc = 1;
- } else {
- sch->opm = chp_get_sch_opm(sch);
- sch->isc = 3;
- }
- sch->lpm = sch->schib.pmcw.pam & sch->opm;
-
- CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X "
- "- PIM = %02X, PAM = %02X, POM = %02X\n",
- sch->schib.pmcw.dev, sch->schid.ssid,
- sch->schid.sch_no, sch->schib.pmcw.pim,
- sch->schib.pmcw.pam, sch->schib.pmcw.pom);
-
- /*
- * We now have to initially ...
- * ... enable "concurrent sense"
- * ... enable "multipath mode" if more than one
- * CHPID is available. This is done regardless
- * whether multiple paths are available for us.
- */
- sch->schib.pmcw.csense = 1; /* concurrent sense */
- sch->schib.pmcw.ena = 0;
- if ((sch->lpm & (sch->lpm - 1)) != 0)
- sch->schib.pmcw.mp = 1; /* multipath mode */
- /* clean up possible residual cmf stuff */
- sch->schib.pmcw.mme = 0;
- sch->schib.pmcw.mbfc = 0;
- sch->schib.pmcw.mbi = 0;
- sch->schib.mba = 0;
+ CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
+ sch->schid.ssid, sch->schid.sch_no, sch->st);
return 0;
out:
if (!cio_is_console(schid))
* enable console I/O-interrupt subclass 1
*/
ctl_set_bit(6, 30);
- console_subchannel.isc = 1;
console_subchannel.schib.pmcw.isc = 1;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
}
static int
-__clear_subchannel_easy(struct subchannel_id schid)
+__clear_io_subchannel_easy(struct subchannel_id schid)
{
int retry;
case -ENODEV:
break;
default: /* -EBUSY */
- if (__clear_subchannel_easy(schid))
- break; /* give up... */
+ switch (schib.pmcw.st) {
+ case SUBCHANNEL_TYPE_IO:
+ if (__clear_io_subchannel_easy(schid))
+ goto out; /* give up... */
+ break;
+ default:
+ /* No default clear strategy */
+ break;
+ }
stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
+out:
return 0;
}
#include <asm/param.h> /* HZ */
#include <asm/cmb.h>
+#include "chp.h"
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
struct ccw_device_private *priv;
sch_set_cdev(sch, cdev);
- sch->driver = &io_subchannel_driver;
cdev->ccwlock = sch->lock;
/* Init private data. */
dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
}
-static int
-io_subchannel_probe (struct subchannel *sch)
+static void io_subchannel_init_fields(struct subchannel *sch)
+{
+ if (cio_is_console(sch->schid))
+ sch->opm = 0xff;
+ else
+ sch->opm = chp_get_sch_opm(sch);
+ sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ sch->isc = cio_is_console(sch->schid) ? 1 : 3;
+
+ CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X"
+ " - PIM = %02X, PAM = %02X, POM = %02X\n",
+ sch->schib.pmcw.dev, sch->schid.ssid,
+ sch->schid.sch_no, sch->schib.pmcw.pim,
+ sch->schib.pmcw.pam, sch->schib.pmcw.pom);
+ /* Initially set up some fields in the pmcw. */
+ sch->schib.pmcw.ena = 0;
+ sch->schib.pmcw.csense = 1; /* concurrent sense */
+ if ((sch->lpm & (sch->lpm - 1)) != 0)
+ sch->schib.pmcw.mp = 1; /* multipath mode */
+ /* clean up possible residual cmf stuff */
+ sch->schib.pmcw.mme = 0;
+ sch->schib.pmcw.mbfc = 0;
+ sch->schib.pmcw.mbi = 0;
+ sch->schib.mba = 0;
+}
+
+static int io_subchannel_probe(struct subchannel *sch)
{
struct ccw_device *cdev;
int rc;
get_device(&cdev->dev);
return 0;
}
+ io_subchannel_init_fields(sch);
/*
* First check if a fitting device may be found amongst the
* disconnected devices or in the orphanage.
return &ccw_console_lock;
}
-static int
-ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
+static int ccw_device_console_enable(struct ccw_device *cdev,
+ struct subchannel *sch)
{
int rc;
/* Attach subchannel private data. */
sch->private = cio_get_console_priv();
memset(sch->private, 0, sizeof(struct io_subchannel_private));
+ io_subchannel_init_fields(sch);
+ sch->driver = &io_subchannel_driver;
/* Initialize the ccw_device structure. */
cdev->dev.parent= &sch->dev;
rc = io_subchannel_recog(cdev, sch);