diff options
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 314 |
1 files changed, 227 insertions, 87 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index fb613d70c2cb..794bfd962266 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #define KMSG_COMPONENT "dasd" | 11 | #define KMSG_COMPONENT "dasd" |
12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
13 | 13 | ||
14 | #include <linux/kernel_stat.h> | ||
14 | #include <linux/kmod.h> | 15 | #include <linux/kmod.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
@@ -368,6 +369,11 @@ dasd_state_ready_to_online(struct dasd_device * device) | |||
368 | device->state = DASD_STATE_ONLINE; | 369 | device->state = DASD_STATE_ONLINE; |
369 | if (device->block) { | 370 | if (device->block) { |
370 | dasd_schedule_block_bh(device->block); | 371 | dasd_schedule_block_bh(device->block); |
372 | if ((device->features & DASD_FEATURE_USERAW)) { | ||
373 | disk = device->block->gdp; | ||
374 | kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); | ||
375 | return 0; | ||
376 | } | ||
371 | disk = device->block->bdev->bd_disk; | 377 | disk = device->block->bdev->bd_disk; |
372 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); | 378 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); |
373 | while ((part = disk_part_iter_next(&piter))) | 379 | while ((part = disk_part_iter_next(&piter))) |
@@ -393,7 +399,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device) | |||
393 | return rc; | 399 | return rc; |
394 | } | 400 | } |
395 | device->state = DASD_STATE_READY; | 401 | device->state = DASD_STATE_READY; |
396 | if (device->block) { | 402 | if (device->block && !(device->features & DASD_FEATURE_USERAW)) { |
397 | disk = device->block->bdev->bd_disk; | 403 | disk = device->block->bdev->bd_disk; |
398 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); | 404 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); |
399 | while ((part = disk_part_iter_next(&piter))) | 405 | while ((part = disk_part_iter_next(&piter))) |
@@ -744,10 +750,6 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, | |||
744 | char *data; | 750 | char *data; |
745 | int size; | 751 | int size; |
746 | 752 | ||
747 | /* Sanity checks */ | ||
748 | BUG_ON(datasize > PAGE_SIZE || | ||
749 | (cplength*sizeof(struct ccw1)) > PAGE_SIZE); | ||
750 | |||
751 | size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; | 753 | size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; |
752 | if (cplength > 0) | 754 | if (cplength > 0) |
753 | size += cplength * sizeof(struct ccw1); | 755 | size += cplength * sizeof(struct ccw1); |
@@ -853,7 +855,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) | |||
853 | rc = ccw_device_clear(device->cdev, (long) cqr); | 855 | rc = ccw_device_clear(device->cdev, (long) cqr); |
854 | switch (rc) { | 856 | switch (rc) { |
855 | case 0: /* termination successful */ | 857 | case 0: /* termination successful */ |
856 | cqr->retries--; | ||
857 | cqr->status = DASD_CQR_CLEAR_PENDING; | 858 | cqr->status = DASD_CQR_CLEAR_PENDING; |
858 | cqr->stopclk = get_clock(); | 859 | cqr->stopclk = get_clock(); |
859 | cqr->starttime = 0; | 860 | cqr->starttime = 0; |
@@ -905,6 +906,16 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
905 | return rc; | 906 | return rc; |
906 | } | 907 | } |
907 | device = (struct dasd_device *) cqr->startdev; | 908 | device = (struct dasd_device *) cqr->startdev; |
909 | if (((cqr->block && | ||
910 | test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) || | ||
911 | test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) && | ||
912 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
913 | DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p " | ||
914 | "because of stolen lock", cqr); | ||
915 | cqr->status = DASD_CQR_ERROR; | ||
916 | cqr->intrc = -EPERM; | ||
917 | return -EPERM; | ||
918 | } | ||
908 | if (cqr->retries < 0) { | 919 | if (cqr->retries < 0) { |
909 | /* internal error 14 - start_IO run out of retries */ | 920 | /* internal error 14 - start_IO run out of retries */ |
910 | sprintf(errorstring, "14 %p", cqr); | 921 | sprintf(errorstring, "14 %p", cqr); |
@@ -916,6 +927,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
916 | cqr->startclk = get_clock(); | 927 | cqr->startclk = get_clock(); |
917 | cqr->starttime = jiffies; | 928 | cqr->starttime = jiffies; |
918 | cqr->retries--; | 929 | cqr->retries--; |
930 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { | ||
931 | cqr->lpm &= device->path_data.opm; | ||
932 | if (!cqr->lpm) | ||
933 | cqr->lpm = device->path_data.opm; | ||
934 | } | ||
919 | if (cqr->cpmode == 1) { | 935 | if (cqr->cpmode == 1) { |
920 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, | 936 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, |
921 | (long) cqr, cqr->lpm); | 937 | (long) cqr, cqr->lpm); |
@@ -928,35 +944,53 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
928 | cqr->status = DASD_CQR_IN_IO; | 944 | cqr->status = DASD_CQR_IN_IO; |
929 | break; | 945 | break; |
930 | case -EBUSY: | 946 | case -EBUSY: |
931 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 947 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
932 | "start_IO: device busy, retry later"); | 948 | "start_IO: device busy, retry later"); |
933 | break; | 949 | break; |
934 | case -ETIMEDOUT: | 950 | case -ETIMEDOUT: |
935 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 951 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
936 | "start_IO: request timeout, retry later"); | 952 | "start_IO: request timeout, retry later"); |
937 | break; | 953 | break; |
938 | case -EACCES: | 954 | case -EACCES: |
939 | /* -EACCES indicates that the request used only a | 955 | /* -EACCES indicates that the request used only a subset of the |
940 | * subset of the available pathes and all these | 956 | * available paths and all these paths are gone. If the lpm of |
941 | * pathes are gone. | 957 | * this request was only a subset of the opm (e.g. the ppm) then |
942 | * Do a retry with all available pathes. | 958 | * we just do a retry with all available paths. |
959 | * If we already use the full opm, something is amiss, and we | ||
960 | * need a full path verification. | ||
943 | */ | 961 | */ |
944 | cqr->lpm = LPM_ANYPATH; | 962 | if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { |
945 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 963 | DBF_DEV_EVENT(DBF_WARNING, device, |
946 | "start_IO: selected pathes gone," | 964 | "start_IO: selected paths gone (%x)", |
947 | " retry on all pathes"); | 965 | cqr->lpm); |
966 | } else if (cqr->lpm != device->path_data.opm) { | ||
967 | cqr->lpm = device->path_data.opm; | ||
968 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | ||
969 | "start_IO: selected paths gone," | ||
970 | " retry on all paths"); | ||
971 | } else { | ||
972 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
973 | "start_IO: all paths in opm gone," | ||
974 | " do path verification"); | ||
975 | dasd_generic_last_path_gone(device); | ||
976 | device->path_data.opm = 0; | ||
977 | device->path_data.ppm = 0; | ||
978 | device->path_data.npm = 0; | ||
979 | device->path_data.tbvpm = | ||
980 | ccw_device_get_path_mask(device->cdev); | ||
981 | } | ||
948 | break; | 982 | break; |
949 | case -ENODEV: | 983 | case -ENODEV: |
950 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 984 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
951 | "start_IO: -ENODEV device gone, retry"); | 985 | "start_IO: -ENODEV device gone, retry"); |
952 | break; | 986 | break; |
953 | case -EIO: | 987 | case -EIO: |
954 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 988 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
955 | "start_IO: -EIO device gone, retry"); | 989 | "start_IO: -EIO device gone, retry"); |
956 | break; | 990 | break; |
957 | case -EINVAL: | 991 | case -EINVAL: |
958 | /* most likely caused in power management context */ | 992 | /* most likely caused in power management context */ |
959 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 993 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
960 | "start_IO: -EINVAL device currently " | 994 | "start_IO: -EINVAL device currently " |
961 | "not accessible"); | 995 | "not accessible"); |
962 | break; | 996 | break; |
@@ -1076,6 +1110,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1076 | unsigned long long now; | 1110 | unsigned long long now; |
1077 | int expires; | 1111 | int expires; |
1078 | 1112 | ||
1113 | kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; | ||
1079 | if (IS_ERR(irb)) { | 1114 | if (IS_ERR(irb)) { |
1080 | switch (PTR_ERR(irb)) { | 1115 | switch (PTR_ERR(irb)) { |
1081 | case -EIO: | 1116 | case -EIO: |
@@ -1094,16 +1129,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1094 | } | 1129 | } |
1095 | 1130 | ||
1096 | now = get_clock(); | 1131 | now = get_clock(); |
1097 | |||
1098 | /* check for unsolicited interrupts */ | ||
1099 | cqr = (struct dasd_ccw_req *) intparm; | 1132 | cqr = (struct dasd_ccw_req *) intparm; |
1100 | if (!cqr || ((scsw_cc(&irb->scsw) == 1) && | 1133 | /* check for conditions that should be handled immediately */ |
1101 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && | 1134 | if (!cqr || |
1102 | ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) || | 1135 | !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && |
1103 | (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND | | 1136 | scsw_cstat(&irb->scsw) == 0)) { |
1104 | SCSW_STCTL_ALERT_STATUS))))) { | ||
1105 | if (cqr && cqr->status == DASD_CQR_IN_IO) | ||
1106 | cqr->status = DASD_CQR_QUEUED; | ||
1107 | if (cqr) | 1137 | if (cqr) |
1108 | memcpy(&cqr->irb, irb, sizeof(*irb)); | 1138 | memcpy(&cqr->irb, irb, sizeof(*irb)); |
1109 | device = dasd_device_from_cdev_locked(cdev); | 1139 | device = dasd_device_from_cdev_locked(cdev); |
@@ -1114,17 +1144,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1114 | dasd_put_device(device); | 1144 | dasd_put_device(device); |
1115 | return; | 1145 | return; |
1116 | } | 1146 | } |
1117 | device->discipline->dump_sense_dbf(device, irb, | 1147 | device->discipline->dump_sense_dbf(device, irb, "int"); |
1118 | "unsolicited"); | 1148 | if (device->features & DASD_FEATURE_ERPLOG) |
1119 | if ((device->features & DASD_FEATURE_ERPLOG)) | 1149 | device->discipline->dump_sense(device, cqr, irb); |
1120 | device->discipline->dump_sense(device, cqr, | 1150 | device->discipline->check_for_device_change(device, cqr, irb); |
1121 | irb); | ||
1122 | dasd_device_clear_timer(device); | ||
1123 | device->discipline->handle_unsolicited_interrupt(device, | ||
1124 | irb); | ||
1125 | dasd_put_device(device); | 1151 | dasd_put_device(device); |
1126 | return; | ||
1127 | } | 1152 | } |
1153 | if (!cqr) | ||
1154 | return; | ||
1128 | 1155 | ||
1129 | device = (struct dasd_device *) cqr->startdev; | 1156 | device = (struct dasd_device *) cqr->startdev; |
1130 | if (!device || | 1157 | if (!device || |
@@ -1164,25 +1191,19 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1164 | struct dasd_ccw_req, devlist); | 1191 | struct dasd_ccw_req, devlist); |
1165 | } | 1192 | } |
1166 | } else { /* error */ | 1193 | } else { /* error */ |
1167 | memcpy(&cqr->irb, irb, sizeof(struct irb)); | ||
1168 | /* log sense for every failed I/O to s390 debugfeature */ | ||
1169 | dasd_log_sense_dbf(cqr, irb); | ||
1170 | if (device->features & DASD_FEATURE_ERPLOG) { | ||
1171 | dasd_log_sense(cqr, irb); | ||
1172 | } | ||
1173 | |||
1174 | /* | 1194 | /* |
1175 | * If we don't want complex ERP for this request, then just | 1195 | * If we don't want complex ERP for this request, then just |
1176 | * reset this and retry it in the fastpath | 1196 | * reset this and retry it in the fastpath |
1177 | */ | 1197 | */ |
1178 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && | 1198 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && |
1179 | cqr->retries > 0) { | 1199 | cqr->retries > 0) { |
1180 | if (cqr->lpm == LPM_ANYPATH) | 1200 | if (cqr->lpm == device->path_data.opm) |
1181 | DBF_DEV_EVENT(DBF_DEBUG, device, | 1201 | DBF_DEV_EVENT(DBF_DEBUG, device, |
1182 | "default ERP in fastpath " | 1202 | "default ERP in fastpath " |
1183 | "(%i retries left)", | 1203 | "(%i retries left)", |
1184 | cqr->retries); | 1204 | cqr->retries); |
1185 | cqr->lpm = LPM_ANYPATH; | 1205 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) |
1206 | cqr->lpm = device->path_data.opm; | ||
1186 | cqr->status = DASD_CQR_QUEUED; | 1207 | cqr->status = DASD_CQR_QUEUED; |
1187 | next = cqr; | 1208 | next = cqr; |
1188 | } else | 1209 | } else |
@@ -1210,13 +1231,13 @@ enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) | |||
1210 | goto out; | 1231 | goto out; |
1211 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || | 1232 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || |
1212 | device->state != device->target || | 1233 | device->state != device->target || |
1213 | !device->discipline->handle_unsolicited_interrupt){ | 1234 | !device->discipline->check_for_device_change){ |
1214 | dasd_put_device(device); | 1235 | dasd_put_device(device); |
1215 | goto out; | 1236 | goto out; |
1216 | } | 1237 | } |
1217 | 1238 | if (device->discipline->dump_sense_dbf) | |
1218 | dasd_device_clear_timer(device); | 1239 | device->discipline->dump_sense_dbf(device, irb, "uc"); |
1219 | device->discipline->handle_unsolicited_interrupt(device, irb); | 1240 | device->discipline->check_for_device_change(device, NULL, irb); |
1220 | dasd_put_device(device); | 1241 | dasd_put_device(device); |
1221 | out: | 1242 | out: |
1222 | return UC_TODO_RETRY; | 1243 | return UC_TODO_RETRY; |
@@ -1366,8 +1387,14 @@ static void __dasd_device_start_head(struct dasd_device *device) | |||
1366 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); | 1387 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); |
1367 | if (cqr->status != DASD_CQR_QUEUED) | 1388 | if (cqr->status != DASD_CQR_QUEUED) |
1368 | return; | 1389 | return; |
1369 | /* when device is stopped, return request to previous layer */ | 1390 | /* when device is stopped, return request to previous layer |
1370 | if (device->stopped) { | 1391 | * exception: only the disconnect or unresumed bits are set and the |
1392 | * cqr is a path verification request | ||
1393 | */ | ||
1394 | if (device->stopped && | ||
1395 | !(!(device->stopped & ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM)) | ||
1396 | && test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))) { | ||
1397 | cqr->intrc = -EAGAIN; | ||
1371 | cqr->status = DASD_CQR_CLEARED; | 1398 | cqr->status = DASD_CQR_CLEARED; |
1372 | dasd_schedule_device_bh(device); | 1399 | dasd_schedule_device_bh(device); |
1373 | return; | 1400 | return; |
@@ -1383,6 +1410,23 @@ static void __dasd_device_start_head(struct dasd_device *device) | |||
1383 | dasd_device_set_timer(device, 50); | 1410 | dasd_device_set_timer(device, 50); |
1384 | } | 1411 | } |
1385 | 1412 | ||
1413 | static void __dasd_device_check_path_events(struct dasd_device *device) | ||
1414 | { | ||
1415 | int rc; | ||
1416 | |||
1417 | if (device->path_data.tbvpm) { | ||
1418 | if (device->stopped & ~(DASD_STOPPED_DC_WAIT | | ||
1419 | DASD_UNRESUMED_PM)) | ||
1420 | return; | ||
1421 | rc = device->discipline->verify_path( | ||
1422 | device, device->path_data.tbvpm); | ||
1423 | if (rc) | ||
1424 | dasd_device_set_timer(device, 50); | ||
1425 | else | ||
1426 | device->path_data.tbvpm = 0; | ||
1427 | } | ||
1428 | }; | ||
1429 | |||
1386 | /* | 1430 | /* |
1387 | * Go through all request on the dasd_device request queue, | 1431 | * Go through all request on the dasd_device request queue, |
1388 | * terminate them on the cdev if necessary, and return them to the | 1432 | * terminate them on the cdev if necessary, and return them to the |
@@ -1457,6 +1501,7 @@ static void dasd_device_tasklet(struct dasd_device *device) | |||
1457 | __dasd_device_check_expire(device); | 1501 | __dasd_device_check_expire(device); |
1458 | /* find final requests on ccw queue */ | 1502 | /* find final requests on ccw queue */ |
1459 | __dasd_device_process_ccw_queue(device, &final_queue); | 1503 | __dasd_device_process_ccw_queue(device, &final_queue); |
1504 | __dasd_device_check_path_events(device); | ||
1460 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1505 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1461 | /* Now call the callback function of requests with final status */ | 1506 | /* Now call the callback function of requests with final status */ |
1462 | __dasd_device_process_final_queue(device, &final_queue); | 1507 | __dasd_device_process_final_queue(device, &final_queue); |
@@ -1613,7 +1658,12 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1613 | continue; | 1658 | continue; |
1614 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ | 1659 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ |
1615 | continue; | 1660 | continue; |
1616 | 1661 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && | |
1662 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
1663 | cqr->status = DASD_CQR_FAILED; | ||
1664 | cqr->intrc = -EPERM; | ||
1665 | continue; | ||
1666 | } | ||
1617 | /* Non-temporary stop condition will trigger fail fast */ | 1667 | /* Non-temporary stop condition will trigger fail fast */ |
1618 | if (device->stopped & ~DASD_STOPPED_PENDING && | 1668 | if (device->stopped & ~DASD_STOPPED_PENDING && |
1619 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 1669 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
@@ -1621,7 +1671,6 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1621 | cqr->status = DASD_CQR_FAILED; | 1671 | cqr->status = DASD_CQR_FAILED; |
1622 | continue; | 1672 | continue; |
1623 | } | 1673 | } |
1624 | |||
1625 | /* Don't try to start requests if device is stopped */ | 1674 | /* Don't try to start requests if device is stopped */ |
1626 | if (interruptible) { | 1675 | if (interruptible) { |
1627 | rc = wait_event_interruptible( | 1676 | rc = wait_event_interruptible( |
@@ -1706,13 +1755,18 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
1706 | int rc; | 1755 | int rc; |
1707 | 1756 | ||
1708 | device = cqr->startdev; | 1757 | device = cqr->startdev; |
1758 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && | ||
1759 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
1760 | cqr->status = DASD_CQR_FAILED; | ||
1761 | cqr->intrc = -EPERM; | ||
1762 | return -EIO; | ||
1763 | } | ||
1709 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | 1764 | spin_lock_irq(get_ccwdev_lock(device->cdev)); |
1710 | rc = _dasd_term_running_cqr(device); | 1765 | rc = _dasd_term_running_cqr(device); |
1711 | if (rc) { | 1766 | if (rc) { |
1712 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1767 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1713 | return rc; | 1768 | return rc; |
1714 | } | 1769 | } |
1715 | |||
1716 | cqr->callback = dasd_wakeup_cb; | 1770 | cqr->callback = dasd_wakeup_cb; |
1717 | cqr->callback_data = DASD_SLEEPON_START_TAG; | 1771 | cqr->callback_data = DASD_SLEEPON_START_TAG; |
1718 | cqr->status = DASD_CQR_QUEUED; | 1772 | cqr->status = DASD_CQR_QUEUED; |
@@ -2016,6 +2070,13 @@ static void __dasd_block_start_head(struct dasd_block *block) | |||
2016 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { | 2070 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { |
2017 | if (cqr->status != DASD_CQR_FILLED) | 2071 | if (cqr->status != DASD_CQR_FILLED) |
2018 | continue; | 2072 | continue; |
2073 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) && | ||
2074 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
2075 | cqr->status = DASD_CQR_FAILED; | ||
2076 | cqr->intrc = -EPERM; | ||
2077 | dasd_schedule_block_bh(block); | ||
2078 | continue; | ||
2079 | } | ||
2019 | /* Non-temporary stop condition will trigger fail fast */ | 2080 | /* Non-temporary stop condition will trigger fail fast */ |
2020 | if (block->base->stopped & ~DASD_STOPPED_PENDING && | 2081 | if (block->base->stopped & ~DASD_STOPPED_PENDING && |
2021 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2082 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
@@ -2201,8 +2262,20 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
2201 | { | 2262 | { |
2202 | int max; | 2263 | int max; |
2203 | 2264 | ||
2204 | blk_queue_logical_block_size(block->request_queue, block->bp_block); | 2265 | if (block->base->features & DASD_FEATURE_USERAW) { |
2205 | max = block->base->discipline->max_blocks << block->s2b_shift; | 2266 | /* |
2267 | * the max_blocks value for raw_track access is 256 | ||
2268 | * it is higher than the native ECKD value because we | ||
2269 | * only need one ccw per track | ||
2270 | * so the max_hw_sectors are | ||
2271 | * 2048 x 512B = 1024kB = 16 tracks | ||
2272 | */ | ||
2273 | max = 2048; | ||
2274 | } else { | ||
2275 | max = block->base->discipline->max_blocks << block->s2b_shift; | ||
2276 | } | ||
2277 | blk_queue_logical_block_size(block->request_queue, | ||
2278 | block->bp_block); | ||
2206 | blk_queue_max_hw_sectors(block->request_queue, max); | 2279 | blk_queue_max_hw_sectors(block->request_queue, max); |
2207 | blk_queue_max_segments(block->request_queue, -1L); | 2280 | blk_queue_max_segments(block->request_queue, -1L); |
2208 | /* with page sized segments we can translate each segement into | 2281 | /* with page sized segments we can translate each segement into |
@@ -2588,10 +2661,53 @@ int dasd_generic_set_offline(struct ccw_device *cdev) | |||
2588 | return 0; | 2661 | return 0; |
2589 | } | 2662 | } |
2590 | 2663 | ||
2664 | int dasd_generic_last_path_gone(struct dasd_device *device) | ||
2665 | { | ||
2666 | struct dasd_ccw_req *cqr; | ||
2667 | |||
2668 | dev_warn(&device->cdev->dev, "No operational channel path is left " | ||
2669 | "for the device\n"); | ||
2670 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", "last path gone"); | ||
2671 | /* First of all call extended error reporting. */ | ||
2672 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | ||
2673 | |||
2674 | if (device->state < DASD_STATE_BASIC) | ||
2675 | return 0; | ||
2676 | /* Device is active. We want to keep it. */ | ||
2677 | list_for_each_entry(cqr, &device->ccw_queue, devlist) | ||
2678 | if ((cqr->status == DASD_CQR_IN_IO) || | ||
2679 | (cqr->status == DASD_CQR_CLEAR_PENDING)) { | ||
2680 | cqr->status = DASD_CQR_QUEUED; | ||
2681 | cqr->retries++; | ||
2682 | } | ||
2683 | dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2684 | dasd_device_clear_timer(device); | ||
2685 | dasd_schedule_device_bh(device); | ||
2686 | return 1; | ||
2687 | } | ||
2688 | EXPORT_SYMBOL_GPL(dasd_generic_last_path_gone); | ||
2689 | |||
2690 | int dasd_generic_path_operational(struct dasd_device *device) | ||
2691 | { | ||
2692 | dev_info(&device->cdev->dev, "A channel path to the device has become " | ||
2693 | "operational\n"); | ||
2694 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", "path operational"); | ||
2695 | dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2696 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2697 | dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); | ||
2698 | dasd_restore_device(device); | ||
2699 | return 1; | ||
2700 | } | ||
2701 | dasd_schedule_device_bh(device); | ||
2702 | if (device->block) | ||
2703 | dasd_schedule_block_bh(device->block); | ||
2704 | return 1; | ||
2705 | } | ||
2706 | EXPORT_SYMBOL_GPL(dasd_generic_path_operational); | ||
2707 | |||
2591 | int dasd_generic_notify(struct ccw_device *cdev, int event) | 2708 | int dasd_generic_notify(struct ccw_device *cdev, int event) |
2592 | { | 2709 | { |
2593 | struct dasd_device *device; | 2710 | struct dasd_device *device; |
2594 | struct dasd_ccw_req *cqr; | ||
2595 | int ret; | 2711 | int ret; |
2596 | 2712 | ||
2597 | device = dasd_device_from_cdev_locked(cdev); | 2713 | device = dasd_device_from_cdev_locked(cdev); |
@@ -2602,41 +2718,64 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2602 | case CIO_GONE: | 2718 | case CIO_GONE: |
2603 | case CIO_BOXED: | 2719 | case CIO_BOXED: |
2604 | case CIO_NO_PATH: | 2720 | case CIO_NO_PATH: |
2605 | /* First of all call extended error reporting. */ | 2721 | device->path_data.opm = 0; |
2606 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | 2722 | device->path_data.ppm = 0; |
2607 | 2723 | device->path_data.npm = 0; | |
2608 | if (device->state < DASD_STATE_BASIC) | 2724 | ret = dasd_generic_last_path_gone(device); |
2609 | break; | ||
2610 | /* Device is active. We want to keep it. */ | ||
2611 | list_for_each_entry(cqr, &device->ccw_queue, devlist) | ||
2612 | if (cqr->status == DASD_CQR_IN_IO) { | ||
2613 | cqr->status = DASD_CQR_QUEUED; | ||
2614 | cqr->retries++; | ||
2615 | } | ||
2616 | dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2617 | dasd_device_clear_timer(device); | ||
2618 | dasd_schedule_device_bh(device); | ||
2619 | ret = 1; | ||
2620 | break; | 2725 | break; |
2621 | case CIO_OPER: | 2726 | case CIO_OPER: |
2622 | /* FIXME: add a sanity check. */ | ||
2623 | dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2624 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2625 | dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); | ||
2626 | dasd_restore_device(device); | ||
2627 | ret = 1; | ||
2628 | break; | ||
2629 | } | ||
2630 | dasd_schedule_device_bh(device); | ||
2631 | if (device->block) | ||
2632 | dasd_schedule_block_bh(device->block); | ||
2633 | ret = 1; | 2727 | ret = 1; |
2728 | if (device->path_data.opm) | ||
2729 | ret = dasd_generic_path_operational(device); | ||
2634 | break; | 2730 | break; |
2635 | } | 2731 | } |
2636 | dasd_put_device(device); | 2732 | dasd_put_device(device); |
2637 | return ret; | 2733 | return ret; |
2638 | } | 2734 | } |
2639 | 2735 | ||
2736 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | ||
2737 | { | ||
2738 | int chp; | ||
2739 | __u8 oldopm, eventlpm; | ||
2740 | struct dasd_device *device; | ||
2741 | |||
2742 | device = dasd_device_from_cdev_locked(cdev); | ||
2743 | if (IS_ERR(device)) | ||
2744 | return; | ||
2745 | for (chp = 0; chp < 8; chp++) { | ||
2746 | eventlpm = 0x80 >> chp; | ||
2747 | if (path_event[chp] & PE_PATH_GONE) { | ||
2748 | oldopm = device->path_data.opm; | ||
2749 | device->path_data.opm &= ~eventlpm; | ||
2750 | device->path_data.ppm &= ~eventlpm; | ||
2751 | device->path_data.npm &= ~eventlpm; | ||
2752 | if (oldopm && !device->path_data.opm) | ||
2753 | dasd_generic_last_path_gone(device); | ||
2754 | } | ||
2755 | if (path_event[chp] & PE_PATH_AVAILABLE) { | ||
2756 | device->path_data.opm &= ~eventlpm; | ||
2757 | device->path_data.ppm &= ~eventlpm; | ||
2758 | device->path_data.npm &= ~eventlpm; | ||
2759 | device->path_data.tbvpm |= eventlpm; | ||
2760 | dasd_schedule_device_bh(device); | ||
2761 | } | ||
2762 | } | ||
2763 | dasd_put_device(device); | ||
2764 | } | ||
2765 | EXPORT_SYMBOL_GPL(dasd_generic_path_event); | ||
2766 | |||
2767 | int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) | ||
2768 | { | ||
2769 | if (!device->path_data.opm && lpm) { | ||
2770 | device->path_data.opm = lpm; | ||
2771 | dasd_generic_path_operational(device); | ||
2772 | } else | ||
2773 | device->path_data.opm |= lpm; | ||
2774 | return 0; | ||
2775 | } | ||
2776 | EXPORT_SYMBOL_GPL(dasd_generic_verify_path); | ||
2777 | |||
2778 | |||
2640 | int dasd_generic_pm_freeze(struct ccw_device *cdev) | 2779 | int dasd_generic_pm_freeze(struct ccw_device *cdev) |
2641 | { | 2780 | { |
2642 | struct dasd_ccw_req *cqr, *n; | 2781 | struct dasd_ccw_req *cqr, *n; |
@@ -2646,6 +2785,10 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
2646 | 2785 | ||
2647 | if (IS_ERR(device)) | 2786 | if (IS_ERR(device)) |
2648 | return PTR_ERR(device); | 2787 | return PTR_ERR(device); |
2788 | |||
2789 | if (device->discipline->freeze) | ||
2790 | rc = device->discipline->freeze(device); | ||
2791 | |||
2649 | /* disallow new I/O */ | 2792 | /* disallow new I/O */ |
2650 | dasd_device_set_stop_bits(device, DASD_STOPPED_PM); | 2793 | dasd_device_set_stop_bits(device, DASD_STOPPED_PM); |
2651 | /* clear active requests */ | 2794 | /* clear active requests */ |
@@ -2682,9 +2825,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
2682 | list_splice_tail(&freeze_queue, &device->ccw_queue); | 2825 | list_splice_tail(&freeze_queue, &device->ccw_queue); |
2683 | spin_unlock_irq(get_ccwdev_lock(cdev)); | 2826 | spin_unlock_irq(get_ccwdev_lock(cdev)); |
2684 | 2827 | ||
2685 | if (device->discipline->freeze) | ||
2686 | rc = device->discipline->freeze(device); | ||
2687 | |||
2688 | dasd_put_device(device); | 2828 | dasd_put_device(device); |
2689 | return rc; | 2829 | return rc; |
2690 | } | 2830 | } |