diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
| -rw-r--r-- | drivers/s390/block/dasd_eckd.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2fb2b9ea97ec..108332b44d98 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | 22 | ||
| 23 | #include <asm/css_chars.h> | ||
| 23 | #include <asm/debug.h> | 24 | #include <asm/debug.h> |
| 24 | #include <asm/idals.h> | 25 | #include <asm/idals.h> |
| 25 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
| @@ -31,8 +32,6 @@ | |||
| 31 | 32 | ||
| 32 | #include "dasd_int.h" | 33 | #include "dasd_int.h" |
| 33 | #include "dasd_eckd.h" | 34 | #include "dasd_eckd.h" |
| 34 | #include "../cio/chsc.h" | ||
| 35 | |||
| 36 | 35 | ||
| 37 | #ifdef PRINTK_HEADER | 36 | #ifdef PRINTK_HEADER |
| 38 | #undef PRINTK_HEADER | 37 | #undef PRINTK_HEADER |
| @@ -140,6 +139,10 @@ dasd_eckd_set_online(struct ccw_device *cdev) | |||
| 140 | static const int sizes_trk0[] = { 28, 148, 84 }; | 139 | static const int sizes_trk0[] = { 28, 148, 84 }; |
| 141 | #define LABEL_SIZE 140 | 140 | #define LABEL_SIZE 140 |
| 142 | 141 | ||
| 142 | /* head and record addresses of count_area read in analysis ccw */ | ||
| 143 | static const int count_area_head[] = { 0, 0, 0, 0, 2 }; | ||
| 144 | static const int count_area_rec[] = { 1, 2, 3, 4, 1 }; | ||
| 145 | |||
| 143 | static inline unsigned int | 146 | static inline unsigned int |
| 144 | round_up_multiple(unsigned int no, unsigned int mult) | 147 | round_up_multiple(unsigned int no, unsigned int mult) |
| 145 | { | 148 | { |
| @@ -212,7 +215,7 @@ check_XRC (struct ccw1 *de_ccw, | |||
| 212 | 215 | ||
| 213 | rc = get_sync_clock(&data->ep_sys_time); | 216 | rc = get_sync_clock(&data->ep_sys_time); |
| 214 | /* Ignore return code if sync clock is switched off. */ | 217 | /* Ignore return code if sync clock is switched off. */ |
| 215 | if (rc == -ENOSYS || rc == -EACCES) | 218 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 216 | rc = 0; | 219 | rc = 0; |
| 217 | 220 | ||
| 218 | de_ccw->count = sizeof(struct DE_eckd_data); | 221 | de_ccw->count = sizeof(struct DE_eckd_data); |
| @@ -323,7 +326,7 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | |||
| 323 | 326 | ||
| 324 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); | 327 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); |
| 325 | /* Ignore return code if sync clock is switched off. */ | 328 | /* Ignore return code if sync clock is switched off. */ |
| 326 | if (rc == -ENOSYS || rc == -EACCES) | 329 | if (rc == -EOPNOTSUPP || rc == -EACCES) |
| 327 | rc = 0; | 330 | rc = 0; |
| 328 | return rc; | 331 | return rc; |
| 329 | } | 332 | } |
| @@ -1507,7 +1510,8 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, | |||
| 1507 | * call might change behaviour of DASD devices. | 1510 | * call might change behaviour of DASD devices. |
| 1508 | */ | 1511 | */ |
| 1509 | static int | 1512 | static int |
| 1510 | dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | 1513 | dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav, |
| 1514 | unsigned long flags) | ||
| 1511 | { | 1515 | { |
| 1512 | struct dasd_ccw_req *cqr; | 1516 | struct dasd_ccw_req *cqr; |
| 1513 | int rc; | 1517 | int rc; |
| @@ -1516,10 +1520,19 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | |||
| 1516 | if (IS_ERR(cqr)) | 1520 | if (IS_ERR(cqr)) |
| 1517 | return PTR_ERR(cqr); | 1521 | return PTR_ERR(cqr); |
| 1518 | 1522 | ||
| 1523 | /* | ||
| 1524 | * set flags e.g. turn on failfast, to prevent blocking | ||
| 1525 | * the calling function should handle failed requests | ||
| 1526 | */ | ||
| 1527 | cqr->flags |= flags; | ||
| 1528 | |||
| 1519 | rc = dasd_sleep_on(cqr); | 1529 | rc = dasd_sleep_on(cqr); |
| 1520 | if (!rc) | 1530 | if (!rc) |
| 1521 | /* trigger CIO to reprobe devices */ | 1531 | /* trigger CIO to reprobe devices */ |
| 1522 | css_schedule_reprobe(); | 1532 | css_schedule_reprobe(); |
| 1533 | else if (cqr->intrc == -EAGAIN) | ||
| 1534 | rc = -EAGAIN; | ||
| 1535 | |||
| 1523 | dasd_sfree_request(cqr, cqr->memdev); | 1536 | dasd_sfree_request(cqr, cqr->memdev); |
| 1524 | return rc; | 1537 | return rc; |
| 1525 | } | 1538 | } |
| @@ -1527,7 +1540,8 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) | |||
| 1527 | /* | 1540 | /* |
| 1528 | * Valide storage server of current device. | 1541 | * Valide storage server of current device. |
| 1529 | */ | 1542 | */ |
| 1530 | static void dasd_eckd_validate_server(struct dasd_device *device) | 1543 | static int dasd_eckd_validate_server(struct dasd_device *device, |
| 1544 | unsigned long flags) | ||
| 1531 | { | 1545 | { |
| 1532 | int rc; | 1546 | int rc; |
| 1533 | struct dasd_eckd_private *private; | 1547 | struct dasd_eckd_private *private; |
| @@ -1536,17 +1550,18 @@ static void dasd_eckd_validate_server(struct dasd_device *device) | |||
| 1536 | private = (struct dasd_eckd_private *) device->private; | 1550 | private = (struct dasd_eckd_private *) device->private; |
| 1537 | if (private->uid.type == UA_BASE_PAV_ALIAS || | 1551 | if (private->uid.type == UA_BASE_PAV_ALIAS || |
| 1538 | private->uid.type == UA_HYPER_PAV_ALIAS) | 1552 | private->uid.type == UA_HYPER_PAV_ALIAS) |
| 1539 | return; | 1553 | return 0; |
| 1540 | if (dasd_nopav || MACHINE_IS_VM) | 1554 | if (dasd_nopav || MACHINE_IS_VM) |
| 1541 | enable_pav = 0; | 1555 | enable_pav = 0; |
| 1542 | else | 1556 | else |
| 1543 | enable_pav = 1; | 1557 | enable_pav = 1; |
| 1544 | rc = dasd_eckd_psf_ssc(device, enable_pav); | 1558 | rc = dasd_eckd_psf_ssc(device, enable_pav, flags); |
| 1545 | 1559 | ||
| 1546 | /* may be requested feature is not available on server, | 1560 | /* may be requested feature is not available on server, |
| 1547 | * therefore just report error and go ahead */ | 1561 | * therefore just report error and go ahead */ |
| 1548 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " | 1562 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " |
| 1549 | "returned rc=%d", private->uid.ssid, rc); | 1563 | "returned rc=%d", private->uid.ssid, rc); |
| 1564 | return rc; | ||
| 1550 | } | 1565 | } |
| 1551 | 1566 | ||
| 1552 | /* | 1567 | /* |
| @@ -1556,7 +1571,13 @@ static void dasd_eckd_do_validate_server(struct work_struct *work) | |||
| 1556 | { | 1571 | { |
| 1557 | struct dasd_device *device = container_of(work, struct dasd_device, | 1572 | struct dasd_device *device = container_of(work, struct dasd_device, |
| 1558 | kick_validate); | 1573 | kick_validate); |
| 1559 | dasd_eckd_validate_server(device); | 1574 | if (dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST) |
| 1575 | == -EAGAIN) { | ||
| 1576 | /* schedule worker again if failed */ | ||
| 1577 | schedule_work(&device->kick_validate); | ||
| 1578 | return; | ||
| 1579 | } | ||
| 1580 | |||
| 1560 | dasd_put_device(device); | 1581 | dasd_put_device(device); |
| 1561 | } | 1582 | } |
| 1562 | 1583 | ||
| @@ -1685,7 +1706,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1685 | if (rc) | 1706 | if (rc) |
| 1686 | goto out_err2; | 1707 | goto out_err2; |
| 1687 | 1708 | ||
| 1688 | dasd_eckd_validate_server(device); | 1709 | dasd_eckd_validate_server(device, 0); |
| 1689 | 1710 | ||
| 1690 | /* device may report different configuration data after LCU setup */ | 1711 | /* device may report different configuration data after LCU setup */ |
| 1691 | rc = dasd_eckd_read_conf(device); | 1712 | rc = dasd_eckd_read_conf(device); |
| @@ -1922,7 +1943,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1922 | count_area = NULL; | 1943 | count_area = NULL; |
| 1923 | for (i = 0; i < 3; i++) { | 1944 | for (i = 0; i < 3; i++) { |
| 1924 | if (private->count_area[i].kl != 4 || | 1945 | if (private->count_area[i].kl != 4 || |
| 1925 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4) { | 1946 | private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4 || |
| 1947 | private->count_area[i].cyl != 0 || | ||
| 1948 | private->count_area[i].head != count_area_head[i] || | ||
| 1949 | private->count_area[i].record != count_area_rec[i]) { | ||
| 1926 | private->uses_cdl = 0; | 1950 | private->uses_cdl = 0; |
| 1927 | break; | 1951 | break; |
| 1928 | } | 1952 | } |
| @@ -1934,7 +1958,10 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
| 1934 | for (i = 0; i < 5; i++) { | 1958 | for (i = 0; i < 5; i++) { |
| 1935 | if ((private->count_area[i].kl != 0) || | 1959 | if ((private->count_area[i].kl != 0) || |
| 1936 | (private->count_area[i].dl != | 1960 | (private->count_area[i].dl != |
| 1937 | private->count_area[0].dl)) | 1961 | private->count_area[0].dl) || |
| 1962 | private->count_area[i].cyl != 0 || | ||
| 1963 | private->count_area[i].head != count_area_head[i] || | ||
| 1964 | private->count_area[i].record != count_area_rec[i]) | ||
| 1938 | break; | 1965 | break; |
| 1939 | } | 1966 | } |
| 1940 | if (i == 5) | 1967 | if (i == 5) |
| @@ -4153,7 +4180,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device) | |||
| 4153 | rc = dasd_alias_make_device_known_to_lcu(device); | 4180 | rc = dasd_alias_make_device_known_to_lcu(device); |
| 4154 | if (rc) | 4181 | if (rc) |
| 4155 | return rc; | 4182 | return rc; |
| 4156 | dasd_eckd_validate_server(device); | 4183 | dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST); |
| 4157 | 4184 | ||
| 4158 | /* RE-Read Configuration Data */ | 4185 | /* RE-Read Configuration Data */ |
| 4159 | rc = dasd_eckd_read_conf(device); | 4186 | rc = dasd_eckd_read_conf(device); |
