diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5130d7c67239b337c71eeca67762f7061ee06abb..4b8f29f834219701bb4721fc27772bd9dba2578f 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 94cd813bdcfef8d2a281eceef1d9fae79be97d08..234aa068dd8f35ffac770d395f8123fbd6e9c576 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 e608e8cad88e307ecc6b757c84ba421169c3fd66..e4d6537cdd87afca2114401042775fb35989b40f 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)