aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
authorStefan Haberland <stefan.haberland@de.ibm.com>2012-09-11 09:10:58 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-17 03:58:18 -0400
commit12d7b1078bb374fc3e2955b9f2815415a66157b6 (patch)
treec99de58b079166e536a83a1b869daaa2fcfbe323 /drivers/s390/block
parent4db84d4f07b87c452c6000e0595dc9570ed21b41 (diff)
s390/dasd: fix pathgroup race
If a new path is available we need to verify the path data. If it is the first path for a device the stop bits are removed after path verification. If a pathgroup is established we need to set system characteristics for the lcu. Therefore I/O has to be started. If the device is stopped the set system characteristics worker may block the path verification worker and the device is blocked. Turn on failfast for set system characteristics CQR to prevent a deadlock with the path verification worker. If a pathgroup is established on a device that is not in use trigger path verification. Maybe we were not informed about a working path. Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com> Reviewed-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd.c11
-rw-r--r--drivers/s390/block/dasd_eckd.c32
2 files changed, 36 insertions, 7 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 6498d15f874f..0595c763dafd 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2157,6 +2157,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
2157 test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && 2157 test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
2158 (!dasd_eer_enabled(device))) { 2158 (!dasd_eer_enabled(device))) {
2159 cqr->status = DASD_CQR_FAILED; 2159 cqr->status = DASD_CQR_FAILED;
2160 cqr->intrc = -EAGAIN;
2160 continue; 2161 continue;
2161 } 2162 }
2162 /* Don't try to start requests if device is stopped */ 2163 /* Don't try to start requests if device is stopped */
@@ -3270,6 +3271,16 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
3270 dasd_schedule_device_bh(device); 3271 dasd_schedule_device_bh(device);
3271 } 3272 }
3272 if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { 3273 if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) {
3274 if (!(device->path_data.opm & eventlpm) &&
3275 !(device->path_data.tbvpm & eventlpm)) {
3276 /*
3277 * we can not establish a pathgroup on an
3278 * unavailable path, so trigger a path
3279 * verification first
3280 */
3281 device->path_data.tbvpm |= eventlpm;
3282 dasd_schedule_device_bh(device);
3283 }
3273 DBF_DEV_EVENT(DBF_WARNING, device, "%s", 3284 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
3274 "Pathgroup re-established\n"); 3285 "Pathgroup re-established\n");
3275 if (device->discipline->kick_validate) 3286 if (device->discipline->kick_validate)
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 2fb2b9ea97ec..c48c72abbefc 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1507,7 +1507,8 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
1507 * call might change behaviour of DASD devices. 1507 * call might change behaviour of DASD devices.
1508 */ 1508 */
1509static int 1509static int
1510dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) 1510dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav,
1511 unsigned long flags)
1511{ 1512{
1512 struct dasd_ccw_req *cqr; 1513 struct dasd_ccw_req *cqr;
1513 int rc; 1514 int rc;
@@ -1516,10 +1517,19 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav)
1516 if (IS_ERR(cqr)) 1517 if (IS_ERR(cqr))
1517 return PTR_ERR(cqr); 1518 return PTR_ERR(cqr);
1518 1519
1520 /*
1521 * set flags e.g. turn on failfast, to prevent blocking
1522 * the calling function should handle failed requests
1523 */
1524 cqr->flags |= flags;
1525
1519 rc = dasd_sleep_on(cqr); 1526 rc = dasd_sleep_on(cqr);
1520 if (!rc) 1527 if (!rc)
1521 /* trigger CIO to reprobe devices */ 1528 /* trigger CIO to reprobe devices */
1522 css_schedule_reprobe(); 1529 css_schedule_reprobe();
1530 else if (cqr->intrc == -EAGAIN)
1531 rc = -EAGAIN;
1532
1523 dasd_sfree_request(cqr, cqr->memdev); 1533 dasd_sfree_request(cqr, cqr->memdev);
1524 return rc; 1534 return rc;
1525} 1535}
@@ -1527,7 +1537,8 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav)
1527/* 1537/*
1528 * Valide storage server of current device. 1538 * Valide storage server of current device.
1529 */ 1539 */
1530static void dasd_eckd_validate_server(struct dasd_device *device) 1540static int dasd_eckd_validate_server(struct dasd_device *device,
1541 unsigned long flags)
1531{ 1542{
1532 int rc; 1543 int rc;
1533 struct dasd_eckd_private *private; 1544 struct dasd_eckd_private *private;
@@ -1536,17 +1547,18 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
1536 private = (struct dasd_eckd_private *) device->private; 1547 private = (struct dasd_eckd_private *) device->private;
1537 if (private->uid.type == UA_BASE_PAV_ALIAS || 1548 if (private->uid.type == UA_BASE_PAV_ALIAS ||
1538 private->uid.type == UA_HYPER_PAV_ALIAS) 1549 private->uid.type == UA_HYPER_PAV_ALIAS)
1539 return; 1550 return 0;
1540 if (dasd_nopav || MACHINE_IS_VM) 1551 if (dasd_nopav || MACHINE_IS_VM)
1541 enable_pav = 0; 1552 enable_pav = 0;
1542 else 1553 else
1543 enable_pav = 1; 1554 enable_pav = 1;
1544 rc = dasd_eckd_psf_ssc(device, enable_pav); 1555 rc = dasd_eckd_psf_ssc(device, enable_pav, flags);
1545 1556
1546 /* may be requested feature is not available on server, 1557 /* may be requested feature is not available on server,
1547 * therefore just report error and go ahead */ 1558 * therefore just report error and go ahead */
1548 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " 1559 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x "
1549 "returned rc=%d", private->uid.ssid, rc); 1560 "returned rc=%d", private->uid.ssid, rc);
1561 return rc;
1550} 1562}
1551 1563
1552/* 1564/*
@@ -1556,7 +1568,13 @@ static void dasd_eckd_do_validate_server(struct work_struct *work)
1556{ 1568{
1557 struct dasd_device *device = container_of(work, struct dasd_device, 1569 struct dasd_device *device = container_of(work, struct dasd_device,
1558 kick_validate); 1570 kick_validate);
1559 dasd_eckd_validate_server(device); 1571 if (dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST)
1572 == -EAGAIN) {
1573 /* schedule worker again if failed */
1574 schedule_work(&device->kick_validate);
1575 return;
1576 }
1577
1560 dasd_put_device(device); 1578 dasd_put_device(device);
1561} 1579}
1562 1580
@@ -1685,7 +1703,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
1685 if (rc) 1703 if (rc)
1686 goto out_err2; 1704 goto out_err2;
1687 1705
1688 dasd_eckd_validate_server(device); 1706 dasd_eckd_validate_server(device, 0);
1689 1707
1690 /* device may report different configuration data after LCU setup */ 1708 /* device may report different configuration data after LCU setup */
1691 rc = dasd_eckd_read_conf(device); 1709 rc = dasd_eckd_read_conf(device);
@@ -4153,7 +4171,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device)
4153 rc = dasd_alias_make_device_known_to_lcu(device); 4171 rc = dasd_alias_make_device_known_to_lcu(device);
4154 if (rc) 4172 if (rc)
4155 return rc; 4173 return rc;
4156 dasd_eckd_validate_server(device); 4174 dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST);
4157 4175
4158 /* RE-Read Configuration Data */ 4176 /* RE-Read Configuration Data */
4159 rc = dasd_eckd_read_conf(device); 4177 rc = dasd_eckd_read_conf(device);