diff options
author | Stefan Haberland <stefan.haberland@de.ibm.com> | 2011-01-05 06:48:06 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2011-01-05 06:47:30 -0500 |
commit | e4dbb0f2b5dd6a836d0e5c60aa5f573e0bbcf76a (patch) | |
tree | cb18d0b08f2ccc8d6a078456b77f111805777db8 /drivers/s390/block | |
parent | 6f272b9cec285a9610a2acf101f694bc58bed37e (diff) |
[S390] dasd: Add support for raw ECKD access.
Normal I/O operations through the DASD device driver give only access
to the data fields of an ECKD device even for track based I/O.
This patch extends the DASD device driver to give access to whole
ECKD tracks including count, key and data fields.
Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 23 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 55 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 194 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 2 |
4 files changed, 266 insertions, 8 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 82d9ce36bd0b..4e266f43332d 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -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))) |
@@ -2258,8 +2263,20 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
2258 | { | 2263 | { |
2259 | int max; | 2264 | int max; |
2260 | 2265 | ||
2261 | blk_queue_logical_block_size(block->request_queue, block->bp_block); | 2266 | if (block->base->features & DASD_FEATURE_USERAW) { |
2262 | max = block->base->discipline->max_blocks << block->s2b_shift; | 2267 | /* |
2268 | * the max_blocks value for raw_track access is 256 | ||
2269 | * it is higher than the native ECKD value because we | ||
2270 | * only need one ccw per track | ||
2271 | * so the max_hw_sectors are | ||
2272 | * 2048 x 512B = 1024kB = 16 tracks | ||
2273 | */ | ||
2274 | max = 2048; | ||
2275 | } else { | ||
2276 | max = block->base->discipline->max_blocks << block->s2b_shift; | ||
2277 | } | ||
2278 | blk_queue_logical_block_size(block->request_queue, | ||
2279 | block->bp_block); | ||
2263 | blk_queue_max_hw_sectors(block->request_queue, max); | 2280 | blk_queue_max_hw_sectors(block->request_queue, max); |
2264 | blk_queue_max_segments(block->request_queue, -1L); | 2281 | blk_queue_max_segments(block->request_queue, -1L); |
2265 | /* with page sized segments we can translate each segement into | 2282 | /* with page sized segments we can translate each segement into |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 47fc88692494..cb6a67bc89ff 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)) |
@@ -857,7 +859,7 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, | |||
857 | spin_lock(&dasd_devmap_lock); | 859 | spin_lock(&dasd_devmap_lock); |
858 | /* Changing diag discipline flag is only allowed in offline state. */ | 860 | /* Changing diag discipline flag is only allowed in offline state. */ |
859 | rc = count; | 861 | rc = count; |
860 | if (!devmap->device) { | 862 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { |
861 | if (val) | 863 | if (val) |
862 | devmap->features |= DASD_FEATURE_USEDIAG; | 864 | devmap->features |= DASD_FEATURE_USEDIAG; |
863 | else | 865 | else |
@@ -870,6 +872,56 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, | |||
870 | 872 | ||
871 | static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); | 873 | static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); |
872 | 874 | ||
875 | /* | ||
876 | * use_raw controls whether the driver should give access to raw eckd data or | ||
877 | * operate in standard mode | ||
878 | */ | ||
879 | static ssize_t | ||
880 | dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
881 | { | ||
882 | struct dasd_devmap *devmap; | ||
883 | int use_raw; | ||
884 | |||
885 | devmap = dasd_find_busid(dev_name(dev)); | ||
886 | if (!IS_ERR(devmap)) | ||
887 | use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; | ||
888 | else | ||
889 | use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; | ||
890 | return sprintf(buf, use_raw ? "1\n" : "0\n"); | ||
891 | } | ||
892 | |||
893 | static ssize_t | ||
894 | dasd_use_raw_store(struct device *dev, struct device_attribute *attr, | ||
895 | const char *buf, size_t count) | ||
896 | { | ||
897 | struct dasd_devmap *devmap; | ||
898 | ssize_t rc; | ||
899 | unsigned long val; | ||
900 | |||
901 | devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); | ||
902 | if (IS_ERR(devmap)) | ||
903 | return PTR_ERR(devmap); | ||
904 | |||
905 | if ((strict_strtoul(buf, 10, &val) != 0) || val > 1) | ||
906 | return -EINVAL; | ||
907 | |||
908 | spin_lock(&dasd_devmap_lock); | ||
909 | /* Changing diag discipline flag is only allowed in offline state. */ | ||
910 | rc = count; | ||
911 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { | ||
912 | if (val) | ||
913 | devmap->features |= DASD_FEATURE_USERAW; | ||
914 | else | ||
915 | devmap->features &= ~DASD_FEATURE_USERAW; | ||
916 | } else | ||
917 | rc = -EPERM; | ||
918 | spin_unlock(&dasd_devmap_lock); | ||
919 | return rc; | ||
920 | } | ||
921 | |||
922 | static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, | ||
923 | dasd_use_raw_store); | ||
924 | |||
873 | static ssize_t | 925 | static ssize_t |
874 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, | 926 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, |
875 | char *buf) | 927 | char *buf) |
@@ -1232,6 +1284,7 @@ static struct attribute * dasd_attrs[] = { | |||
1232 | &dev_attr_vendor.attr, | 1284 | &dev_attr_vendor.attr, |
1233 | &dev_attr_uid.attr, | 1285 | &dev_attr_uid.attr, |
1234 | &dev_attr_use_diag.attr, | 1286 | &dev_attr_use_diag.attr, |
1287 | &dev_attr_raw_track_access.attr, | ||
1235 | &dev_attr_eer_enabled.attr, | 1288 | &dev_attr_eer_enabled.attr, |
1236 | &dev_attr_erplog.attr, | 1289 | &dev_attr_erplog.attr, |
1237 | &dev_attr_failfast.attr, | 1290 | &dev_attr_failfast.attr, |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 46eafce3a0a6..318672d05563 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; |
@@ -385,6 +394,23 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, | |||
385 | data->length = reclen; | 394 | data->length = reclen; |
386 | data->operation.operation = 0x03; | 395 | data->operation.operation = 0x03; |
387 | 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; | ||
388 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | 414 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: |
389 | data->auxiliary.length_valid = 0x1; | 415 | data->auxiliary.length_valid = 0x1; |
390 | data->length = reclen; /* not tlf, as one might think */ | 416 | data->length = reclen; /* not tlf, as one might think */ |
@@ -408,6 +434,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, | |||
408 | case DASD_ECKD_CCW_READ_COUNT: | 434 | case DASD_ECKD_CCW_READ_COUNT: |
409 | data->operation.operation = 0x06; | 435 | data->operation.operation = 0x06; |
410 | 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; | ||
411 | case DASD_ECKD_CCW_READ_TRACK_DATA: | 443 | case DASD_ECKD_CCW_READ_TRACK_DATA: |
412 | data->auxiliary.length_valid = 0x1; | 444 | data->auxiliary.length_valid = 0x1; |
413 | data->length = tlf; | 445 | data->length = tlf; |
@@ -451,10 +483,16 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
451 | 483 | ||
452 | ccw->cmd_code = DASD_ECKD_CCW_PFX; | 484 | ccw->cmd_code = DASD_ECKD_CCW_PFX; |
453 | ccw->flags = 0; | 485 | ccw->flags = 0; |
454 | ccw->count = sizeof(*pfxdata); | 486 | if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) { |
455 | 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 | } | ||
456 | 495 | ||
457 | memset(pfxdata, 0, sizeof(*pfxdata)); | ||
458 | /* prefix data */ | 496 | /* prefix data */ |
459 | if (format > 1) { | 497 | if (format > 1) { |
460 | DBF_DEV_EVENT(DBF_ERR, basedev, | 498 | DBF_DEV_EVENT(DBF_ERR, basedev, |
@@ -488,6 +526,7 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
488 | dedata->mask.perm = 0x1; | 526 | dedata->mask.perm = 0x1; |
489 | dedata->attributes.operation = basepriv->attrib.operation; | 527 | dedata->attributes.operation = basepriv->attrib.operation; |
490 | break; | 528 | break; |
529 | case DASD_ECKD_CCW_READ_TRACK: | ||
491 | case DASD_ECKD_CCW_READ_TRACK_DATA: | 530 | case DASD_ECKD_CCW_READ_TRACK_DATA: |
492 | dedata->mask.perm = 0x1; | 531 | dedata->mask.perm = 0x1; |
493 | dedata->attributes.operation = basepriv->attrib.operation; | 532 | dedata->attributes.operation = basepriv->attrib.operation; |
@@ -514,6 +553,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
514 | dedata->attributes.operation = DASD_BYPASS_CACHE; | 553 | dedata->attributes.operation = DASD_BYPASS_CACHE; |
515 | rc = check_XRC_on_prefix(pfxdata, basedev); | 554 | rc = check_XRC_on_prefix(pfxdata, basedev); |
516 | 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; | ||
517 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | 561 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: |
518 | dedata->mask.perm = 0x02; | 562 | dedata->mask.perm = 0x02; |
519 | dedata->attributes.operation = basepriv->attrib.operation; | 563 | dedata->attributes.operation = basepriv->attrib.operation; |
@@ -1607,6 +1651,13 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1607 | dasd_sfree_request(init_cqr, device); | 1651 | dasd_sfree_request(init_cqr, device); |
1608 | } | 1652 | } |
1609 | 1653 | ||
1654 | if (device->features & DASD_FEATURE_USERAW) { | ||
1655 | block->bp_block = DASD_RAW_BLOCKSIZE; | ||
1656 | blk_per_trk = DASD_RAW_BLOCK_PER_TRACK; | ||
1657 | block->s2b_shift = 3; | ||
1658 | goto raw; | ||
1659 | } | ||
1660 | |||
1610 | if (status == INIT_CQR_UNFORMATTED) { | 1661 | if (status == INIT_CQR_UNFORMATTED) { |
1611 | dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); | 1662 | dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); |
1612 | return -EMEDIUMTYPE; | 1663 | return -EMEDIUMTYPE; |
@@ -1644,6 +1695,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1644 | dev_warn(&device->cdev->dev, | 1695 | dev_warn(&device->cdev->dev, |
1645 | "Track 0 has no records following the VTOC\n"); | 1696 | "Track 0 has no records following the VTOC\n"); |
1646 | } | 1697 | } |
1698 | |||
1647 | if (count_area != NULL && count_area->kl == 0) { | 1699 | if (count_area != NULL && count_area->kl == 0) { |
1648 | /* we found notthing violating our disk layout */ | 1700 | /* we found notthing violating our disk layout */ |
1649 | if (dasd_check_blocksize(count_area->dl) == 0) | 1701 | if (dasd_check_blocksize(count_area->dl) == 0) |
@@ -1659,6 +1711,8 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) | |||
1659 | block->s2b_shift++; | 1711 | block->s2b_shift++; |
1660 | 1712 | ||
1661 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); | 1713 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); |
1714 | |||
1715 | raw: | ||
1662 | block->blocks = (private->real_cyl * | 1716 | block->blocks = (private->real_cyl * |
1663 | private->rdc_data.trk_per_cyl * | 1717 | private->rdc_data.trk_per_cyl * |
1664 | blk_per_trk); | 1718 | blk_per_trk); |
@@ -2741,6 +2795,135 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2741 | return cqr; | 2795 | return cqr; |
2742 | } | 2796 | } |
2743 | 2797 | ||
2798 | static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | ||
2799 | struct dasd_block *block, | ||
2800 | struct request *req) | ||
2801 | { | ||
2802 | struct dasd_eckd_private *private; | ||
2803 | unsigned long *idaws; | ||
2804 | struct dasd_device *basedev; | ||
2805 | struct dasd_ccw_req *cqr; | ||
2806 | struct ccw1 *ccw; | ||
2807 | struct req_iterator iter; | ||
2808 | struct bio_vec *bv; | ||
2809 | char *dst; | ||
2810 | unsigned char cmd; | ||
2811 | unsigned int trkcount; | ||
2812 | unsigned int seg_len, len_to_track_end; | ||
2813 | unsigned int first_offs; | ||
2814 | unsigned int cidaw, cplength, datasize; | ||
2815 | sector_t first_trk, last_trk; | ||
2816 | unsigned int pfx_datasize; | ||
2817 | |||
2818 | /* | ||
2819 | * raw track access needs to be mutiple of 64k and on 64k boundary | ||
2820 | */ | ||
2821 | if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) { | ||
2822 | cqr = ERR_PTR(-EINVAL); | ||
2823 | goto out; | ||
2824 | } | ||
2825 | if (((blk_rq_pos(req) + blk_rq_sectors(req)) % | ||
2826 | DASD_RAW_SECTORS_PER_TRACK) != 0) { | ||
2827 | cqr = ERR_PTR(-EINVAL); | ||
2828 | goto out; | ||
2829 | } | ||
2830 | |||
2831 | first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK; | ||
2832 | last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) / | ||
2833 | DASD_RAW_SECTORS_PER_TRACK; | ||
2834 | trkcount = last_trk - first_trk + 1; | ||
2835 | first_offs = 0; | ||
2836 | basedev = block->base; | ||
2837 | private = (struct dasd_eckd_private *) basedev->private; | ||
2838 | |||
2839 | if (rq_data_dir(req) == READ) | ||
2840 | cmd = DASD_ECKD_CCW_READ_TRACK; | ||
2841 | else if (rq_data_dir(req) == WRITE) | ||
2842 | cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK; | ||
2843 | else { | ||
2844 | cqr = ERR_PTR(-EINVAL); | ||
2845 | goto out; | ||
2846 | } | ||
2847 | |||
2848 | /* | ||
2849 | * Raw track based I/O needs IDAWs for each page, | ||
2850 | * and not just for 64 bit addresses. | ||
2851 | */ | ||
2852 | cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK; | ||
2853 | |||
2854 | /* 1x prefix + one read/write ccw per track */ | ||
2855 | cplength = 1 + trkcount; | ||
2856 | |||
2857 | /* | ||
2858 | * struct PFX_eckd_data has up to 2 byte as extended parameter | ||
2859 | * this is needed for write full track and has to be mentioned | ||
2860 | * seperately | ||
2861 | * add 8 instead of 2 to keep 8 byte boundary | ||
2862 | */ | ||
2863 | pfx_datasize = sizeof(struct PFX_eckd_data) + 8; | ||
2864 | |||
2865 | datasize = pfx_datasize + cidaw * sizeof(unsigned long long); | ||
2866 | |||
2867 | /* Allocate the ccw request. */ | ||
2868 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, | ||
2869 | datasize, startdev); | ||
2870 | if (IS_ERR(cqr)) | ||
2871 | goto out; | ||
2872 | ccw = cqr->cpaddr; | ||
2873 | |||
2874 | if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd, | ||
2875 | basedev, startdev, 1 /* format */, first_offs + 1, | ||
2876 | trkcount, 0, 0) == -EAGAIN) { | ||
2877 | /* Clock not in sync and XRC is enabled. | ||
2878 | * Try again later. | ||
2879 | */ | ||
2880 | dasd_sfree_request(cqr, startdev); | ||
2881 | cqr = ERR_PTR(-EAGAIN); | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | idaws = (unsigned long *)(cqr->data + pfx_datasize); | ||
2886 | |||
2887 | len_to_track_end = 0; | ||
2888 | |||
2889 | rq_for_each_segment(bv, req, iter) { | ||
2890 | dst = page_address(bv->bv_page) + bv->bv_offset; | ||
2891 | seg_len = bv->bv_len; | ||
2892 | if (!len_to_track_end) { | ||
2893 | ccw[-1].flags |= CCW_FLAG_CC; | ||
2894 | ccw->cmd_code = cmd; | ||
2895 | /* maximum 3390 track size */ | ||
2896 | ccw->count = 57326; | ||
2897 | /* 64k map to one track */ | ||
2898 | len_to_track_end = 65536; | ||
2899 | ccw->cda = (__u32)(addr_t)idaws; | ||
2900 | ccw->flags |= CCW_FLAG_IDA; | ||
2901 | ccw->flags |= CCW_FLAG_SLI; | ||
2902 | ccw++; | ||
2903 | } | ||
2904 | len_to_track_end -= seg_len; | ||
2905 | idaws = idal_create_words(idaws, dst, seg_len); | ||
2906 | } | ||
2907 | |||
2908 | if (blk_noretry_request(req) || | ||
2909 | block->base->features & DASD_FEATURE_FAILFAST) | ||
2910 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
2911 | cqr->startdev = startdev; | ||
2912 | cqr->memdev = startdev; | ||
2913 | cqr->block = block; | ||
2914 | cqr->expires = startdev->default_expires * HZ; | ||
2915 | cqr->lpm = startdev->path_data.ppm; | ||
2916 | cqr->retries = 256; | ||
2917 | cqr->buildclk = get_clock(); | ||
2918 | cqr->status = DASD_CQR_FILLED; | ||
2919 | |||
2920 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | ||
2921 | cqr = NULL; | ||
2922 | out: | ||
2923 | return cqr; | ||
2924 | } | ||
2925 | |||
2926 | |||
2744 | static int | 2927 | static int |
2745 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | 2928 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) |
2746 | { | 2929 | { |
@@ -2845,7 +3028,10 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, | |||
2845 | 3028 | ||
2846 | spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); | 3029 | spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); |
2847 | private->count++; | 3030 | private->count++; |
2848 | cqr = dasd_eckd_build_cp(startdev, block, req); | 3031 | if ((base->features & DASD_FEATURE_USERAW)) |
3032 | cqr = dasd_raw_build_cp(startdev, block, req); | ||
3033 | else | ||
3034 | cqr = dasd_eckd_build_cp(startdev, block, req); | ||
2849 | if (IS_ERR(cqr)) | 3035 | if (IS_ERR(cqr)) |
2850 | private->count--; | 3036 | private->count--; |
2851 | spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); | 3037 | spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 5051f374cbcb..4a688a873a77 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -37,11 +37,13 @@ | |||
37 | #define DASD_ECKD_CCW_WRITE_KD_MT 0x8d | 37 | #define DASD_ECKD_CCW_WRITE_KD_MT 0x8d |
38 | #define DASD_ECKD_CCW_READ_KD_MT 0x8e | 38 | #define DASD_ECKD_CCW_READ_KD_MT 0x8e |
39 | #define DASD_ECKD_CCW_RELEASE 0x94 | 39 | #define DASD_ECKD_CCW_RELEASE 0x94 |
40 | #define DASD_ECKD_CCW_WRITE_FULL_TRACK 0x95 | ||
40 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e | 41 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e |
41 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d | 42 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d |
42 | #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 | 43 | #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 |
43 | #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 | 44 | #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 |
44 | #define DASD_ECKD_CCW_RESERVE 0xB4 | 45 | #define DASD_ECKD_CCW_RESERVE 0xB4 |
46 | #define DASD_ECKD_CCW_READ_TRACK 0xDE | ||
45 | #define DASD_ECKD_CCW_PFX 0xE7 | 47 | #define DASD_ECKD_CCW_PFX 0xE7 |
46 | #define DASD_ECKD_CCW_PFX_READ 0xEA | 48 | #define DASD_ECKD_CCW_PFX_READ 0xEA |
47 | #define DASD_ECKD_CCW_RSCK 0xF9 | 49 | #define DASD_ECKD_CCW_RSCK 0xF9 |