diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/s390/block | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/Kconfig | 24 | ||||
-rw-r--r-- | drivers/s390/block/dasd.c | 376 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 27 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 10 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 187 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.c | 28 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.h | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 810 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 18 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eer.c | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_erp.c | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 27 | ||||
-rw-r--r-- | drivers/s390/block/dasd_genhd.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 38 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 143 | ||||
-rw-r--r-- | drivers/s390/block/dasd_proc.c | 1 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/xpram.c | 4 |
18 files changed, 1317 insertions, 395 deletions
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 07883197f474..8e477bb1f3f6 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
@@ -2,7 +2,8 @@ comment "S/390 block device drivers" | |||
2 | depends on S390 && BLOCK | 2 | depends on S390 && BLOCK |
3 | 3 | ||
4 | config BLK_DEV_XPRAM | 4 | config BLK_DEV_XPRAM |
5 | tristate "XPRAM disk support" | 5 | def_tristate m |
6 | prompt "XPRAM disk support" | ||
6 | depends on S390 && BLOCK | 7 | depends on S390 && BLOCK |
7 | help | 8 | help |
8 | Select this option if you want to use your expanded storage on S/390 | 9 | Select this option if you want to use your expanded storage on S/390 |
@@ -12,13 +13,15 @@ config BLK_DEV_XPRAM | |||
12 | xpram. If unsure, say "N". | 13 | xpram. If unsure, say "N". |
13 | 14 | ||
14 | config DCSSBLK | 15 | config DCSSBLK |
15 | tristate "DCSSBLK support" | 16 | def_tristate m |
17 | prompt "DCSSBLK support" | ||
16 | depends on S390 && BLOCK | 18 | depends on S390 && BLOCK |
17 | help | 19 | help |
18 | Support for dcss block device | 20 | Support for dcss block device |
19 | 21 | ||
20 | config DASD | 22 | config DASD |
21 | tristate "Support for DASD devices" | 23 | def_tristate y |
24 | prompt "Support for DASD devices" | ||
22 | depends on CCW && BLOCK | 25 | depends on CCW && BLOCK |
23 | select IOSCHED_DEADLINE | 26 | select IOSCHED_DEADLINE |
24 | help | 27 | help |
@@ -27,28 +30,32 @@ config DASD | |||
27 | natively on a single image or an LPAR. | 30 | natively on a single image or an LPAR. |
28 | 31 | ||
29 | config DASD_PROFILE | 32 | config DASD_PROFILE |
30 | bool "Profiling support for dasd devices" | 33 | def_bool y |
34 | prompt "Profiling support for dasd devices" | ||
31 | depends on DASD | 35 | depends on DASD |
32 | help | 36 | help |
33 | Enable this option if you want to see profiling information | 37 | Enable this option if you want to see profiling information |
34 | in /proc/dasd/statistics. | 38 | in /proc/dasd/statistics. |
35 | 39 | ||
36 | config DASD_ECKD | 40 | config DASD_ECKD |
37 | tristate "Support for ECKD Disks" | 41 | def_tristate y |
42 | prompt "Support for ECKD Disks" | ||
38 | depends on DASD | 43 | depends on DASD |
39 | help | 44 | help |
40 | ECKD devices are the most commonly used devices. You should enable | 45 | ECKD devices are the most commonly used devices. You should enable |
41 | this option unless you are very sure to have no ECKD device. | 46 | this option unless you are very sure to have no ECKD device. |
42 | 47 | ||
43 | config DASD_FBA | 48 | config DASD_FBA |
44 | tristate "Support for FBA Disks" | 49 | def_tristate y |
50 | prompt "Support for FBA Disks" | ||
45 | depends on DASD | 51 | depends on DASD |
46 | help | 52 | help |
47 | Select this option to be able to access FBA devices. It is safe to | 53 | Select this option to be able to access FBA devices. It is safe to |
48 | say "Y". | 54 | say "Y". |
49 | 55 | ||
50 | config DASD_DIAG | 56 | config DASD_DIAG |
51 | tristate "Support for DIAG access to Disks" | 57 | def_tristate y |
58 | prompt "Support for DIAG access to Disks" | ||
52 | depends on DASD | 59 | depends on DASD |
53 | help | 60 | help |
54 | Select this option if you want to use Diagnose250 command to access | 61 | Select this option if you want to use Diagnose250 command to access |
@@ -56,7 +63,8 @@ config DASD_DIAG | |||
56 | say "N". | 63 | say "N". |
57 | 64 | ||
58 | config DASD_EER | 65 | config DASD_EER |
59 | bool "Extended error reporting (EER)" | 66 | def_bool y |
67 | prompt "Extended error reporting (EER)" | ||
60 | depends on DASD | 68 | depends on DASD |
61 | help | 69 | help |
62 | This driver provides a character device interface to the | 70 | This driver provides a character device interface to the |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8373ca0de8e0..86b6f1cc1b10 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> |
@@ -21,7 +22,6 @@ | |||
21 | #include <linux/hdreg.h> | 22 | #include <linux/hdreg.h> |
22 | #include <linux/async.h> | 23 | #include <linux/async.h> |
23 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
24 | #include <linux/smp_lock.h> | ||
25 | 25 | ||
26 | #include <asm/ccwdev.h> | 26 | #include <asm/ccwdev.h> |
27 | #include <asm/ebcdic.h> | 27 | #include <asm/ebcdic.h> |
@@ -369,6 +369,11 @@ dasd_state_ready_to_online(struct dasd_device * device) | |||
369 | device->state = DASD_STATE_ONLINE; | 369 | device->state = DASD_STATE_ONLINE; |
370 | if (device->block) { | 370 | if (device->block) { |
371 | 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 | } | ||
372 | disk = device->block->bdev->bd_disk; | 377 | disk = device->block->bdev->bd_disk; |
373 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); | 378 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); |
374 | while ((part = disk_part_iter_next(&piter))) | 379 | while ((part = disk_part_iter_next(&piter))) |
@@ -394,7 +399,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device) | |||
394 | return rc; | 399 | return rc; |
395 | } | 400 | } |
396 | device->state = DASD_STATE_READY; | 401 | device->state = DASD_STATE_READY; |
397 | if (device->block) { | 402 | if (device->block && !(device->features & DASD_FEATURE_USERAW)) { |
398 | disk = device->block->bdev->bd_disk; | 403 | disk = device->block->bdev->bd_disk; |
399 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); | 404 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); |
400 | while ((part = disk_part_iter_next(&piter))) | 405 | while ((part = disk_part_iter_next(&piter))) |
@@ -745,10 +750,6 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, | |||
745 | char *data; | 750 | char *data; |
746 | int size; | 751 | int size; |
747 | 752 | ||
748 | /* Sanity checks */ | ||
749 | BUG_ON(datasize > PAGE_SIZE || | ||
750 | (cplength*sizeof(struct ccw1)) > PAGE_SIZE); | ||
751 | |||
752 | size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; | 753 | size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; |
753 | if (cplength > 0) | 754 | if (cplength > 0) |
754 | size += cplength * sizeof(struct ccw1); | 755 | size += cplength * sizeof(struct ccw1); |
@@ -854,7 +855,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) | |||
854 | rc = ccw_device_clear(device->cdev, (long) cqr); | 855 | rc = ccw_device_clear(device->cdev, (long) cqr); |
855 | switch (rc) { | 856 | switch (rc) { |
856 | case 0: /* termination successful */ | 857 | case 0: /* termination successful */ |
857 | cqr->retries--; | ||
858 | cqr->status = DASD_CQR_CLEAR_PENDING; | 858 | cqr->status = DASD_CQR_CLEAR_PENDING; |
859 | cqr->stopclk = get_clock(); | 859 | cqr->stopclk = get_clock(); |
860 | cqr->starttime = 0; | 860 | cqr->starttime = 0; |
@@ -906,6 +906,16 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
906 | return rc; | 906 | return rc; |
907 | } | 907 | } |
908 | 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 | } | ||
909 | if (cqr->retries < 0) { | 919 | if (cqr->retries < 0) { |
910 | /* internal error 14 - start_IO run out of retries */ | 920 | /* internal error 14 - start_IO run out of retries */ |
911 | sprintf(errorstring, "14 %p", cqr); | 921 | sprintf(errorstring, "14 %p", cqr); |
@@ -917,6 +927,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
917 | cqr->startclk = get_clock(); | 927 | cqr->startclk = get_clock(); |
918 | cqr->starttime = jiffies; | 928 | cqr->starttime = jiffies; |
919 | 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 | } | ||
920 | if (cqr->cpmode == 1) { | 935 | if (cqr->cpmode == 1) { |
921 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, | 936 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, |
922 | (long) cqr, cqr->lpm); | 937 | (long) cqr, cqr->lpm); |
@@ -929,35 +944,53 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
929 | cqr->status = DASD_CQR_IN_IO; | 944 | cqr->status = DASD_CQR_IN_IO; |
930 | break; | 945 | break; |
931 | case -EBUSY: | 946 | case -EBUSY: |
932 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 947 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
933 | "start_IO: device busy, retry later"); | 948 | "start_IO: device busy, retry later"); |
934 | break; | 949 | break; |
935 | case -ETIMEDOUT: | 950 | case -ETIMEDOUT: |
936 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 951 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
937 | "start_IO: request timeout, retry later"); | 952 | "start_IO: request timeout, retry later"); |
938 | break; | 953 | break; |
939 | case -EACCES: | 954 | case -EACCES: |
940 | /* -EACCES indicates that the request used only a | 955 | /* -EACCES indicates that the request used only a subset of the |
941 | * subset of the available pathes and all these | 956 | * available paths and all these paths are gone. If the lpm of |
942 | * pathes are gone. | 957 | * this request was only a subset of the opm (e.g. the ppm) then |
943 | * 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. | ||
944 | */ | 961 | */ |
945 | cqr->lpm = LPM_ANYPATH; | 962 | if (test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { |
946 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 963 | DBF_DEV_EVENT(DBF_WARNING, device, |
947 | "start_IO: selected pathes gone," | 964 | "start_IO: selected paths gone (%x)", |
948 | " 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 | } | ||
949 | break; | 982 | break; |
950 | case -ENODEV: | 983 | case -ENODEV: |
951 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 984 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
952 | "start_IO: -ENODEV device gone, retry"); | 985 | "start_IO: -ENODEV device gone, retry"); |
953 | break; | 986 | break; |
954 | case -EIO: | 987 | case -EIO: |
955 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 988 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
956 | "start_IO: -EIO device gone, retry"); | 989 | "start_IO: -EIO device gone, retry"); |
957 | break; | 990 | break; |
958 | case -EINVAL: | 991 | case -EINVAL: |
959 | /* most likely caused in power management context */ | 992 | /* most likely caused in power management context */ |
960 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 993 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
961 | "start_IO: -EINVAL device currently " | 994 | "start_IO: -EINVAL device currently " |
962 | "not accessible"); | 995 | "not accessible"); |
963 | break; | 996 | break; |
@@ -1077,6 +1110,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1077 | unsigned long long now; | 1110 | unsigned long long now; |
1078 | int expires; | 1111 | int expires; |
1079 | 1112 | ||
1113 | kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++; | ||
1080 | if (IS_ERR(irb)) { | 1114 | if (IS_ERR(irb)) { |
1081 | switch (PTR_ERR(irb)) { | 1115 | switch (PTR_ERR(irb)) { |
1082 | case -EIO: | 1116 | case -EIO: |
@@ -1095,23 +1129,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1095 | } | 1129 | } |
1096 | 1130 | ||
1097 | now = get_clock(); | 1131 | now = get_clock(); |
1098 | |||
1099 | /* check for unsolicited interrupts */ | ||
1100 | cqr = (struct dasd_ccw_req *) intparm; | 1132 | cqr = (struct dasd_ccw_req *) intparm; |
1101 | if (!cqr || ((scsw_cc(&irb->scsw) == 1) && | 1133 | /* check for conditions that should be handled immediately */ |
1102 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && | 1134 | if (!cqr || |
1103 | (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) { | 1135 | !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && |
1104 | if (cqr && cqr->status == DASD_CQR_IN_IO) | 1136 | scsw_cstat(&irb->scsw) == 0)) { |
1105 | cqr->status = DASD_CQR_QUEUED; | 1137 | if (cqr) |
1138 | memcpy(&cqr->irb, irb, sizeof(*irb)); | ||
1106 | device = dasd_device_from_cdev_locked(cdev); | 1139 | device = dasd_device_from_cdev_locked(cdev); |
1107 | if (!IS_ERR(device)) { | 1140 | if (IS_ERR(device)) |
1108 | dasd_device_clear_timer(device); | 1141 | return; |
1109 | device->discipline->handle_unsolicited_interrupt(device, | 1142 | /* ignore unsolicited interrupts for DIAG discipline */ |
1110 | irb); | 1143 | if (device->discipline == dasd_diag_discipline_pointer) { |
1111 | dasd_put_device(device); | 1144 | dasd_put_device(device); |
1145 | return; | ||
1112 | } | 1146 | } |
1113 | return; | 1147 | device->discipline->dump_sense_dbf(device, irb, "int"); |
1148 | if (device->features & DASD_FEATURE_ERPLOG) | ||
1149 | device->discipline->dump_sense(device, cqr, irb); | ||
1150 | device->discipline->check_for_device_change(device, cqr, irb); | ||
1151 | dasd_put_device(device); | ||
1114 | } | 1152 | } |
1153 | if (!cqr) | ||
1154 | return; | ||
1115 | 1155 | ||
1116 | device = (struct dasd_device *) cqr->startdev; | 1156 | device = (struct dasd_device *) cqr->startdev; |
1117 | if (!device || | 1157 | if (!device || |
@@ -1151,25 +1191,19 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1151 | struct dasd_ccw_req, devlist); | 1191 | struct dasd_ccw_req, devlist); |
1152 | } | 1192 | } |
1153 | } else { /* error */ | 1193 | } else { /* error */ |
1154 | memcpy(&cqr->irb, irb, sizeof(struct irb)); | ||
1155 | /* log sense for every failed I/O to s390 debugfeature */ | ||
1156 | dasd_log_sense_dbf(cqr, irb); | ||
1157 | if (device->features & DASD_FEATURE_ERPLOG) { | ||
1158 | dasd_log_sense(cqr, irb); | ||
1159 | } | ||
1160 | |||
1161 | /* | 1194 | /* |
1162 | * 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 |
1163 | * reset this and retry it in the fastpath | 1196 | * reset this and retry it in the fastpath |
1164 | */ | 1197 | */ |
1165 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && | 1198 | if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && |
1166 | cqr->retries > 0) { | 1199 | cqr->retries > 0) { |
1167 | if (cqr->lpm == LPM_ANYPATH) | 1200 | if (cqr->lpm == device->path_data.opm) |
1168 | DBF_DEV_EVENT(DBF_DEBUG, device, | 1201 | DBF_DEV_EVENT(DBF_DEBUG, device, |
1169 | "default ERP in fastpath " | 1202 | "default ERP in fastpath " |
1170 | "(%i retries left)", | 1203 | "(%i retries left)", |
1171 | cqr->retries); | 1204 | cqr->retries); |
1172 | cqr->lpm = LPM_ANYPATH; | 1205 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) |
1206 | cqr->lpm = device->path_data.opm; | ||
1173 | cqr->status = DASD_CQR_QUEUED; | 1207 | cqr->status = DASD_CQR_QUEUED; |
1174 | next = cqr; | 1208 | next = cqr; |
1175 | } else | 1209 | } else |
@@ -1197,13 +1231,13 @@ enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) | |||
1197 | goto out; | 1231 | goto out; |
1198 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || | 1232 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || |
1199 | device->state != device->target || | 1233 | device->state != device->target || |
1200 | !device->discipline->handle_unsolicited_interrupt){ | 1234 | !device->discipline->check_for_device_change){ |
1201 | dasd_put_device(device); | 1235 | dasd_put_device(device); |
1202 | goto out; | 1236 | goto out; |
1203 | } | 1237 | } |
1204 | 1238 | if (device->discipline->dump_sense_dbf) | |
1205 | dasd_device_clear_timer(device); | 1239 | device->discipline->dump_sense_dbf(device, irb, "uc"); |
1206 | device->discipline->handle_unsolicited_interrupt(device, irb); | 1240 | device->discipline->check_for_device_change(device, NULL, irb); |
1207 | dasd_put_device(device); | 1241 | dasd_put_device(device); |
1208 | out: | 1242 | out: |
1209 | return UC_TODO_RETRY; | 1243 | return UC_TODO_RETRY; |
@@ -1353,8 +1387,14 @@ static void __dasd_device_start_head(struct dasd_device *device) | |||
1353 | 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); |
1354 | if (cqr->status != DASD_CQR_QUEUED) | 1388 | if (cqr->status != DASD_CQR_QUEUED) |
1355 | return; | 1389 | return; |
1356 | /* when device is stopped, return request to previous layer */ | 1390 | /* when device is stopped, return request to previous layer |
1357 | 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; | ||
1358 | cqr->status = DASD_CQR_CLEARED; | 1398 | cqr->status = DASD_CQR_CLEARED; |
1359 | dasd_schedule_device_bh(device); | 1399 | dasd_schedule_device_bh(device); |
1360 | return; | 1400 | return; |
@@ -1370,6 +1410,23 @@ static void __dasd_device_start_head(struct dasd_device *device) | |||
1370 | dasd_device_set_timer(device, 50); | 1410 | dasd_device_set_timer(device, 50); |
1371 | } | 1411 | } |
1372 | 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 | |||
1373 | /* | 1430 | /* |
1374 | * Go through all request on the dasd_device request queue, | 1431 | * Go through all request on the dasd_device request queue, |
1375 | * 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 |
@@ -1444,6 +1501,7 @@ static void dasd_device_tasklet(struct dasd_device *device) | |||
1444 | __dasd_device_check_expire(device); | 1501 | __dasd_device_check_expire(device); |
1445 | /* find final requests on ccw queue */ | 1502 | /* find final requests on ccw queue */ |
1446 | __dasd_device_process_ccw_queue(device, &final_queue); | 1503 | __dasd_device_process_ccw_queue(device, &final_queue); |
1504 | __dasd_device_check_path_events(device); | ||
1447 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1505 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1448 | /* Now call the callback function of requests with final status */ | 1506 | /* Now call the callback function of requests with final status */ |
1449 | __dasd_device_process_final_queue(device, &final_queue); | 1507 | __dasd_device_process_final_queue(device, &final_queue); |
@@ -1600,7 +1658,12 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1600 | continue; | 1658 | continue; |
1601 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ | 1659 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ |
1602 | continue; | 1660 | continue; |
1603 | 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 | } | ||
1604 | /* Non-temporary stop condition will trigger fail fast */ | 1667 | /* Non-temporary stop condition will trigger fail fast */ |
1605 | if (device->stopped & ~DASD_STOPPED_PENDING && | 1668 | if (device->stopped & ~DASD_STOPPED_PENDING && |
1606 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 1669 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
@@ -1608,7 +1671,6 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) | |||
1608 | cqr->status = DASD_CQR_FAILED; | 1671 | cqr->status = DASD_CQR_FAILED; |
1609 | continue; | 1672 | continue; |
1610 | } | 1673 | } |
1611 | |||
1612 | /* Don't try to start requests if device is stopped */ | 1674 | /* Don't try to start requests if device is stopped */ |
1613 | if (interruptible) { | 1675 | if (interruptible) { |
1614 | rc = wait_event_interruptible( | 1676 | rc = wait_event_interruptible( |
@@ -1680,11 +1742,20 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) | |||
1680 | static inline int _dasd_term_running_cqr(struct dasd_device *device) | 1742 | static inline int _dasd_term_running_cqr(struct dasd_device *device) |
1681 | { | 1743 | { |
1682 | struct dasd_ccw_req *cqr; | 1744 | struct dasd_ccw_req *cqr; |
1745 | int rc; | ||
1683 | 1746 | ||
1684 | if (list_empty(&device->ccw_queue)) | 1747 | if (list_empty(&device->ccw_queue)) |
1685 | return 0; | 1748 | return 0; |
1686 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); | 1749 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); |
1687 | return device->discipline->term_IO(cqr); | 1750 | rc = device->discipline->term_IO(cqr); |
1751 | if (!rc) | ||
1752 | /* | ||
1753 | * CQR terminated because a more important request is pending. | ||
1754 | * Undo decreasing of retry counter because this is | ||
1755 | * not an error case. | ||
1756 | */ | ||
1757 | cqr->retries++; | ||
1758 | return rc; | ||
1688 | } | 1759 | } |
1689 | 1760 | ||
1690 | int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | 1761 | int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) |
@@ -1693,13 +1764,18 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
1693 | int rc; | 1764 | int rc; |
1694 | 1765 | ||
1695 | device = cqr->startdev; | 1766 | device = cqr->startdev; |
1767 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) && | ||
1768 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
1769 | cqr->status = DASD_CQR_FAILED; | ||
1770 | cqr->intrc = -EPERM; | ||
1771 | return -EIO; | ||
1772 | } | ||
1696 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | 1773 | spin_lock_irq(get_ccwdev_lock(device->cdev)); |
1697 | rc = _dasd_term_running_cqr(device); | 1774 | rc = _dasd_term_running_cqr(device); |
1698 | if (rc) { | 1775 | if (rc) { |
1699 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1776 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1700 | return rc; | 1777 | return rc; |
1701 | } | 1778 | } |
1702 | |||
1703 | cqr->callback = dasd_wakeup_cb; | 1779 | cqr->callback = dasd_wakeup_cb; |
1704 | cqr->callback_data = DASD_SLEEPON_START_TAG; | 1780 | cqr->callback_data = DASD_SLEEPON_START_TAG; |
1705 | cqr->status = DASD_CQR_QUEUED; | 1781 | cqr->status = DASD_CQR_QUEUED; |
@@ -1850,7 +1926,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
1850 | return; | 1926 | return; |
1851 | } | 1927 | } |
1852 | /* Now we try to fetch requests from the request queue */ | 1928 | /* Now we try to fetch requests from the request queue */ |
1853 | while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { | 1929 | while ((req = blk_peek_request(queue))) { |
1854 | if (basedev->features & DASD_FEATURE_READONLY && | 1930 | if (basedev->features & DASD_FEATURE_READONLY && |
1855 | rq_data_dir(req) == WRITE) { | 1931 | rq_data_dir(req) == WRITE) { |
1856 | DBF_DEV_EVENT(DBF_ERR, basedev, | 1932 | DBF_DEV_EVENT(DBF_ERR, basedev, |
@@ -2003,6 +2079,13 @@ static void __dasd_block_start_head(struct dasd_block *block) | |||
2003 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { | 2079 | list_for_each_entry(cqr, &block->ccw_queue, blocklist) { |
2004 | if (cqr->status != DASD_CQR_FILLED) | 2080 | if (cqr->status != DASD_CQR_FILLED) |
2005 | continue; | 2081 | continue; |
2082 | if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) && | ||
2083 | !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) { | ||
2084 | cqr->status = DASD_CQR_FAILED; | ||
2085 | cqr->intrc = -EPERM; | ||
2086 | dasd_schedule_block_bh(block); | ||
2087 | continue; | ||
2088 | } | ||
2006 | /* Non-temporary stop condition will trigger fail fast */ | 2089 | /* Non-temporary stop condition will trigger fail fast */ |
2007 | if (block->base->stopped & ~DASD_STOPPED_PENDING && | 2090 | if (block->base->stopped & ~DASD_STOPPED_PENDING && |
2008 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | 2091 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && |
@@ -2188,8 +2271,20 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
2188 | { | 2271 | { |
2189 | int max; | 2272 | int max; |
2190 | 2273 | ||
2191 | blk_queue_logical_block_size(block->request_queue, block->bp_block); | 2274 | if (block->base->features & DASD_FEATURE_USERAW) { |
2192 | max = block->base->discipline->max_blocks << block->s2b_shift; | 2275 | /* |
2276 | * the max_blocks value for raw_track access is 256 | ||
2277 | * it is higher than the native ECKD value because we | ||
2278 | * only need one ccw per track | ||
2279 | * so the max_hw_sectors are | ||
2280 | * 2048 x 512B = 1024kB = 16 tracks | ||
2281 | */ | ||
2282 | max = 2048; | ||
2283 | } else { | ||
2284 | max = block->base->discipline->max_blocks << block->s2b_shift; | ||
2285 | } | ||
2286 | blk_queue_logical_block_size(block->request_queue, | ||
2287 | block->bp_block); | ||
2193 | blk_queue_max_hw_sectors(block->request_queue, max); | 2288 | blk_queue_max_hw_sectors(block->request_queue, max); |
2194 | blk_queue_max_segments(block->request_queue, -1L); | 2289 | blk_queue_max_segments(block->request_queue, -1L); |
2195 | /* with page sized segments we can translate each segement into | 2290 | /* with page sized segments we can translate each segement into |
@@ -2197,7 +2292,6 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
2197 | */ | 2292 | */ |
2198 | blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); | 2293 | blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); |
2199 | blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); | 2294 | blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); |
2200 | blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN); | ||
2201 | } | 2295 | } |
2202 | 2296 | ||
2203 | /* | 2297 | /* |
@@ -2229,16 +2323,14 @@ static void dasd_flush_request_queue(struct dasd_block *block) | |||
2229 | 2323 | ||
2230 | static int dasd_open(struct block_device *bdev, fmode_t mode) | 2324 | static int dasd_open(struct block_device *bdev, fmode_t mode) |
2231 | { | 2325 | { |
2232 | struct dasd_block *block = bdev->bd_disk->private_data; | ||
2233 | struct dasd_device *base; | 2326 | struct dasd_device *base; |
2234 | int rc; | 2327 | int rc; |
2235 | 2328 | ||
2236 | if (!block) | 2329 | base = dasd_device_from_gendisk(bdev->bd_disk); |
2330 | if (!base) | ||
2237 | return -ENODEV; | 2331 | return -ENODEV; |
2238 | 2332 | ||
2239 | lock_kernel(); | 2333 | atomic_inc(&base->block->open_count); |
2240 | base = block->base; | ||
2241 | atomic_inc(&block->open_count); | ||
2242 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { | 2334 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { |
2243 | rc = -ENODEV; | 2335 | rc = -ENODEV; |
2244 | goto unlock; | 2336 | goto unlock; |
@@ -2271,25 +2363,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) | |||
2271 | goto out; | 2363 | goto out; |
2272 | } | 2364 | } |
2273 | 2365 | ||
2274 | unlock_kernel(); | 2366 | dasd_put_device(base); |
2275 | return 0; | 2367 | return 0; |
2276 | 2368 | ||
2277 | out: | 2369 | out: |
2278 | module_put(base->discipline->owner); | 2370 | module_put(base->discipline->owner); |
2279 | unlock: | 2371 | unlock: |
2280 | atomic_dec(&block->open_count); | 2372 | atomic_dec(&base->block->open_count); |
2281 | unlock_kernel(); | 2373 | dasd_put_device(base); |
2282 | return rc; | 2374 | return rc; |
2283 | } | 2375 | } |
2284 | 2376 | ||
2285 | static int dasd_release(struct gendisk *disk, fmode_t mode) | 2377 | static int dasd_release(struct gendisk *disk, fmode_t mode) |
2286 | { | 2378 | { |
2287 | struct dasd_block *block = disk->private_data; | 2379 | struct dasd_device *base; |
2380 | |||
2381 | base = dasd_device_from_gendisk(disk); | ||
2382 | if (!base) | ||
2383 | return -ENODEV; | ||
2288 | 2384 | ||
2289 | lock_kernel(); | 2385 | atomic_dec(&base->block->open_count); |
2290 | atomic_dec(&block->open_count); | 2386 | module_put(base->discipline->owner); |
2291 | module_put(block->base->discipline->owner); | 2387 | dasd_put_device(base); |
2292 | unlock_kernel(); | ||
2293 | return 0; | 2388 | return 0; |
2294 | } | 2389 | } |
2295 | 2390 | ||
@@ -2298,20 +2393,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) | |||
2298 | */ | 2393 | */ |
2299 | static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 2394 | static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
2300 | { | 2395 | { |
2301 | struct dasd_block *block; | ||
2302 | struct dasd_device *base; | 2396 | struct dasd_device *base; |
2303 | 2397 | ||
2304 | block = bdev->bd_disk->private_data; | 2398 | base = dasd_device_from_gendisk(bdev->bd_disk); |
2305 | if (!block) | 2399 | if (!base) |
2306 | return -ENODEV; | 2400 | return -ENODEV; |
2307 | base = block->base; | ||
2308 | 2401 | ||
2309 | if (!base->discipline || | 2402 | if (!base->discipline || |
2310 | !base->discipline->fill_geometry) | 2403 | !base->discipline->fill_geometry) { |
2404 | dasd_put_device(base); | ||
2311 | return -EINVAL; | 2405 | return -EINVAL; |
2312 | 2406 | } | |
2313 | base->discipline->fill_geometry(block, geo); | 2407 | base->discipline->fill_geometry(base->block, geo); |
2314 | geo->start = get_start_sect(bdev) >> block->s2b_shift; | 2408 | geo->start = get_start_sect(bdev) >> base->block->s2b_shift; |
2409 | dasd_put_device(base); | ||
2315 | return 0; | 2410 | return 0; |
2316 | } | 2411 | } |
2317 | 2412 | ||
@@ -2448,7 +2543,6 @@ void dasd_generic_remove(struct ccw_device *cdev) | |||
2448 | dasd_set_target_state(device, DASD_STATE_NEW); | 2543 | dasd_set_target_state(device, DASD_STATE_NEW); |
2449 | /* dasd_delete_device destroys the device reference. */ | 2544 | /* dasd_delete_device destroys the device reference. */ |
2450 | block = device->block; | 2545 | block = device->block; |
2451 | device->block = NULL; | ||
2452 | dasd_delete_device(device); | 2546 | dasd_delete_device(device); |
2453 | /* | 2547 | /* |
2454 | * life cycle of block is bound to device, so delete it after | 2548 | * life cycle of block is bound to device, so delete it after |
@@ -2570,7 +2664,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) | |||
2570 | dasd_set_target_state(device, DASD_STATE_NEW); | 2664 | dasd_set_target_state(device, DASD_STATE_NEW); |
2571 | /* dasd_delete_device destroys the device reference. */ | 2665 | /* dasd_delete_device destroys the device reference. */ |
2572 | block = device->block; | 2666 | block = device->block; |
2573 | device->block = NULL; | ||
2574 | dasd_delete_device(device); | 2667 | dasd_delete_device(device); |
2575 | /* | 2668 | /* |
2576 | * life cycle of block is bound to device, so delete it after | 2669 | * life cycle of block is bound to device, so delete it after |
@@ -2581,10 +2674,53 @@ int dasd_generic_set_offline(struct ccw_device *cdev) | |||
2581 | return 0; | 2674 | return 0; |
2582 | } | 2675 | } |
2583 | 2676 | ||
2677 | int dasd_generic_last_path_gone(struct dasd_device *device) | ||
2678 | { | ||
2679 | struct dasd_ccw_req *cqr; | ||
2680 | |||
2681 | dev_warn(&device->cdev->dev, "No operational channel path is left " | ||
2682 | "for the device\n"); | ||
2683 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", "last path gone"); | ||
2684 | /* First of all call extended error reporting. */ | ||
2685 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | ||
2686 | |||
2687 | if (device->state < DASD_STATE_BASIC) | ||
2688 | return 0; | ||
2689 | /* Device is active. We want to keep it. */ | ||
2690 | list_for_each_entry(cqr, &device->ccw_queue, devlist) | ||
2691 | if ((cqr->status == DASD_CQR_IN_IO) || | ||
2692 | (cqr->status == DASD_CQR_CLEAR_PENDING)) { | ||
2693 | cqr->status = DASD_CQR_QUEUED; | ||
2694 | cqr->retries++; | ||
2695 | } | ||
2696 | dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2697 | dasd_device_clear_timer(device); | ||
2698 | dasd_schedule_device_bh(device); | ||
2699 | return 1; | ||
2700 | } | ||
2701 | EXPORT_SYMBOL_GPL(dasd_generic_last_path_gone); | ||
2702 | |||
2703 | int dasd_generic_path_operational(struct dasd_device *device) | ||
2704 | { | ||
2705 | dev_info(&device->cdev->dev, "A channel path to the device has become " | ||
2706 | "operational\n"); | ||
2707 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", "path operational"); | ||
2708 | dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2709 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2710 | dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); | ||
2711 | dasd_restore_device(device); | ||
2712 | return 1; | ||
2713 | } | ||
2714 | dasd_schedule_device_bh(device); | ||
2715 | if (device->block) | ||
2716 | dasd_schedule_block_bh(device->block); | ||
2717 | return 1; | ||
2718 | } | ||
2719 | EXPORT_SYMBOL_GPL(dasd_generic_path_operational); | ||
2720 | |||
2584 | int dasd_generic_notify(struct ccw_device *cdev, int event) | 2721 | int dasd_generic_notify(struct ccw_device *cdev, int event) |
2585 | { | 2722 | { |
2586 | struct dasd_device *device; | 2723 | struct dasd_device *device; |
2587 | struct dasd_ccw_req *cqr; | ||
2588 | int ret; | 2724 | int ret; |
2589 | 2725 | ||
2590 | device = dasd_device_from_cdev_locked(cdev); | 2726 | device = dasd_device_from_cdev_locked(cdev); |
@@ -2595,41 +2731,64 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2595 | case CIO_GONE: | 2731 | case CIO_GONE: |
2596 | case CIO_BOXED: | 2732 | case CIO_BOXED: |
2597 | case CIO_NO_PATH: | 2733 | case CIO_NO_PATH: |
2598 | /* First of all call extended error reporting. */ | 2734 | device->path_data.opm = 0; |
2599 | dasd_eer_write(device, NULL, DASD_EER_NOPATH); | 2735 | device->path_data.ppm = 0; |
2600 | 2736 | device->path_data.npm = 0; | |
2601 | if (device->state < DASD_STATE_BASIC) | 2737 | ret = dasd_generic_last_path_gone(device); |
2602 | break; | ||
2603 | /* Device is active. We want to keep it. */ | ||
2604 | list_for_each_entry(cqr, &device->ccw_queue, devlist) | ||
2605 | if (cqr->status == DASD_CQR_IN_IO) { | ||
2606 | cqr->status = DASD_CQR_QUEUED; | ||
2607 | cqr->retries++; | ||
2608 | } | ||
2609 | dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2610 | dasd_device_clear_timer(device); | ||
2611 | dasd_schedule_device_bh(device); | ||
2612 | ret = 1; | ||
2613 | break; | 2738 | break; |
2614 | case CIO_OPER: | 2739 | case CIO_OPER: |
2615 | /* FIXME: add a sanity check. */ | ||
2616 | dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); | ||
2617 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2618 | dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); | ||
2619 | dasd_restore_device(device); | ||
2620 | ret = 1; | ||
2621 | break; | ||
2622 | } | ||
2623 | dasd_schedule_device_bh(device); | ||
2624 | if (device->block) | ||
2625 | dasd_schedule_block_bh(device->block); | ||
2626 | ret = 1; | 2740 | ret = 1; |
2741 | if (device->path_data.opm) | ||
2742 | ret = dasd_generic_path_operational(device); | ||
2627 | break; | 2743 | break; |
2628 | } | 2744 | } |
2629 | dasd_put_device(device); | 2745 | dasd_put_device(device); |
2630 | return ret; | 2746 | return ret; |
2631 | } | 2747 | } |
2632 | 2748 | ||
2749 | void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) | ||
2750 | { | ||
2751 | int chp; | ||
2752 | __u8 oldopm, eventlpm; | ||
2753 | struct dasd_device *device; | ||
2754 | |||
2755 | device = dasd_device_from_cdev_locked(cdev); | ||
2756 | if (IS_ERR(device)) | ||
2757 | return; | ||
2758 | for (chp = 0; chp < 8; chp++) { | ||
2759 | eventlpm = 0x80 >> chp; | ||
2760 | if (path_event[chp] & PE_PATH_GONE) { | ||
2761 | oldopm = device->path_data.opm; | ||
2762 | device->path_data.opm &= ~eventlpm; | ||
2763 | device->path_data.ppm &= ~eventlpm; | ||
2764 | device->path_data.npm &= ~eventlpm; | ||
2765 | if (oldopm && !device->path_data.opm) | ||
2766 | dasd_generic_last_path_gone(device); | ||
2767 | } | ||
2768 | if (path_event[chp] & PE_PATH_AVAILABLE) { | ||
2769 | device->path_data.opm &= ~eventlpm; | ||
2770 | device->path_data.ppm &= ~eventlpm; | ||
2771 | device->path_data.npm &= ~eventlpm; | ||
2772 | device->path_data.tbvpm |= eventlpm; | ||
2773 | dasd_schedule_device_bh(device); | ||
2774 | } | ||
2775 | } | ||
2776 | dasd_put_device(device); | ||
2777 | } | ||
2778 | EXPORT_SYMBOL_GPL(dasd_generic_path_event); | ||
2779 | |||
2780 | int dasd_generic_verify_path(struct dasd_device *device, __u8 lpm) | ||
2781 | { | ||
2782 | if (!device->path_data.opm && lpm) { | ||
2783 | device->path_data.opm = lpm; | ||
2784 | dasd_generic_path_operational(device); | ||
2785 | } else | ||
2786 | device->path_data.opm |= lpm; | ||
2787 | return 0; | ||
2788 | } | ||
2789 | EXPORT_SYMBOL_GPL(dasd_generic_verify_path); | ||
2790 | |||
2791 | |||
2633 | int dasd_generic_pm_freeze(struct ccw_device *cdev) | 2792 | int dasd_generic_pm_freeze(struct ccw_device *cdev) |
2634 | { | 2793 | { |
2635 | struct dasd_ccw_req *cqr, *n; | 2794 | struct dasd_ccw_req *cqr, *n; |
@@ -2639,6 +2798,10 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
2639 | 2798 | ||
2640 | if (IS_ERR(device)) | 2799 | if (IS_ERR(device)) |
2641 | return PTR_ERR(device); | 2800 | return PTR_ERR(device); |
2801 | |||
2802 | if (device->discipline->freeze) | ||
2803 | rc = device->discipline->freeze(device); | ||
2804 | |||
2642 | /* disallow new I/O */ | 2805 | /* disallow new I/O */ |
2643 | dasd_device_set_stop_bits(device, DASD_STOPPED_PM); | 2806 | dasd_device_set_stop_bits(device, DASD_STOPPED_PM); |
2644 | /* clear active requests */ | 2807 | /* clear active requests */ |
@@ -2675,9 +2838,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
2675 | list_splice_tail(&freeze_queue, &device->ccw_queue); | 2838 | list_splice_tail(&freeze_queue, &device->ccw_queue); |
2676 | spin_unlock_irq(get_ccwdev_lock(cdev)); | 2839 | spin_unlock_irq(get_ccwdev_lock(cdev)); |
2677 | 2840 | ||
2678 | if (device->discipline->freeze) | ||
2679 | rc = device->discipline->freeze(device); | ||
2680 | |||
2681 | dasd_put_device(device); | 2841 | dasd_put_device(device); |
2682 | return rc; | 2842 | return rc; |
2683 | } | 2843 | } |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 85bfd8794856..87a0cf160fe5 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -152,9 +152,9 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) | |||
152 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 152 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
153 | opm = ccw_device_get_path_mask(device->cdev); | 153 | opm = ccw_device_get_path_mask(device->cdev); |
154 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 154 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
155 | //FIXME: start with get_opm ? | ||
156 | if (erp->lpm == 0) | 155 | if (erp->lpm == 0) |
157 | erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); | 156 | erp->lpm = device->path_data.opm & |
157 | ~(erp->irb.esw.esw0.sublog.lpum); | ||
158 | else | 158 | else |
159 | erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); | 159 | erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); |
160 | 160 | ||
@@ -221,6 +221,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) | |||
221 | ccw->cmd_code = CCW_CMD_DCTL; | 221 | ccw->cmd_code = CCW_CMD_DCTL; |
222 | ccw->count = 4; | 222 | ccw->count = 4; |
223 | ccw->cda = (__u32)(addr_t) DCTL_data; | 223 | ccw->cda = (__u32)(addr_t) DCTL_data; |
224 | dctl_cqr->flags = erp->flags; | ||
224 | dctl_cqr->function = dasd_3990_erp_DCTL; | 225 | dctl_cqr->function = dasd_3990_erp_DCTL; |
225 | dctl_cqr->refers = erp; | 226 | dctl_cqr->refers = erp; |
226 | dctl_cqr->startdev = device; | 227 | dctl_cqr->startdev = device; |
@@ -269,10 +270,11 @@ static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp) | |||
269 | { | 270 | { |
270 | erp->function = dasd_3990_erp_action_1; | 271 | erp->function = dasd_3990_erp_action_1; |
271 | dasd_3990_erp_alternate_path(erp); | 272 | dasd_3990_erp_alternate_path(erp); |
272 | if (erp->status == DASD_CQR_FAILED) { | 273 | if (erp->status == DASD_CQR_FAILED && |
274 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { | ||
273 | erp->status = DASD_CQR_FILLED; | 275 | erp->status = DASD_CQR_FILLED; |
274 | erp->retries = 10; | 276 | erp->retries = 10; |
275 | erp->lpm = LPM_ANYPATH; | 277 | erp->lpm = erp->startdev->path_data.opm; |
276 | erp->function = dasd_3990_erp_action_1_sec; | 278 | erp->function = dasd_3990_erp_action_1_sec; |
277 | } | 279 | } |
278 | return erp; | 280 | return erp; |
@@ -1710,6 +1712,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) | |||
1710 | ccw->cda = cpa; | 1712 | ccw->cda = cpa; |
1711 | 1713 | ||
1712 | /* fill erp related fields */ | 1714 | /* fill erp related fields */ |
1715 | erp->flags = default_erp->flags; | ||
1713 | erp->function = dasd_3990_erp_action_1B_32; | 1716 | erp->function = dasd_3990_erp_action_1B_32; |
1714 | erp->refers = default_erp->refers; | 1717 | erp->refers = default_erp->refers; |
1715 | erp->startdev = device; | 1718 | erp->startdev = device; |
@@ -1905,15 +1908,14 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense) | |||
1905 | static void | 1908 | static void |
1906 | dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) | 1909 | dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) |
1907 | { | 1910 | { |
1908 | |||
1909 | if (sense[25] & DASD_SENSE_BIT_3) { | 1911 | if (sense[25] & DASD_SENSE_BIT_3) { |
1910 | dasd_3990_erp_alternate_path(erp); | 1912 | dasd_3990_erp_alternate_path(erp); |
1911 | 1913 | ||
1912 | if (erp->status == DASD_CQR_FAILED) { | 1914 | if (erp->status == DASD_CQR_FAILED && |
1915 | !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) { | ||
1913 | /* reset the lpm and the status to be able to | 1916 | /* reset the lpm and the status to be able to |
1914 | * try further actions. */ | 1917 | * try further actions. */ |
1915 | 1918 | erp->lpm = erp->startdev->path_data.opm; | |
1916 | erp->lpm = 0; | ||
1917 | erp->status = DASD_CQR_NEED_ERP; | 1919 | erp->status = DASD_CQR_NEED_ERP; |
1918 | } | 1920 | } |
1919 | } | 1921 | } |
@@ -2197,7 +2199,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) | |||
2197 | 2199 | ||
2198 | /* | 2200 | /* |
2199 | ***************************************************************************** | 2201 | ***************************************************************************** |
2200 | * main ERP control fuctions (24 and 32 byte sense) | 2202 | * main ERP control functions (24 and 32 byte sense) |
2201 | ***************************************************************************** | 2203 | ***************************************************************************** |
2202 | */ | 2204 | */ |
2203 | 2205 | ||
@@ -2205,7 +2207,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) | |||
2205 | * DASD_3990_ERP_CONTROL_CHECK | 2207 | * DASD_3990_ERP_CONTROL_CHECK |
2206 | * | 2208 | * |
2207 | * DESCRIPTION | 2209 | * DESCRIPTION |
2208 | * Does a generic inspection if a control check occured and sets up | 2210 | * Does a generic inspection if a control check occurred and sets up |
2209 | * the related error recovery procedure | 2211 | * the related error recovery procedure |
2210 | * | 2212 | * |
2211 | * PARAMETER | 2213 | * PARAMETER |
@@ -2248,7 +2250,7 @@ dasd_3990_erp_inspect(struct dasd_ccw_req *erp) | |||
2248 | struct dasd_ccw_req *erp_new = NULL; | 2250 | struct dasd_ccw_req *erp_new = NULL; |
2249 | char *sense; | 2251 | char *sense; |
2250 | 2252 | ||
2251 | /* if this problem occured on an alias retry on base */ | 2253 | /* if this problem occurred on an alias retry on base */ |
2252 | erp_new = dasd_3990_erp_inspect_alias(erp); | 2254 | erp_new = dasd_3990_erp_inspect_alias(erp); |
2253 | if (erp_new) | 2255 | if (erp_new) |
2254 | return erp_new; | 2256 | return erp_new; |
@@ -2280,7 +2282,7 @@ dasd_3990_erp_inspect(struct dasd_ccw_req *erp) | |||
2280 | * DASD_3990_ERP_ADD_ERP | 2282 | * DASD_3990_ERP_ADD_ERP |
2281 | * | 2283 | * |
2282 | * DESCRIPTION | 2284 | * DESCRIPTION |
2283 | * This funtion adds an additional request block (ERP) to the head of | 2285 | * This function adds an additional request block (ERP) to the head of |
2284 | * the given cqr (or erp). | 2286 | * the given cqr (or erp). |
2285 | * For a command mode cqr the erp is initialized as an default erp | 2287 | * For a command mode cqr the erp is initialized as an default erp |
2286 | * (retry TIC). | 2288 | * (retry TIC). |
@@ -2354,6 +2356,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) | |||
2354 | ccw->cda = (long)(cqr->cpaddr); | 2356 | ccw->cda = (long)(cqr->cpaddr); |
2355 | } | 2357 | } |
2356 | 2358 | ||
2359 | erp->flags = cqr->flags; | ||
2357 | erp->function = dasd_3990_erp_add_erp; | 2360 | erp->function = dasd_3990_erp_add_erp; |
2358 | erp->refers = cqr; | 2361 | erp->refers = cqr; |
2359 | erp->startdev = device; | 2362 | erp->startdev = device; |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 4155805dcdff..c388eda1e2b1 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
253 | */ | 253 | */ |
254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) | 254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) |
255 | { | 255 | { |
256 | struct dasd_eckd_private *private; | ||
257 | unsigned long flags; | 256 | unsigned long flags; |
258 | struct alias_server *server; | 257 | struct alias_server *server; |
259 | struct alias_lcu *lcu; | 258 | struct alias_lcu *lcu; |
260 | struct dasd_uid uid; | 259 | struct dasd_uid uid; |
261 | 260 | ||
262 | private = (struct dasd_eckd_private *) device->private; | ||
263 | device->discipline->get_uid(device, &uid); | 261 | device->discipline->get_uid(device, &uid); |
264 | lcu = NULL; | 262 | lcu = NULL; |
265 | spin_lock_irqsave(&aliastree.lock, flags); | 263 | spin_lock_irqsave(&aliastree.lock, flags); |
@@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
279 | 277 | ||
280 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | 278 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) |
281 | { | 279 | { |
282 | struct dasd_eckd_private *private; | ||
283 | unsigned long flags; | 280 | unsigned long flags; |
284 | struct alias_server *server; | 281 | struct alias_server *server; |
285 | struct alias_lcu *lcu; | 282 | struct alias_lcu *lcu; |
286 | struct dasd_uid uid; | 283 | struct dasd_uid uid; |
287 | 284 | ||
288 | private = (struct dasd_eckd_private *) device->private; | ||
289 | device->discipline->get_uid(device, &uid); | 285 | device->discipline->get_uid(device, &uid); |
290 | lcu = NULL; | 286 | lcu = NULL; |
291 | spin_lock_irqsave(&aliastree.lock, flags); | 287 | spin_lock_irqsave(&aliastree.lock, flags); |
@@ -319,6 +315,9 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
319 | 315 | ||
320 | private = (struct dasd_eckd_private *) device->private; | 316 | private = (struct dasd_eckd_private *) device->private; |
321 | lcu = private->lcu; | 317 | lcu = private->lcu; |
318 | /* nothing to do if already disconnected */ | ||
319 | if (!lcu) | ||
320 | return; | ||
322 | device->discipline->get_uid(device, &uid); | 321 | device->discipline->get_uid(device, &uid); |
323 | spin_lock_irqsave(&lcu->lock, flags); | 322 | spin_lock_irqsave(&lcu->lock, flags); |
324 | list_del_init(&device->alias_list); | 323 | list_del_init(&device->alias_list); |
@@ -680,6 +679,9 @@ int dasd_alias_remove_device(struct dasd_device *device) | |||
680 | 679 | ||
681 | private = (struct dasd_eckd_private *) device->private; | 680 | private = (struct dasd_eckd_private *) device->private; |
682 | lcu = private->lcu; | 681 | lcu = private->lcu; |
682 | /* nothing to do if already removed */ | ||
683 | if (!lcu) | ||
684 | return 0; | ||
683 | spin_lock_irqsave(&lcu->lock, flags); | 685 | spin_lock_irqsave(&lcu->lock, flags); |
684 | _remove_device_from_lcu(lcu, device); | 686 | _remove_device_from_lcu(lcu, device); |
685 | spin_unlock_irqrestore(&lcu->lock, flags); | 687 | spin_unlock_irqrestore(&lcu->lock, flags); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 8d41f3ed38d7..d71511c7850a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -208,6 +208,8 @@ dasd_feature_list(char *str, char **endp) | |||
208 | features |= DASD_FEATURE_READONLY; | 208 | features |= DASD_FEATURE_READONLY; |
209 | else if (len == 4 && !strncmp(str, "diag", 4)) | 209 | else if (len == 4 && !strncmp(str, "diag", 4)) |
210 | features |= DASD_FEATURE_USEDIAG; | 210 | features |= DASD_FEATURE_USEDIAG; |
211 | else if (len == 3 && !strncmp(str, "raw", 3)) | ||
212 | features |= DASD_FEATURE_USERAW; | ||
211 | else if (len == 6 && !strncmp(str, "erplog", 6)) | 213 | else if (len == 6 && !strncmp(str, "erplog", 6)) |
212 | features |= DASD_FEATURE_ERPLOG; | 214 | features |= DASD_FEATURE_ERPLOG; |
213 | else if (len == 8 && !strncmp(str, "failfast", 8)) | 215 | else if (len == 8 && !strncmp(str, "failfast", 8)) |
@@ -300,7 +302,7 @@ dasd_parse_keyword( char *parsestring ) { | |||
300 | /* | 302 | /* |
301 | * Try to interprete the first element on the comma separated parse string | 303 | * Try to interprete the first element on the comma separated parse string |
302 | * as a device number or a range of devices. If the interpretation is | 304 | * as a device number or a range of devices. If the interpretation is |
303 | * successfull, create the matching dasd_devmap entries and return a pointer | 305 | * successful, create the matching dasd_devmap entries and return a pointer |
304 | * to the residual string. | 306 | * to the residual string. |
305 | * If interpretation fails or in case of an error, return an error code. | 307 | * If interpretation fails or in case of an error, return an error code. |
306 | */ | 308 | */ |
@@ -639,6 +641,7 @@ dasd_put_device_wake(struct dasd_device *device) | |||
639 | { | 641 | { |
640 | wake_up(&dasd_delete_wq); | 642 | wake_up(&dasd_delete_wq); |
641 | } | 643 | } |
644 | EXPORT_SYMBOL_GPL(dasd_put_device_wake); | ||
642 | 645 | ||
643 | /* | 646 | /* |
644 | * Return dasd_device structure associated with cdev. | 647 | * Return dasd_device structure associated with cdev. |
@@ -671,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) | |||
671 | return device; | 674 | return device; |
672 | } | 675 | } |
673 | 676 | ||
677 | void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) | ||
678 | { | ||
679 | struct dasd_devmap *devmap; | ||
680 | |||
681 | devmap = dasd_find_busid(dev_name(&device->cdev->dev)); | ||
682 | if (IS_ERR(devmap)) | ||
683 | return; | ||
684 | spin_lock(&dasd_devmap_lock); | ||
685 | gdp->private_data = devmap; | ||
686 | spin_unlock(&dasd_devmap_lock); | ||
687 | } | ||
688 | |||
689 | struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) | ||
690 | { | ||
691 | struct dasd_device *device; | ||
692 | struct dasd_devmap *devmap; | ||
693 | |||
694 | if (!gdp->private_data) | ||
695 | return NULL; | ||
696 | device = NULL; | ||
697 | spin_lock(&dasd_devmap_lock); | ||
698 | devmap = gdp->private_data; | ||
699 | if (devmap && devmap->device) { | ||
700 | device = devmap->device; | ||
701 | dasd_get_device(device); | ||
702 | } | ||
703 | spin_unlock(&dasd_devmap_lock); | ||
704 | return device; | ||
705 | } | ||
706 | |||
674 | /* | 707 | /* |
675 | * SECTION: files in sysfs | 708 | * SECTION: files in sysfs |
676 | */ | 709 | */ |
@@ -856,7 +889,7 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, | |||
856 | spin_lock(&dasd_devmap_lock); | 889 | spin_lock(&dasd_devmap_lock); |
857 | /* Changing diag discipline flag is only allowed in offline state. */ | 890 | /* Changing diag discipline flag is only allowed in offline state. */ |
858 | rc = count; | 891 | rc = count; |
859 | if (!devmap->device) { | 892 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { |
860 | if (val) | 893 | if (val) |
861 | devmap->features |= DASD_FEATURE_USEDIAG; | 894 | devmap->features |= DASD_FEATURE_USEDIAG; |
862 | else | 895 | else |
@@ -869,6 +902,56 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, | |||
869 | 902 | ||
870 | static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); | 903 | static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); |
871 | 904 | ||
905 | /* | ||
906 | * use_raw controls whether the driver should give access to raw eckd data or | ||
907 | * operate in standard mode | ||
908 | */ | ||
909 | static ssize_t | ||
910 | dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
911 | { | ||
912 | struct dasd_devmap *devmap; | ||
913 | int use_raw; | ||
914 | |||
915 | devmap = dasd_find_busid(dev_name(dev)); | ||
916 | if (!IS_ERR(devmap)) | ||
917 | use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; | ||
918 | else | ||
919 | use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; | ||
920 | return sprintf(buf, use_raw ? "1\n" : "0\n"); | ||
921 | } | ||
922 | |||
923 | static ssize_t | ||
924 | dasd_use_raw_store(struct device *dev, struct device_attribute *attr, | ||
925 | const char *buf, size_t count) | ||
926 | { | ||
927 | struct dasd_devmap *devmap; | ||
928 | ssize_t rc; | ||
929 | unsigned long val; | ||
930 | |||
931 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | ||
932 | if (IS_ERR(devmap)) | ||
933 | return PTR_ERR(devmap); | ||
934 | |||
935 | if ((strict_strtoul(buf, 10, &val) != 0) || val > 1) | ||
936 | return -EINVAL; | ||
937 | |||
938 | spin_lock(&dasd_devmap_lock); | ||
939 | /* Changing diag discipline flag is only allowed in offline state. */ | ||
940 | rc = count; | ||
941 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { | ||
942 | if (val) | ||
943 | devmap->features |= DASD_FEATURE_USERAW; | ||
944 | else | ||
945 | devmap->features &= ~DASD_FEATURE_USERAW; | ||
946 | } else | ||
947 | rc = -EPERM; | ||
948 | spin_unlock(&dasd_devmap_lock); | ||
949 | return rc; | ||
950 | } | ||
951 | |||
952 | static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, | ||
953 | dasd_use_raw_store); | ||
954 | |||
872 | static ssize_t | 955 | static ssize_t |
873 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, | 956 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, |
874 | char *buf) | 957 | char *buf) |
@@ -1126,6 +1209,103 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr, | |||
1126 | 1209 | ||
1127 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); | 1210 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); |
1128 | 1211 | ||
1212 | static ssize_t dasd_reservation_policy_show(struct device *dev, | ||
1213 | struct device_attribute *attr, | ||
1214 | char *buf) | ||
1215 | { | ||
1216 | struct dasd_devmap *devmap; | ||
1217 | int rc = 0; | ||
1218 | |||
1219 | devmap = dasd_find_busid(dev_name(dev)); | ||
1220 | if (IS_ERR(devmap)) { | ||
1221 | rc = snprintf(buf, PAGE_SIZE, "ignore\n"); | ||
1222 | } else { | ||
1223 | spin_lock(&dasd_devmap_lock); | ||
1224 | if (devmap->features & DASD_FEATURE_FAILONSLCK) | ||
1225 | rc = snprintf(buf, PAGE_SIZE, "fail\n"); | ||
1226 | else | ||
1227 | rc = snprintf(buf, PAGE_SIZE, "ignore\n"); | ||
1228 | spin_unlock(&dasd_devmap_lock); | ||
1229 | } | ||
1230 | return rc; | ||
1231 | } | ||
1232 | |||
1233 | static ssize_t dasd_reservation_policy_store(struct device *dev, | ||
1234 | struct device_attribute *attr, | ||
1235 | const char *buf, size_t count) | ||
1236 | { | ||
1237 | struct dasd_devmap *devmap; | ||
1238 | int rc; | ||
1239 | |||
1240 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | ||
1241 | if (IS_ERR(devmap)) | ||
1242 | return PTR_ERR(devmap); | ||
1243 | rc = 0; | ||
1244 | spin_lock(&dasd_devmap_lock); | ||
1245 | if (sysfs_streq("ignore", buf)) | ||
1246 | devmap->features &= ~DASD_FEATURE_FAILONSLCK; | ||
1247 | else if (sysfs_streq("fail", buf)) | ||
1248 | devmap->features |= DASD_FEATURE_FAILONSLCK; | ||
1249 | else | ||
1250 | rc = -EINVAL; | ||
1251 | if (devmap->device) | ||
1252 | devmap->device->features = devmap->features; | ||
1253 | spin_unlock(&dasd_devmap_lock); | ||
1254 | if (rc) | ||
1255 | return rc; | ||
1256 | else | ||
1257 | return count; | ||
1258 | } | ||
1259 | |||
1260 | static DEVICE_ATTR(reservation_policy, 0644, | ||
1261 | dasd_reservation_policy_show, dasd_reservation_policy_store); | ||
1262 | |||
1263 | static ssize_t dasd_reservation_state_show(struct device *dev, | ||
1264 | struct device_attribute *attr, | ||
1265 | char *buf) | ||
1266 | { | ||
1267 | struct dasd_device *device; | ||
1268 | int rc = 0; | ||
1269 | |||
1270 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1271 | if (IS_ERR(device)) | ||
1272 | return snprintf(buf, PAGE_SIZE, "none\n"); | ||
1273 | |||
1274 | if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) | ||
1275 | rc = snprintf(buf, PAGE_SIZE, "reserved\n"); | ||
1276 | else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) | ||
1277 | rc = snprintf(buf, PAGE_SIZE, "lost\n"); | ||
1278 | else | ||
1279 | rc = snprintf(buf, PAGE_SIZE, "none\n"); | ||
1280 | dasd_put_device(device); | ||
1281 | return rc; | ||
1282 | } | ||
1283 | |||
1284 | static ssize_t dasd_reservation_state_store(struct device *dev, | ||
1285 | struct device_attribute *attr, | ||
1286 | const char *buf, size_t count) | ||
1287 | { | ||
1288 | struct dasd_device *device; | ||
1289 | int rc = 0; | ||
1290 | |||
1291 | device = dasd_device_from_cdev(to_ccwdev(dev)); | ||
1292 | if (IS_ERR(device)) | ||
1293 | return -ENODEV; | ||
1294 | if (sysfs_streq("reset", buf)) | ||
1295 | clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); | ||
1296 | else | ||
1297 | rc = -EINVAL; | ||
1298 | dasd_put_device(device); | ||
1299 | |||
1300 | if (rc) | ||
1301 | return rc; | ||
1302 | else | ||
1303 | return count; | ||
1304 | } | ||
1305 | |||
1306 | static DEVICE_ATTR(last_known_reservation_state, 0644, | ||
1307 | dasd_reservation_state_show, dasd_reservation_state_store); | ||
1308 | |||
1129 | static struct attribute * dasd_attrs[] = { | 1309 | static struct attribute * dasd_attrs[] = { |
1130 | &dev_attr_readonly.attr, | 1310 | &dev_attr_readonly.attr, |
1131 | &dev_attr_discipline.attr, | 1311 | &dev_attr_discipline.attr, |
@@ -1134,10 +1314,13 @@ static struct attribute * dasd_attrs[] = { | |||
1134 | &dev_attr_vendor.attr, | 1314 | &dev_attr_vendor.attr, |
1135 | &dev_attr_uid.attr, | 1315 | &dev_attr_uid.attr, |
1136 | &dev_attr_use_diag.attr, | 1316 | &dev_attr_use_diag.attr, |
1317 | &dev_attr_raw_track_access.attr, | ||
1137 | &dev_attr_eer_enabled.attr, | 1318 | &dev_attr_eer_enabled.attr, |
1138 | &dev_attr_erplog.attr, | 1319 | &dev_attr_erplog.attr, |
1139 | &dev_attr_failfast.attr, | 1320 | &dev_attr_failfast.attr, |
1140 | &dev_attr_expires.attr, | 1321 | &dev_attr_expires.attr, |
1322 | &dev_attr_reservation_policy.attr, | ||
1323 | &dev_attr_last_known_reservation_state.attr, | ||
1141 | NULL, | 1324 | NULL, |
1142 | }; | 1325 | }; |
1143 | 1326 | ||
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 2b3bc3ec0541..46784b83c5c4 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #define KMSG_COMPONENT "dasd" | 11 | #define KMSG_COMPONENT "dasd" |
12 | 12 | ||
13 | #include <linux/kernel_stat.h> | ||
13 | #include <linux/stddef.h> | 14 | #include <linux/stddef.h> |
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
@@ -23,7 +24,7 @@ | |||
23 | #include <asm/debug.h> | 24 | #include <asm/debug.h> |
24 | #include <asm/ebcdic.h> | 25 | #include <asm/ebcdic.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | #include <asm/s390_ext.h> | 27 | #include <asm/irq.h> |
27 | #include <asm/vtoc.h> | 28 | #include <asm/vtoc.h> |
28 | #include <asm/diag.h> | 29 | #include <asm/diag.h> |
29 | 30 | ||
@@ -228,29 +229,27 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr) | |||
228 | } | 229 | } |
229 | 230 | ||
230 | /* Handle external interruption. */ | 231 | /* Handle external interruption. */ |
231 | static void | 232 | static void dasd_ext_handler(unsigned int ext_int_code, |
232 | dasd_ext_handler(__u16 code) | 233 | unsigned int param32, unsigned long param64) |
233 | { | 234 | { |
234 | struct dasd_ccw_req *cqr, *next; | 235 | struct dasd_ccw_req *cqr, *next; |
235 | struct dasd_device *device; | 236 | struct dasd_device *device; |
236 | unsigned long long expires; | 237 | unsigned long long expires; |
237 | unsigned long flags; | 238 | unsigned long flags; |
238 | u8 int_code, status; | ||
239 | addr_t ip; | 239 | addr_t ip; |
240 | int rc; | 240 | int rc; |
241 | 241 | ||
242 | int_code = *((u8 *) DASD_DIAG_LC_INT_CODE); | 242 | switch (ext_int_code >> 24) { |
243 | status = *((u8 *) DASD_DIAG_LC_INT_STATUS); | ||
244 | switch (int_code) { | ||
245 | case DASD_DIAG_CODE_31BIT: | 243 | case DASD_DIAG_CODE_31BIT: |
246 | ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT); | 244 | ip = (addr_t) param32; |
247 | break; | 245 | break; |
248 | case DASD_DIAG_CODE_64BIT: | 246 | case DASD_DIAG_CODE_64BIT: |
249 | ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT); | 247 | ip = (addr_t) param64; |
250 | break; | 248 | break; |
251 | default: | 249 | default: |
252 | return; | 250 | return; |
253 | } | 251 | } |
252 | kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; | ||
254 | if (!ip) { /* no intparm: unsolicited interrupt */ | 253 | if (!ip) { /* no intparm: unsolicited interrupt */ |
255 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " | 254 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " |
256 | "interrupt"); | 255 | "interrupt"); |
@@ -281,7 +280,7 @@ dasd_ext_handler(__u16 code) | |||
281 | cqr->stopclk = get_clock(); | 280 | cqr->stopclk = get_clock(); |
282 | 281 | ||
283 | expires = 0; | 282 | expires = 0; |
284 | if (status == 0) { | 283 | if ((ext_int_code & 0xff0000) == 0) { |
285 | cqr->status = DASD_CQR_SUCCESS; | 284 | cqr->status = DASD_CQR_SUCCESS; |
286 | /* Start first request on queue if possible -> fast_io. */ | 285 | /* Start first request on queue if possible -> fast_io. */ |
287 | if (!list_empty(&device->ccw_queue)) { | 286 | if (!list_empty(&device->ccw_queue)) { |
@@ -296,8 +295,8 @@ dasd_ext_handler(__u16 code) | |||
296 | } else { | 295 | } else { |
297 | cqr->status = DASD_CQR_QUEUED; | 296 | cqr->status = DASD_CQR_QUEUED; |
298 | DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for " | 297 | DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for " |
299 | "request %p was %d (%d retries left)", cqr, status, | 298 | "request %p was %d (%d retries left)", cqr, |
300 | cqr->retries); | 299 | (ext_int_code >> 16) & 0xff, cqr->retries); |
301 | dasd_diag_erp(device); | 300 | dasd_diag_erp(device); |
302 | } | 301 | } |
303 | 302 | ||
@@ -620,6 +619,7 @@ static struct dasd_discipline dasd_diag_discipline = { | |||
620 | .ebcname = "DIAG", | 619 | .ebcname = "DIAG", |
621 | .max_blocks = DIAG_MAX_BLOCKS, | 620 | .max_blocks = DIAG_MAX_BLOCKS, |
622 | .check_device = dasd_diag_check_device, | 621 | .check_device = dasd_diag_check_device, |
622 | .verify_path = dasd_generic_verify_path, | ||
623 | .fill_geometry = dasd_diag_fill_geometry, | 623 | .fill_geometry = dasd_diag_fill_geometry, |
624 | .start_IO = dasd_start_diag, | 624 | .start_IO = dasd_start_diag, |
625 | .term_IO = dasd_diag_term_IO, | 625 | .term_IO = dasd_diag_term_IO, |
@@ -642,7 +642,7 @@ dasd_diag_init(void) | |||
642 | } | 642 | } |
643 | ASCEBC(dasd_diag_discipline.ebcname, 4); | 643 | ASCEBC(dasd_diag_discipline.ebcname, 4); |
644 | 644 | ||
645 | ctl_set_bit(0, 9); | 645 | service_subclass_irq_register(); |
646 | register_external_interrupt(0x2603, dasd_ext_handler); | 646 | register_external_interrupt(0x2603, dasd_ext_handler); |
647 | dasd_diag_discipline_pointer = &dasd_diag_discipline; | 647 | dasd_diag_discipline_pointer = &dasd_diag_discipline; |
648 | return 0; | 648 | return 0; |
@@ -652,7 +652,7 @@ static void __exit | |||
652 | dasd_diag_cleanup(void) | 652 | dasd_diag_cleanup(void) |
653 | { | 653 | { |
654 | unregister_external_interrupt(0x2603, dasd_ext_handler); | 654 | unregister_external_interrupt(0x2603, dasd_ext_handler); |
655 | ctl_clear_bit(0, 9); | 655 | service_subclass_irq_unregister(); |
656 | dasd_diag_discipline_pointer = NULL; | 656 | dasd_diag_discipline_pointer = NULL; |
657 | } | 657 | } |
658 | 658 | ||
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h index b8c78267ff3e..4f71fbe60c82 100644 --- a/drivers/s390/block/dasd_diag.h +++ b/drivers/s390/block/dasd_diag.h | |||
@@ -18,10 +18,6 @@ | |||
18 | #define DEV_CLASS_FBA 0x01 | 18 | #define DEV_CLASS_FBA 0x01 |
19 | #define DEV_CLASS_ECKD 0x04 | 19 | #define DEV_CLASS_ECKD 0x04 |
20 | 20 | ||
21 | #define DASD_DIAG_LC_INT_CODE 132 | ||
22 | #define DASD_DIAG_LC_INT_STATUS 133 | ||
23 | #define DASD_DIAG_LC_INT_PARM_31BIT 128 | ||
24 | #define DASD_DIAG_LC_INT_PARM_64BIT 4536 | ||
25 | #define DASD_DIAG_CODE_31BIT 0x03 | 21 | #define DASD_DIAG_CODE_31BIT 0x03 |
26 | #define DASD_DIAG_CODE_64BIT 0x07 | 22 | #define DASD_DIAG_CODE_64BIT 0x07 |
27 | 23 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 66360c24bd48..30fb979d684d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -54,6 +54,15 @@ | |||
54 | #define ECKD_F7(i) (i->factor7) | 54 | #define ECKD_F7(i) (i->factor7) |
55 | #define ECKD_F8(i) (i->factor8) | 55 | #define ECKD_F8(i) (i->factor8) |
56 | 56 | ||
57 | /* | ||
58 | * raw track access always map to 64k in memory | ||
59 | * so it maps to 16 blocks of 4k per track | ||
60 | */ | ||
61 | #define DASD_RAW_BLOCK_PER_TRACK 16 | ||
62 | #define DASD_RAW_BLOCKSIZE 4096 | ||
63 | /* 64k are 128 x 512 byte sectors */ | ||
64 | #define DASD_RAW_SECTORS_PER_TRACK 128 | ||
65 | |||
57 | MODULE_LICENSE("GPL"); | 66 | MODULE_LICENSE("GPL"); |
58 | 67 | ||
59 | static struct dasd_discipline dasd_eckd_discipline; | 68 | static struct dasd_discipline dasd_eckd_discipline; |
@@ -63,7 +72,7 @@ static struct dasd_discipline dasd_eckd_discipline; | |||
63 | static struct ccw_device_id dasd_eckd_ids[] = { | 72 | static struct ccw_device_id dasd_eckd_ids[] = { |
64 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1}, | 73 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1}, |
65 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2}, | 74 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2}, |
66 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3}, | 75 | { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3380, 0), .driver_info = 0x3}, |
67 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4}, | 76 | { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4}, |
68 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5}, | 77 | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5}, |
69 | { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6}, | 78 | { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6}, |
@@ -90,6 +99,18 @@ static struct { | |||
90 | } *dasd_reserve_req; | 99 | } *dasd_reserve_req; |
91 | static DEFINE_MUTEX(dasd_reserve_mutex); | 100 | static DEFINE_MUTEX(dasd_reserve_mutex); |
92 | 101 | ||
102 | /* definitions for the path verification worker */ | ||
103 | struct path_verification_work_data { | ||
104 | struct work_struct worker; | ||
105 | struct dasd_device *device; | ||
106 | struct dasd_ccw_req cqr; | ||
107 | struct ccw1 ccw; | ||
108 | __u8 rcd_buffer[DASD_ECKD_RCD_DATA_SIZE]; | ||
109 | int isglobal; | ||
110 | __u8 tbvpm; | ||
111 | }; | ||
112 | static struct path_verification_work_data *path_verification_worker; | ||
113 | static DEFINE_MUTEX(dasd_path_verification_mutex); | ||
93 | 114 | ||
94 | /* initial attempt at a probe function. this can be simplified once | 115 | /* initial attempt at a probe function. this can be simplified once |
95 | * the other detection code is gone */ | 116 | * the other detection code is gone */ |
@@ -373,6 +394,23 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, | |||
373 | data->length = reclen; | 394 | data->length = reclen; |
374 | data->operation.operation = 0x03; | 395 | data->operation.operation = 0x03; |
375 | break; | 396 | break; |
397 | case DASD_ECKD_CCW_WRITE_FULL_TRACK: | ||
398 | data->operation.orientation = 0x0; | ||
399 | data->operation.operation = 0x3F; | ||
400 | data->extended_operation = 0x11; | ||
401 | data->length = 0; | ||
402 | data->extended_parameter_length = 0x02; | ||
403 | if (data->count > 8) { | ||
404 | data->extended_parameter[0] = 0xFF; | ||
405 | data->extended_parameter[1] = 0xFF; | ||
406 | data->extended_parameter[1] <<= (16 - count); | ||
407 | } else { | ||
408 | data->extended_parameter[0] = 0xFF; | ||
409 | data->extended_parameter[0] <<= (8 - count); | ||
410 | data->extended_parameter[1] = 0x00; | ||
411 | } | ||
412 | data->sector = 0xFF; | ||
413 | break; | ||
376 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | 414 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: |
377 | data->auxiliary.length_valid = 0x1; | 415 | data->auxiliary.length_valid = 0x1; |
378 | data->length = reclen; /* not tlf, as one might think */ | 416 | data->length = reclen; /* not tlf, as one might think */ |
@@ -396,6 +434,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, | |||
396 | case DASD_ECKD_CCW_READ_COUNT: | 434 | case DASD_ECKD_CCW_READ_COUNT: |
397 | data->operation.operation = 0x06; | 435 | data->operation.operation = 0x06; |
398 | break; | 436 | break; |
437 | case DASD_ECKD_CCW_READ_TRACK: | ||
438 | data->operation.orientation = 0x1; | ||
439 | data->operation.operation = 0x0C; | ||
440 | data->extended_parameter_length = 0; | ||
441 | data->sector = 0xFF; | ||
442 | break; | ||
399 | case DASD_ECKD_CCW_READ_TRACK_DATA: | 443 | case DASD_ECKD_CCW_READ_TRACK_DATA: |
400 | data->auxiliary.length_valid = 0x1; | 444 | data->auxiliary.length_valid = 0x1; |
401 | data->length = tlf; | 445 | data->length = tlf; |
@@ -439,10 +483,16 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
439 | 483 | ||
440 | ccw->cmd_code = DASD_ECKD_CCW_PFX; | 484 | ccw->cmd_code = DASD_ECKD_CCW_PFX; |
441 | ccw->flags = 0; | 485 | ccw->flags = 0; |
442 | ccw->count = sizeof(*pfxdata); | 486 | if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) { |
443 | ccw->cda = (__u32) __pa(pfxdata); | 487 | ccw->count = sizeof(*pfxdata) + 2; |
488 | ccw->cda = (__u32) __pa(pfxdata); | ||
489 | memset(pfxdata, 0, sizeof(*pfxdata) + 2); | ||
490 | } else { | ||
491 | ccw->count = sizeof(*pfxdata); | ||
492 | ccw->cda = (__u32) __pa(pfxdata); | ||
493 | memset(pfxdata, 0, sizeof(*pfxdata)); | ||
494 | } | ||
444 | 495 | ||
445 | memset(pfxdata, 0, sizeof(*pfxdata)); | ||
446 | /* prefix data */ | 496 | /* prefix data */ |
447 | if (format > 1) { | 497 | if (format > 1) { |
448 | DBF_DEV_EVENT(DBF_ERR, basedev, | 498 | DBF_DEV_EVENT(DBF_ERR, basedev, |
@@ -476,6 +526,7 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
476 | dedata->mask.perm = 0x1; | 526 | dedata->mask.perm = 0x1; |
477 | dedata->attributes.operation = basepriv->attrib.operation; | 527 | dedata->attributes.operation = basepriv->attrib.operation; |
478 | break; | 528 | break; |
529 | case DASD_ECKD_CCW_READ_TRACK: | ||
479 | case DASD_ECKD_CCW_READ_TRACK_DATA: | 530 | case DASD_ECKD_CCW_READ_TRACK_DATA: |
480 | dedata->mask.perm = 0x1; | 531 | dedata->mask.perm = 0x1; |
481 | dedata->attributes.operation = basepriv->attrib.operation; | 532 | dedata->attributes.operation = basepriv->attrib.operation; |
@@ -502,6 +553,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
502 | dedata->attributes.operation = DASD_BYPASS_CACHE; | 553 | dedata->attributes.operation = DASD_BYPASS_CACHE; |
503 | rc = check_XRC_on_prefix(pfxdata, basedev); | 554 | rc = check_XRC_on_prefix(pfxdata, basedev); |
504 | break; | 555 | break; |
556 | case DASD_ECKD_CCW_WRITE_FULL_TRACK: | ||
557 | dedata->mask.perm = 0x03; | ||
558 | dedata->attributes.operation = basepriv->attrib.operation; | ||
559 | dedata->blk_size = 0; | ||
560 | break; | ||
505 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | 561 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: |
506 | dedata->mask.perm = 0x02; | 562 | dedata->mask.perm = 0x02; |
507 | dedata->attributes.operation = basepriv->attrib.operation; | 563 | dedata->attributes.operation = basepriv->attrib.operation; |
@@ -755,26 +811,27 @@ static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) | |||
755 | return -EINVAL; | 811 | return -EINVAL; |
756 | } | 812 | } |
757 | 813 | ||
758 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | 814 | static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device, |
759 | void *rcd_buffer, | 815 | struct dasd_ccw_req *cqr, |
760 | struct ciw *ciw, __u8 lpm) | 816 | __u8 *rcd_buffer, |
817 | __u8 lpm) | ||
761 | { | 818 | { |
762 | struct dasd_ccw_req *cqr; | ||
763 | struct ccw1 *ccw; | 819 | struct ccw1 *ccw; |
764 | 820 | /* | |
765 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, ciw->count, | 821 | * buffer has to start with EBCDIC "V1.0" to show |
766 | device); | 822 | * support for virtual device SNEQ |
767 | 823 | */ | |
768 | if (IS_ERR(cqr)) { | 824 | rcd_buffer[0] = 0xE5; |
769 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 825 | rcd_buffer[1] = 0xF1; |
770 | "Could not allocate RCD request"); | 826 | rcd_buffer[2] = 0x4B; |
771 | return cqr; | 827 | rcd_buffer[3] = 0xF0; |
772 | } | ||
773 | 828 | ||
774 | ccw = cqr->cpaddr; | 829 | ccw = cqr->cpaddr; |
775 | ccw->cmd_code = ciw->cmd; | 830 | ccw->cmd_code = DASD_ECKD_CCW_RCD; |
831 | ccw->flags = 0; | ||
776 | ccw->cda = (__u32)(addr_t)rcd_buffer; | 832 | ccw->cda = (__u32)(addr_t)rcd_buffer; |
777 | ccw->count = ciw->count; | 833 | ccw->count = DASD_ECKD_RCD_DATA_SIZE; |
834 | cqr->magic = DASD_ECKD_MAGIC; | ||
778 | 835 | ||
779 | cqr->startdev = device; | 836 | cqr->startdev = device; |
780 | cqr->memdev = device; | 837 | cqr->memdev = device; |
@@ -784,7 +841,30 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | |||
784 | cqr->retries = 256; | 841 | cqr->retries = 256; |
785 | cqr->buildclk = get_clock(); | 842 | cqr->buildclk = get_clock(); |
786 | cqr->status = DASD_CQR_FILLED; | 843 | cqr->status = DASD_CQR_FILLED; |
787 | return cqr; | 844 | set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); |
845 | } | ||
846 | |||
847 | static int dasd_eckd_read_conf_immediately(struct dasd_device *device, | ||
848 | struct dasd_ccw_req *cqr, | ||
849 | __u8 *rcd_buffer, | ||
850 | __u8 lpm) | ||
851 | { | ||
852 | struct ciw *ciw; | ||
853 | int rc; | ||
854 | /* | ||
855 | * sanity check: scan for RCD command in extended SenseID data | ||
856 | * some devices do not support RCD | ||
857 | */ | ||
858 | ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); | ||
859 | if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD) | ||
860 | return -EOPNOTSUPP; | ||
861 | |||
862 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm); | ||
863 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
864 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
865 | cqr->retries = 5; | ||
866 | rc = dasd_sleep_on_immediatly(cqr); | ||
867 | return rc; | ||
788 | } | 868 | } |
789 | 869 | ||
790 | static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | 870 | static int dasd_eckd_read_conf_lpm(struct dasd_device *device, |
@@ -797,32 +877,29 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
797 | struct dasd_ccw_req *cqr; | 877 | struct dasd_ccw_req *cqr; |
798 | 878 | ||
799 | /* | 879 | /* |
800 | * scan for RCD command in extended SenseID data | 880 | * sanity check: scan for RCD command in extended SenseID data |
881 | * some devices do not support RCD | ||
801 | */ | 882 | */ |
802 | ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); | 883 | ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); |
803 | if (!ciw || ciw->cmd == 0) { | 884 | if (!ciw || ciw->cmd != DASD_ECKD_CCW_RCD) { |
804 | ret = -EOPNOTSUPP; | 885 | ret = -EOPNOTSUPP; |
805 | goto out_error; | 886 | goto out_error; |
806 | } | 887 | } |
807 | rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); | 888 | rcd_buf = kzalloc(DASD_ECKD_RCD_DATA_SIZE, GFP_KERNEL | GFP_DMA); |
808 | if (!rcd_buf) { | 889 | if (!rcd_buf) { |
809 | ret = -ENOMEM; | 890 | ret = -ENOMEM; |
810 | goto out_error; | 891 | goto out_error; |
811 | } | 892 | } |
812 | 893 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */, | |
813 | /* | 894 | 0, /* use rcd_buf as data ara */ |
814 | * buffer has to start with EBCDIC "V1.0" to show | 895 | device); |
815 | * support for virtual device SNEQ | ||
816 | */ | ||
817 | rcd_buf[0] = 0xE5; | ||
818 | rcd_buf[1] = 0xF1; | ||
819 | rcd_buf[2] = 0x4B; | ||
820 | rcd_buf[3] = 0xF0; | ||
821 | cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); | ||
822 | if (IS_ERR(cqr)) { | 896 | if (IS_ERR(cqr)) { |
823 | ret = PTR_ERR(cqr); | 897 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
898 | "Could not allocate RCD request"); | ||
899 | ret = -ENOMEM; | ||
824 | goto out_error; | 900 | goto out_error; |
825 | } | 901 | } |
902 | dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buf, lpm); | ||
826 | ret = dasd_sleep_on(cqr); | 903 | ret = dasd_sleep_on(cqr); |
827 | /* | 904 | /* |
828 | * on success we update the user input parms | 905 | * on success we update the user input parms |
@@ -831,7 +908,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
831 | if (ret) | 908 | if (ret) |
832 | goto out_error; | 909 | goto out_error; |
833 | 910 | ||
834 | *rcd_buffer_size = ciw->count; | 911 | *rcd_buffer_size = DASD_ECKD_RCD_DATA_SIZE; |
835 | *rcd_buffer = rcd_buf; | 912 | *rcd_buffer = rcd_buf; |
836 | return 0; | 913 | return 0; |
837 | out_error: | 914 | out_error: |
@@ -901,18 +978,18 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
901 | void *conf_data; | 978 | void *conf_data; |
902 | int conf_len, conf_data_saved; | 979 | int conf_len, conf_data_saved; |
903 | int rc; | 980 | int rc; |
904 | __u8 lpm; | 981 | __u8 lpm, opm; |
905 | struct dasd_eckd_private *private; | 982 | struct dasd_eckd_private *private; |
906 | struct dasd_eckd_path *path_data; | 983 | struct dasd_path *path_data; |
907 | 984 | ||
908 | private = (struct dasd_eckd_private *) device->private; | 985 | private = (struct dasd_eckd_private *) device->private; |
909 | path_data = (struct dasd_eckd_path *) &private->path_data; | 986 | path_data = &device->path_data; |
910 | path_data->opm = ccw_device_get_path_mask(device->cdev); | 987 | opm = ccw_device_get_path_mask(device->cdev); |
911 | lpm = 0x80; | 988 | lpm = 0x80; |
912 | conf_data_saved = 0; | 989 | conf_data_saved = 0; |
913 | /* get configuration data per operational path */ | 990 | /* get configuration data per operational path */ |
914 | for (lpm = 0x80; lpm; lpm>>= 1) { | 991 | for (lpm = 0x80; lpm; lpm>>= 1) { |
915 | if (lpm & path_data->opm){ | 992 | if (lpm & opm) { |
916 | rc = dasd_eckd_read_conf_lpm(device, &conf_data, | 993 | rc = dasd_eckd_read_conf_lpm(device, &conf_data, |
917 | &conf_len, lpm); | 994 | &conf_len, lpm); |
918 | if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ | 995 | if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ |
@@ -925,6 +1002,8 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
925 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | 1002 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
926 | "No configuration data " | 1003 | "No configuration data " |
927 | "retrieved"); | 1004 | "retrieved"); |
1005 | /* no further analysis possible */ | ||
1006 | path_data->opm |= lpm; | ||
928 | continue; /* no error */ | 1007 | continue; /* no error */ |
929 | } | 1008 | } |
930 | /* save first valid configuration data */ | 1009 | /* save first valid configuration data */ |
@@ -948,6 +1027,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
948 | path_data->ppm |= lpm; | 1027 | path_data->ppm |= lpm; |
949 | break; | 1028 | break; |
950 | } | 1029 | } |
1030 | path_data->opm |= lpm; | ||
951 | if (conf_data != private->conf_data) | 1031 | if (conf_data != private->conf_data) |
952 | kfree(conf_data); | 1032 | kfree(conf_data); |
953 | } | 1033 | } |
@@ -955,6 +1035,140 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
955 | return 0; | 1035 | return 0; |
956 | } | 1036 | } |
957 | 1037 | ||
1038 | static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) | ||
1039 | { | ||
1040 | struct dasd_eckd_private *private; | ||
1041 | int mdc; | ||
1042 | u32 fcx_max_data; | ||
1043 | |||
1044 | private = (struct dasd_eckd_private *) device->private; | ||
1045 | if (private->fcx_max_data) { | ||
1046 | mdc = ccw_device_get_mdc(device->cdev, lpm); | ||
1047 | if ((mdc < 0)) { | ||
1048 | dev_warn(&device->cdev->dev, | ||
1049 | "Detecting the maximum data size for zHPF " | ||
1050 | "requests failed (rc=%d) for a new path %x\n", | ||
1051 | mdc, lpm); | ||
1052 | return mdc; | ||
1053 | } | ||
1054 | fcx_max_data = mdc * FCX_MAX_DATA_FACTOR; | ||
1055 | if (fcx_max_data < private->fcx_max_data) { | ||
1056 | dev_warn(&device->cdev->dev, | ||
1057 | "The maximum data size for zHPF requests %u " | ||
1058 | "on a new path %x is below the active maximum " | ||
1059 | "%u\n", fcx_max_data, lpm, | ||
1060 | private->fcx_max_data); | ||
1061 | return -EACCES; | ||
1062 | } | ||
1063 | } | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static void do_path_verification_work(struct work_struct *work) | ||
1068 | { | ||
1069 | struct path_verification_work_data *data; | ||
1070 | struct dasd_device *device; | ||
1071 | __u8 lpm, opm, npm, ppm, epm; | ||
1072 | unsigned long flags; | ||
1073 | int rc; | ||
1074 | |||
1075 | data = container_of(work, struct path_verification_work_data, worker); | ||
1076 | device = data->device; | ||
1077 | |||
1078 | opm = 0; | ||
1079 | npm = 0; | ||
1080 | ppm = 0; | ||
1081 | epm = 0; | ||
1082 | for (lpm = 0x80; lpm; lpm >>= 1) { | ||
1083 | if (lpm & data->tbvpm) { | ||
1084 | memset(data->rcd_buffer, 0, sizeof(data->rcd_buffer)); | ||
1085 | memset(&data->cqr, 0, sizeof(data->cqr)); | ||
1086 | data->cqr.cpaddr = &data->ccw; | ||
1087 | rc = dasd_eckd_read_conf_immediately(device, &data->cqr, | ||
1088 | data->rcd_buffer, | ||
1089 | lpm); | ||
1090 | if (!rc) { | ||
1091 | switch (dasd_eckd_path_access(data->rcd_buffer, | ||
1092 | DASD_ECKD_RCD_DATA_SIZE)) { | ||
1093 | case 0x02: | ||
1094 | npm |= lpm; | ||
1095 | break; | ||
1096 | case 0x03: | ||
1097 | ppm |= lpm; | ||
1098 | break; | ||
1099 | } | ||
1100 | opm |= lpm; | ||
1101 | } else if (rc == -EOPNOTSUPP) { | ||
1102 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | ||
1103 | "path verification: No configuration " | ||
1104 | "data retrieved"); | ||
1105 | opm |= lpm; | ||
1106 | } else if (rc == -EAGAIN) { | ||
1107 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | ||
1108 | "path verification: device is stopped," | ||
1109 | " try again later"); | ||
1110 | epm |= lpm; | ||
1111 | } else { | ||
1112 | dev_warn(&device->cdev->dev, | ||
1113 | "Reading device feature codes failed " | ||
1114 | "(rc=%d) for new path %x\n", rc, lpm); | ||
1115 | continue; | ||
1116 | } | ||
1117 | if (verify_fcx_max_data(device, lpm)) { | ||
1118 | opm &= ~lpm; | ||
1119 | npm &= ~lpm; | ||
1120 | ppm &= ~lpm; | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | /* | ||
1125 | * There is a small chance that a path is lost again between | ||
1126 | * above path verification and the following modification of | ||
1127 | * the device opm mask. We could avoid that race here by using | ||
1128 | * yet another path mask, but we rather deal with this unlikely | ||
1129 | * situation in dasd_start_IO. | ||
1130 | */ | ||
1131 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
1132 | if (!device->path_data.opm && opm) { | ||
1133 | device->path_data.opm = opm; | ||
1134 | dasd_generic_path_operational(device); | ||
1135 | } else | ||
1136 | device->path_data.opm |= opm; | ||
1137 | device->path_data.npm |= npm; | ||
1138 | device->path_data.ppm |= ppm; | ||
1139 | device->path_data.tbvpm |= epm; | ||
1140 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
1141 | |||
1142 | dasd_put_device(device); | ||
1143 | if (data->isglobal) | ||
1144 | mutex_unlock(&dasd_path_verification_mutex); | ||
1145 | else | ||
1146 | kfree(data); | ||
1147 | } | ||
1148 | |||
1149 | static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm) | ||
1150 | { | ||
1151 | struct path_verification_work_data *data; | ||
1152 | |||
1153 | data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA); | ||
1154 | if (!data) { | ||
1155 | if (mutex_trylock(&dasd_path_verification_mutex)) { | ||
1156 | data = path_verification_worker; | ||
1157 | data->isglobal = 1; | ||
1158 | } else | ||
1159 | return -ENOMEM; | ||
1160 | } else { | ||
1161 | memset(data, 0, sizeof(*data)); | ||
1162 | data->isglobal = 0; | ||
1163 | } | ||
1164 | INIT_WORK(&data->worker, do_path_verification_work); | ||
1165 | dasd_get_device(device); | ||
1166 | data->device = device; | ||
1167 | data->tbvpm = lpm; | ||
1168 | schedule_work(&data->worker); | ||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
958 | static int dasd_eckd_read_features(struct dasd_device *device) | 1172 | static int dasd_eckd_read_features(struct dasd_device *device) |
959 | { | 1173 | { |
960 | struct dasd_psf_prssd_data *prssdp; | 1174 | struct dasd_psf_prssd_data *prssdp; |
@@ -1105,6 +1319,37 @@ static void dasd_eckd_validate_server(struct dasd_device *device) | |||
1105 | "returned rc=%d", private->uid.ssid, rc); | 1319 | "returned rc=%d", private->uid.ssid, rc); |
1106 | } | 1320 | } |
1107 | 1321 | ||
1322 | static u32 get_fcx_max_data(struct dasd_device *device) | ||
1323 | { | ||
1324 | #if defined(CONFIG_64BIT) | ||
1325 | int tpm, mdc; | ||
1326 | int fcx_in_css, fcx_in_gneq, fcx_in_features; | ||
1327 | struct dasd_eckd_private *private; | ||
1328 | |||
1329 | if (dasd_nofcx) | ||
1330 | return 0; | ||
1331 | /* is transport mode supported? */ | ||
1332 | private = (struct dasd_eckd_private *) device->private; | ||
1333 | fcx_in_css = css_general_characteristics.fcx; | ||
1334 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; | ||
1335 | fcx_in_features = private->features.feature[40] & 0x80; | ||
1336 | tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; | ||
1337 | |||
1338 | if (!tpm) | ||
1339 | return 0; | ||
1340 | |||
1341 | mdc = ccw_device_get_mdc(device->cdev, 0); | ||
1342 | if (mdc < 0) { | ||
1343 | dev_warn(&device->cdev->dev, "Detecting the maximum supported" | ||
1344 | " data size for zHPF requests failed\n"); | ||
1345 | return 0; | ||
1346 | } else | ||
1347 | return mdc * FCX_MAX_DATA_FACTOR; | ||
1348 | #else | ||
1349 | return 0; | ||
1350 | #endif | ||
1351 | } | ||
1352 | |||
1108 | /* | 1353 | /* |
1109 | * Check device characteristics. | 1354 | * Check device characteristics. |
1110 | * If the device is accessible using ECKD discipline, the device is enabled. | 1355 | * If the device is accessible using ECKD discipline, the device is enabled. |
@@ -1190,7 +1435,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1190 | goto out_err2; | 1435 | goto out_err2; |
1191 | } | 1436 | } |
1192 | /* | 1437 | /* |
1193 | * dasd_eckd_vaildate_server is done on the first device that | 1438 | * dasd_eckd_validate_server is done on the first device that |
1194 | * is found for an LCU. All later other devices have to wait | 1439 | * is found for an LCU. All later other devices have to wait |
1195 | * for it, so they will read the correct feature codes. | 1440 | * for it, so they will read the correct feature codes. |
1196 | */ | 1441 | */ |
@@ -1216,13 +1461,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1216 | "Read device characteristic failed, rc=%d", rc); | 1461 | "Read device characteristic failed, rc=%d", rc); |
1217 | goto out_err3; | 1462 | goto out_err3; |
1218 | } | 1463 | } |
1219 | /* find the vaild cylinder size */ | 1464 | /* find the valid cylinder size */ |
1220 | if (private->rdc_data.no_cyl == LV_COMPAT_CYL && | 1465 | if (private->rdc_data.no_cyl == LV_COMPAT_CYL && |
1221 | private->rdc_data.long_no_cyl) | 1466 | private->rdc_data.long_no_cyl) |
1222 | private->real_cyl = private->rdc_data.long_no_cyl; | 1467 | private->real_cyl = private->rdc_data.long_no_cyl; |
1223 | else | 1468 | else |
1224 | private->real_cyl = private->rdc_data.no_cyl; | 1469 | private->real_cyl = private->rdc_data.no_cyl; |
1225 | 1470 | ||
1471 | private->fcx_max_data = get_fcx_max_data(device); | ||
1472 | |||
1226 | readonly = dasd_device_is_ro(device); | 1473 | readonly = dasd_device_is_ro(device); |
1227 | if (readonly) | 1474 | if (readonly) |
1228 | set_bit(DASD_FLAG_DEVICE_RO, &device->flags); | 1475 | set_bit(DASD_FLAG_DEVICE_RO, &device->flags); |
@@ -1364,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, | |||
1364 | 1611 | ||
1365 | static int dasd_eckd_start_analysis(struct dasd_block *block) | 1612 | static int dasd_eckd_start_analysis(struct dasd_block *block) |
1366 | { | 1613 | { |
1367 | struct dasd_eckd_private *private; | ||
1368 | struct dasd_ccw_req *init_cqr; | 1614 | struct dasd_ccw_req *init_cqr; |
1369 | 1615 | ||
1370 | private = (struct dasd_eckd_private *) block->base->private; | ||
1371 | init_cqr = dasd_eckd_analysis_ccw(block->base); | 1616 | init_cqr = dasd_eckd_analysis_ccw(block->base); |
1372 | if (IS_ERR(init_cqr)) | 1617 | if (IS_ERR(init_cqr)) |
1373 | return PTR_ERR(init_cqr); | 1618 | return PTR_ERR(init_cqr); |
@@ -1404,6 +1649,13 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1404 | dasd_sfree_request(init_cqr, device); | 1649 | dasd_sfree_request(init_cqr, device); |
1405 | } | 1650 | } |
1406 | 1651 | ||
1652 | if (device->features & DASD_FEATURE_USERAW) { | ||
1653 | block->bp_block = DASD_RAW_BLOCKSIZE; | ||
1654 | blk_per_trk = DASD_RAW_BLOCK_PER_TRACK; | ||
1655 | block->s2b_shift = 3; | ||
1656 | goto raw; | ||
1657 | } | ||
1658 | |||
1407 | if (status == INIT_CQR_UNFORMATTED) { | 1659 | if (status == INIT_CQR_UNFORMATTED) { |
1408 | dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); | 1660 | dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); |
1409 | return -EMEDIUMTYPE; | 1661 | return -EMEDIUMTYPE; |
@@ -1441,6 +1693,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1441 | dev_warn(&device->cdev->dev, | 1693 | dev_warn(&device->cdev->dev, |
1442 | "Track 0 has no records following the VTOC\n"); | 1694 | "Track 0 has no records following the VTOC\n"); |
1443 | } | 1695 | } |
1696 | |||
1444 | if (count_area != NULL && count_area->kl == 0) { | 1697 | if (count_area != NULL && count_area->kl == 0) { |
1445 | /* we found notthing violating our disk layout */ | 1698 | /* we found notthing violating our disk layout */ |
1446 | if (dasd_check_blocksize(count_area->dl) == 0) | 1699 | if (dasd_check_blocksize(count_area->dl) == 0) |
@@ -1456,6 +1709,8 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1456 | block->s2b_shift++; | 1709 | block->s2b_shift++; |
1457 | 1710 | ||
1458 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); | 1711 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); |
1712 | |||
1713 | raw: | ||
1459 | block->blocks = (private->real_cyl * | 1714 | block->blocks = (private->real_cyl * |
1460 | private->rdc_data.trk_per_cyl * | 1715 | private->rdc_data.trk_per_cyl * |
1461 | blk_per_trk); | 1716 | blk_per_trk); |
@@ -1716,6 +1971,7 @@ static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) | |||
1716 | if (cqr->block && (cqr->startdev != cqr->block->base)) { | 1971 | if (cqr->block && (cqr->startdev != cqr->block->base)) { |
1717 | dasd_eckd_reset_ccw_to_base_io(cqr); | 1972 | dasd_eckd_reset_ccw_to_base_io(cqr); |
1718 | cqr->startdev = cqr->block->base; | 1973 | cqr->startdev = cqr->block->base; |
1974 | cqr->lpm = cqr->block->base->path_data.opm; | ||
1719 | } | 1975 | } |
1720 | }; | 1976 | }; |
1721 | 1977 | ||
@@ -1744,9 +2000,9 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr) | |||
1744 | return dasd_default_erp_postaction; | 2000 | return dasd_default_erp_postaction; |
1745 | } | 2001 | } |
1746 | 2002 | ||
1747 | 2003 | static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |
1748 | static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | 2004 | struct dasd_ccw_req *cqr, |
1749 | struct irb *irb) | 2005 | struct irb *irb) |
1750 | { | 2006 | { |
1751 | char mask; | 2007 | char mask; |
1752 | char *sense = NULL; | 2008 | char *sense = NULL; |
@@ -1770,51 +2026,42 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1770 | /* schedule worker to reload device */ | 2026 | /* schedule worker to reload device */ |
1771 | dasd_reload_device(device); | 2027 | dasd_reload_device(device); |
1772 | } | 2028 | } |
1773 | |||
1774 | dasd_generic_handle_state_change(device); | 2029 | dasd_generic_handle_state_change(device); |
1775 | return; | 2030 | return; |
1776 | } | 2031 | } |
1777 | 2032 | ||
2033 | sense = dasd_get_sense(irb); | ||
2034 | if (!sense) | ||
2035 | return; | ||
2036 | |||
1778 | /* summary unit check */ | 2037 | /* summary unit check */ |
1779 | if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && | 2038 | if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) && |
1780 | (irb->ecw[7] == 0x0D)) { | 2039 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { |
1781 | dasd_alias_handle_summary_unit_check(device, irb); | 2040 | dasd_alias_handle_summary_unit_check(device, irb); |
1782 | return; | 2041 | return; |
1783 | } | 2042 | } |
1784 | 2043 | ||
1785 | sense = dasd_get_sense(irb); | ||
1786 | /* service information message SIM */ | 2044 | /* service information message SIM */ |
1787 | if (sense && !(sense[27] & DASD_SENSE_BIT_0) && | 2045 | if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) && |
1788 | ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { | 2046 | ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { |
1789 | dasd_3990_erp_handle_sim(device, sense); | 2047 | dasd_3990_erp_handle_sim(device, sense); |
1790 | dasd_schedule_device_bh(device); | ||
1791 | return; | 2048 | return; |
1792 | } | 2049 | } |
1793 | 2050 | ||
1794 | if ((scsw_cc(&irb->scsw) == 1) && | 2051 | /* loss of device reservation is handled via base devices only |
1795 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && | 2052 | * as alias devices may be used with several bases |
1796 | (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && | 2053 | */ |
1797 | (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) { | 2054 | if (device->block && (sense[27] & DASD_SENSE_BIT_0) && |
1798 | /* fake irb do nothing, they are handled elsewhere */ | 2055 | (sense[7] == 0x3F) && |
1799 | dasd_schedule_device_bh(device); | 2056 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && |
1800 | return; | 2057 | test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { |
1801 | } | 2058 | if (device->features & DASD_FEATURE_FAILONSLCK) |
1802 | 2059 | set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); | |
1803 | if (!sense) { | 2060 | clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); |
1804 | /* just report other unsolicited interrupts */ | 2061 | dev_err(&device->cdev->dev, |
1805 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | 2062 | "The device reservation was lost\n"); |
1806 | "unsolicited interrupt received"); | ||
1807 | } else { | ||
1808 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
1809 | "unsolicited interrupt received " | ||
1810 | "(sense available)"); | ||
1811 | device->discipline->dump_sense_dbf(device, irb, "unsolicited"); | ||
1812 | } | 2063 | } |
1813 | 2064 | } | |
1814 | dasd_schedule_device_bh(device); | ||
1815 | return; | ||
1816 | }; | ||
1817 | |||
1818 | 2065 | ||
1819 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | 2066 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( |
1820 | struct dasd_device *startdev, | 2067 | struct dasd_device *startdev, |
@@ -1995,7 +2242,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | |||
1995 | cqr->memdev = startdev; | 2242 | cqr->memdev = startdev; |
1996 | cqr->block = block; | 2243 | cqr->block = block; |
1997 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 2244 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
1998 | cqr->lpm = private->path_data.ppm; | 2245 | cqr->lpm = startdev->path_data.ppm; |
1999 | cqr->retries = 256; | 2246 | cqr->retries = 256; |
2000 | cqr->buildclk = get_clock(); | 2247 | cqr->buildclk = get_clock(); |
2001 | cqr->status = DASD_CQR_FILLED; | 2248 | cqr->status = DASD_CQR_FILLED; |
@@ -2015,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2015 | unsigned int blk_per_trk, | 2262 | unsigned int blk_per_trk, |
2016 | unsigned int blksize) | 2263 | unsigned int blksize) |
2017 | { | 2264 | { |
2018 | struct dasd_eckd_private *private; | ||
2019 | unsigned long *idaws; | 2265 | unsigned long *idaws; |
2020 | struct dasd_ccw_req *cqr; | 2266 | struct dasd_ccw_req *cqr; |
2021 | struct ccw1 *ccw; | 2267 | struct ccw1 *ccw; |
@@ -2034,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2034 | unsigned int recoffs; | 2280 | unsigned int recoffs; |
2035 | 2281 | ||
2036 | basedev = block->base; | 2282 | basedev = block->base; |
2037 | private = (struct dasd_eckd_private *) basedev->private; | ||
2038 | if (rq_data_dir(req) == READ) | 2283 | if (rq_data_dir(req) == READ) |
2039 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2284 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
2040 | else if (rq_data_dir(req) == WRITE) | 2285 | else if (rq_data_dir(req) == WRITE) |
@@ -2172,7 +2417,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2172 | cqr->memdev = startdev; | 2417 | cqr->memdev = startdev; |
2173 | cqr->block = block; | 2418 | cqr->block = block; |
2174 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 2419 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
2175 | cqr->lpm = private->path_data.ppm; | 2420 | cqr->lpm = startdev->path_data.ppm; |
2176 | cqr->retries = 256; | 2421 | cqr->retries = 256; |
2177 | cqr->buildclk = get_clock(); | 2422 | cqr->buildclk = get_clock(); |
2178 | cqr->status = DASD_CQR_FILLED; | 2423 | cqr->status = DASD_CQR_FILLED; |
@@ -2307,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw, | |||
2307 | 2552 | ||
2308 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, | 2553 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, |
2309 | &pfxdata, sizeof(pfxdata), total_data_size); | 2554 | &pfxdata, sizeof(pfxdata), total_data_size); |
2310 | 2555 | return IS_ERR(dcw) ? PTR_ERR(dcw) : 0; | |
2311 | return rc; | ||
2312 | } | 2556 | } |
2313 | 2557 | ||
2314 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | 2558 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( |
@@ -2324,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2324 | unsigned int blk_per_trk, | 2568 | unsigned int blk_per_trk, |
2325 | unsigned int blksize) | 2569 | unsigned int blksize) |
2326 | { | 2570 | { |
2327 | struct dasd_eckd_private *private; | ||
2328 | struct dasd_ccw_req *cqr; | 2571 | struct dasd_ccw_req *cqr; |
2329 | struct req_iterator iter; | 2572 | struct req_iterator iter; |
2330 | struct bio_vec *bv; | 2573 | struct bio_vec *bv; |
@@ -2337,9 +2580,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2337 | struct tidaw *last_tidaw = NULL; | 2580 | struct tidaw *last_tidaw = NULL; |
2338 | int itcw_op; | 2581 | int itcw_op; |
2339 | size_t itcw_size; | 2582 | size_t itcw_size; |
2583 | u8 tidaw_flags; | ||
2584 | unsigned int seg_len, part_len, len_to_track_end; | ||
2585 | unsigned char new_track; | ||
2586 | sector_t recid, trkid; | ||
2587 | unsigned int offs; | ||
2588 | unsigned int count, count_to_trk_end; | ||
2340 | 2589 | ||
2341 | basedev = block->base; | 2590 | basedev = block->base; |
2342 | private = (struct dasd_eckd_private *) basedev->private; | ||
2343 | if (rq_data_dir(req) == READ) { | 2591 | if (rq_data_dir(req) == READ) { |
2344 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2592 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
2345 | itcw_op = ITCW_OP_READ; | 2593 | itcw_op = ITCW_OP_READ; |
@@ -2352,12 +2600,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2352 | /* trackbased I/O needs address all memory via TIDAWs, | 2600 | /* trackbased I/O needs address all memory via TIDAWs, |
2353 | * not just for 64 bit addresses. This allows us to map | 2601 | * not just for 64 bit addresses. This allows us to map |
2354 | * each segment directly to one tidaw. | 2602 | * each segment directly to one tidaw. |
2603 | * In the case of write requests, additional tidaws may | ||
2604 | * be needed when a segment crosses a track boundary. | ||
2355 | */ | 2605 | */ |
2356 | trkcount = last_trk - first_trk + 1; | 2606 | trkcount = last_trk - first_trk + 1; |
2357 | ctidaw = 0; | 2607 | ctidaw = 0; |
2358 | rq_for_each_segment(bv, req, iter) { | 2608 | rq_for_each_segment(bv, req, iter) { |
2359 | ++ctidaw; | 2609 | ++ctidaw; |
2360 | } | 2610 | } |
2611 | if (rq_data_dir(req) == WRITE) | ||
2612 | ctidaw += (last_trk - first_trk); | ||
2361 | 2613 | ||
2362 | /* Allocate the ccw request. */ | 2614 | /* Allocate the ccw request. */ |
2363 | itcw_size = itcw_calc_size(0, ctidaw, 0); | 2615 | itcw_size = itcw_calc_size(0, ctidaw, 0); |
@@ -2365,15 +2617,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2365 | if (IS_ERR(cqr)) | 2617 | if (IS_ERR(cqr)) |
2366 | return cqr; | 2618 | return cqr; |
2367 | 2619 | ||
2368 | cqr->cpmode = 1; | ||
2369 | cqr->startdev = startdev; | ||
2370 | cqr->memdev = startdev; | ||
2371 | cqr->block = block; | ||
2372 | cqr->expires = 100*HZ; | ||
2373 | cqr->buildclk = get_clock(); | ||
2374 | cqr->status = DASD_CQR_FILLED; | ||
2375 | cqr->retries = 10; | ||
2376 | |||
2377 | /* transfer length factor: how many bytes to read from the last track */ | 2620 | /* transfer length factor: how many bytes to read from the last track */ |
2378 | if (first_trk == last_trk) | 2621 | if (first_trk == last_trk) |
2379 | tlf = last_offs - first_offs + 1; | 2622 | tlf = last_offs - first_offs + 1; |
@@ -2382,8 +2625,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2382 | tlf *= blksize; | 2625 | tlf *= blksize; |
2383 | 2626 | ||
2384 | itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); | 2627 | itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); |
2628 | if (IS_ERR(itcw)) { | ||
2629 | dasd_sfree_request(cqr, startdev); | ||
2630 | return ERR_PTR(-EINVAL); | ||
2631 | } | ||
2385 | cqr->cpaddr = itcw_get_tcw(itcw); | 2632 | cqr->cpaddr = itcw_get_tcw(itcw); |
2386 | |||
2387 | if (prepare_itcw(itcw, first_trk, last_trk, | 2633 | if (prepare_itcw(itcw, first_trk, last_trk, |
2388 | cmd, basedev, startdev, | 2634 | cmd, basedev, startdev, |
2389 | first_offs + 1, | 2635 | first_offs + 1, |
@@ -2396,31 +2642,70 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2396 | dasd_sfree_request(cqr, startdev); | 2642 | dasd_sfree_request(cqr, startdev); |
2397 | return ERR_PTR(-EAGAIN); | 2643 | return ERR_PTR(-EAGAIN); |
2398 | } | 2644 | } |
2399 | 2645 | len_to_track_end = 0; | |
2400 | /* | 2646 | /* |
2401 | * A tidaw can address 4k of memory, but must not cross page boundaries | 2647 | * A tidaw can address 4k of memory, but must not cross page boundaries |
2402 | * We can let the block layer handle this by setting | 2648 | * We can let the block layer handle this by setting |
2403 | * blk_queue_segment_boundary to page boundaries and | 2649 | * blk_queue_segment_boundary to page boundaries and |
2404 | * blk_max_segment_size to page size when setting up the request queue. | 2650 | * blk_max_segment_size to page size when setting up the request queue. |
2651 | * For write requests, a TIDAW must not cross track boundaries, because | ||
2652 | * we have to set the CBC flag on the last tidaw for each track. | ||
2405 | */ | 2653 | */ |
2406 | rq_for_each_segment(bv, req, iter) { | 2654 | if (rq_data_dir(req) == WRITE) { |
2407 | dst = page_address(bv->bv_page) + bv->bv_offset; | 2655 | new_track = 1; |
2408 | last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); | 2656 | recid = first_rec; |
2409 | if (IS_ERR(last_tidaw)) | 2657 | rq_for_each_segment(bv, req, iter) { |
2410 | return (struct dasd_ccw_req *)last_tidaw; | 2658 | dst = page_address(bv->bv_page) + bv->bv_offset; |
2659 | seg_len = bv->bv_len; | ||
2660 | while (seg_len) { | ||
2661 | if (new_track) { | ||
2662 | trkid = recid; | ||
2663 | offs = sector_div(trkid, blk_per_trk); | ||
2664 | count_to_trk_end = blk_per_trk - offs; | ||
2665 | count = min((last_rec - recid + 1), | ||
2666 | (sector_t)count_to_trk_end); | ||
2667 | len_to_track_end = count * blksize; | ||
2668 | recid += count; | ||
2669 | new_track = 0; | ||
2670 | } | ||
2671 | part_len = min(seg_len, len_to_track_end); | ||
2672 | seg_len -= part_len; | ||
2673 | len_to_track_end -= part_len; | ||
2674 | /* We need to end the tidaw at track end */ | ||
2675 | if (!len_to_track_end) { | ||
2676 | new_track = 1; | ||
2677 | tidaw_flags = TIDAW_FLAGS_INSERT_CBC; | ||
2678 | } else | ||
2679 | tidaw_flags = 0; | ||
2680 | last_tidaw = itcw_add_tidaw(itcw, tidaw_flags, | ||
2681 | dst, part_len); | ||
2682 | if (IS_ERR(last_tidaw)) | ||
2683 | return ERR_PTR(-EINVAL); | ||
2684 | dst += part_len; | ||
2685 | } | ||
2686 | } | ||
2687 | } else { | ||
2688 | rq_for_each_segment(bv, req, iter) { | ||
2689 | dst = page_address(bv->bv_page) + bv->bv_offset; | ||
2690 | last_tidaw = itcw_add_tidaw(itcw, 0x00, | ||
2691 | dst, bv->bv_len); | ||
2692 | if (IS_ERR(last_tidaw)) | ||
2693 | return ERR_PTR(-EINVAL); | ||
2694 | } | ||
2411 | } | 2695 | } |
2412 | 2696 | last_tidaw->flags |= TIDAW_FLAGS_LAST; | |
2413 | last_tidaw->flags |= 0x80; | 2697 | last_tidaw->flags &= ~TIDAW_FLAGS_INSERT_CBC; |
2414 | itcw_finalize(itcw); | 2698 | itcw_finalize(itcw); |
2415 | 2699 | ||
2416 | if (blk_noretry_request(req) || | 2700 | if (blk_noretry_request(req) || |
2417 | block->base->features & DASD_FEATURE_FAILFAST) | 2701 | block->base->features & DASD_FEATURE_FAILFAST) |
2418 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 2702 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
2703 | cqr->cpmode = 1; | ||
2419 | cqr->startdev = startdev; | 2704 | cqr->startdev = startdev; |
2420 | cqr->memdev = startdev; | 2705 | cqr->memdev = startdev; |
2421 | cqr->block = block; | 2706 | cqr->block = block; |
2422 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ | 2707 | cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */ |
2423 | cqr->lpm = private->path_data.ppm; | 2708 | cqr->lpm = startdev->path_data.ppm; |
2424 | cqr->retries = 256; | 2709 | cqr->retries = 256; |
2425 | cqr->buildclk = get_clock(); | 2710 | cqr->buildclk = get_clock(); |
2426 | cqr->status = DASD_CQR_FILLED; | 2711 | cqr->status = DASD_CQR_FILLED; |
@@ -2431,11 +2716,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2431 | struct dasd_block *block, | 2716 | struct dasd_block *block, |
2432 | struct request *req) | 2717 | struct request *req) |
2433 | { | 2718 | { |
2434 | int tpm, cmdrtd, cmdwtd; | 2719 | int cmdrtd, cmdwtd; |
2435 | int use_prefix; | 2720 | int use_prefix; |
2436 | #if defined(CONFIG_64BIT) | 2721 | int fcx_multitrack; |
2437 | int fcx_in_css, fcx_in_gneq, fcx_in_features; | ||
2438 | #endif | ||
2439 | struct dasd_eckd_private *private; | 2722 | struct dasd_eckd_private *private; |
2440 | struct dasd_device *basedev; | 2723 | struct dasd_device *basedev; |
2441 | sector_t first_rec, last_rec; | 2724 | sector_t first_rec, last_rec; |
@@ -2443,6 +2726,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2443 | unsigned int first_offs, last_offs; | 2726 | unsigned int first_offs, last_offs; |
2444 | unsigned int blk_per_trk, blksize; | 2727 | unsigned int blk_per_trk, blksize; |
2445 | int cdlspecial; | 2728 | int cdlspecial; |
2729 | unsigned int data_size; | ||
2446 | struct dasd_ccw_req *cqr; | 2730 | struct dasd_ccw_req *cqr; |
2447 | 2731 | ||
2448 | basedev = block->base; | 2732 | basedev = block->base; |
@@ -2461,15 +2745,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2461 | last_offs = sector_div(last_trk, blk_per_trk); | 2745 | last_offs = sector_div(last_trk, blk_per_trk); |
2462 | cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); | 2746 | cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); |
2463 | 2747 | ||
2464 | /* is transport mode supported? */ | 2748 | fcx_multitrack = private->features.feature[40] & 0x20; |
2465 | #if defined(CONFIG_64BIT) | 2749 | data_size = blk_rq_bytes(req); |
2466 | fcx_in_css = css_general_characteristics.fcx; | 2750 | /* tpm write request add CBC data on each track boundary */ |
2467 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; | 2751 | if (rq_data_dir(req) == WRITE) |
2468 | fcx_in_features = private->features.feature[40] & 0x80; | 2752 | data_size += (last_trk - first_trk) * 4; |
2469 | tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; | ||
2470 | #else | ||
2471 | tpm = 0; | ||
2472 | #endif | ||
2473 | 2753 | ||
2474 | /* is read track data and write track data in command mode supported? */ | 2754 | /* is read track data and write track data in command mode supported? */ |
2475 | cmdrtd = private->features.feature[9] & 0x20; | 2755 | cmdrtd = private->features.feature[9] & 0x20; |
@@ -2479,13 +2759,15 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2479 | cqr = NULL; | 2759 | cqr = NULL; |
2480 | if (cdlspecial || dasd_page_cache) { | 2760 | if (cdlspecial || dasd_page_cache) { |
2481 | /* do nothing, just fall through to the cmd mode single case */ | 2761 | /* do nothing, just fall through to the cmd mode single case */ |
2482 | } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { | 2762 | } else if ((data_size <= private->fcx_max_data) |
2763 | && (fcx_multitrack || (first_trk == last_trk))) { | ||
2483 | cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, | 2764 | cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, |
2484 | first_rec, last_rec, | 2765 | first_rec, last_rec, |
2485 | first_trk, last_trk, | 2766 | first_trk, last_trk, |
2486 | first_offs, last_offs, | 2767 | first_offs, last_offs, |
2487 | blk_per_trk, blksize); | 2768 | blk_per_trk, blksize); |
2488 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | 2769 | if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) && |
2770 | (PTR_ERR(cqr) != -ENOMEM)) | ||
2489 | cqr = NULL; | 2771 | cqr = NULL; |
2490 | } else if (use_prefix && | 2772 | } else if (use_prefix && |
2491 | (((rq_data_dir(req) == READ) && cmdrtd) || | 2773 | (((rq_data_dir(req) == READ) && cmdrtd) || |
@@ -2495,7 +2777,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2495 | first_trk, last_trk, | 2777 | first_trk, last_trk, |
2496 | first_offs, last_offs, | 2778 | first_offs, last_offs, |
2497 | blk_per_trk, blksize); | 2779 | blk_per_trk, blksize); |
2498 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | 2780 | if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) && |
2781 | (PTR_ERR(cqr) != -ENOMEM)) | ||
2499 | cqr = NULL; | 2782 | cqr = NULL; |
2500 | } | 2783 | } |
2501 | if (!cqr) | 2784 | if (!cqr) |
@@ -2507,6 +2790,133 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2507 | return cqr; | 2790 | return cqr; |
2508 | } | 2791 | } |
2509 | 2792 | ||
2793 | static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | ||
2794 | struct dasd_block *block, | ||
2795 | struct request *req) | ||
2796 | { | ||
2797 | unsigned long *idaws; | ||
2798 | struct dasd_device *basedev; | ||
2799 | struct dasd_ccw_req *cqr; | ||
2800 | struct ccw1 *ccw; | ||
2801 | struct req_iterator iter; | ||
2802 | struct bio_vec *bv; | ||
2803 | char *dst; | ||
2804 | unsigned char cmd; | ||
2805 | unsigned int trkcount; | ||
2806 | unsigned int seg_len, len_to_track_end; | ||
2807 | unsigned int first_offs; | ||
2808 | unsigned int cidaw, cplength, datasize; | ||
2809 | sector_t first_trk, last_trk; | ||
2810 | unsigned int pfx_datasize; | ||
2811 | |||
2812 | /* | ||
2813 | * raw track access needs to be mutiple of 64k and on 64k boundary | ||
2814 | */ | ||
2815 | if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) { | ||
2816 | cqr = ERR_PTR(-EINVAL); | ||
2817 | goto out; | ||
2818 | } | ||
2819 | if (((blk_rq_pos(req) + blk_rq_sectors(req)) % | ||
2820 | DASD_RAW_SECTORS_PER_TRACK) != 0) { | ||
2821 | cqr = ERR_PTR(-EINVAL); | ||
2822 | goto out; | ||
2823 | } | ||
2824 | |||
2825 | first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK; | ||
2826 | last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) / | ||
2827 | DASD_RAW_SECTORS_PER_TRACK; | ||
2828 | trkcount = last_trk - first_trk + 1; | ||
2829 | first_offs = 0; | ||
2830 | basedev = block->base; | ||
2831 | |||
2832 | if (rq_data_dir(req) == READ) | ||
2833 | cmd = DASD_ECKD_CCW_READ_TRACK; | ||
2834 | else if (rq_data_dir(req) == WRITE) | ||
2835 | cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK; | ||
2836 | else { | ||
2837 | cqr = ERR_PTR(-EINVAL); | ||
2838 | goto out; | ||
2839 | } | ||
2840 | |||
2841 | /* | ||
2842 | * Raw track based I/O needs IDAWs for each page, | ||
2843 | * and not just for 64 bit addresses. | ||
2844 | */ | ||
2845 | cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK; | ||
2846 | |||
2847 | /* 1x prefix + one read/write ccw per track */ | ||
2848 | cplength = 1 + trkcount; | ||
2849 | |||
2850 | /* | ||
2851 | * struct PFX_eckd_data has up to 2 byte as extended parameter | ||
2852 | * this is needed for write full track and has to be mentioned | ||
2853 | * separately | ||
2854 | * add 8 instead of 2 to keep 8 byte boundary | ||
2855 | */ | ||
2856 | pfx_datasize = sizeof(struct PFX_eckd_data) + 8; | ||
2857 | |||
2858 | datasize = pfx_datasize + cidaw * sizeof(unsigned long long); | ||
2859 | |||
2860 | /* Allocate the ccw request. */ | ||
2861 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, | ||
2862 | datasize, startdev); | ||
2863 | if (IS_ERR(cqr)) | ||
2864 | goto out; | ||
2865 | ccw = cqr->cpaddr; | ||
2866 | |||
2867 | if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd, | ||
2868 | basedev, startdev, 1 /* format */, first_offs + 1, | ||
2869 | trkcount, 0, 0) == -EAGAIN) { | ||
2870 | /* Clock not in sync and XRC is enabled. | ||
2871 | * Try again later. | ||
2872 | */ | ||
2873 | dasd_sfree_request(cqr, startdev); | ||
2874 | cqr = ERR_PTR(-EAGAIN); | ||
2875 | goto out; | ||
2876 | } | ||
2877 | |||
2878 | idaws = (unsigned long *)(cqr->data + pfx_datasize); | ||
2879 | |||
2880 | len_to_track_end = 0; | ||
2881 | |||
2882 | rq_for_each_segment(bv, req, iter) { | ||
2883 | dst = page_address(bv->bv_page) + bv->bv_offset; | ||
2884 | seg_len = bv->bv_len; | ||
2885 | if (!len_to_track_end) { | ||
2886 | ccw[-1].flags |= CCW_FLAG_CC; | ||
2887 | ccw->cmd_code = cmd; | ||
2888 | /* maximum 3390 track size */ | ||
2889 | ccw->count = 57326; | ||
2890 | /* 64k map to one track */ | ||
2891 | len_to_track_end = 65536; | ||
2892 | ccw->cda = (__u32)(addr_t)idaws; | ||
2893 | ccw->flags |= CCW_FLAG_IDA; | ||
2894 | ccw->flags |= CCW_FLAG_SLI; | ||
2895 | ccw++; | ||
2896 | } | ||
2897 | len_to_track_end -= seg_len; | ||
2898 | idaws = idal_create_words(idaws, dst, seg_len); | ||
2899 | } | ||
2900 | |||
2901 | if (blk_noretry_request(req) || | ||
2902 | block->base->features & DASD_FEATURE_FAILFAST) | ||
2903 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
2904 | cqr->startdev = startdev; | ||
2905 | cqr->memdev = startdev; | ||
2906 | cqr->block = block; | ||
2907 | cqr->expires = startdev->default_expires * HZ; | ||
2908 | cqr->lpm = startdev->path_data.ppm; | ||
2909 | cqr->retries = 256; | ||
2910 | cqr->buildclk = get_clock(); | ||
2911 | cqr->status = DASD_CQR_FILLED; | ||
2912 | |||
2913 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | ||
2914 | cqr = NULL; | ||
2915 | out: | ||
2916 | return cqr; | ||
2917 | } | ||
2918 | |||
2919 | |||
2510 | static int | 2920 | static int |
2511 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | 2921 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) |
2512 | { | 2922 | { |
@@ -2611,7 +3021,10 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, | |||
2611 | 3021 | ||
2612 | spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); | 3022 | spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); |
2613 | private->count++; | 3023 | private->count++; |
2614 | cqr = dasd_eckd_build_cp(startdev, block, req); | 3024 | if ((base->features & DASD_FEATURE_USERAW)) |
3025 | cqr = dasd_raw_build_cp(startdev, block, req); | ||
3026 | else | ||
3027 | cqr = dasd_eckd_build_cp(startdev, block, req); | ||
2615 | if (IS_ERR(cqr)) | 3028 | if (IS_ERR(cqr)) |
2616 | private->count--; | 3029 | private->count--; |
2617 | spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); | 3030 | spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); |
@@ -2699,6 +3112,8 @@ dasd_eckd_release(struct dasd_device *device) | |||
2699 | cqr->status = DASD_CQR_FILLED; | 3112 | cqr->status = DASD_CQR_FILLED; |
2700 | 3113 | ||
2701 | rc = dasd_sleep_on_immediatly(cqr); | 3114 | rc = dasd_sleep_on_immediatly(cqr); |
3115 | if (!rc) | ||
3116 | clear_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
2702 | 3117 | ||
2703 | if (useglobal) | 3118 | if (useglobal) |
2704 | mutex_unlock(&dasd_reserve_mutex); | 3119 | mutex_unlock(&dasd_reserve_mutex); |
@@ -2752,6 +3167,8 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
2752 | cqr->status = DASD_CQR_FILLED; | 3167 | cqr->status = DASD_CQR_FILLED; |
2753 | 3168 | ||
2754 | rc = dasd_sleep_on_immediatly(cqr); | 3169 | rc = dasd_sleep_on_immediatly(cqr); |
3170 | if (!rc) | ||
3171 | set_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
2755 | 3172 | ||
2756 | if (useglobal) | 3173 | if (useglobal) |
2757 | mutex_unlock(&dasd_reserve_mutex); | 3174 | mutex_unlock(&dasd_reserve_mutex); |
@@ -2804,6 +3221,76 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
2804 | cqr->status = DASD_CQR_FILLED; | 3221 | cqr->status = DASD_CQR_FILLED; |
2805 | 3222 | ||
2806 | rc = dasd_sleep_on_immediatly(cqr); | 3223 | rc = dasd_sleep_on_immediatly(cqr); |
3224 | if (!rc) | ||
3225 | set_bit(DASD_FLAG_IS_RESERVED, &device->flags); | ||
3226 | |||
3227 | if (useglobal) | ||
3228 | mutex_unlock(&dasd_reserve_mutex); | ||
3229 | else | ||
3230 | dasd_sfree_request(cqr, cqr->memdev); | ||
3231 | return rc; | ||
3232 | } | ||
3233 | |||
3234 | /* | ||
3235 | * SNID - Sense Path Group ID | ||
3236 | * This ioctl may be used in situations where I/O is stalled due to | ||
3237 | * a reserve, so if the normal dasd_smalloc_request fails, we use the | ||
3238 | * preallocated dasd_reserve_req. | ||
3239 | */ | ||
3240 | static int dasd_eckd_snid(struct dasd_device *device, | ||
3241 | void __user *argp) | ||
3242 | { | ||
3243 | struct dasd_ccw_req *cqr; | ||
3244 | int rc; | ||
3245 | struct ccw1 *ccw; | ||
3246 | int useglobal; | ||
3247 | struct dasd_snid_ioctl_data usrparm; | ||
3248 | |||
3249 | if (!capable(CAP_SYS_ADMIN)) | ||
3250 | return -EACCES; | ||
3251 | |||
3252 | if (copy_from_user(&usrparm, argp, sizeof(usrparm))) | ||
3253 | return -EFAULT; | ||
3254 | |||
3255 | useglobal = 0; | ||
3256 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, | ||
3257 | sizeof(struct dasd_snid_data), device); | ||
3258 | if (IS_ERR(cqr)) { | ||
3259 | mutex_lock(&dasd_reserve_mutex); | ||
3260 | useglobal = 1; | ||
3261 | cqr = &dasd_reserve_req->cqr; | ||
3262 | memset(cqr, 0, sizeof(*cqr)); | ||
3263 | memset(&dasd_reserve_req->ccw, 0, | ||
3264 | sizeof(dasd_reserve_req->ccw)); | ||
3265 | cqr->cpaddr = &dasd_reserve_req->ccw; | ||
3266 | cqr->data = &dasd_reserve_req->data; | ||
3267 | cqr->magic = DASD_ECKD_MAGIC; | ||
3268 | } | ||
3269 | ccw = cqr->cpaddr; | ||
3270 | ccw->cmd_code = DASD_ECKD_CCW_SNID; | ||
3271 | ccw->flags |= CCW_FLAG_SLI; | ||
3272 | ccw->count = 12; | ||
3273 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
3274 | cqr->startdev = device; | ||
3275 | cqr->memdev = device; | ||
3276 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
3277 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
3278 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
3279 | cqr->retries = 5; | ||
3280 | cqr->expires = 10 * HZ; | ||
3281 | cqr->buildclk = get_clock(); | ||
3282 | cqr->status = DASD_CQR_FILLED; | ||
3283 | cqr->lpm = usrparm.path_mask; | ||
3284 | |||
3285 | rc = dasd_sleep_on_immediatly(cqr); | ||
3286 | /* verify that I/O processing didn't modify the path mask */ | ||
3287 | if (!rc && usrparm.path_mask && (cqr->lpm != usrparm.path_mask)) | ||
3288 | rc = -EIO; | ||
3289 | if (!rc) { | ||
3290 | usrparm.data = *((struct dasd_snid_data *)cqr->data); | ||
3291 | if (copy_to_user(argp, &usrparm, sizeof(usrparm))) | ||
3292 | rc = -EFAULT; | ||
3293 | } | ||
2807 | 3294 | ||
2808 | if (useglobal) | 3295 | if (useglobal) |
2809 | mutex_unlock(&dasd_reserve_mutex); | 3296 | mutex_unlock(&dasd_reserve_mutex); |
@@ -3047,6 +3534,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) | |||
3047 | return dasd_eckd_reserve(device); | 3534 | return dasd_eckd_reserve(device); |
3048 | case BIODASDSLCK: | 3535 | case BIODASDSLCK: |
3049 | return dasd_eckd_steal_lock(device); | 3536 | return dasd_eckd_steal_lock(device); |
3537 | case BIODASDSNID: | ||
3538 | return dasd_eckd_snid(device, argp); | ||
3050 | case BIODASDSYMMIO: | 3539 | case BIODASDSYMMIO: |
3051 | return dasd_symm_io(device, argp); | 3540 | return dasd_symm_io(device, argp); |
3052 | default: | 3541 | default: |
@@ -3093,19 +3582,19 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb, | |||
3093 | char *reason) | 3582 | char *reason) |
3094 | { | 3583 | { |
3095 | u64 *sense; | 3584 | u64 *sense; |
3585 | u64 *stat; | ||
3096 | 3586 | ||
3097 | sense = (u64 *) dasd_get_sense(irb); | 3587 | sense = (u64 *) dasd_get_sense(irb); |
3588 | stat = (u64 *) &irb->scsw; | ||
3098 | if (sense) { | 3589 | if (sense) { |
3099 | DBF_DEV_EVENT(DBF_EMERG, device, | 3590 | DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : " |
3100 | "%s: %s %02x%02x%02x %016llx %016llx %016llx " | 3591 | "%016llx %016llx %016llx %016llx", |
3101 | "%016llx", reason, | 3592 | reason, *stat, *((u32 *) (stat + 1)), |
3102 | scsw_is_tm(&irb->scsw) ? "t" : "c", | 3593 | sense[0], sense[1], sense[2], sense[3]); |
3103 | scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw), | ||
3104 | scsw_dstat(&irb->scsw), sense[0], sense[1], | ||
3105 | sense[2], sense[3]); | ||
3106 | } else { | 3594 | } else { |
3107 | DBF_DEV_EVENT(DBF_EMERG, device, "%s", | 3595 | DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : %s", |
3108 | "SORRY - NO VALID SENSE AVAILABLE\n"); | 3596 | reason, *stat, *((u32 *) (stat + 1)), |
3597 | "NO VALID SENSE"); | ||
3109 | } | 3598 | } |
3110 | } | 3599 | } |
3111 | 3600 | ||
@@ -3131,9 +3620,12 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, | |||
3131 | " I/O status report for device %s:\n", | 3620 | " I/O status report for device %s:\n", |
3132 | dev_name(&device->cdev->dev)); | 3621 | dev_name(&device->cdev->dev)); |
3133 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3622 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3134 | " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", | 3623 | " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X " |
3135 | req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), | 3624 | "CS:%02X RC:%d\n", |
3136 | scsw_cc(&irb->scsw), req ? req->intrc : 0); | 3625 | req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw), |
3626 | scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw), | ||
3627 | scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw), | ||
3628 | req ? req->intrc : 0); | ||
3137 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3629 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3138 | " device %s: Failing CCW: %p\n", | 3630 | " device %s: Failing CCW: %p\n", |
3139 | dev_name(&device->cdev->dev), | 3631 | dev_name(&device->cdev->dev), |
@@ -3218,10 +3710,8 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3218 | { | 3710 | { |
3219 | char *page; | 3711 | char *page; |
3220 | int len, sl, sct, residual; | 3712 | int len, sl, sct, residual; |
3221 | |||
3222 | struct tsb *tsb; | 3713 | struct tsb *tsb; |
3223 | u8 *sense; | 3714 | u8 *sense, *rcq; |
3224 | |||
3225 | 3715 | ||
3226 | page = (char *) get_zeroed_page(GFP_ATOMIC); | 3716 | page = (char *) get_zeroed_page(GFP_ATOMIC); |
3227 | if (page == NULL) { | 3717 | if (page == NULL) { |
@@ -3234,11 +3724,13 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3234 | " I/O status report for device %s:\n", | 3724 | " I/O status report for device %s:\n", |
3235 | dev_name(&device->cdev->dev)); | 3725 | dev_name(&device->cdev->dev)); |
3236 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3726 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3237 | " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d " | 3727 | " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X " |
3238 | "fcxs: 0x%02X schxs: 0x%02X\n", req, | 3728 | "CS:%02X fcxs:%02X schxs:%02X RC:%d\n", |
3239 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), | 3729 | req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw), |
3240 | scsw_cc(&irb->scsw), req->intrc, | 3730 | scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw), |
3241 | irb->scsw.tm.fcxs, irb->scsw.tm.schxs); | 3731 | scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw), |
3732 | irb->scsw.tm.fcxs, irb->scsw.tm.schxs, | ||
3733 | req ? req->intrc : 0); | ||
3242 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3734 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3243 | " device %s: Failing TCW: %p\n", | 3735 | " device %s: Failing TCW: %p\n", |
3244 | dev_name(&device->cdev->dev), | 3736 | dev_name(&device->cdev->dev), |
@@ -3246,7 +3738,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3246 | 3738 | ||
3247 | tsb = NULL; | 3739 | tsb = NULL; |
3248 | sense = NULL; | 3740 | sense = NULL; |
3249 | if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01)) | 3741 | if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01)) |
3250 | tsb = tcw_get_tsb( | 3742 | tsb = tcw_get_tsb( |
3251 | (struct tcw *)(unsigned long)irb->scsw.tm.tcw); | 3743 | (struct tcw *)(unsigned long)irb->scsw.tm.tcw); |
3252 | 3744 | ||
@@ -3285,12 +3777,15 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3285 | case 2: /* ts_ddpc */ | 3777 | case 2: /* ts_ddpc */ |
3286 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3778 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3287 | " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); | 3779 | " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); |
3288 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3780 | for (sl = 0; sl < 2; sl++) { |
3289 | " tsb->tsa.ddpc.rcq: "); | 3781 | len += sprintf(page + len, |
3290 | for (sl = 0; sl < 16; sl++) { | 3782 | KERN_ERR PRINTK_HEADER |
3783 | " tsb->tsa.ddpc.rcq %2d-%2d: ", | ||
3784 | (8 * sl), ((8 * sl) + 7)); | ||
3785 | rcq = tsb->tsa.ddpc.rcq; | ||
3291 | for (sct = 0; sct < 8; sct++) { | 3786 | for (sct = 0; sct < 8; sct++) { |
3292 | len += sprintf(page + len, " %02x", | 3787 | len += sprintf(page + len, " %02x", |
3293 | tsb->tsa.ddpc.rcq[sl]); | 3788 | rcq[8 * sl + sct]); |
3294 | } | 3789 | } |
3295 | len += sprintf(page + len, "\n"); | 3790 | len += sprintf(page + len, "\n"); |
3296 | } | 3791 | } |
@@ -3344,7 +3839,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3344 | static void dasd_eckd_dump_sense(struct dasd_device *device, | 3839 | static void dasd_eckd_dump_sense(struct dasd_device *device, |
3345 | struct dasd_ccw_req *req, struct irb *irb) | 3840 | struct dasd_ccw_req *req, struct irb *irb) |
3346 | { | 3841 | { |
3347 | if (req && scsw_is_tm(&req->irb.scsw)) | 3842 | if (scsw_is_tm(&irb->scsw)) |
3348 | dasd_eckd_dump_sense_tcw(device, req, irb); | 3843 | dasd_eckd_dump_sense_tcw(device, req, irb); |
3349 | else | 3844 | else |
3350 | dasd_eckd_dump_sense_ccw(device, req, irb); | 3845 | dasd_eckd_dump_sense_ccw(device, req, irb); |
@@ -3479,14 +3974,17 @@ out_err: | |||
3479 | } | 3974 | } |
3480 | 3975 | ||
3481 | static struct ccw_driver dasd_eckd_driver = { | 3976 | static struct ccw_driver dasd_eckd_driver = { |
3482 | .name = "dasd-eckd", | 3977 | .driver = { |
3483 | .owner = THIS_MODULE, | 3978 | .name = "dasd-eckd", |
3979 | .owner = THIS_MODULE, | ||
3980 | }, | ||
3484 | .ids = dasd_eckd_ids, | 3981 | .ids = dasd_eckd_ids, |
3485 | .probe = dasd_eckd_probe, | 3982 | .probe = dasd_eckd_probe, |
3486 | .remove = dasd_generic_remove, | 3983 | .remove = dasd_generic_remove, |
3487 | .set_offline = dasd_generic_set_offline, | 3984 | .set_offline = dasd_generic_set_offline, |
3488 | .set_online = dasd_eckd_set_online, | 3985 | .set_online = dasd_eckd_set_online, |
3489 | .notify = dasd_generic_notify, | 3986 | .notify = dasd_generic_notify, |
3987 | .path_event = dasd_generic_path_event, | ||
3490 | .freeze = dasd_generic_pm_freeze, | 3988 | .freeze = dasd_generic_pm_freeze, |
3491 | .thaw = dasd_generic_restore_device, | 3989 | .thaw = dasd_generic_restore_device, |
3492 | .restore = dasd_generic_restore_device, | 3990 | .restore = dasd_generic_restore_device, |
@@ -3510,10 +4008,11 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3510 | .owner = THIS_MODULE, | 4008 | .owner = THIS_MODULE, |
3511 | .name = "ECKD", | 4009 | .name = "ECKD", |
3512 | .ebcname = "ECKD", | 4010 | .ebcname = "ECKD", |
3513 | .max_blocks = 240, | 4011 | .max_blocks = 190, |
3514 | .check_device = dasd_eckd_check_characteristics, | 4012 | .check_device = dasd_eckd_check_characteristics, |
3515 | .uncheck_device = dasd_eckd_uncheck_device, | 4013 | .uncheck_device = dasd_eckd_uncheck_device, |
3516 | .do_analysis = dasd_eckd_do_analysis, | 4014 | .do_analysis = dasd_eckd_do_analysis, |
4015 | .verify_path = dasd_eckd_verify_path, | ||
3517 | .ready_to_online = dasd_eckd_ready_to_online, | 4016 | .ready_to_online = dasd_eckd_ready_to_online, |
3518 | .online_to_ready = dasd_eckd_online_to_ready, | 4017 | .online_to_ready = dasd_eckd_online_to_ready, |
3519 | .fill_geometry = dasd_eckd_fill_geometry, | 4018 | .fill_geometry = dasd_eckd_fill_geometry, |
@@ -3523,7 +4022,7 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3523 | .format_device = dasd_eckd_format_device, | 4022 | .format_device = dasd_eckd_format_device, |
3524 | .erp_action = dasd_eckd_erp_action, | 4023 | .erp_action = dasd_eckd_erp_action, |
3525 | .erp_postaction = dasd_eckd_erp_postaction, | 4024 | .erp_postaction = dasd_eckd_erp_postaction, |
3526 | .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt, | 4025 | .check_for_device_change = dasd_eckd_check_for_device_change, |
3527 | .build_cp = dasd_eckd_build_alias_cp, | 4026 | .build_cp = dasd_eckd_build_alias_cp, |
3528 | .free_cp = dasd_eckd_free_alias_cp, | 4027 | .free_cp = dasd_eckd_free_alias_cp, |
3529 | .dump_sense = dasd_eckd_dump_sense, | 4028 | .dump_sense = dasd_eckd_dump_sense, |
@@ -3546,11 +4045,19 @@ dasd_eckd_init(void) | |||
3546 | GFP_KERNEL | GFP_DMA); | 4045 | GFP_KERNEL | GFP_DMA); |
3547 | if (!dasd_reserve_req) | 4046 | if (!dasd_reserve_req) |
3548 | return -ENOMEM; | 4047 | return -ENOMEM; |
4048 | path_verification_worker = kmalloc(sizeof(*path_verification_worker), | ||
4049 | GFP_KERNEL | GFP_DMA); | ||
4050 | if (!path_verification_worker) { | ||
4051 | kfree(dasd_reserve_req); | ||
4052 | return -ENOMEM; | ||
4053 | } | ||
3549 | ret = ccw_driver_register(&dasd_eckd_driver); | 4054 | ret = ccw_driver_register(&dasd_eckd_driver); |
3550 | if (!ret) | 4055 | if (!ret) |
3551 | wait_for_device_probe(); | 4056 | wait_for_device_probe(); |
3552 | else | 4057 | else { |
4058 | kfree(path_verification_worker); | ||
3553 | kfree(dasd_reserve_req); | 4059 | kfree(dasd_reserve_req); |
4060 | } | ||
3554 | return ret; | 4061 | return ret; |
3555 | } | 4062 | } |
3556 | 4063 | ||
@@ -3558,6 +4065,7 @@ static void __exit | |||
3558 | dasd_eckd_cleanup(void) | 4065 | dasd_eckd_cleanup(void) |
3559 | { | 4066 | { |
3560 | ccw_driver_unregister(&dasd_eckd_driver); | 4067 | ccw_driver_unregister(&dasd_eckd_driver); |
4068 | kfree(path_verification_worker); | ||
3561 | kfree(dasd_reserve_req); | 4069 | kfree(dasd_reserve_req); |
3562 | } | 4070 | } |
3563 | 4071 | ||
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 0eb49655a6cd..4a688a873a77 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #define DASD_ECKD_CCW_WRITE_CKD 0x1d | 27 | #define DASD_ECKD_CCW_WRITE_CKD 0x1d |
28 | #define DASD_ECKD_CCW_READ_CKD 0x1e | 28 | #define DASD_ECKD_CCW_READ_CKD 0x1e |
29 | #define DASD_ECKD_CCW_PSF 0x27 | 29 | #define DASD_ECKD_CCW_PSF 0x27 |
30 | #define DASD_ECKD_CCW_SNID 0x34 | ||
30 | #define DASD_ECKD_CCW_RSSD 0x3e | 31 | #define DASD_ECKD_CCW_RSSD 0x3e |
31 | #define DASD_ECKD_CCW_LOCATE_RECORD 0x47 | 32 | #define DASD_ECKD_CCW_LOCATE_RECORD 0x47 |
32 | #define DASD_ECKD_CCW_SNSS 0x54 | 33 | #define DASD_ECKD_CCW_SNSS 0x54 |
@@ -36,14 +37,17 @@ | |||
36 | #define DASD_ECKD_CCW_WRITE_KD_MT 0x8d | 37 | #define DASD_ECKD_CCW_WRITE_KD_MT 0x8d |
37 | #define DASD_ECKD_CCW_READ_KD_MT 0x8e | 38 | #define DASD_ECKD_CCW_READ_KD_MT 0x8e |
38 | #define DASD_ECKD_CCW_RELEASE 0x94 | 39 | #define DASD_ECKD_CCW_RELEASE 0x94 |
40 | #define DASD_ECKD_CCW_WRITE_FULL_TRACK 0x95 | ||
39 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e | 41 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e |
40 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d | 42 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d |
41 | #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 | 43 | #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 |
42 | #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 | 44 | #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 |
43 | #define DASD_ECKD_CCW_RESERVE 0xB4 | 45 | #define DASD_ECKD_CCW_RESERVE 0xB4 |
46 | #define DASD_ECKD_CCW_READ_TRACK 0xDE | ||
44 | #define DASD_ECKD_CCW_PFX 0xE7 | 47 | #define DASD_ECKD_CCW_PFX 0xE7 |
45 | #define DASD_ECKD_CCW_PFX_READ 0xEA | 48 | #define DASD_ECKD_CCW_PFX_READ 0xEA |
46 | #define DASD_ECKD_CCW_RSCK 0xF9 | 49 | #define DASD_ECKD_CCW_RSCK 0xF9 |
50 | #define DASD_ECKD_CCW_RCD 0xFA | ||
47 | 51 | ||
48 | /* | 52 | /* |
49 | * Perform Subsystem Function / Sub-Orders | 53 | * Perform Subsystem Function / Sub-Orders |
@@ -56,6 +60,11 @@ | |||
56 | */ | 60 | */ |
57 | #define LV_COMPAT_CYL 0xFFFE | 61 | #define LV_COMPAT_CYL 0xFFFE |
58 | 62 | ||
63 | |||
64 | #define FCX_MAX_DATA_FACTOR 65536 | ||
65 | #define DASD_ECKD_RCD_DATA_SIZE 256 | ||
66 | |||
67 | |||
59 | /***************************************************************************** | 68 | /***************************************************************************** |
60 | * SECTION: Type Definitions | 69 | * SECTION: Type Definitions |
61 | ****************************************************************************/ | 70 | ****************************************************************************/ |
@@ -330,12 +339,6 @@ struct dasd_gneq { | |||
330 | __u8 reserved2[22]; | 339 | __u8 reserved2[22]; |
331 | } __attribute__ ((packed)); | 340 | } __attribute__ ((packed)); |
332 | 341 | ||
333 | struct dasd_eckd_path { | ||
334 | __u8 opm; | ||
335 | __u8 ppm; | ||
336 | __u8 npm; | ||
337 | }; | ||
338 | |||
339 | struct dasd_rssd_features { | 342 | struct dasd_rssd_features { |
340 | char feature[256]; | 343 | char feature[256]; |
341 | } __attribute__((packed)); | 344 | } __attribute__((packed)); |
@@ -441,7 +444,6 @@ struct dasd_eckd_private { | |||
441 | struct vd_sneq *vdsneq; | 444 | struct vd_sneq *vdsneq; |
442 | struct dasd_gneq *gneq; | 445 | struct dasd_gneq *gneq; |
443 | 446 | ||
444 | struct dasd_eckd_path path_data; | ||
445 | struct eckd_count count_area[5]; | 447 | struct eckd_count count_area[5]; |
446 | int init_cqr_status; | 448 | int init_cqr_status; |
447 | int uses_cdl; | 449 | int uses_cdl; |
@@ -454,6 +456,8 @@ struct dasd_eckd_private { | |||
454 | struct alias_pav_group *pavgroup; | 456 | struct alias_pav_group *pavgroup; |
455 | struct alias_lcu *lcu; | 457 | struct alias_lcu *lcu; |
456 | int count; | 458 | int count; |
459 | |||
460 | u32 fcx_max_data; | ||
457 | }; | 461 | }; |
458 | 462 | ||
459 | 463 | ||
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 7158f9528ecc..77f778b7b070 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/poll.h> | 18 | #include <linux/poll.h> |
19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/smp_lock.h> | ||
21 | #include <linux/err.h> | 20 | #include <linux/err.h> |
22 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
23 | 22 | ||
@@ -474,6 +473,7 @@ int dasd_eer_enable(struct dasd_device *device) | |||
474 | cqr->retries = 255; | 473 | cqr->retries = 255; |
475 | cqr->expires = 10 * HZ; | 474 | cqr->expires = 10 * HZ; |
476 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 475 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
476 | set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags); | ||
477 | 477 | ||
478 | ccw = cqr->cpaddr; | 478 | ccw = cqr->cpaddr; |
479 | ccw->cmd_code = DASD_ECKD_CCW_SNSS; | 479 | ccw->cmd_code = DASD_ECKD_CCW_SNSS; |
@@ -670,6 +670,7 @@ static const struct file_operations dasd_eer_fops = { | |||
670 | .read = &dasd_eer_read, | 670 | .read = &dasd_eer_read, |
671 | .poll = &dasd_eer_poll, | 671 | .poll = &dasd_eer_poll, |
672 | .owner = THIS_MODULE, | 672 | .owner = THIS_MODULE, |
673 | .llseek = noop_llseek, | ||
673 | }; | 674 | }; |
674 | 675 | ||
675 | static struct miscdevice *dasd_eer_dev = NULL; | 676 | static struct miscdevice *dasd_eer_dev = NULL; |
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 7656384a811d..0eafe2e421e7 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c | |||
@@ -96,7 +96,8 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr) | |||
96 | DBF_DEV_EVENT(DBF_DEBUG, device, | 96 | DBF_DEV_EVENT(DBF_DEBUG, device, |
97 | "default ERP called (%i retries left)", | 97 | "default ERP called (%i retries left)", |
98 | cqr->retries); | 98 | cqr->retries); |
99 | cqr->lpm = LPM_ANYPATH; | 99 | if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) |
100 | cqr->lpm = device->path_data.opm; | ||
100 | cqr->status = DASD_CQR_FILLED; | 101 | cqr->status = DASD_CQR_FILLED; |
101 | } else { | 102 | } else { |
102 | pr_err("%s: default ERP has run out of retries and failed\n", | 103 | pr_err("%s: default ERP has run out of retries and failed\n", |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index bec5486e0e6d..4b71b1164868 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -65,14 +65,17 @@ dasd_fba_set_online(struct ccw_device *cdev) | |||
65 | } | 65 | } |
66 | 66 | ||
67 | static struct ccw_driver dasd_fba_driver = { | 67 | static struct ccw_driver dasd_fba_driver = { |
68 | .name = "dasd-fba", | 68 | .driver = { |
69 | .owner = THIS_MODULE, | 69 | .name = "dasd-fba", |
70 | .owner = THIS_MODULE, | ||
71 | }, | ||
70 | .ids = dasd_fba_ids, | 72 | .ids = dasd_fba_ids, |
71 | .probe = dasd_fba_probe, | 73 | .probe = dasd_fba_probe, |
72 | .remove = dasd_generic_remove, | 74 | .remove = dasd_generic_remove, |
73 | .set_offline = dasd_generic_set_offline, | 75 | .set_offline = dasd_generic_set_offline, |
74 | .set_online = dasd_fba_set_online, | 76 | .set_online = dasd_fba_set_online, |
75 | .notify = dasd_generic_notify, | 77 | .notify = dasd_generic_notify, |
78 | .path_event = dasd_generic_path_event, | ||
76 | .freeze = dasd_generic_pm_freeze, | 79 | .freeze = dasd_generic_pm_freeze, |
77 | .thaw = dasd_generic_restore_device, | 80 | .thaw = dasd_generic_restore_device, |
78 | .restore = dasd_generic_restore_device, | 81 | .restore = dasd_generic_restore_device, |
@@ -164,6 +167,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
164 | } | 167 | } |
165 | 168 | ||
166 | device->default_expires = DASD_EXPIRES; | 169 | device->default_expires = DASD_EXPIRES; |
170 | device->path_data.opm = LPM_ANYPATH; | ||
167 | 171 | ||
168 | readonly = dasd_device_is_ro(device); | 172 | readonly = dasd_device_is_ro(device); |
169 | if (readonly) | 173 | if (readonly) |
@@ -231,24 +235,16 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) | |||
231 | return NULL; | 235 | return NULL; |
232 | } | 236 | } |
233 | 237 | ||
234 | static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, | 238 | static void dasd_fba_check_for_device_change(struct dasd_device *device, |
235 | struct irb *irb) | 239 | struct dasd_ccw_req *cqr, |
240 | struct irb *irb) | ||
236 | { | 241 | { |
237 | char mask; | 242 | char mask; |
238 | 243 | ||
239 | /* first of all check for state change pending interrupt */ | 244 | /* first of all check for state change pending interrupt */ |
240 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 245 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
241 | if ((irb->scsw.cmd.dstat & mask) == mask) { | 246 | if ((irb->scsw.cmd.dstat & mask) == mask) |
242 | dasd_generic_handle_state_change(device); | 247 | dasd_generic_handle_state_change(device); |
243 | return; | ||
244 | } | ||
245 | |||
246 | /* check for unsolicited interrupts */ | ||
247 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
248 | "unsolicited interrupt received"); | ||
249 | device->discipline->dump_sense_dbf(device, irb, "unsolicited"); | ||
250 | dasd_schedule_device_bh(device); | ||
251 | return; | ||
252 | }; | 248 | }; |
253 | 249 | ||
254 | static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | 250 | static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, |
@@ -596,13 +592,14 @@ static struct dasd_discipline dasd_fba_discipline = { | |||
596 | .max_blocks = 96, | 592 | .max_blocks = 96, |
597 | .check_device = dasd_fba_check_characteristics, | 593 | .check_device = dasd_fba_check_characteristics, |
598 | .do_analysis = dasd_fba_do_analysis, | 594 | .do_analysis = dasd_fba_do_analysis, |
595 | .verify_path = dasd_generic_verify_path, | ||
599 | .fill_geometry = dasd_fba_fill_geometry, | 596 | .fill_geometry = dasd_fba_fill_geometry, |
600 | .start_IO = dasd_start_IO, | 597 | .start_IO = dasd_start_IO, |
601 | .term_IO = dasd_term_IO, | 598 | .term_IO = dasd_term_IO, |
602 | .handle_terminated_request = dasd_fba_handle_terminated_request, | 599 | .handle_terminated_request = dasd_fba_handle_terminated_request, |
603 | .erp_action = dasd_fba_erp_action, | 600 | .erp_action = dasd_fba_erp_action, |
604 | .erp_postaction = dasd_fba_erp_postaction, | 601 | .erp_postaction = dasd_fba_erp_postaction, |
605 | .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt, | 602 | .check_for_device_change = dasd_fba_check_for_device_change, |
606 | .build_cp = dasd_fba_build_cp, | 603 | .build_cp = dasd_fba_build_cp, |
607 | .free_cp = dasd_fba_free_cp, | 604 | .free_cp = dasd_fba_free_cp, |
608 | .dump_sense = dasd_fba_dump_sense, | 605 | .dump_sense = dasd_fba_dump_sense, |
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 30a1ca3d08b7..19a1ff03d65e 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
@@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) | |||
73 | if (base->features & DASD_FEATURE_READONLY || | 73 | if (base->features & DASD_FEATURE_READONLY || |
74 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) | 74 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) |
75 | set_disk_ro(gdp, 1); | 75 | set_disk_ro(gdp, 1); |
76 | gdp->private_data = block; | 76 | dasd_add_link_to_gendisk(gdp, base); |
77 | gdp->queue = block->request_queue; | 77 | gdp->queue = block->request_queue; |
78 | block->gdp = gdp; | 78 | block->gdp = gdp; |
79 | set_capacity(block->gdp, 0); | 79 | set_capacity(block->gdp, 0); |
@@ -103,7 +103,7 @@ int dasd_scan_partitions(struct dasd_block *block) | |||
103 | struct block_device *bdev; | 103 | struct block_device *bdev; |
104 | 104 | ||
105 | bdev = bdget_disk(block->gdp, 0); | 105 | bdev = bdget_disk(block->gdp, 0); |
106 | if (!bdev || blkdev_get(bdev, FMODE_READ) < 0) | 106 | if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0) |
107 | return -ENODEV; | 107 | return -ENODEV; |
108 | /* | 108 | /* |
109 | * See fs/partition/check.c:register_disk,rescan_partitions | 109 | * See fs/partition/check.c:register_disk,rescan_partitions |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 500678d7116c..d1e4f2c1264c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -231,6 +231,11 @@ struct dasd_ccw_req { | |||
231 | /* per dasd_ccw_req flags */ | 231 | /* per dasd_ccw_req flags */ |
232 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ | 232 | #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ |
233 | #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ | 233 | #define DASD_CQR_FLAGS_FAILFAST 1 /* FAILFAST */ |
234 | #define DASD_CQR_VERIFY_PATH 2 /* path verification request */ | ||
235 | #define DASD_CQR_ALLOW_SLOCK 3 /* Try this request even when lock was | ||
236 | * stolen. Should not be combined with | ||
237 | * DASD_CQR_FLAGS_USE_ERP | ||
238 | */ | ||
234 | 239 | ||
235 | /* Signature for error recovery functions. */ | 240 | /* Signature for error recovery functions. */ |
236 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 241 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
@@ -287,6 +292,14 @@ struct dasd_discipline { | |||
287 | int (*do_analysis) (struct dasd_block *); | 292 | int (*do_analysis) (struct dasd_block *); |
288 | 293 | ||
289 | /* | 294 | /* |
295 | * This function is called, when new paths become available. | ||
296 | * Disciplins may use this callback to do necessary setup work, | ||
297 | * e.g. verify that new path is compatible with the current | ||
298 | * configuration. | ||
299 | */ | ||
300 | int (*verify_path)(struct dasd_device *, __u8); | ||
301 | |||
302 | /* | ||
290 | * Last things to do when a device is set online, and first things | 303 | * Last things to do when a device is set online, and first things |
291 | * when it is set offline. | 304 | * when it is set offline. |
292 | */ | 305 | */ |
@@ -325,9 +338,9 @@ struct dasd_discipline { | |||
325 | void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, | 338 | void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, |
326 | struct irb *); | 339 | struct irb *); |
327 | void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); | 340 | void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *); |
328 | 341 | void (*check_for_device_change) (struct dasd_device *, | |
329 | void (*handle_unsolicited_interrupt) (struct dasd_device *, | 342 | struct dasd_ccw_req *, |
330 | struct irb *); | 343 | struct irb *); |
331 | 344 | ||
332 | /* i/o control functions. */ | 345 | /* i/o control functions. */ |
333 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); | 346 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); |
@@ -362,6 +375,13 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; | |||
362 | #define DASD_EER_STATECHANGE 3 | 375 | #define DASD_EER_STATECHANGE 3 |
363 | #define DASD_EER_PPRCSUSPEND 4 | 376 | #define DASD_EER_PPRCSUSPEND 4 |
364 | 377 | ||
378 | struct dasd_path { | ||
379 | __u8 opm; | ||
380 | __u8 tbvpm; | ||
381 | __u8 ppm; | ||
382 | __u8 npm; | ||
383 | }; | ||
384 | |||
365 | struct dasd_device { | 385 | struct dasd_device { |
366 | /* Block device stuff. */ | 386 | /* Block device stuff. */ |
367 | struct dasd_block *block; | 387 | struct dasd_block *block; |
@@ -377,6 +397,7 @@ struct dasd_device { | |||
377 | struct dasd_discipline *discipline; | 397 | struct dasd_discipline *discipline; |
378 | struct dasd_discipline *base_discipline; | 398 | struct dasd_discipline *base_discipline; |
379 | char *private; | 399 | char *private; |
400 | struct dasd_path path_data; | ||
380 | 401 | ||
381 | /* Device state and target state. */ | 402 | /* Device state and target state. */ |
382 | int state, target; | 403 | int state, target; |
@@ -456,6 +477,9 @@ struct dasd_block { | |||
456 | * confuse this with the user specified | 477 | * confuse this with the user specified |
457 | * read-only feature. | 478 | * read-only feature. |
458 | */ | 479 | */ |
480 | #define DASD_FLAG_IS_RESERVED 7 /* The device is reserved */ | ||
481 | #define DASD_FLAG_LOCK_STOLEN 8 /* The device lock was stolen */ | ||
482 | |||
459 | 483 | ||
460 | void dasd_put_device_wake(struct dasd_device *); | 484 | void dasd_put_device_wake(struct dasd_device *); |
461 | 485 | ||
@@ -620,10 +644,15 @@ void dasd_generic_remove (struct ccw_device *cdev); | |||
620 | int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); | 644 | int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); |
621 | int dasd_generic_set_offline (struct ccw_device *cdev); | 645 | int dasd_generic_set_offline (struct ccw_device *cdev); |
622 | int dasd_generic_notify(struct ccw_device *, int); | 646 | int dasd_generic_notify(struct ccw_device *, int); |
647 | int dasd_generic_last_path_gone(struct dasd_device *); | ||
648 | int dasd_generic_path_operational(struct dasd_device *); | ||
649 | |||
623 | void dasd_generic_handle_state_change(struct dasd_device *); | 650 | void dasd_generic_handle_state_change(struct dasd_device *); |
624 | int dasd_generic_pm_freeze(struct ccw_device *); | 651 | int dasd_generic_pm_freeze(struct ccw_device *); |
625 | int dasd_generic_restore_device(struct ccw_device *); | 652 | int dasd_generic_restore_device(struct ccw_device *); |
626 | enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *); | 653 | enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *); |
654 | void dasd_generic_path_event(struct ccw_device *, int *); | ||
655 | int dasd_generic_verify_path(struct dasd_device *, __u8); | ||
627 | 656 | ||
628 | int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); | 657 | int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); |
629 | char *dasd_get_sense(struct irb *); | 658 | char *dasd_get_sense(struct irb *); |
@@ -657,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *); | |||
657 | struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); | 686 | struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); |
658 | struct dasd_device *dasd_device_from_devindex(int); | 687 | struct dasd_device *dasd_device_from_devindex(int); |
659 | 688 | ||
689 | void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); | ||
690 | struct dasd_device *dasd_device_from_gendisk(struct gendisk *); | ||
691 | |||
660 | int dasd_parse(void); | 692 | int dasd_parse(void); |
661 | int dasd_busid_known(const char *); | 693 | int dasd_busid_known(const char *); |
662 | 694 | ||
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 1557214944f7..72261e4c516d 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/major.h> | 16 | #include <linux/major.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/blkpg.h> | 18 | #include <linux/blkpg.h> |
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
21 | #include <asm/compat.h> | 20 | #include <asm/compat.h> |
22 | #include <asm/ccwdev.h> | 21 | #include <asm/ccwdev.h> |
@@ -43,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp) | |||
43 | static int | 42 | static int |
44 | dasd_ioctl_enable(struct block_device *bdev) | 43 | dasd_ioctl_enable(struct block_device *bdev) |
45 | { | 44 | { |
46 | struct dasd_block *block = bdev->bd_disk->private_data; | 45 | struct dasd_device *base; |
47 | 46 | ||
48 | if (!capable(CAP_SYS_ADMIN)) | 47 | if (!capable(CAP_SYS_ADMIN)) |
49 | return -EACCES; | 48 | return -EACCES; |
50 | 49 | ||
51 | dasd_enable_device(block->base); | 50 | base = dasd_device_from_gendisk(bdev->bd_disk); |
51 | if (!base) | ||
52 | return -ENODEV; | ||
53 | |||
54 | dasd_enable_device(base); | ||
52 | /* Formatting the dasd device can change the capacity. */ | 55 | /* Formatting the dasd device can change the capacity. */ |
53 | mutex_lock(&bdev->bd_mutex); | 56 | mutex_lock(&bdev->bd_mutex); |
54 | i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); | 57 | i_size_write(bdev->bd_inode, |
58 | (loff_t)get_capacity(base->block->gdp) << 9); | ||
55 | mutex_unlock(&bdev->bd_mutex); | 59 | mutex_unlock(&bdev->bd_mutex); |
60 | dasd_put_device(base); | ||
56 | return 0; | 61 | return 0; |
57 | } | 62 | } |
58 | 63 | ||
@@ -63,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev) | |||
63 | static int | 68 | static int |
64 | dasd_ioctl_disable(struct block_device *bdev) | 69 | dasd_ioctl_disable(struct block_device *bdev) |
65 | { | 70 | { |
66 | struct dasd_block *block = bdev->bd_disk->private_data; | 71 | struct dasd_device *base; |
67 | 72 | ||
68 | if (!capable(CAP_SYS_ADMIN)) | 73 | if (!capable(CAP_SYS_ADMIN)) |
69 | return -EACCES; | 74 | return -EACCES; |
70 | 75 | ||
76 | base = dasd_device_from_gendisk(bdev->bd_disk); | ||
77 | if (!base) | ||
78 | return -ENODEV; | ||
71 | /* | 79 | /* |
72 | * Man this is sick. We don't do a real disable but only downgrade | 80 | * Man this is sick. We don't do a real disable but only downgrade |
73 | * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses | 81 | * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses |
@@ -76,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev) | |||
76 | * using the BIODASDFMT ioctl. Therefore the correct state for the | 84 | * using the BIODASDFMT ioctl. Therefore the correct state for the |
77 | * device is DASD_STATE_BASIC that allows to do basic i/o. | 85 | * device is DASD_STATE_BASIC that allows to do basic i/o. |
78 | */ | 86 | */ |
79 | dasd_set_target_state(block->base, DASD_STATE_BASIC); | 87 | dasd_set_target_state(base, DASD_STATE_BASIC); |
80 | /* | 88 | /* |
81 | * Set i_size to zero, since read, write, etc. check against this | 89 | * Set i_size to zero, since read, write, etc. check against this |
82 | * value. | 90 | * value. |
@@ -84,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev) | |||
84 | mutex_lock(&bdev->bd_mutex); | 92 | mutex_lock(&bdev->bd_mutex); |
85 | i_size_write(bdev->bd_inode, 0); | 93 | i_size_write(bdev->bd_inode, 0); |
86 | mutex_unlock(&bdev->bd_mutex); | 94 | mutex_unlock(&bdev->bd_mutex); |
95 | dasd_put_device(base); | ||
87 | return 0; | 96 | return 0; |
88 | } | 97 | } |
89 | 98 | ||
@@ -192,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) | |||
192 | static int | 201 | static int |
193 | dasd_ioctl_format(struct block_device *bdev, void __user *argp) | 202 | dasd_ioctl_format(struct block_device *bdev, void __user *argp) |
194 | { | 203 | { |
195 | struct dasd_block *block = bdev->bd_disk->private_data; | 204 | struct dasd_device *base; |
196 | struct format_data_t fdata; | 205 | struct format_data_t fdata; |
206 | int rc; | ||
197 | 207 | ||
198 | if (!capable(CAP_SYS_ADMIN)) | 208 | if (!capable(CAP_SYS_ADMIN)) |
199 | return -EACCES; | 209 | return -EACCES; |
200 | if (!argp) | 210 | if (!argp) |
201 | return -EINVAL; | 211 | return -EINVAL; |
202 | 212 | base = dasd_device_from_gendisk(bdev->bd_disk); | |
203 | if (block->base->features & DASD_FEATURE_READONLY || | 213 | if (!base) |
204 | test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | 214 | return -ENODEV; |
215 | if (base->features & DASD_FEATURE_READONLY || | ||
216 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { | ||
217 | dasd_put_device(base); | ||
205 | return -EROFS; | 218 | return -EROFS; |
206 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) | 219 | } |
220 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { | ||
221 | dasd_put_device(base); | ||
207 | return -EFAULT; | 222 | return -EFAULT; |
223 | } | ||
208 | if (bdev != bdev->bd_contains) { | 224 | if (bdev != bdev->bd_contains) { |
209 | pr_warning("%s: The specified DASD is a partition and cannot " | 225 | pr_warning("%s: The specified DASD is a partition and cannot " |
210 | "be formatted\n", | 226 | "be formatted\n", |
211 | dev_name(&block->base->cdev->dev)); | 227 | dev_name(&base->cdev->dev)); |
228 | dasd_put_device(base); | ||
212 | return -EINVAL; | 229 | return -EINVAL; |
213 | } | 230 | } |
214 | return dasd_format(block, &fdata); | 231 | rc = dasd_format(base->block, &fdata); |
232 | dasd_put_device(base); | ||
233 | return rc; | ||
215 | } | 234 | } |
216 | 235 | ||
217 | #ifdef CONFIG_DASD_PROFILE | 236 | #ifdef CONFIG_DASD_PROFILE |
@@ -341,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block, | |||
341 | static int | 360 | static int |
342 | dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | 361 | dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) |
343 | { | 362 | { |
344 | struct dasd_block *block = bdev->bd_disk->private_data; | 363 | struct dasd_device *base; |
345 | int intval; | 364 | int intval, rc; |
346 | 365 | ||
347 | if (!capable(CAP_SYS_ADMIN)) | 366 | if (!capable(CAP_SYS_ADMIN)) |
348 | return -EACCES; | 367 | return -EACCES; |
@@ -351,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | |||
351 | return -EINVAL; | 370 | return -EINVAL; |
352 | if (get_user(intval, (int __user *)argp)) | 371 | if (get_user(intval, (int __user *)argp)) |
353 | return -EFAULT; | 372 | return -EFAULT; |
354 | if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | 373 | base = dasd_device_from_gendisk(bdev->bd_disk); |
374 | if (!base) | ||
375 | return -ENODEV; | ||
376 | if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { | ||
377 | dasd_put_device(base); | ||
355 | return -EROFS; | 378 | return -EROFS; |
379 | } | ||
356 | set_disk_ro(bdev->bd_disk, intval); | 380 | set_disk_ro(bdev->bd_disk, intval); |
357 | return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); | 381 | rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); |
382 | dasd_put_device(base); | ||
383 | return rc; | ||
358 | } | 384 | } |
359 | 385 | ||
360 | static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, | 386 | static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, |
@@ -370,74 +396,81 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, | |||
370 | return ret; | 396 | return ret; |
371 | } | 397 | } |
372 | 398 | ||
373 | static int | 399 | int dasd_ioctl(struct block_device *bdev, fmode_t mode, |
374 | dasd_do_ioctl(struct block_device *bdev, fmode_t mode, | 400 | unsigned int cmd, unsigned long arg) |
375 | unsigned int cmd, unsigned long arg) | ||
376 | { | 401 | { |
377 | struct dasd_block *block = bdev->bd_disk->private_data; | 402 | struct dasd_block *block; |
403 | struct dasd_device *base; | ||
378 | void __user *argp; | 404 | void __user *argp; |
405 | int rc; | ||
379 | 406 | ||
380 | if (is_compat_task()) | 407 | if (is_compat_task()) |
381 | argp = compat_ptr(arg); | 408 | argp = compat_ptr(arg); |
382 | else | 409 | else |
383 | argp = (void __user *)arg; | 410 | argp = (void __user *)arg; |
384 | 411 | ||
385 | if (!block) | ||
386 | return -ENODEV; | ||
387 | |||
388 | if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { | 412 | if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { |
389 | PRINT_DEBUG("empty data ptr"); | 413 | PRINT_DEBUG("empty data ptr"); |
390 | return -EINVAL; | 414 | return -EINVAL; |
391 | } | 415 | } |
392 | 416 | ||
417 | base = dasd_device_from_gendisk(bdev->bd_disk); | ||
418 | if (!base) | ||
419 | return -ENODEV; | ||
420 | block = base->block; | ||
421 | rc = 0; | ||
393 | switch (cmd) { | 422 | switch (cmd) { |
394 | case BIODASDDISABLE: | 423 | case BIODASDDISABLE: |
395 | return dasd_ioctl_disable(bdev); | 424 | rc = dasd_ioctl_disable(bdev); |
425 | break; | ||
396 | case BIODASDENABLE: | 426 | case BIODASDENABLE: |
397 | return dasd_ioctl_enable(bdev); | 427 | rc = dasd_ioctl_enable(bdev); |
428 | break; | ||
398 | case BIODASDQUIESCE: | 429 | case BIODASDQUIESCE: |
399 | return dasd_ioctl_quiesce(block); | 430 | rc = dasd_ioctl_quiesce(block); |
431 | break; | ||
400 | case BIODASDRESUME: | 432 | case BIODASDRESUME: |
401 | return dasd_ioctl_resume(block); | 433 | rc = dasd_ioctl_resume(block); |
434 | break; | ||
402 | case BIODASDFMT: | 435 | case BIODASDFMT: |
403 | return dasd_ioctl_format(bdev, argp); | 436 | rc = dasd_ioctl_format(bdev, argp); |
437 | break; | ||
404 | case BIODASDINFO: | 438 | case BIODASDINFO: |
405 | return dasd_ioctl_information(block, cmd, argp); | 439 | rc = dasd_ioctl_information(block, cmd, argp); |
440 | break; | ||
406 | case BIODASDINFO2: | 441 | case BIODASDINFO2: |
407 | return dasd_ioctl_information(block, cmd, argp); | 442 | rc = dasd_ioctl_information(block, cmd, argp); |
443 | break; | ||
408 | case BIODASDPRRD: | 444 | case BIODASDPRRD: |
409 | return dasd_ioctl_read_profile(block, argp); | 445 | rc = dasd_ioctl_read_profile(block, argp); |
446 | break; | ||
410 | case BIODASDPRRST: | 447 | case BIODASDPRRST: |
411 | return dasd_ioctl_reset_profile(block); | 448 | rc = dasd_ioctl_reset_profile(block); |
449 | break; | ||
412 | case BLKROSET: | 450 | case BLKROSET: |
413 | return dasd_ioctl_set_ro(bdev, argp); | 451 | rc = dasd_ioctl_set_ro(bdev, argp); |
452 | break; | ||
414 | case DASDAPIVER: | 453 | case DASDAPIVER: |
415 | return dasd_ioctl_api_version(argp); | 454 | rc = dasd_ioctl_api_version(argp); |
455 | break; | ||
416 | case BIODASDCMFENABLE: | 456 | case BIODASDCMFENABLE: |
417 | return enable_cmf(block->base->cdev); | 457 | rc = enable_cmf(base->cdev); |
458 | break; | ||
418 | case BIODASDCMFDISABLE: | 459 | case BIODASDCMFDISABLE: |
419 | return disable_cmf(block->base->cdev); | 460 | rc = disable_cmf(base->cdev); |
461 | break; | ||
420 | case BIODASDREADALLCMB: | 462 | case BIODASDREADALLCMB: |
421 | return dasd_ioctl_readall_cmb(block, cmd, argp); | 463 | rc = dasd_ioctl_readall_cmb(block, cmd, argp); |
464 | break; | ||
422 | default: | 465 | default: |
423 | /* if the discipline has an ioctl method try it. */ | 466 | /* if the discipline has an ioctl method try it. */ |
424 | if (block->base->discipline->ioctl) { | 467 | if (base->discipline->ioctl) { |
425 | int rval = block->base->discipline->ioctl(block, cmd, argp); | 468 | rc = base->discipline->ioctl(block, cmd, argp); |
426 | if (rval != -ENOIOCTLCMD) | 469 | if (rc == -ENOIOCTLCMD) |
427 | return rval; | 470 | rc = -EINVAL; |
428 | } | 471 | } else |
429 | 472 | rc = -EINVAL; | |
430 | return -EINVAL; | ||
431 | } | 473 | } |
432 | } | 474 | dasd_put_device(base); |
433 | |||
434 | int dasd_ioctl(struct block_device *bdev, fmode_t mode, | ||
435 | unsigned int cmd, unsigned long arg) | ||
436 | { | ||
437 | int rc; | ||
438 | |||
439 | lock_kernel(); | ||
440 | rc = dasd_do_ioctl(bdev, mode, cmd, arg); | ||
441 | unlock_kernel(); | ||
442 | return rc; | 475 | return rc; |
443 | } | 476 | } |
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 2eb025592809..c4a6a31bd9cd 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
@@ -251,7 +251,6 @@ static ssize_t dasd_stats_proc_write(struct file *file, | |||
251 | buffer = dasd_get_user_string(user_buf, user_len); | 251 | buffer = dasd_get_user_string(user_buf, user_len); |
252 | if (IS_ERR(buffer)) | 252 | if (IS_ERR(buffer)) |
253 | return PTR_ERR(buffer); | 253 | return PTR_ERR(buffer); |
254 | DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer); | ||
255 | 254 | ||
256 | /* check for valid verbs */ | 255 | /* check for valid verbs */ |
257 | str = skip_spaces(buffer); | 256 | str = skip_spaces(buffer); |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 2bd72aa34c59..9b43ae94beba 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <linux/smp_lock.h> | ||
18 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
19 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
20 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
@@ -776,7 +775,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) | |||
776 | struct dcssblk_dev_info *dev_info; | 775 | struct dcssblk_dev_info *dev_info; |
777 | int rc; | 776 | int rc; |
778 | 777 | ||
779 | lock_kernel(); | ||
780 | dev_info = bdev->bd_disk->private_data; | 778 | dev_info = bdev->bd_disk->private_data; |
781 | if (NULL == dev_info) { | 779 | if (NULL == dev_info) { |
782 | rc = -ENODEV; | 780 | rc = -ENODEV; |
@@ -786,7 +784,6 @@ dcssblk_open(struct block_device *bdev, fmode_t mode) | |||
786 | bdev->bd_block_size = 4096; | 784 | bdev->bd_block_size = 4096; |
787 | rc = 0; | 785 | rc = 0; |
788 | out: | 786 | out: |
789 | unlock_kernel(); | ||
790 | return rc; | 787 | return rc; |
791 | } | 788 | } |
792 | 789 | ||
@@ -797,7 +794,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) | |||
797 | struct segment_info *entry; | 794 | struct segment_info *entry; |
798 | int rc; | 795 | int rc; |
799 | 796 | ||
800 | lock_kernel(); | ||
801 | if (!dev_info) { | 797 | if (!dev_info) { |
802 | rc = -ENODEV; | 798 | rc = -ENODEV; |
803 | goto out; | 799 | goto out; |
@@ -815,7 +811,6 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) | |||
815 | up_write(&dcssblk_devices_sem); | 811 | up_write(&dcssblk_devices_sem); |
816 | rc = 0; | 812 | rc = 0; |
817 | out: | 813 | out: |
818 | unlock_kernel(); | ||
819 | return rc; | 814 | return rc; |
820 | } | 815 | } |
821 | 816 | ||
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index c881a14fa5dd..1f6a4d894e73 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c | |||
@@ -62,8 +62,8 @@ static int xpram_devs; | |||
62 | /* | 62 | /* |
63 | * Parameter parsing functions. | 63 | * Parameter parsing functions. |
64 | */ | 64 | */ |
65 | static int __initdata devs = XPRAM_DEVS; | 65 | static int devs = XPRAM_DEVS; |
66 | static char __initdata *sizes[XPRAM_MAX_DEVS]; | 66 | static char *sizes[XPRAM_MAX_DEVS]; |
67 | 67 | ||
68 | module_param(devs, int, 0); | 68 | module_param(devs, int, 0); |
69 | module_param_array(sizes, charp, NULL, 0); | 69 | module_param_array(sizes, charp, NULL, 0); |