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

s390/cio: recover from bad paths

In some situations we don't receive notification from firmware that
a previously unusable channelpath is usable again.

Schedule recovery for devices that return from path verification
without using all potentially usable paths. The recovery thread will
periodically trigger a path verification on the affected devices.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Suggested-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
55fb7347 c8b85024

+24 -3
+9 -3
drivers/s390/cio/device.c
··· 1225 1225 static int recovery_check(struct device *dev, void *data) 1226 1226 { 1227 1227 struct ccw_device *cdev = to_ccwdev(dev); 1228 + struct subchannel *sch; 1228 1229 int *redo = data; 1229 1230 1230 1231 spin_lock_irq(cdev->ccwlock); 1231 1232 switch (cdev->private->state) { 1233 + case DEV_STATE_ONLINE: 1234 + sch = to_subchannel(cdev->dev.parent); 1235 + if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm) 1236 + break; 1237 + /* fall through */ 1232 1238 case DEV_STATE_DISCONNECTED: 1233 1239 CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", 1234 1240 cdev->private->dev_id.ssid, ··· 1266 1260 } 1267 1261 spin_unlock_irq(&recovery_lock); 1268 1262 } else 1269 - CIO_MSG_EVENT(4, "recovery: end\n"); 1263 + CIO_MSG_EVENT(3, "recovery: end\n"); 1270 1264 } 1271 1265 1272 1266 static DECLARE_WORK(recovery_work, recovery_work_func); ··· 1280 1274 schedule_work(&recovery_work); 1281 1275 } 1282 1276 1283 - static void ccw_device_schedule_recovery(void) 1277 + void ccw_device_schedule_recovery(void) 1284 1278 { 1285 1279 unsigned long flags; 1286 1280 1287 - CIO_MSG_EVENT(4, "recovery: schedule\n"); 1281 + CIO_MSG_EVENT(3, "recovery: schedule\n"); 1288 1282 spin_lock_irqsave(&recovery_lock, flags); 1289 1283 if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { 1290 1284 recovery_phase = 0;
+1
drivers/s390/cio/device.h
··· 134 134 void ccw_device_set_notoper(struct ccw_device *cdev); 135 135 136 136 void ccw_device_set_timeout(struct ccw_device *, int); 137 + void ccw_device_schedule_recovery(void); 137 138 138 139 /* Channel measurement facility related */ 139 140 void retry_set_schib(struct ccw_device *cdev);
+12
drivers/s390/cio/device_fsm.c
··· 476 476 } 477 477 } 478 478 479 + static void ccw_device_handle_broken_paths(struct ccw_device *cdev) 480 + { 481 + struct subchannel *sch = to_subchannel(cdev->dev.parent); 482 + u8 broken_paths = (sch->schib.pmcw.pam & sch->opm) ^ sch->vpm; 483 + 484 + if (broken_paths && (cdev->private->path_broken_mask != broken_paths)) 485 + ccw_device_schedule_recovery(); 486 + 487 + cdev->private->path_broken_mask = broken_paths; 488 + } 489 + 479 490 void ccw_device_verify_done(struct ccw_device *cdev, int err) 480 491 { 481 492 struct subchannel *sch; ··· 519 508 memset(&cdev->private->irb, 0, sizeof(struct irb)); 520 509 } 521 510 ccw_device_report_path_events(cdev); 511 + ccw_device_handle_broken_paths(cdev); 522 512 break; 523 513 case -ETIME: 524 514 case -EUSERS:
+2
drivers/s390/cio/io_sch.h
··· 131 131 not operable */ 132 132 u8 path_gone_mask; /* mask of paths, that became unavailable */ 133 133 u8 path_new_mask; /* mask of paths, that became available */ 134 + u8 path_broken_mask; /* mask of paths, which were found to be 135 + unusable */ 134 136 struct { 135 137 unsigned int fast:1; /* post with "channel end" */ 136 138 unsigned int repall:1; /* report every interrupt status */