Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Peter Oberparleiter and committed by
Martin Schwidefsky
454e1fa1 4257aaec

+68 -24
+4
arch/s390/include/asm/ccwdev.h
··· 142 142 extern int ccw_device_set_options_mask(struct ccw_device *, unsigned long); 143 143 extern int ccw_device_set_options(struct ccw_device *, unsigned long); 144 144 extern void ccw_device_clear_options(struct ccw_device *, unsigned long); 145 + int ccw_device_is_pathgroup(struct ccw_device *cdev); 146 + int ccw_device_is_multipath(struct ccw_device *cdev); 145 147 146 148 /* Allow for i/o completion notification after primary interrupt status. */ 147 149 #define CCWDEV_EARLY_NOTIFICATION 0x0001 ··· 153 151 #define CCWDEV_DO_PATHGROUP 0x0004 154 152 /* Allow forced onlining of boxed devices. */ 155 153 #define CCWDEV_ALLOW_FORCE 0x0008 154 + /* Try to use multipath mode. */ 155 + #define CCWDEV_DO_MULTIPATH 0x0010 156 156 157 157 extern int ccw_device_start(struct ccw_device *, struct ccw1 *, 158 158 unsigned long, __u8, unsigned long);
-7
drivers/s390/block/dasd.c
··· 2208 2208 { 2209 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 2211 ret = dasd_add_sysfs_files(cdev); 2219 2212 if (ret) { 2220 2213 DBF_EVENT(DBF_WARNING,
+11 -1
drivers/s390/block/dasd_eckd.c
··· 86 86 int ret; 87 87 88 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 91 if (ret) { 91 92 DBF_EVENT(DBF_WARNING, 92 93 "dasd_eckd_probe: could not set ccw-device options " ··· 1091 1090 struct dasd_block *block; 1092 1091 int is_known, rc; 1093 1092 1093 + if (!ccw_device_is_pathgroup(device->cdev)) { 1094 + dev_warn(&device->cdev->dev, 1095 + "A channel path group could not be established\n"); 1096 + return -EIO; 1097 + } 1098 + if (!ccw_device_is_multipath(device->cdev)) { 1099 + dev_info(&device->cdev->dev, 1100 + "The DASD is not operating in multipath mode\n"); 1101 + } 1094 1102 private = (struct dasd_eckd_private *) device->private; 1095 1103 if (!private) { 1096 1104 private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
+2 -1
drivers/s390/char/tape_core.c
··· 579 579 device = tape_alloc_device(); 580 580 if (IS_ERR(device)) 581 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 584 ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group); 584 585 if (ret) { 585 586 tape_put_device(device);
+1 -1
drivers/s390/cio/device_fsm.c
··· 601 601 if (cdev->private->state != DEV_STATE_ONLINE) 602 602 return -EINVAL; 603 603 /* Are we doing path grouping? */ 604 - if (!cdev->private->options.pgroup) { 604 + if (!cdev->private->flags.pgroup) { 605 605 /* No, set state offline immediately. */ 606 606 ccw_device_done(cdev, DEV_STATE_OFFLINE); 607 607 return 0;
+27
drivers/s390/cio/device_ops.c
··· 46 46 cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0; 47 47 cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0; 48 48 cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0; 49 + cdev->private->options.mpath = (flags & CCWDEV_DO_MULTIPATH) != 0; 49 50 return 0; 50 51 } 51 52 ··· 75 74 cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0; 76 75 cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0; 77 76 cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0; 77 + cdev->private->options.mpath |= (flags & CCWDEV_DO_MULTIPATH) != 0; 78 78 return 0; 79 79 } 80 80 ··· 92 90 cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0; 93 91 cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0; 94 92 cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0; 93 + cdev->private->options.mpath &= (flags & CCWDEV_DO_MULTIPATH) == 0; 95 94 } 95 + 96 + /** 97 + * ccw_device_is_pathgroup - determine if paths to this device are grouped 98 + * @cdev: ccw device 99 + * 100 + * Return non-zero if there is a path group, zero otherwise. 101 + */ 102 + int ccw_device_is_pathgroup(struct ccw_device *cdev) 103 + { 104 + return cdev->private->flags.pgroup; 105 + } 106 + EXPORT_SYMBOL(ccw_device_is_pathgroup); 107 + 108 + /** 109 + * ccw_device_is_multipath - determine if device is operating in multipath mode 110 + * @cdev: ccw device 111 + * 112 + * Return non-zero if device is operating in multipath mode, zero otherwise. 113 + */ 114 + int ccw_device_is_multipath(struct ccw_device *cdev) 115 + { 116 + return cdev->private->flags.mpath; 117 + } 118 + EXPORT_SYMBOL(ccw_device_is_multipath); 96 119 97 120 /** 98 121 * ccw_device_clear() - terminate I/O request processing
+20 -13
drivers/s390/cio/device_pgid.c
··· 30 30 { 31 31 struct subchannel *sch = to_subchannel(cdev->dev.parent); 32 32 struct ccw_dev_id *id = &cdev->private->dev_id; 33 - int mpath = !cdev->private->flags.pgid_single; 34 - int pgroup = cdev->private->options.pgroup; 33 + int mpath = cdev->private->flags.mpath; 34 + int pgroup = cdev->private->flags.pgroup; 35 35 36 36 if (rc) 37 37 goto out; ··· 150 150 fn = SPID_FUNC_ESTABLISH; 151 151 else 152 152 fn = SPID_FUNC_RESIGN; 153 - if (!cdev->private->flags.pgid_single) 153 + if (cdev->private->flags.mpath) 154 154 fn |= SPID_FUNC_MULTI_PATH; 155 155 spid_build_cp(cdev, fn); 156 156 ccw_request_start(cdev); ··· 177 177 case -EACCES: 178 178 break; 179 179 case -EOPNOTSUPP: 180 - if (!cdev->private->flags.pgid_single) { 180 + if (cdev->private->flags.mpath) { 181 181 /* Try without multipathing. */ 182 - cdev->private->flags.pgid_single = 1; 182 + cdev->private->flags.mpath = 0; 183 183 goto out_restart; 184 184 } 185 185 /* Try without pathgrouping. */ 186 - cdev->private->options.pgroup = 0; 186 + cdev->private->flags.pgroup = 0; 187 187 goto out_restart; 188 188 default: 189 189 goto err; ··· 374 374 req->timeout = PGID_TIMEOUT; 375 375 req->maxretries = PGID_RETRIES; 376 376 req->lpm = 0x80; 377 - if (cdev->private->options.pgroup) { 377 + if (cdev->private->flags.pgroup) { 378 378 req->callback = spid_callback; 379 379 spid_do(cdev); 380 380 } else { ··· 400 400 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 401 401 if (!cdev->private->flags.pgid_rdy) { 402 402 /* No pathgrouping possible. */ 403 - cdev->private->options.pgroup = 0; 404 - cdev->private->flags.pgid_single = 1; 405 - } else 406 - cdev->private->flags.pgid_single = 0; 403 + cdev->private->flags.pgroup = 0; 404 + cdev->private->flags.mpath = 0; 405 + } else { 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 414 cdev->private->flags.doverify = 0; 408 415 verify_start(cdev); 409 416 } ··· 426 419 if (rc) 427 420 goto out; 428 421 /* Ensure consistent multipathing state at device and channel. */ 429 - cdev->private->flags.pgid_single = 1; 422 + cdev->private->flags.mpath = 0; 430 423 if (sch->config.mp) { 431 424 sch->config.mp = 0; 432 425 rc = cio_commit_config(sch); ··· 460 453 req->lpm = sch->schib.pmcw.pam & sch->opm; 461 454 req->callback = disband_callback; 462 455 fn = SPID_FUNC_DISBAND; 463 - if (!cdev->private->flags.pgid_single) 456 + if (cdev->private->flags.mpath) 464 457 fn |= SPID_FUNC_MULTI_PATH; 465 458 spid_build_cp(cdev, fn); 466 459 ccw_request_start(cdev);
+3 -1
drivers/s390/cio/io_sch.h
··· 156 156 unsigned int repall:1; /* report every interrupt status */ 157 157 unsigned int pgroup:1; /* do path grouping */ 158 158 unsigned int force:1; /* allow forced online */ 159 + unsigned int mpath:1; /* do multipathing */ 159 160 } __attribute__ ((packed)) options; 160 161 struct { 161 - unsigned int pgid_single:1; /* use single path for Set PGID */ 162 162 unsigned int esid:1; /* Ext. SenseID supported by HW */ 163 163 unsigned int dosense:1; /* delayed SENSE required */ 164 164 unsigned int doverify:1; /* delayed path verification */ ··· 167 167 unsigned int fake_irb:1; /* deliver faked irb */ 168 168 unsigned int resuming:1; /* recognition while resume */ 169 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 172 } __attribute__((packed)) flags; 171 173 unsigned long intparm; /* user interruption parameter */ 172 174 struct qdio_irq *qdio_data;