aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2008-07-14 03:58:45 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:05 -0400
commitc820de39bd083222f5be2563181c87493e436f7c (patch)
tree4861db1aeca00d55d76b5844ad209d81a2795105 /drivers/s390/cio/device.c
parent7e9db9eaefdb8798730790214ff1b7746006ec98 (diff)
[S390] cio: Rework css driver.
Rework the css driver methods to provide sane callbacks for subchannels of all types. As a bonus, this cleans up and simplyfies the machine check handling for I/O subchannels a lot. 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>
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c365
1 files changed, 279 insertions, 86 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 23b129fd4d8d..9281b25087a6 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -2,8 +2,7 @@
2 * drivers/s390/cio/device.c 2 * drivers/s390/cio/device.c
3 * bus driver for ccw devices 3 * bus driver for ccw devices
4 * 4 *
5 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, 5 * Copyright IBM Corp. 2002,2008
6 * IBM Corporation
7 * Author(s): Arnd Bergmann (arndb@de.ibm.com) 6 * Author(s): Arnd Bergmann (arndb@de.ibm.com)
8 * Cornelia Huck (cornelia.huck@de.ibm.com) 7 * Cornelia Huck (cornelia.huck@de.ibm.com)
9 * Martin Schwidefsky (schwidefsky@de.ibm.com) 8 * Martin Schwidefsky (schwidefsky@de.ibm.com)
@@ -126,19 +125,17 @@ struct bus_type ccw_bus_type;
126static void io_subchannel_irq(struct subchannel *); 125static void io_subchannel_irq(struct subchannel *);
127static int io_subchannel_probe(struct subchannel *); 126static int io_subchannel_probe(struct subchannel *);
128static int io_subchannel_remove(struct subchannel *); 127static int io_subchannel_remove(struct subchannel *);
129static int io_subchannel_notify(struct subchannel *, int);
130static void io_subchannel_verify(struct subchannel *);
131static void io_subchannel_ioterm(struct subchannel *);
132static void io_subchannel_shutdown(struct subchannel *); 128static void io_subchannel_shutdown(struct subchannel *);
129static int io_subchannel_sch_event(struct subchannel *, int);
130static int io_subchannel_chp_event(struct subchannel *, void *, int);
133 131
134static struct css_driver io_subchannel_driver = { 132static struct css_driver io_subchannel_driver = {
135 .owner = THIS_MODULE, 133 .owner = THIS_MODULE,
136 .subchannel_type = SUBCHANNEL_TYPE_IO, 134 .subchannel_type = SUBCHANNEL_TYPE_IO,
137 .name = "io_subchannel", 135 .name = "io_subchannel",
138 .irq = io_subchannel_irq, 136 .irq = io_subchannel_irq,
139 .notify = io_subchannel_notify, 137 .sch_event = io_subchannel_sch_event,
140 .verify = io_subchannel_verify, 138 .chp_event = io_subchannel_chp_event,
141 .termination = io_subchannel_ioterm,
142 .probe = io_subchannel_probe, 139 .probe = io_subchannel_probe,
143 .remove = io_subchannel_remove, 140 .remove = io_subchannel_remove,
144 .shutdown = io_subchannel_shutdown, 141 .shutdown = io_subchannel_shutdown,
@@ -786,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch,
786 sch_set_cdev(sch, cdev); 783 sch_set_cdev(sch, cdev);
787 cdev->private->schid = sch->schid; 784 cdev->private->schid = sch->schid;
788 cdev->ccwlock = sch->lock; 785 cdev->ccwlock = sch->lock;
789 device_trigger_reprobe(sch); 786 ccw_device_trigger_reprobe(cdev);
790 spin_unlock_irq(sch->lock); 787 spin_unlock_irq(sch->lock);
791} 788}
792 789
@@ -1265,11 +1262,7 @@ static int io_subchannel_notify(struct subchannel *sch, int event)
1265 cdev = sch_get_cdev(sch); 1262 cdev = sch_get_cdev(sch);
1266 if (!cdev) 1263 if (!cdev)
1267 return 0; 1264 return 0;
1268 if (!cdev->drv) 1265 return ccw_device_notify(cdev, event);
1269 return 0;
1270 if (!cdev->online)
1271 return 0;
1272 return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
1273} 1266}
1274 1267
1275static void io_subchannel_verify(struct subchannel *sch) 1268static void io_subchannel_verify(struct subchannel *sch)
@@ -1281,22 +1274,98 @@ static void io_subchannel_verify(struct subchannel *sch)
1281 dev_fsm_event(cdev, DEV_EVENT_VERIFY); 1274 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1282} 1275}
1283 1276
1284static void io_subchannel_ioterm(struct subchannel *sch) 1277static int check_for_io_on_path(struct subchannel *sch, int mask)
1285{ 1278{
1286 struct ccw_device *cdev; 1279 int cc;
1287 1280
1288 cdev = sch_get_cdev(sch); 1281 cc = stsch(sch->schid, &sch->schib);
1289 if (!cdev) 1282 if (cc)
1290 return; 1283 return 0;
1291 /* Internal I/O will be retried by the interrupt handler. */ 1284 if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask)
1292 if (cdev->private->flags.intretry) 1285 return 1;
1286 return 0;
1287}
1288
1289static void terminate_internal_io(struct subchannel *sch,
1290 struct ccw_device *cdev)
1291{
1292 if (cio_clear(sch)) {
1293 /* Recheck device in case clear failed. */
1294 sch->lpm = 0;
1295 if (cdev->online)
1296 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1297 else
1298 css_schedule_eval(sch->schid);
1293 return; 1299 return;
1300 }
1294 cdev->private->state = DEV_STATE_CLEAR_VERIFY; 1301 cdev->private->state = DEV_STATE_CLEAR_VERIFY;
1302 /* Request retry of internal operation. */
1303 cdev->private->flags.intretry = 1;
1304 /* Call handler. */
1295 if (cdev->handler) 1305 if (cdev->handler)
1296 cdev->handler(cdev, cdev->private->intparm, 1306 cdev->handler(cdev, cdev->private->intparm,
1297 ERR_PTR(-EIO)); 1307 ERR_PTR(-EIO));
1298} 1308}
1299 1309
1310static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
1311{
1312 struct ccw_device *cdev;
1313
1314 cdev = sch_get_cdev(sch);
1315 if (!cdev)
1316 return;
1317 if (check_for_io_on_path(sch, mask)) {
1318 if (cdev->private->state == DEV_STATE_ONLINE)
1319 ccw_device_kill_io(cdev);
1320 else {
1321 terminate_internal_io(sch, cdev);
1322 /* Re-start path verification. */
1323 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1324 }
1325 } else
1326 /* trigger path verification. */
1327 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1328
1329}
1330
1331static int io_subchannel_chp_event(struct subchannel *sch, void *data,
1332 int event)
1333{
1334 int mask;
1335 struct res_acc_data *res_data;
1336
1337 res_data = data;
1338 mask = chp_ssd_get_mask(&sch->ssd_info, res_data);
1339 if (!mask)
1340 return 0;
1341 switch (event) {
1342 case CHP_VARY_OFF:
1343 sch->opm &= ~mask;
1344 sch->lpm &= ~mask;
1345 io_subchannel_terminate_path(sch, mask);
1346 break;
1347 case CHP_VARY_ON:
1348 sch->opm |= mask;
1349 sch->lpm |= mask;
1350 io_subchannel_verify(sch);
1351 break;
1352 case CHP_OFFLINE:
1353 if (stsch(sch->schid, &sch->schib))
1354 return -ENXIO;
1355 if (!css_sch_is_valid(&sch->schib))
1356 return -ENODEV;
1357 io_subchannel_terminate_path(sch, mask);
1358 break;
1359 case CHP_ONLINE:
1360 if (stsch(sch->schid, &sch->schib))
1361 return -ENXIO;
1362 sch->lpm |= mask & sch->opm;
1363 io_subchannel_verify(sch);
1364 break;
1365 }
1366 return 0;
1367}
1368
1300static void 1369static void
1301io_subchannel_shutdown(struct subchannel *sch) 1370io_subchannel_shutdown(struct subchannel *sch)
1302{ 1371{
@@ -1326,6 +1395,195 @@ io_subchannel_shutdown(struct subchannel *sch)
1326 cio_disable_subchannel(sch); 1395 cio_disable_subchannel(sch);
1327} 1396}
1328 1397
1398static int io_subchannel_get_status(struct subchannel *sch)
1399{
1400 struct schib schib;
1401
1402 if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
1403 return CIO_GONE;
1404 if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
1405 return CIO_REVALIDATE;
1406 if (!sch->lpm)
1407 return CIO_NO_PATH;
1408 return CIO_OPER;
1409}
1410
1411static int device_is_disconnected(struct ccw_device *cdev)
1412{
1413 if (!cdev)
1414 return 0;
1415 return (cdev->private->state == DEV_STATE_DISCONNECTED ||
1416 cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
1417}
1418
1419static int recovery_check(struct device *dev, void *data)
1420{
1421 struct ccw_device *cdev = to_ccwdev(dev);
1422 int *redo = data;
1423
1424 spin_lock_irq(cdev->ccwlock);
1425 switch (cdev->private->state) {
1426 case DEV_STATE_DISCONNECTED:
1427 CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
1428 cdev->private->dev_id.ssid,
1429 cdev->private->dev_id.devno);
1430 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1431 *redo = 1;
1432 break;
1433 case DEV_STATE_DISCONNECTED_SENSE_ID:
1434 *redo = 1;
1435 break;
1436 }
1437 spin_unlock_irq(cdev->ccwlock);
1438
1439 return 0;
1440}
1441
1442static void recovery_work_func(struct work_struct *unused)
1443{
1444 int redo = 0;
1445
1446 bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
1447 if (redo) {
1448 spin_lock_irq(&recovery_lock);
1449 if (!timer_pending(&recovery_timer)) {
1450 if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
1451 recovery_phase++;
1452 mod_timer(&recovery_timer, jiffies +
1453 recovery_delay[recovery_phase] * HZ);
1454 }
1455 spin_unlock_irq(&recovery_lock);
1456 } else
1457 CIO_MSG_EVENT(4, "recovery: end\n");
1458}
1459
1460static DECLARE_WORK(recovery_work, recovery_work_func);
1461
1462static void recovery_func(unsigned long data)
1463{
1464 /*
1465 * We can't do our recovery in softirq context and it's not
1466 * performance critical, so we schedule it.
1467 */
1468 schedule_work(&recovery_work);
1469}
1470
1471static void ccw_device_schedule_recovery(void)
1472{
1473 unsigned long flags;
1474
1475 CIO_MSG_EVENT(4, "recovery: schedule\n");
1476 spin_lock_irqsave(&recovery_lock, flags);
1477 if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
1478 recovery_phase = 0;
1479 mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
1480 }
1481 spin_unlock_irqrestore(&recovery_lock, flags);
1482}
1483
1484static void device_set_disconnected(struct ccw_device *cdev)
1485{
1486 if (!cdev)
1487 return;
1488 ccw_device_set_timeout(cdev, 0);
1489 cdev->private->flags.fake_irb = 0;
1490 cdev->private->state = DEV_STATE_DISCONNECTED;
1491 if (cdev->online)
1492 ccw_device_schedule_recovery();
1493}
1494
1495static int io_subchannel_sch_event(struct subchannel *sch, int slow)
1496{
1497 int event, ret, disc;
1498 unsigned long flags;
1499 enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
1500 struct ccw_device *cdev;
1501
1502 spin_lock_irqsave(sch->lock, flags);
1503 cdev = sch_get_cdev(sch);
1504 disc = device_is_disconnected(cdev);
1505 if (disc && slow) {
1506 /* Disconnected devices are evaluated directly only.*/
1507 spin_unlock_irqrestore(sch->lock, flags);
1508 return 0;
1509 }
1510 /* No interrupt after machine check - kill pending timers. */
1511 if (cdev)
1512 ccw_device_set_timeout(cdev, 0);
1513 if (!disc && !slow) {
1514 /* Non-disconnected devices are evaluated on the slow path. */
1515 spin_unlock_irqrestore(sch->lock, flags);
1516 return -EAGAIN;
1517 }
1518 event = io_subchannel_get_status(sch);
1519 CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
1520 sch->schid.ssid, sch->schid.sch_no, event,
1521 disc ? "disconnected" : "normal",
1522 slow ? "slow" : "fast");
1523 /* Analyze subchannel status. */
1524 action = NONE;
1525 switch (event) {
1526 case CIO_NO_PATH:
1527 if (disc) {
1528 /* Check if paths have become available. */
1529 action = REPROBE;
1530 break;
1531 }
1532 /* fall through */
1533 case CIO_GONE:
1534 /* Prevent unwanted effects when opening lock. */
1535 cio_disable_subchannel(sch);
1536 device_set_disconnected(cdev);
1537 /* Ask driver what to do with device. */
1538 action = UNREGISTER;
1539 spin_unlock_irqrestore(sch->lock, flags);
1540 ret = io_subchannel_notify(sch, event);
1541 spin_lock_irqsave(sch->lock, flags);
1542 if (ret)
1543 action = NONE;
1544 break;
1545 case CIO_REVALIDATE:
1546 /* Device will be removed, so no notify necessary. */
1547 if (disc)
1548 /* Reprobe because immediate unregister might block. */
1549 action = REPROBE;
1550 else
1551 action = UNREGISTER_PROBE;
1552 break;
1553 case CIO_OPER:
1554 if (disc)
1555 /* Get device operational again. */
1556 action = REPROBE;
1557 break;
1558 }
1559 /* Perform action. */
1560 ret = 0;
1561 switch (action) {
1562 case UNREGISTER:
1563 case UNREGISTER_PROBE:
1564 /* Unregister device (will use subchannel lock). */
1565 spin_unlock_irqrestore(sch->lock, flags);
1566 css_sch_device_unregister(sch);
1567 spin_lock_irqsave(sch->lock, flags);
1568
1569 /* Reset intparm to zeroes. */
1570 sch->schib.pmcw.intparm = 0;
1571 cio_modify(sch);
1572 break;
1573 case REPROBE:
1574 ccw_device_trigger_reprobe(cdev);
1575 break;
1576 default:
1577 break;
1578 }
1579 spin_unlock_irqrestore(sch->lock, flags);
1580 /* Probe if necessary. */
1581 if (action == UNREGISTER_PROBE)
1582 ret = css_probe_device(sch->schid);
1583
1584 return ret;
1585}
1586
1329#ifdef CONFIG_CCW_CONSOLE 1587#ifdef CONFIG_CCW_CONSOLE
1330static struct ccw_device console_cdev; 1588static struct ccw_device console_cdev;
1331static struct ccw_device_private console_private; 1589static struct ccw_device_private console_private;
@@ -1558,71 +1816,6 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
1558 return sch->schid; 1816 return sch->schid;
1559} 1817}
1560 1818
1561static int recovery_check(struct device *dev, void *data)
1562{
1563 struct ccw_device *cdev = to_ccwdev(dev);
1564 int *redo = data;
1565
1566 spin_lock_irq(cdev->ccwlock);
1567 switch (cdev->private->state) {
1568 case DEV_STATE_DISCONNECTED:
1569 CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n",
1570 cdev->private->dev_id.ssid,
1571 cdev->private->dev_id.devno);
1572 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
1573 *redo = 1;
1574 break;
1575 case DEV_STATE_DISCONNECTED_SENSE_ID:
1576 *redo = 1;
1577 break;
1578 }
1579 spin_unlock_irq(cdev->ccwlock);
1580
1581 return 0;
1582}
1583
1584static void recovery_work_func(struct work_struct *unused)
1585{
1586 int redo = 0;
1587
1588 bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
1589 if (redo) {
1590 spin_lock_irq(&recovery_lock);
1591 if (!timer_pending(&recovery_timer)) {
1592 if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
1593 recovery_phase++;
1594 mod_timer(&recovery_timer, jiffies +
1595 recovery_delay[recovery_phase] * HZ);
1596 }
1597 spin_unlock_irq(&recovery_lock);
1598 } else
1599 CIO_MSG_EVENT(4, "recovery: end\n");
1600}
1601
1602static DECLARE_WORK(recovery_work, recovery_work_func);
1603
1604static void recovery_func(unsigned long data)
1605{
1606 /*
1607 * We can't do our recovery in softirq context and it's not
1608 * performance critical, so we schedule it.
1609 */
1610 schedule_work(&recovery_work);
1611}
1612
1613void ccw_device_schedule_recovery(void)
1614{
1615 unsigned long flags;
1616
1617 CIO_MSG_EVENT(4, "recovery: schedule\n");
1618 spin_lock_irqsave(&recovery_lock, flags);
1619 if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
1620 recovery_phase = 0;
1621 mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
1622 }
1623 spin_unlock_irqrestore(&recovery_lock, flags);
1624}
1625
1626MODULE_LICENSE("GPL"); 1819MODULE_LICENSE("GPL");
1627EXPORT_SYMBOL(ccw_device_set_online); 1820EXPORT_SYMBOL(ccw_device_set_online);
1628EXPORT_SYMBOL(ccw_device_set_offline); 1821EXPORT_SYMBOL(ccw_device_set_offline);