diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 72187e54dca..3bb4e472d73 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/config.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/device.h> @@ -239,13 +238,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) /* Check for single path devices. */ if (sch->schib.pmcw.pim == 0x80) goto out_unreg; - if (sch->vpm == mask) - goto out_unreg; if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && - (sch->schib.pmcw.lpum == mask) && - (sch->vpm == 0)) { + (sch->schib.pmcw.lpum == mask)) { int cc; cc = cio_clear(sch); @@ -260,6 +256,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) /* trigger path verification. */ if (sch->driver && sch->driver->verify) sch->driver->verify(&sch->dev); + else if (sch->lpm == mask) + goto out_unreg; out_unlock: spin_unlock_irq(&sch->lock); return 0; @@ -380,6 +378,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) if (chp_mask == 0) { spin_unlock_irq(&sch->lock); + put_device(&sch->dev); return 0; } old_lpm = sch->lpm; @@ -394,7 +393,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) spin_unlock_irq(&sch->lock); put_device(&sch->dev); - return (res_data->fla_mask == 0xffff) ? -ENODEV : 0; + return 0; } @@ -918,12 +917,13 @@ chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count) chp = to_channelpath(container_of(kobj, struct device, kobj)); css = to_css(chp->dev.parent); - size = sizeof(struct cmg_chars); + size = sizeof(struct cmg_entry); /* Only allow single reads. */ if (off || count < size) return 0; chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id); + count = size; return count; } @@ -1392,10 +1392,8 @@ new_channel_path(int chpid) /* fill in status, etc. */ chp->id = chpid; chp->state = 1; - chp->dev = (struct device) { - .parent = &css[0]->device, - .release = chp_release, - }; + chp->dev.parent = &css[0]->device; + chp->dev.release = chp_release; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); /* Obtain channel path description and fill it in. */ @@ -1465,6 +1463,40 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) return desc; } +static int reset_channel_path(struct channel_path *chp) +{ + int cc; + + cc = rchp(chp->id); + switch (cc) { + case 0: + return 0; + case 2: + return -EBUSY; + default: + return -ENODEV; + } +} + +static void reset_channel_paths_css(struct channel_subsystem *css) +{ + int i; + + for (i = 0; i <= __MAX_CHPID; i++) { + if (css->chps[i]) + reset_channel_path(css->chps[i]); + } +} + +void cio_reset_channel_paths(void) +{ + int i; + + for (i = 0; i <= __MAX_CSSID; i++) { + if (css[i] && css[i]->valid) + reset_channel_paths_css(css[i]); + } +} static int __init chsc_alloc_sei_area(void) |