[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: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
b4a33acb69
commit
0ae7a7b250
|
@ -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 @@
|
||||||
* 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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
/* 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);
|
if (err)
|
||||||
/* We stop here for non-io subchannels. */
|
|
||||||
err = sch->st;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialization for io subchannels. */
|
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
|
||||||
if (!css_sch_is_valid(&sch->schib)) {
|
sch->schid.ssid, sch->schid.sch_no, sch->st);
|
||||||
err = -ENODEV;
|
|
||||||
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;
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
if (!cio_is_console(schid))
|
if (!cio_is_console(schid))
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Reference in New Issue