diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-07-14 03:58:43 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:05 -0400 |
commit | 0ae7a7b250bdf7ee87c8346164ef3c47fb79dfbd (patch) | |
tree | 95da6f03f135cf1a754eba262117a2ae8fd072a5 | |
parent | b4a33acb690525c5ca37e177f5cd26c62d3ef976 (diff) |
[S390] cio: Register all subchannels.
Register all valid subchannels, not only I/O subchannels.
Move I/O subchannel specific initialization to io_subchannel_probe().
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
-rw-r--r-- | drivers/s390/cio/chp.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 126 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 19 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 38 |
5 files changed, 85 insertions, 101 deletions
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 65286563c592..59c2fc069d9e 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <asm/chpid.h> | 13 | #include <asm/chpid.h> |
14 | #include "chsc.h" | 14 | #include "chsc.h" |
15 | #include "css.h" | ||
15 | 16 | ||
16 | #define CHP_STATUS_STANDBY 0 | 17 | #define CHP_STATUS_STANDBY 0 |
17 | #define CHP_STATUS_CONFIGURED 1 | 18 | #define CHP_STATUS_CONFIGURED 1 |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 7b5969ed05cd..903e23ae8ed5 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/s390/cio/cio.c | 2 | * drivers/s390/cio/cio.c |
3 | * S/390 common I/O routines -- low level i/o calls | 3 | * S/390 common I/O routines -- low level i/o calls |
4 | * | 4 | * |
5 | * Copyright (C) IBM Corp. 1999,2006 | 5 | * Copyright IBM Corp. 1999,2008 |
6 | * Author(s): Ingo Adlung (adlung@de.ibm.com) | 6 | * Author(s): Ingo Adlung (adlung@de.ibm.com) |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 7 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
8 | * Arnd Bergmann (arndb@de.ibm.com) | 8 | * Arnd Bergmann (arndb@de.ibm.com) |
@@ -494,27 +494,46 @@ int cio_create_sch_lock(struct subchannel *sch) | |||
494 | return 0; | 494 | return 0; |
495 | } | 495 | } |
496 | 496 | ||
497 | /* | 497 | static int cio_validate_io_subchannel(struct subchannel *sch) |
498 | * cio_validate_subchannel() | 498 | { |
499 | /* Initialization for io subchannels. */ | ||
500 | if (!css_sch_is_valid(&sch->schib)) | ||
501 | return -ENODEV; | ||
502 | |||
503 | /* Devno is valid. */ | ||
504 | if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) { | ||
505 | /* | ||
506 | * This device must not be known to Linux. So we simply | ||
507 | * say that there is no device and return ENODEV. | ||
508 | */ | ||
509 | CIO_MSG_EVENT(6, "Blacklisted device detected " | ||
510 | "at devno %04X, subchannel set %x\n", | ||
511 | sch->schib.pmcw.dev, sch->schid.ssid); | ||
512 | return -ENODEV; | ||
513 | } | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * cio_validate_subchannel - basic validation of subchannel | ||
519 | * @sch: subchannel structure to be filled out | ||
520 | * @schid: subchannel id | ||
499 | * | 521 | * |
500 | * Find out subchannel type and initialize struct subchannel. | 522 | * Find out subchannel type and initialize struct subchannel. |
501 | * Return codes: | 523 | * Return codes: |
502 | * SUBCHANNEL_TYPE_IO for a normal io subchannel | 524 | * 0 on success |
503 | * SUBCHANNEL_TYPE_CHSC for a chsc subchannel | ||
504 | * SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel | ||
505 | * SUBCHANNEL_TYPE_ADM for a adm(?) subchannel | ||
506 | * -ENXIO for non-defined subchannels | 525 | * -ENXIO for non-defined subchannels |
507 | * -ENODEV for subchannels with invalid device number or blacklisted devices | 526 | * -ENODEV for invalid subchannels or blacklisted devices |
527 | * -EIO for subchannels in an invalid subchannel set | ||
508 | */ | 528 | */ |
509 | int | 529 | int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) |
510 | cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | ||
511 | { | 530 | { |
512 | char dbf_txt[15]; | 531 | char dbf_txt[15]; |
513 | int ccode; | 532 | int ccode; |
514 | int err; | 533 | int err; |
515 | 534 | ||
516 | sprintf (dbf_txt, "valsch%x", schid.sch_no); | 535 | sprintf(dbf_txt, "valsch%x", schid.sch_no); |
517 | CIO_TRACE_EVENT (4, dbf_txt); | 536 | CIO_TRACE_EVENT(4, dbf_txt); |
518 | 537 | ||
519 | /* Nuke all fields. */ | 538 | /* Nuke all fields. */ |
520 | memset(sch, 0, sizeof(struct subchannel)); | 539 | memset(sch, 0, sizeof(struct subchannel)); |
@@ -545,68 +564,18 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
545 | } | 564 | } |
546 | /* Copy subchannel type from path management control word. */ | 565 | /* Copy subchannel type from path management control word. */ |
547 | sch->st = sch->schib.pmcw.st; | 566 | sch->st = sch->schib.pmcw.st; |
548 | 567 | switch (sch->st) { | |
549 | /* | 568 | case SUBCHANNEL_TYPE_IO: |
550 | * ... just being curious we check for non I/O subchannels | 569 | err = cio_validate_io_subchannel(sch); |
551 | */ | 570 | break; |
552 | if (sch->st != 0) { | 571 | default: |
553 | CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports " | 572 | err = 0; |
554 | "non-I/O subchannel type %04X\n", | ||
555 | sch->schid.ssid, sch->schid.sch_no, sch->st); | ||
556 | /* We stop here for non-io subchannels. */ | ||
557 | err = sch->st; | ||
558 | goto out; | ||
559 | } | 573 | } |
560 | 574 | if (err) | |
561 | /* Initialization for io subchannels. */ | ||
562 | if (!css_sch_is_valid(&sch->schib)) { | ||
563 | err = -ENODEV; | ||
564 | goto out; | 575 | goto out; |
565 | } | ||
566 | 576 | ||
567 | /* Devno is valid. */ | 577 | CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", |
568 | if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { | 578 | sch->schid.ssid, sch->schid.sch_no, sch->st); |
569 | /* | ||
570 | * This device must not be known to Linux. So we simply | ||
571 | * say that there is no device and return ENODEV. | ||
572 | */ | ||
573 | CIO_MSG_EVENT(6, "Blacklisted device detected " | ||
574 | "at devno %04X, subchannel set %x\n", | ||
575 | sch->schib.pmcw.dev, sch->schid.ssid); | ||
576 | err = -ENODEV; | ||
577 | goto out; | ||
578 | } | ||
579 | if (cio_is_console(sch->schid)) { | ||
580 | sch->opm = 0xff; | ||
581 | sch->isc = 1; | ||
582 | } else { | ||
583 | sch->opm = chp_get_sch_opm(sch); | ||
584 | sch->isc = 3; | ||
585 | } | ||
586 | sch->lpm = sch->schib.pmcw.pam & sch->opm; | ||
587 | |||
588 | CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X " | ||
589 | "- PIM = %02X, PAM = %02X, POM = %02X\n", | ||
590 | sch->schib.pmcw.dev, sch->schid.ssid, | ||
591 | sch->schid.sch_no, sch->schib.pmcw.pim, | ||
592 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | ||
593 | |||
594 | /* | ||
595 | * We now have to initially ... | ||
596 | * ... enable "concurrent sense" | ||
597 | * ... enable "multipath mode" if more than one | ||
598 | * CHPID is available. This is done regardless | ||
599 | * whether multiple paths are available for us. | ||
600 | */ | ||
601 | sch->schib.pmcw.csense = 1; /* concurrent sense */ | ||
602 | sch->schib.pmcw.ena = 0; | ||
603 | if ((sch->lpm & (sch->lpm - 1)) != 0) | ||
604 | sch->schib.pmcw.mp = 1; /* multipath mode */ | ||
605 | /* clean up possible residual cmf stuff */ | ||
606 | sch->schib.pmcw.mme = 0; | ||
607 | sch->schib.pmcw.mbfc = 0; | ||
608 | sch->schib.pmcw.mbi = 0; | ||
609 | sch->schib.mba = 0; | ||
610 | return 0; | 579 | return 0; |
611 | out: | 580 | out: |
612 | if (!cio_is_console(schid)) | 581 | if (!cio_is_console(schid)) |
@@ -793,7 +762,6 @@ cio_probe_console(void) | |||
793 | * enable console I/O-interrupt subclass 1 | 762 | * enable console I/O-interrupt subclass 1 |
794 | */ | 763 | */ |
795 | ctl_set_bit(6, 30); | 764 | ctl_set_bit(6, 30); |
796 | console_subchannel.isc = 1; | ||
797 | console_subchannel.schib.pmcw.isc = 1; | 765 | console_subchannel.schib.pmcw.isc = 1; |
798 | console_subchannel.schib.pmcw.intparm = | 766 | console_subchannel.schib.pmcw.intparm = |
799 | (u32)(addr_t)&console_subchannel; | 767 | (u32)(addr_t)&console_subchannel; |
@@ -864,7 +832,7 @@ static void udelay_reset(unsigned long usecs) | |||
864 | } | 832 | } |
865 | 833 | ||
866 | static int | 834 | static int |
867 | __clear_subchannel_easy(struct subchannel_id schid) | 835 | __clear_io_subchannel_easy(struct subchannel_id schid) |
868 | { | 836 | { |
869 | int retry; | 837 | int retry; |
870 | 838 | ||
@@ -921,11 +889,19 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | |||
921 | case -ENODEV: | 889 | case -ENODEV: |
922 | break; | 890 | break; |
923 | default: /* -EBUSY */ | 891 | default: /* -EBUSY */ |
924 | if (__clear_subchannel_easy(schid)) | 892 | switch (schib.pmcw.st) { |
925 | break; /* give up... */ | 893 | case SUBCHANNEL_TYPE_IO: |
894 | if (__clear_io_subchannel_easy(schid)) | ||
895 | goto out; /* give up... */ | ||
896 | break; | ||
897 | default: | ||
898 | /* No default clear strategy */ | ||
899 | break; | ||
900 | } | ||
926 | stsch(schid, &schib); | 901 | stsch(schid, &schib); |
927 | __disable_subchannel_easy(schid, &schib); | 902 | __disable_subchannel_easy(schid, &schib); |
928 | } | 903 | } |
904 | out: | ||
929 | return 0; | 905 | return 0; |
930 | } | 906 | } |
931 | 907 | ||
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index a76956512b2d..b7f4b52c5a9a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -121,25 +121,6 @@ css_alloc_subchannel(struct subchannel_id schid) | |||
121 | kfree(sch); | 121 | kfree(sch); |
122 | return ERR_PTR(ret); | 122 | return ERR_PTR(ret); |
123 | } | 123 | } |
124 | |||
125 | if (sch->st != SUBCHANNEL_TYPE_IO) { | ||
126 | /* For now we ignore all non-io subchannels. */ | ||
127 | kfree(sch); | ||
128 | return ERR_PTR(-EINVAL); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Set intparm to subchannel address. | ||
133 | * This is fine even on 64bit since the subchannel is always located | ||
134 | * under 2G. | ||
135 | */ | ||
136 | sch->schib.pmcw.intparm = (u32)(addr_t)sch; | ||
137 | ret = cio_modify(sch); | ||
138 | if (ret) { | ||
139 | kfree(sch->lock); | ||
140 | kfree(sch); | ||
141 | return ERR_PTR(ret); | ||
142 | } | ||
143 | return sch; | 124 | return sch; |
144 | } | 125 | } |
145 | 126 | ||
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index e1913518f354..bfe0ada43f2c 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -60,8 +60,6 @@ struct pgid { | |||
60 | 60 | ||
61 | /* | 61 | /* |
62 | * A css driver handles all subchannels of one type. | 62 | * A css driver handles all subchannels of one type. |
63 | * Currently, we only care about I/O subchannels (type 0), these | ||
64 | * have a ccw_device connected to them. | ||
65 | */ | 63 | */ |
66 | struct subchannel; | 64 | struct subchannel; |
67 | struct css_driver { | 65 | struct css_driver { |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e22813db74a2..0ed5a81260bc 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/param.h> /* HZ */ | 24 | #include <asm/param.h> /* HZ */ |
25 | #include <asm/cmb.h> | 25 | #include <asm/cmb.h> |
26 | 26 | ||
27 | #include "chp.h" | ||
27 | #include "cio.h" | 28 | #include "cio.h" |
28 | #include "cio_debug.h" | 29 | #include "cio_debug.h" |
29 | #include "css.h" | 30 | #include "css.h" |
@@ -1037,7 +1038,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
1037 | struct ccw_device_private *priv; | 1038 | struct ccw_device_private *priv; |
1038 | 1039 | ||
1039 | sch_set_cdev(sch, cdev); | 1040 | sch_set_cdev(sch, cdev); |
1040 | sch->driver = &io_subchannel_driver; | ||
1041 | cdev->ccwlock = sch->lock; | 1041 | cdev->ccwlock = sch->lock; |
1042 | 1042 | ||
1043 | /* Init private data. */ | 1043 | /* Init private data. */ |
@@ -1122,8 +1122,33 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
1122 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1122 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
1123 | } | 1123 | } |
1124 | 1124 | ||
1125 | static int | 1125 | static void io_subchannel_init_fields(struct subchannel *sch) |
1126 | io_subchannel_probe (struct subchannel *sch) | 1126 | { |
1127 | if (cio_is_console(sch->schid)) | ||
1128 | sch->opm = 0xff; | ||
1129 | else | ||
1130 | sch->opm = chp_get_sch_opm(sch); | ||
1131 | sch->lpm = sch->schib.pmcw.pam & sch->opm; | ||
1132 | sch->isc = cio_is_console(sch->schid) ? 1 : 3; | ||
1133 | |||
1134 | CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X" | ||
1135 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | ||
1136 | sch->schib.pmcw.dev, sch->schid.ssid, | ||
1137 | sch->schid.sch_no, sch->schib.pmcw.pim, | ||
1138 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | ||
1139 | /* Initially set up some fields in the pmcw. */ | ||
1140 | sch->schib.pmcw.ena = 0; | ||
1141 | sch->schib.pmcw.csense = 1; /* concurrent sense */ | ||
1142 | if ((sch->lpm & (sch->lpm - 1)) != 0) | ||
1143 | sch->schib.pmcw.mp = 1; /* multipath mode */ | ||
1144 | /* clean up possible residual cmf stuff */ | ||
1145 | sch->schib.pmcw.mme = 0; | ||
1146 | sch->schib.pmcw.mbfc = 0; | ||
1147 | sch->schib.pmcw.mbi = 0; | ||
1148 | sch->schib.mba = 0; | ||
1149 | } | ||
1150 | |||
1151 | static int io_subchannel_probe(struct subchannel *sch) | ||
1127 | { | 1152 | { |
1128 | struct ccw_device *cdev; | 1153 | struct ccw_device *cdev; |
1129 | int rc; | 1154 | int rc; |
@@ -1152,6 +1177,7 @@ io_subchannel_probe (struct subchannel *sch) | |||
1152 | get_device(&cdev->dev); | 1177 | get_device(&cdev->dev); |
1153 | return 0; | 1178 | return 0; |
1154 | } | 1179 | } |
1180 | io_subchannel_init_fields(sch); | ||
1155 | /* | 1181 | /* |
1156 | * First check if a fitting device may be found amongst the | 1182 | * First check if a fitting device may be found amongst the |
1157 | * disconnected devices or in the orphanage. | 1183 | * disconnected devices or in the orphanage. |
@@ -1297,14 +1323,16 @@ spinlock_t * cio_get_console_lock(void) | |||
1297 | return &ccw_console_lock; | 1323 | return &ccw_console_lock; |
1298 | } | 1324 | } |
1299 | 1325 | ||
1300 | static int | 1326 | static int ccw_device_console_enable(struct ccw_device *cdev, |
1301 | ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) | 1327 | struct subchannel *sch) |
1302 | { | 1328 | { |
1303 | int rc; | 1329 | int rc; |
1304 | 1330 | ||
1305 | /* Attach subchannel private data. */ | 1331 | /* Attach subchannel private data. */ |
1306 | sch->private = cio_get_console_priv(); | 1332 | sch->private = cio_get_console_priv(); |
1307 | memset(sch->private, 0, sizeof(struct io_subchannel_private)); | 1333 | memset(sch->private, 0, sizeof(struct io_subchannel_private)); |
1334 | io_subchannel_init_fields(sch); | ||
1335 | sch->driver = &io_subchannel_driver; | ||
1308 | /* Initialize the ccw_device structure. */ | 1336 | /* Initialize the ccw_device structure. */ |
1309 | cdev->dev.parent= &sch->dev; | 1337 | cdev->dev.parent= &sch->dev; |
1310 | rc = io_subchannel_recog(cdev, sch); | 1338 | rc = io_subchannel_recog(cdev, sch); |