summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/cio.c40
-rw-r--r--drivers/s390/cio/cio.h2
-rw-r--r--drivers/s390/cio/css.c11
3 files changed, 23 insertions, 30 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5130d7c67239..4b8f29f83421 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -526,34 +526,19 @@ int cio_disable_subchannel(struct subchannel *sch)
}
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
-static int cio_check_devno_blacklisted(struct subchannel *sch)
-{
- 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
+ * @schib: subchannel information block to be filled out
*
- * Find out subchannel type and initialize struct subchannel.
+ * Check if subchannel is valid and should be used.
* Return codes:
* 0 on success
* -ENXIO for non-defined subchannels
* -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_id schid, struct schib *schib)
{
char dbf_txt[15];
int ccode;
@@ -568,21 +553,24 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
* If stsch gets an exception, it means the current subchannel set
* is not valid.
*/
- ccode = stsch(schid, &sch->schib);
+ ccode = stsch(schid, schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
}
- sch->st = sch->schib.pmcw.st;
- sch->schid = schid;
- switch (sch->st) {
+ switch (schib->pmcw.st) {
case SUBCHANNEL_TYPE_IO:
case SUBCHANNEL_TYPE_MSG:
- if (!css_sch_is_valid(&sch->schib))
+ if (!css_sch_is_valid(schib))
err = -ENODEV;
- else
- err = cio_check_devno_blacklisted(sch);
+ else if (is_blacklisted(schid.ssid, schib->pmcw.dev)) {
+ CIO_MSG_EVENT(6, "Blacklisted device detected "
+ "at devno %04X, subchannel set %x\n",
+ schib->pmcw.dev, schid.ssid);
+ err = -ENODEV;
+ } else
+ err = 0;
break;
default:
err = 0;
@@ -591,7 +579,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
goto out;
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
- sch->schid.ssid, sch->schid.sch_no, sch->st);
+ schid.ssid, schid.sch_no, schib->pmcw.st);
out:
return err;
}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 94cd813bdcfe..234aa068dd8f 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -119,7 +119,7 @@ DECLARE_PER_CPU(struct irb, cio_irb);
#define to_subchannel(n) container_of(n, struct subchannel, dev)
-extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
+extern int cio_validate_subchannel(struct subchannel_id, struct schib *);
extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index e608e8cad88e..e4d6537cdd87 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -171,15 +171,20 @@ static void css_subchannel_release(struct device *dev)
struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
{
struct subchannel *sch;
+ struct schib schib;
int ret;
+ ret = cio_validate_subchannel(schid, &schib);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
if (!sch)
return ERR_PTR(-ENOMEM);
- ret = cio_validate_subchannel(sch, schid);
- if (ret < 0)
- goto err;
+ sch->schid = schid;
+ sch->schib = schib;
+ sch->st = schib.pmcw.st;
ret = css_sch_create_locks(sch);
if (ret)