s390/dasd: Make raw I/O usable without prefix support
authorJan Höppner <hoeppner@linux.vnet.ibm.com>
Wed, 22 Mar 2017 08:57:56 +0000 (09:57 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 5 Jul 2017 05:35:29 +0000 (07:35 +0200)
The Prefix CCW is not mandatory and raw I/O can also be issued without
it. Check whether the Prefix CCW is supported and if not use the
combination of Define Extent and Locate Record Extended instead.

While at it, sort the variable declarations, replace the gotos with
early exits, and remove an error check at the end which is irrelevant.
Also, remove the XRC check as it is not relevant for raw I/O.

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/block/dasd_eckd.c

index 074a0a9d175500a55896bce0903067b1154f1240..c3e5ad641b0b3fc073098bca96a1c1071b3f556e 100644 (file)
@@ -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;
 }