aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2009-12-07 06:51:30 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:31 -0500
commit454e1fa1ebae7cff707b2e3f12b775c263c8408b (patch)
treeeab290fcacd6faaf7e01e3a637cb9678bb367c66
parent4257aaecffab77bad43e12057f56a5590b360f9f (diff)
[S390] cio: split PGID settings and status
Split setting (driver wants feature enabled) and status (feature setup was successful) for PGID related ccw device features so that setup errors can be detected. Previously, incorrectly handled setup errors could in rare cases lead to erratic I/O behavior and permanently unusuable devices. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/ccwdev.h4
-rw-r--r--drivers/s390/block/dasd.c7
-rw-r--r--drivers/s390/block/dasd_eckd.c12
-rw-r--r--drivers/s390/char/tape_core.c3
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/device_ops.c27
-rw-r--r--drivers/s390/cio/device_pgid.c33
-rw-r--r--drivers/s390/cio/io_sch.h4
8 files changed, 68 insertions, 24 deletions
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index 2a5419551176..f4bd346a52d3 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -142,6 +142,8 @@ struct ccw1;
142extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long); 142extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long);
143extern int ccw_device_set_options(struct ccw_device *, unsigned long); 143extern int ccw_device_set_options(struct ccw_device *, unsigned long);
144extern void ccw_device_clear_options(struct ccw_device *, unsigned long); 144extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
145int ccw_device_is_pathgroup(struct ccw_device *cdev);
146int ccw_device_is_multipath(struct ccw_device *cdev);
145 147
146/* Allow for i/o completion notification after primary interrupt status. */ 148/* Allow for i/o completion notification after primary interrupt status. */
147#define CCWDEV_EARLY_NOTIFICATION 0x0001 149#define CCWDEV_EARLY_NOTIFICATION 0x0001
@@ -151,6 +153,8 @@ extern void ccw_device_clear_options(struct ccw_device *, unsigned long);
151#define CCWDEV_DO_PATHGROUP 0x0004 153#define CCWDEV_DO_PATHGROUP 0x0004
152/* Allow forced onlining of boxed devices. */ 154/* Allow forced onlining of boxed devices. */
153#define CCWDEV_ALLOW_FORCE 0x0008 155#define CCWDEV_ALLOW_FORCE 0x0008
156/* Try to use multipath mode. */
157#define CCWDEV_DO_MULTIPATH 0x0010
154 158
155extern int ccw_device_start(struct ccw_device *, struct ccw1 *, 159extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
156 unsigned long, __u8, unsigned long); 160 unsigned long, __u8, unsigned long);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index aaccc8ecfa8f..58ffbd1d04a1 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2208,13 +2208,6 @@ int dasd_generic_probe(struct ccw_device *cdev,
2208{ 2208{
2209 int ret; 2209 int ret;
2210 2210
2211 ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
2212 if (ret) {
2213 DBF_EVENT(DBF_WARNING,
2214 "dasd_generic_probe: could not set ccw-device options "
2215 "for %s\n", dev_name(&cdev->dev));
2216 return ret;
2217 }
2218 ret = dasd_add_sysfs_files(cdev); 2211 ret = dasd_add_sysfs_files(cdev);
2219 if (ret) { 2212 if (ret) {
2220 DBF_EVENT(DBF_WARNING, 2213 DBF_EVENT(DBF_WARNING,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 417b97cd3f94..a8ec0731609e 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -86,7 +86,8 @@ dasd_eckd_probe (struct ccw_device *cdev)
86 int ret; 86 int ret;
87 87
88 /* set ECKD specific ccw-device options */ 88 /* set ECKD specific ccw-device options */
89 ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE); 89 ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE |
90 CCWDEV_DO_PATHGROUP | CCWDEV_DO_MULTIPATH);
90 if (ret) { 91 if (ret) {
91 DBF_EVENT(DBF_WARNING, 92 DBF_EVENT(DBF_WARNING,
92 "dasd_eckd_probe: could not set ccw-device options " 93 "dasd_eckd_probe: could not set ccw-device options "
@@ -1090,6 +1091,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
1090 struct dasd_block *block; 1091 struct dasd_block *block;
1091 int is_known, rc; 1092 int is_known, rc;
1092 1093
1094 if (!ccw_device_is_pathgroup(device->cdev)) {
1095 dev_warn(&device->cdev->dev,
1096 "A channel path group could not be established\n");
1097 return -EIO;
1098 }
1099 if (!ccw_device_is_multipath(device->cdev)) {
1100 dev_info(&device->cdev->dev,
1101 "The DASD is not operating in multipath mode\n");
1102 }
1093 private = (struct dasd_eckd_private *) device->private; 1103 private = (struct dasd_eckd_private *) device->private;
1094 if (!private) { 1104 if (!private) {
1095 private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); 1105 private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 5cd31e071647..27503a778fcb 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -579,7 +579,8 @@ tape_generic_probe(struct ccw_device *cdev)
579 device = tape_alloc_device(); 579 device = tape_alloc_device();
580 if (IS_ERR(device)) 580 if (IS_ERR(device))
581 return -ENODEV; 581 return -ENODEV;
582 ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); 582 ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP |
583 CCWDEV_DO_MULTIPATH);
583 ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group); 584 ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
584 if (ret) { 585 if (ret) {
585 tape_put_device(device); 586 tape_put_device(device);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 349d8c52c0d0..d6e315dc0f98 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -601,7 +601,7 @@ ccw_device_offline(struct ccw_device *cdev)
601 if (cdev->private->state != DEV_STATE_ONLINE) 601 if (cdev->private->state != DEV_STATE_ONLINE)
602 return -EINVAL; 602 return -EINVAL;
603 /* Are we doing path grouping? */ 603 /* Are we doing path grouping? */
604 if (!cdev->private->options.pgroup) { 604 if (!cdev->private->flags.pgroup) {
605 /* No, set state offline immediately. */ 605 /* No, set state offline immediately. */
606 ccw_device_done(cdev, DEV_STATE_OFFLINE); 606 ccw_device_done(cdev, DEV_STATE_OFFLINE);
607 return 0; 607 return 0;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 5ab90ec42318..d4be16acebe4 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -46,6 +46,7 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
46 cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0; 46 cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0;
47 cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0; 47 cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0;
48 cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0; 48 cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0;
49 cdev->private->options.mpath = (flags & CCWDEV_DO_MULTIPATH) != 0;
49 return 0; 50 return 0;
50} 51}
51 52
@@ -74,6 +75,7 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
74 cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0; 75 cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0;
75 cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0; 76 cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0;
76 cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0; 77 cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0;
78 cdev->private->options.mpath |= (flags & CCWDEV_DO_MULTIPATH) != 0;
77 return 0; 79 return 0;
78} 80}
79 81
@@ -90,9 +92,34 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
90 cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0; 92 cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0;
91 cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0; 93 cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0;
92 cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; 94 cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
95 cdev->private->options.mpath &= (flags & CCWDEV_DO_MULTIPATH) == 0;
93} 96}
94 97
95/** 98/**
99 * ccw_device_is_pathgroup - determine if paths to this device are grouped
100 * @cdev: ccw device
101 *
102 * Return non-zero if there is a path group, zero otherwise.
103 */
104int ccw_device_is_pathgroup(struct ccw_device *cdev)
105{
106 return cdev->private->flags.pgroup;
107}
108EXPORT_SYMBOL(ccw_device_is_pathgroup);
109
110/**
111 * ccw_device_is_multipath - determine if device is operating in multipath mode
112 * @cdev: ccw device
113 *
114 * Return non-zero if device is operating in multipath mode, zero otherwise.
115 */
116int ccw_device_is_multipath(struct ccw_device *cdev)
117{
118 return cdev->private->flags.mpath;
119}
120EXPORT_SYMBOL(ccw_device_is_multipath);
121
122/**
96 * ccw_device_clear() - terminate I/O request processing 123 * ccw_device_clear() - terminate I/O request processing
97 * @cdev: target ccw device 124 * @cdev: target ccw device
98 * @intparm: interruption parameter; value is only used if no I/O is 125 * @intparm: interruption parameter; value is only used if no I/O is
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index ce493144b054..3323042ba755 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -30,8 +30,8 @@ static void verify_done(struct ccw_device *cdev, int rc)
30{ 30{
31 struct subchannel *sch = to_subchannel(cdev->dev.parent); 31 struct subchannel *sch = to_subchannel(cdev->dev.parent);
32 struct ccw_dev_id *id = &cdev->private->dev_id; 32 struct ccw_dev_id *id = &cdev->private->dev_id;
33 int mpath = !cdev->private->flags.pgid_single; 33 int mpath = cdev->private->flags.mpath;
34 int pgroup = cdev->private->options.pgroup; 34 int pgroup = cdev->private->flags.pgroup;
35 35
36 if (rc) 36 if (rc)
37 goto out; 37 goto out;
@@ -150,7 +150,7 @@ static void spid_do(struct ccw_device *cdev)
150 fn = SPID_FUNC_ESTABLISH; 150 fn = SPID_FUNC_ESTABLISH;
151 else 151 else
152 fn = SPID_FUNC_RESIGN; 152 fn = SPID_FUNC_RESIGN;
153 if (!cdev->private->flags.pgid_single) 153 if (cdev->private->flags.mpath)
154 fn |= SPID_FUNC_MULTI_PATH; 154 fn |= SPID_FUNC_MULTI_PATH;
155 spid_build_cp(cdev, fn); 155 spid_build_cp(cdev, fn);
156 ccw_request_start(cdev); 156 ccw_request_start(cdev);
@@ -177,13 +177,13 @@ static void spid_callback(struct ccw_device *cdev, void *data, int rc)
177 case -EACCES: 177 case -EACCES:
178 break; 178 break;
179 case -EOPNOTSUPP: 179 case -EOPNOTSUPP:
180 if (!cdev->private->flags.pgid_single) { 180 if (cdev->private->flags.mpath) {
181 /* Try without multipathing. */ 181 /* Try without multipathing. */
182 cdev->private->flags.pgid_single = 1; 182 cdev->private->flags.mpath = 0;
183 goto out_restart; 183 goto out_restart;
184 } 184 }
185 /* Try without pathgrouping. */ 185 /* Try without pathgrouping. */
186 cdev->private->options.pgroup = 0; 186 cdev->private->flags.pgroup = 0;
187 goto out_restart; 187 goto out_restart;
188 default: 188 default:
189 goto err; 189 goto err;
@@ -374,7 +374,7 @@ static void verify_start(struct ccw_device *cdev)
374 req->timeout = PGID_TIMEOUT; 374 req->timeout = PGID_TIMEOUT;
375 req->maxretries = PGID_RETRIES; 375 req->maxretries = PGID_RETRIES;
376 req->lpm = 0x80; 376 req->lpm = 0x80;
377 if (cdev->private->options.pgroup) { 377 if (cdev->private->flags.pgroup) {
378 req->callback = spid_callback; 378 req->callback = spid_callback;
379 spid_do(cdev); 379 spid_do(cdev);
380 } else { 380 } else {
@@ -400,10 +400,17 @@ void ccw_device_verify_start(struct ccw_device *cdev)
400 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 400 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
401 if (!cdev->private->flags.pgid_rdy) { 401 if (!cdev->private->flags.pgid_rdy) {
402 /* No pathgrouping possible. */ 402 /* No pathgrouping possible. */
403 cdev->private->options.pgroup = 0; 403 cdev->private->flags.pgroup = 0;
404 cdev->private->flags.pgid_single = 1; 404 cdev->private->flags.mpath = 0;
405 } else 405 } else {
406 cdev->private->flags.pgid_single = 0; 406 /*
407 * Initialize pathgroup and multipath state with target values.
408 * They may change in the course of path verification.
409 */
410 cdev->private->flags.pgroup = cdev->private->options.pgroup;
411 cdev->private->flags.mpath = cdev->private->options.mpath;
412
413 }
407 cdev->private->flags.doverify = 0; 414 cdev->private->flags.doverify = 0;
408 verify_start(cdev); 415 verify_start(cdev);
409} 416}
@@ -419,7 +426,7 @@ static void disband_callback(struct ccw_device *cdev, void *data, int rc)
419 if (rc) 426 if (rc)
420 goto out; 427 goto out;
421 /* Ensure consistent multipathing state at device and channel. */ 428 /* Ensure consistent multipathing state at device and channel. */
422 cdev->private->flags.pgid_single = 1; 429 cdev->private->flags.mpath = 0;
423 if (sch->config.mp) { 430 if (sch->config.mp) {
424 sch->config.mp = 0; 431 sch->config.mp = 0;
425 rc = cio_commit_config(sch); 432 rc = cio_commit_config(sch);
@@ -453,7 +460,7 @@ void ccw_device_disband_start(struct ccw_device *cdev)
453 req->lpm = sch->schib.pmcw.pam & sch->opm; 460 req->lpm = sch->schib.pmcw.pam & sch->opm;
454 req->callback = disband_callback; 461 req->callback = disband_callback;
455 fn = SPID_FUNC_DISBAND; 462 fn = SPID_FUNC_DISBAND;
456 if (!cdev->private->flags.pgid_single) 463 if (cdev->private->flags.mpath)
457 fn |= SPID_FUNC_MULTI_PATH; 464 fn |= SPID_FUNC_MULTI_PATH;
458 spid_build_cp(cdev, fn); 465 spid_build_cp(cdev, fn);
459 ccw_request_start(cdev); 466 ccw_request_start(cdev);
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 8942dc092d0a..b387c80d1888 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -156,9 +156,9 @@ struct ccw_device_private {
156 unsigned int repall:1; /* report every interrupt status */ 156 unsigned int repall:1; /* report every interrupt status */
157 unsigned int pgroup:1; /* do path grouping */ 157 unsigned int pgroup:1; /* do path grouping */
158 unsigned int force:1; /* allow forced online */ 158 unsigned int force:1; /* allow forced online */
159 unsigned int mpath:1; /* do multipathing */
159 } __attribute__ ((packed)) options; 160 } __attribute__ ((packed)) options;
160 struct { 161 struct {
161 unsigned int pgid_single:1; /* use single path for Set PGID */
162 unsigned int esid:1; /* Ext. SenseID supported by HW */ 162 unsigned int esid:1; /* Ext. SenseID supported by HW */
163 unsigned int dosense:1; /* delayed SENSE required */ 163 unsigned int dosense:1; /* delayed SENSE required */
164 unsigned int doverify:1; /* delayed path verification */ 164 unsigned int doverify:1; /* delayed path verification */
@@ -167,6 +167,8 @@ struct ccw_device_private {
167 unsigned int fake_irb:1; /* deliver faked irb */ 167 unsigned int fake_irb:1; /* deliver faked irb */
168 unsigned int resuming:1; /* recognition while resume */ 168 unsigned int resuming:1; /* recognition while resume */
169 unsigned int pgid_rdy:1; /* pgids are ready */ 169 unsigned int pgid_rdy:1; /* pgids are ready */
170 unsigned int pgroup:1; /* pathgroup is set up */
171 unsigned int mpath:1; /* multipathing is set up */
170 } __attribute__((packed)) flags; 172 } __attribute__((packed)) flags;
171 unsigned long intparm; /* user interruption parameter */ 173 unsigned long intparm; /* user interruption parameter */
172 struct qdio_irq *qdio_data; 174 struct qdio_irq *qdio_data;