diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2007-04-27 16:01:35 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 16:01:40 +0200 |
commit | 7ad6a24970325294a22a08446d473384c15b928e (patch) | |
tree | c8f1e25035b207e2a45a29138309acaee20d6cb6 /drivers/s390/cio/css.c | |
parent | 83b3370c79b91b9be3f6540c3c914e689134b45f (diff) | |
download | linux-7ad6a24970325294a22a08446d473384c15b928e.tar.bz2 |
[S390] cio: fix subchannel channel-path data usage
Ensure that channel-path related subchannel data is only retrieved and
used when it is valid and that it is updated when it may have changed.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index fcc641e578f4..27c6d9e55b23 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -21,6 +21,7 @@ #include "chsc.h" #include "device.h" #include "idset.h" +#include "chp.h" int css_init_done = 0; static int need_reprobe = 0; @@ -125,8 +126,52 @@ void css_sch_device_unregister(struct subchannel *sch) mutex_unlock(&sch->reg_mutex); } -static int -css_register_subchannel(struct subchannel *sch) +static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) +{ + int i; + int mask; + + memset(ssd, 0, sizeof(struct chsc_ssd_info)); + ssd->path_mask = pmcw->pim; + for (i = 0; i < 8; i++) { + mask = 0x80 >> i; + if (pmcw->pim & mask) { + chp_id_init(&ssd->chpid[i]); + ssd->chpid[i].id = pmcw->chpid[i]; + } + } +} + +static void ssd_register_chpids(struct chsc_ssd_info *ssd) +{ + int i; + int mask; + + for (i = 0; i < 8; i++) { + mask = 0x80 >> i; + if (ssd->path_mask & mask) + if (!chp_is_registered(ssd->chpid[i])) + chp_new(ssd->chpid[i]); + } +} + +void css_update_ssd_info(struct subchannel *sch) +{ + int ret; + + if (cio_is_console(sch->schid)) { + /* Console is initialized too early for functions requiring + * memory allocation. */ + ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); + } else { + ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info); + if (ret) + ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw); + ssd_register_chpids(&sch->ssd_info); + } +} + +static int css_register_subchannel(struct subchannel *sch) { int ret; @@ -135,9 +180,7 @@ css_register_subchannel(struct subchannel *sch) sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; sch->dev.groups = subch_attr_groups; - - css_get_ssd_info(sch); - + css_update_ssd_info(sch); /* make it known to the system */ ret = css_sch_device_register(sch); if (ret) { |