s390/dasd: Refactor prefix_LRE() and related functions
authorJan Höppner <hoeppner@linux.vnet.ibm.com>
Tue, 14 Mar 2017 10:10:16 +0000 (11:10 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 5 Jul 2017 05:35:28 +0000 (07:35 +0200)
We already have define_extent() that prepares necessary data for the
Define Extent CCW. The exact same thing is done in prefix_LRE().

Remove the duplicate code and move commands that were only used in
combination with the Prefix command to define_extent(). One of these
commands needs the blocksize to be specified. Add the blksize parameter
to define_extent() to account for that.

In addition, the check_XRC() function can be made more generic. Do this
and remove the Prefix-specific check_XRC_on_prefix() function.

Furthermore, prefix_LRE() uses fill_LRE_data() to prepare Locate Record
Extended data. Rename the function to fit the scheme better and make it
usable outside of the Prefix context by adding the corresponding CCW
command.

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
drivers/s390/block/dasd_eckd.h

index 122456e4db89cc466dcc36342c12cd2af5ed8096..4fdf1101bd2f90a1234ee71bc52c640822638ab1 100644 (file)
@@ -213,10 +213,8 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
        geo->head |= head;
 }
 
-static int
-check_XRC (struct ccw1         *de_ccw,
-           struct DE_eckd_data *data,
-           struct dasd_device  *device)
+static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data,
+                    struct dasd_device *device)
 {
        struct dasd_eckd_private *private = device->private;
        int rc;
@@ -224,7 +222,7 @@ check_XRC (struct ccw1         *de_ccw,
        if (!private->rdc_data.facilities.XRC_supported)
                return 0;
 
-        /* switch on System Time Stamp - needed for XRC Support */
+       /* switch on System Time Stamp - needed for XRC Support */
        data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
        data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
 
@@ -233,24 +231,30 @@ check_XRC (struct ccw1         *de_ccw,
        if (rc == -EOPNOTSUPP || rc == -EACCES)
                rc = 0;
 
-       de_ccw->count = sizeof(struct DE_eckd_data);
-       de_ccw->flags |= CCW_FLAG_SLI;
+       if (ccw) {
+               ccw->count = sizeof(struct DE_eckd_data);
+               ccw->flags |= CCW_FLAG_SLI;
+       }
+
        return rc;
 }
 
 static int
 define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
-             unsigned int totrk, int cmd, struct dasd_device *device)
+             unsigned int totrk, int cmd, struct dasd_device *device,
+             int blksize)
 {
        struct dasd_eckd_private *private = device->private;
-       u32 begcyl, endcyl;
        u16 heads, beghead, endhead;
+       u32 begcyl, endcyl;
        int rc = 0;
 
-       ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
-       ccw->flags = 0;
-       ccw->count = 16;
-       ccw->cda = (__u32) __pa(data);
+       if (ccw) {
+               ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+               ccw->flags = 0;
+               ccw->count = 16;
+               ccw->cda = (__u32)__pa(data);
+       }
 
        memset(data, 0, sizeof(struct DE_eckd_data));
        switch (cmd) {
@@ -269,18 +273,24 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
                data->mask.perm = 0x1;
                data->attributes.operation = DASD_BYPASS_CACHE;
                break;
+       case DASD_ECKD_CCW_READ_TRACK:
+       case DASD_ECKD_CCW_READ_TRACK_DATA:
+               data->mask.perm = 0x1;
+               data->attributes.operation = private->attrib.operation;
+               data->blk_size = 0;
+               break;
        case DASD_ECKD_CCW_WRITE:
        case DASD_ECKD_CCW_WRITE_MT:
        case DASD_ECKD_CCW_WRITE_KD:
        case DASD_ECKD_CCW_WRITE_KD_MT:
                data->mask.perm = 0x02;
                data->attributes.operation = private->attrib.operation;
-               rc = check_XRC (ccw, data, device);
+               rc = check_XRC(ccw, data, device);
                break;
        case DASD_ECKD_CCW_WRITE_CKD:
        case DASD_ECKD_CCW_WRITE_CKD_MT:
                data->attributes.operation = DASD_BYPASS_CACHE;
-               rc = check_XRC (ccw, data, device);
+               rc = check_XRC(ccw, data, device);
                break;
        case DASD_ECKD_CCW_ERASE:
        case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -288,7 +298,18 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
                data->mask.perm = 0x3;
                data->mask.auth = 0x1;
                data->attributes.operation = DASD_BYPASS_CACHE;
-               rc = check_XRC (ccw, data, device);
+               rc = check_XRC(ccw, data, device);
+               break;
+       case DASD_ECKD_CCW_WRITE_FULL_TRACK:
+               data->mask.perm = 0x03;
+               data->attributes.operation = private->attrib.operation;
+               data->blk_size = 0;
+               break;
+       case DASD_ECKD_CCW_WRITE_TRACK_DATA:
+               data->mask.perm = 0x02;
+               data->attributes.operation = private->attrib.operation;
+               data->blk_size = blksize;
+               rc = check_XRC(ccw, data, device);
                break;
        default:
                dev_err(&device->cdev->dev,
@@ -325,36 +346,26 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
        return rc;
 }
 
-static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
-                              struct dasd_device  *device)
-{
-       struct dasd_eckd_private *private = device->private;
-       int rc;
 
-       if (!private->rdc_data.facilities.XRC_supported)
-               return 0;
-
-       /* switch on System Time Stamp - needed for XRC Support */
-       pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
-       pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */
-       pfxdata->validity.time_stamp = 1;           /* 'Time Stamp Valid'   */
-
-       rc = get_phys_clock(&pfxdata->define_extent.ep_sys_time);
-       /* Ignore return code if sync clock is switched off. */
-       if (rc == -EOPNOTSUPP || rc == -EACCES)
-               rc = 0;
-       return rc;
-}
-
-static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
-                         unsigned int rec_on_trk, int count, int cmd,
-                         struct dasd_device *device, unsigned int reclen,
-                         unsigned int tlf)
+static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data,
+                             unsigned int trk, unsigned int rec_on_trk,
+                             int count, int cmd, struct dasd_device *device,
+                             unsigned int reclen, unsigned int tlf)
 {
        struct dasd_eckd_private *private = device->private;
        int sector;
        int dn, d;
 
+       if (ccw) {
+               ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD_EXT;
+               ccw->flags = 0;
+               if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK)
+                       ccw->count = 22;
+               else
+                       ccw->count = 20;
+               ccw->cda = (__u32)__pa(data);
+       }
+
        memset(data, 0, sizeof(*data));
        sector = 0;
        if (rec_on_trk) {
@@ -481,14 +492,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
 static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
                      unsigned int trk, unsigned int totrk, int cmd,
                      struct dasd_device *basedev, struct dasd_device *startdev,
-                     unsigned char format, unsigned int rec_on_trk, int count,
+                     unsigned int format, unsigned int rec_on_trk, int count,
                      unsigned int blksize, unsigned int tlf)
 {
        struct dasd_eckd_private *basepriv, *startpriv;
-       struct DE_eckd_data *dedata;
        struct LRE_eckd_data *lredata;
-       u32 begcyl, endcyl;
-       u16 heads, beghead, endhead;
+       struct DE_eckd_data *dedata;
        int rc = 0;
 
        basepriv = basedev->private;
@@ -527,98 +536,19 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
                        pfxdata->validity.hyper_pav = 1;
        }
 
-       /* define extend data (mostly)*/
-       switch (cmd) {
-       case DASD_ECKD_CCW_READ_HOME_ADDRESS:
-       case DASD_ECKD_CCW_READ_RECORD_ZERO:
-       case DASD_ECKD_CCW_READ:
-       case DASD_ECKD_CCW_READ_MT:
-       case DASD_ECKD_CCW_READ_CKD:
-       case DASD_ECKD_CCW_READ_CKD_MT:
-       case DASD_ECKD_CCW_READ_KD:
-       case DASD_ECKD_CCW_READ_KD_MT:
-               dedata->mask.perm = 0x1;
-               dedata->attributes.operation = basepriv->attrib.operation;
-               break;
-       case DASD_ECKD_CCW_READ_COUNT:
-               dedata->mask.perm = 0x1;
-               dedata->attributes.operation = DASD_BYPASS_CACHE;
-               break;
-       case DASD_ECKD_CCW_READ_TRACK:
-       case DASD_ECKD_CCW_READ_TRACK_DATA:
-               dedata->mask.perm = 0x1;
-               dedata->attributes.operation = basepriv->attrib.operation;
-               dedata->blk_size = 0;
-               break;
-       case DASD_ECKD_CCW_WRITE:
-       case DASD_ECKD_CCW_WRITE_MT:
-       case DASD_ECKD_CCW_WRITE_KD:
-       case DASD_ECKD_CCW_WRITE_KD_MT:
-               dedata->mask.perm = 0x02;
-               dedata->attributes.operation = basepriv->attrib.operation;
-               rc = check_XRC_on_prefix(pfxdata, basedev);
-               break;
-       case DASD_ECKD_CCW_WRITE_CKD:
-       case DASD_ECKD_CCW_WRITE_CKD_MT:
-               dedata->attributes.operation = DASD_BYPASS_CACHE;
-               rc = check_XRC_on_prefix(pfxdata, basedev);
-               break;
-       case DASD_ECKD_CCW_ERASE:
-       case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
-       case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
-               dedata->mask.perm = 0x3;
-               dedata->mask.auth = 0x1;
-               dedata->attributes.operation = DASD_BYPASS_CACHE;
-               rc = check_XRC_on_prefix(pfxdata, basedev);
-               break;
-       case DASD_ECKD_CCW_WRITE_FULL_TRACK:
-               dedata->mask.perm = 0x03;
-               dedata->attributes.operation = basepriv->attrib.operation;
-               dedata->blk_size = 0;
-               break;
-       case DASD_ECKD_CCW_WRITE_TRACK_DATA:
-               dedata->mask.perm = 0x02;
-               dedata->attributes.operation = basepriv->attrib.operation;
-               dedata->blk_size = blksize;
-               rc = check_XRC_on_prefix(pfxdata, basedev);
-               break;
-       default:
-               DBF_DEV_EVENT(DBF_ERR, basedev,
-                           "PFX LRE unknown opcode 0x%x", cmd);
-               BUG();
-               return -EINVAL;
-       }
-
-       dedata->attributes.mode = 0x3;  /* ECKD */
-
-       if ((basepriv->rdc_data.cu_type == 0x2105 ||
-            basepriv->rdc_data.cu_type == 0x2107 ||
-            basepriv->rdc_data.cu_type == 0x1750)
-           && !(basepriv->uses_cdl && trk < 2))
-               dedata->ga_extended |= 0x40; /* Regular Data Format Mode */
-
-       heads = basepriv->rdc_data.trk_per_cyl;
-       begcyl = trk / heads;
-       beghead = trk % heads;
-       endcyl = totrk / heads;
-       endhead = totrk % heads;
-
-       /* check for sequential prestage - enhance cylinder range */
-       if (dedata->attributes.operation == DASD_SEQ_PRESTAGE ||
-           dedata->attributes.operation == DASD_SEQ_ACCESS) {
-
-               if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl)
-                       endcyl += basepriv->attrib.nr_cyl;
-               else
-                       endcyl = (basepriv->real_cyl - 1);
-       }
+       rc = define_extent(NULL, dedata, trk, totrk, cmd, basedev, blksize);
 
-       set_ch_t(&dedata->beg_ext, begcyl, beghead);
-       set_ch_t(&dedata->end_ext, endcyl, endhead);
+       /*
+        * For some commands the System Time Stamp is set in the define extent
+        * data when XRC is supported. The validity of the time stamp must be
+        * reflected in the prefix data as well.
+        */
+       if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
+               pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid'   */
 
        if (format == 1) {
-               fill_LRE_data(lredata, trk, rec_on_trk, count, cmd,
-                             basedev, blksize, tlf);
+               locate_record_ext(NULL, lredata, trk, rec_on_trk, count, cmd,
+                                 basedev, blksize, tlf);
        }
 
        return rc;
@@ -1887,7 +1817,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        ccw = cqr->cpaddr;
        /* Define extent for the first 3 tracks. */
        define_extent(ccw++, cqr->data, 0, 2,
-                     DASD_ECKD_CCW_READ_COUNT, device);
+                     DASD_ECKD_CCW_READ_COUNT, device, 0);
        LO_data = cqr->data + sizeof(struct DE_eckd_data);
        /* Locate record for the first 4 records on track 0. */
        ccw[-1].flags |= CCW_FLAG_CC;
@@ -2266,7 +2196,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
                           count, 0, 0);
        } else {
                define_extent(ccw++, data, fdata->start_unit, fdata->stop_unit,
-                             DASD_ECKD_CCW_READ_COUNT, startdev);
+                             DASD_ECKD_CCW_READ_COUNT, startdev, 0);
 
                data += sizeof(struct DE_eckd_data);
                ccw[-1].flags |= CCW_FLAG_CC;
@@ -2420,7 +2350,7 @@ dasd_eckd_build_format(struct dasd_device *base,
                } else {
                        define_extent(ccw++, (struct DE_eckd_data *) data,
                                      fdata->start_unit, fdata->stop_unit,
-                                     DASD_ECKD_CCW_WRITE_CKD, startdev);
+                                     DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
                        /* grant subsystem permission to format R0 */
                        if (r0_perm)
                                ((struct DE_eckd_data *) data)
@@ -2444,7 +2374,7 @@ dasd_eckd_build_format(struct dasd_device *base,
                } else {
                        define_extent(ccw++, (struct DE_eckd_data *) data,
                               fdata->start_unit, fdata->stop_unit,
-                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev);
+                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev, 0);
                        data += sizeof(struct DE_eckd_data);
                }
                ccw[-1].flags |= CCW_FLAG_CC;
@@ -2463,7 +2393,7 @@ dasd_eckd_build_format(struct dasd_device *base,
                } else {
                        define_extent(ccw++, (struct DE_eckd_data *) data,
                               fdata->start_unit, fdata->stop_unit,
-                              DASD_ECKD_CCW_WRITE_CKD, startdev);
+                              DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
                        data += sizeof(struct DE_eckd_data);
                }
                ccw[-1].flags |= CCW_FLAG_CC;
@@ -3187,7 +3117,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                                           sizeof(struct PFX_eckd_data));
        } else {
                if (define_extent(ccw++, cqr->data, first_trk,
-                                 last_trk, cmd, basedev) == -EAGAIN) {
+                                 last_trk, cmd, basedev, 0) == -EAGAIN) {
                        /* Clock not in sync and XRC is enabled.
                         * Try again later.
                         */
@@ -3509,12 +3439,19 @@ static int prepare_itcw(struct itcw *itcw,
                dedata->mask.perm = 0x02;
                dedata->attributes.operation = basepriv->attrib.operation;
                dedata->blk_size = blksize;
-               rc = check_XRC_on_prefix(&pfxdata, basedev);
+               rc = check_XRC(NULL, dedata, basedev);
                dedata->ga_extended |= 0x42;
                lredata->operation.orientation = 0x0;
                lredata->operation.operation = 0x3F;
                lredata->extended_operation = 0x23;
                lredata->auxiliary.check_bytes = 0x2;
+               /*
+                * If XRC is supported the System Time Stamp is set. The
+                * validity of the time stamp must be reflected in the prefix
+                * data as well.
+                */
+               if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
+                       pfxdata.validity.time_stamp = 1; /* 'Time Stamp Valid' */
                pfx_cmd = DASD_ECKD_CCW_PFX;
                break;
        case DASD_ECKD_CCW_READ_COUNT_MT:
index e2a710c250a567ff99bbb8ff7e8e22668fca2d84..fb1f537d986a2ff92a18668899ccdc7fe152a3ee 100644 (file)
@@ -29,6 +29,7 @@
 #define DASD_ECKD_CCW_SNID              0x34
 #define DASD_ECKD_CCW_RSSD              0x3e
 #define DASD_ECKD_CCW_LOCATE_RECORD     0x47
+#define DASD_ECKD_CCW_LOCATE_RECORD_EXT         0x4b
 #define DASD_ECKD_CCW_SNSS              0x54
 #define DASD_ECKD_CCW_DEFINE_EXTENT     0x63
 #define DASD_ECKD_CCW_WRITE_MT          0x85