Commit 0ae7a7b2 authored by Cornelia Huck's avatar Cornelia Huck Committed by Heiko Carstens

[S390] cio: Register all subchannels.

Register all valid subchannels, not only I/O subchannels.
Move I/O subchannel specific initialization to io_subchannel_probe().
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent b4a33acb
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <asm/chpid.h> #include <asm/chpid.h>
#include "chsc.h" #include "chsc.h"
#include "css.h"
#define CHP_STATUS_STANDBY 0 #define CHP_STATUS_STANDBY 0
#define CHP_STATUS_CONFIGURED 1 #define CHP_STATUS_CONFIGURED 1
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* drivers/s390/cio/cio.c * drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls * 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) * Author(s): Ingo Adlung (adlung@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com)
* Arnd Bergmann (arndb@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com)
...@@ -494,27 +494,46 @@ int cio_create_sch_lock(struct subchannel *sch) ...@@ -494,27 +494,46 @@ int cio_create_sch_lock(struct subchannel *sch)
return 0; return 0;
} }
/* static int cio_validate_io_subchannel(struct subchannel *sch)
* cio_validate_subchannel() {
/* 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. * Find out subchannel type and initialize struct subchannel.
* Return codes: * Return codes:
* SUBCHANNEL_TYPE_IO for a normal io subchannel * 0 on success
* SUBCHANNEL_TYPE_CHSC for a chsc subchannel
* SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel
* SUBCHANNEL_TYPE_ADM for a adm(?) subchannel
* -ENXIO for non-defined subchannels * -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 int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
{ {
char dbf_txt[15]; char dbf_txt[15];
int ccode; int ccode;
int err; int err;
sprintf (dbf_txt, "valsch%x", schid.sch_no); sprintf(dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT(4, dbf_txt);
/* Nuke all fields. */ /* Nuke all fields. */
memset(sch, 0, sizeof(struct subchannel)); memset(sch, 0, sizeof(struct subchannel));
...@@ -545,68 +564,18 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) ...@@ -545,68 +564,18 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
} }
/* Copy subchannel type from path management control word. */ /* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st; sch->st = sch->schib.pmcw.st;
switch (sch->st) {
/* case SUBCHANNEL_TYPE_IO:
* ... just being curious we check for non I/O subchannels err = cio_validate_io_subchannel(sch);
*/ break;
if (sch->st != 0) { default:
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports " err = 0;
"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;
} }
if (err)
/* Initialization for io subchannels. */
if (!css_sch_is_valid(&sch->schib)) {
err = -ENODEV;
goto out; goto out;
}
/* Devno is valid. */ CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { sch->schid.ssid, sch->schid.sch_no, sch->st);
/*
* 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;
return 0; return 0;
out: out:
if (!cio_is_console(schid)) if (!cio_is_console(schid))
...@@ -793,7 +762,6 @@ cio_probe_console(void) ...@@ -793,7 +762,6 @@ cio_probe_console(void)
* enable console I/O-interrupt subclass 1 * enable console I/O-interrupt subclass 1
*/ */
ctl_set_bit(6, 30); ctl_set_bit(6, 30);
console_subchannel.isc = 1;
console_subchannel.schib.pmcw.isc = 1; console_subchannel.schib.pmcw.isc = 1;
console_subchannel.schib.pmcw.intparm = console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel; (u32)(addr_t)&console_subchannel;
...@@ -864,7 +832,7 @@ static void udelay_reset(unsigned long usecs) ...@@ -864,7 +832,7 @@ static void udelay_reset(unsigned long usecs)
} }
static int static int
__clear_subchannel_easy(struct subchannel_id schid) __clear_io_subchannel_easy(struct subchannel_id schid)
{ {
int retry; int retry;
...@@ -921,11 +889,19 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) ...@@ -921,11 +889,19 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
case -ENODEV: case -ENODEV:
break; break;
default: /* -EBUSY */ default: /* -EBUSY */
if (__clear_subchannel_easy(schid)) switch (schib.pmcw.st) {
break; /* give up... */ case SUBCHANNEL_TYPE_IO:
if (__clear_io_subchannel_easy(schid))
goto out; /* give up... */
break;
default:
/* No default clear strategy */
break;
}
stsch(schid, &schib); stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib); __disable_subchannel_easy(schid, &schib);
} }
out:
return 0; return 0;
} }
......
...@@ -121,25 +121,6 @@ css_alloc_subchannel(struct subchannel_id schid) ...@@ -121,25 +121,6 @@ css_alloc_subchannel(struct subchannel_id schid)
kfree(sch); kfree(sch);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (sch->st != SUBCHANNEL_TYPE_IO) {
/* For now we ignore all non-io subchannels. */
kfree(sch);
return ERR_PTR(-EINVAL);
}
/*
* Set intparm to subchannel address.
* This is fine even on 64bit since the subchannel is always located
* under 2G.
*/
sch->schib.pmcw.intparm = (u32)(addr_t)sch;
ret = cio_modify(sch);
if (ret) {
kfree(sch->lock);
kfree(sch);
return ERR_PTR(ret);
}
return sch; return sch;
} }
......
...@@ -60,8 +60,6 @@ struct pgid { ...@@ -60,8 +60,6 @@ struct pgid {
/* /*
* A css driver handles all subchannels of one type. * A css driver handles all subchannels of one type.
* Currently, we only care about I/O subchannels (type 0), these
* have a ccw_device connected to them.
*/ */
struct subchannel; struct subchannel;
struct css_driver { struct css_driver {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/param.h> /* HZ */ #include <asm/param.h> /* HZ */
#include <asm/cmb.h> #include <asm/cmb.h>
#include "chp.h"
#include "cio.h" #include "cio.h"
#include "cio_debug.h" #include "cio_debug.h"
#include "css.h" #include "css.h"
...@@ -1037,7 +1038,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) ...@@ -1037,7 +1038,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
struct ccw_device_private *priv; struct ccw_device_private *priv;
sch_set_cdev(sch, cdev); sch_set_cdev(sch, cdev);
sch->driver = &io_subchannel_driver;
cdev->ccwlock = sch->lock; cdev->ccwlock = sch->lock;
/* Init private data. */ /* Init private data. */
...@@ -1122,8 +1122,33 @@ static void io_subchannel_irq(struct subchannel *sch) ...@@ -1122,8 +1122,33 @@ static void io_subchannel_irq(struct subchannel *sch)
dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
} }
static int static void io_subchannel_init_fields(struct subchannel *sch)
io_subchannel_probe (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; struct ccw_device *cdev;
int rc; int rc;
...@@ -1152,6 +1177,7 @@ io_subchannel_probe (struct subchannel *sch) ...@@ -1152,6 +1177,7 @@ io_subchannel_probe (struct subchannel *sch)
get_device(&cdev->dev); get_device(&cdev->dev);
return 0; return 0;
} }
io_subchannel_init_fields(sch);
/* /*
* First check if a fitting device may be found amongst the * First check if a fitting device may be found amongst the
* disconnected devices or in the orphanage. * disconnected devices or in the orphanage.
...@@ -1297,14 +1323,16 @@ spinlock_t * cio_get_console_lock(void) ...@@ -1297,14 +1323,16 @@ spinlock_t * cio_get_console_lock(void)
return &ccw_console_lock; return &ccw_console_lock;
} }
static int static int ccw_device_console_enable(struct ccw_device *cdev,
ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) struct subchannel *sch)
{ {
int rc; int rc;
/* Attach subchannel private data. */ /* Attach subchannel private data. */
sch->private = cio_get_console_priv(); sch->private = cio_get_console_priv();
memset(sch->private, 0, sizeof(struct io_subchannel_private)); memset(sch->private, 0, sizeof(struct io_subchannel_private));
io_subchannel_init_fields(sch);
sch->driver = &io_subchannel_driver;
/* Initialize the ccw_device structure. */ /* Initialize the ccw_device structure. */
cdev->dev.parent= &sch->dev; cdev->dev.parent= &sch->dev;
rc = io_subchannel_recog(cdev, sch); rc = io_subchannel_recog(cdev, sch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment