summaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/css.c
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2007-04-27 16:01:35 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2007-04-27 16:01:40 +0200
commit7ad6a24970325294a22a08446d473384c15b928e (patch)
treec8f1e25035b207e2a45a29138309acaee20d6cb6 /drivers/s390/cio/css.c
parent83b3370c79b91b9be3f6540c3c914e689134b45f (diff)
downloadlinux-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.c53
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) {