diff options
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 85 |
1 files changed, 45 insertions, 40 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 074a0a9d1755..c3e5ad641b0b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3783,21 +3783,24 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, struct dasd_block *block, struct request *req) { - unsigned long *idaws; + sector_t start_padding_sectors, end_sector_offset, end_padding_sectors; + unsigned int seg_len, len_to_track_end; + unsigned int cidaw, cplength, datasize; + sector_t first_trk, last_trk, sectors; + struct dasd_eckd_private *base_priv; struct dasd_device *basedev; - struct dasd_ccw_req *cqr; - struct ccw1 *ccw; struct req_iterator iter; + struct dasd_ccw_req *cqr; + unsigned int first_offs; + unsigned int trkcount; + unsigned long *idaws; + unsigned int size; + unsigned char cmd; struct bio_vec bv; + struct ccw1 *ccw; + int use_prefix; + void *data; char *dst; - unsigned char cmd; - unsigned int trkcount; - unsigned int seg_len, len_to_track_end; - unsigned int first_offs; - unsigned int cidaw, cplength, datasize; - sector_t first_trk, last_trk, sectors; - sector_t start_padding_sectors, end_sector_offset, end_padding_sectors; - unsigned int pfx_datasize; /* * raw track access needs to be mutiple of 64k and on 64k boundary @@ -3815,8 +3818,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, DBF_DEV_EVENT(DBF_ERR, basedev, "raw write not track aligned (%lu,%lu) req %p", start_padding_sectors, end_padding_sectors, req); - cqr = ERR_PTR(-EINVAL); - goto out; + return ERR_PTR(-EINVAL); } first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK; @@ -3829,10 +3831,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, cmd = DASD_ECKD_CCW_READ_TRACK; else if (rq_data_dir(req) == WRITE) cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK; - else { - cqr = ERR_PTR(-EINVAL); - goto out; - } + else + return ERR_PTR(-EINVAL); /* * Raw track based I/O needs IDAWs for each page, @@ -3840,38 +3840,46 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, */ cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK; - /* 1x prefix + one read/write ccw per track */ - cplength = 1 + trkcount; - /* - * struct PFX_eckd_data has up to 2 byte as extended parameter - * this is needed for write full track and has to be mentioned - * separately - * add 8 instead of 2 to keep 8 byte boundary + * struct PFX_eckd_data and struct LRE_eckd_data can have up to 2 bytes + * of extended parameter. This is needed for write full track. */ - pfx_datasize = sizeof(struct PFX_eckd_data) + 8; + base_priv = basedev->private; + use_prefix = base_priv->features.feature[8] & 0x01; + if (use_prefix) { + cplength = 1 + trkcount; + size = sizeof(struct PFX_eckd_data) + 2; + } else { + cplength = 2 + trkcount; + size = sizeof(struct DE_eckd_data) + + sizeof(struct LRE_eckd_data) + 2; + } + size = ALIGN(size, 8); - datasize = pfx_datasize + cidaw * sizeof(unsigned long long); + datasize = size + cidaw * sizeof(unsigned long long); /* Allocate the ccw request. */ cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev); if (IS_ERR(cqr)) - goto out; + return cqr; + ccw = cqr->cpaddr; + data = cqr->data; - if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd, - basedev, startdev, 1 /* format */, first_offs + 1, - trkcount, 0, 0) == -EAGAIN) { - /* Clock not in sync and XRC is enabled. - * Try again later. - */ - dasd_sfree_request(cqr, startdev); - cqr = ERR_PTR(-EAGAIN); - goto out; + if (use_prefix) { + prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev, + startdev, 1, first_offs + 1, trkcount, 0, 0); + } else { + define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0); + ccw[-1].flags |= CCW_FLAG_CC; + + data += sizeof(struct DE_eckd_data); + locate_record_ext(ccw++, data, first_trk, first_offs + 1, + trkcount, cmd, basedev, 0, 0); } - idaws = (unsigned long *)(cqr->data + pfx_datasize); + idaws = (unsigned long *)(cqr->data + size); len_to_track_end = 0; if (start_padding_sectors) { ccw[-1].flags |= CCW_FLAG_CC; @@ -3921,9 +3929,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; - if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) - cqr = NULL; -out: return cqr; } |