[S390] dasd: enable prefix independent of pav support
[pandora-kernel.git] / drivers / s390 / block / dasd_eckd.c
index a1ce573..abb2ec8 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
-#include <asm/todclk.h>
 #include <asm/uaccess.h>
 #include <asm/cio.h>
 #include <asm/ccwdev.h>
@@ -86,7 +85,8 @@ dasd_eckd_probe (struct ccw_device *cdev)
        int ret;
 
        /* set ECKD specific ccw-device options */
-       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE |
+                                    CCWDEV_DO_PATHGROUP | CCWDEV_DO_MULTIPATH);
        if (ret) {
                DBF_EVENT(DBF_WARNING,
                       "dasd_eckd_probe: could not set ccw-device options "
@@ -706,7 +706,7 @@ static int dasd_eckd_generate_uid(struct dasd_device *device,
               sizeof(uid->serial) - 1);
        EBCASC(uid->serial, sizeof(uid->serial) - 1);
        uid->ssid = private->gneq->subsystemID;
-       uid->real_unit_addr = private->ned->unit_addr;;
+       uid->real_unit_addr = private->ned->unit_addr;
        if (private->sneq) {
                uid->type = private->sneq->sua_flags;
                if (uid->type == UA_BASE_PAV_ALIAS)
@@ -935,6 +935,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
        struct dasd_eckd_private *private;
 
        private = (struct dasd_eckd_private *) device->private;
+       memset(&private->features, 0, sizeof(struct dasd_rssd_features));
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
                                   (sizeof(struct dasd_psf_prssd_data) +
                                    sizeof(struct dasd_rssd_features)),
@@ -982,7 +983,9 @@ static int dasd_eckd_read_features(struct dasd_device *device)
                features = (struct dasd_rssd_features *) (prssdp + 1);
                memcpy(&private->features, features,
                       sizeof(struct dasd_rssd_features));
-       }
+       } else
+               dev_warn(&device->cdev->dev, "Reading device feature codes"
+                        " failed with rc=%d\n", rc);
        dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
@@ -1009,9 +1012,9 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
        }
        psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
        psf_ssc_data->order = PSF_ORDER_SSC;
-       psf_ssc_data->suborder = 0x40;
+       psf_ssc_data->suborder = 0xc0;
        if (enable_pav) {
-               psf_ssc_data->suborder |= 0x88;
+               psf_ssc_data->suborder |= 0x08;
                psf_ssc_data->reserved[0] = 0x88;
        }
        ccw = cqr->cpaddr;
@@ -1087,6 +1090,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        struct dasd_block *block;
        int is_known, rc;
 
+       if (!ccw_device_is_pathgroup(device->cdev)) {
+               dev_warn(&device->cdev->dev,
+                        "A channel path group could not be established\n");
+               return -EIO;
+       }
+       if (!ccw_device_is_multipath(device->cdev)) {
+               dev_info(&device->cdev->dev,
+                        "The DASD is not operating in multipath mode\n");
+       }
        private = (struct dasd_eckd_private *) device->private;
        if (!private) {
                private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
@@ -1144,9 +1156,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        }
 
        /* Read Feature Codes */
-       rc = dasd_eckd_read_features(device);
-       if (rc)
-               goto out_err3;
+       dasd_eckd_read_features(device);
 
        /* Read Device Characteristics */
        rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
@@ -2337,6 +2347,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
        /* Calculate number of blocks/records per track. */
        blksize = block->bp_block;
        blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+       if (blk_per_trk == 0)
+               return ERR_PTR(-EINVAL);
        /* Calculate record id of first and last block. */
        first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift;
        first_offs = sector_div(first_trk, blk_per_trk);
@@ -3210,8 +3222,10 @@ int dasd_eckd_pm_freeze(struct dasd_device *device)
 int dasd_eckd_restore_device(struct dasd_device *device)
 {
        struct dasd_eckd_private *private;
+       struct dasd_eckd_characteristics temp_rdc_data;
        int is_known, rc;
        struct dasd_uid temp_uid;
+       unsigned long flags;
 
        private = (struct dasd_eckd_private *) device->private;
 
@@ -3224,7 +3238,8 @@ int dasd_eckd_restore_device(struct dasd_device *device)
        rc = dasd_eckd_generate_uid(device, &private->uid);
        dasd_get_uid(device->cdev, &temp_uid);
        if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
-               dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
+               dev_err(&device->cdev->dev, "The UID of the DASD has "
+                       "changed\n");
        if (rc)
                goto out_err;
        dasd_set_uid(device->cdev, &private->uid);
@@ -3241,20 +3256,20 @@ int dasd_eckd_restore_device(struct dasd_device *device)
        }
 
        /* Read Feature Codes */
-       rc = dasd_eckd_read_features(device);
-       if (rc)
-               goto out_err;
+       dasd_eckd_read_features(device);
 
        /* Read Device Characteristics */
-       memset(&private->rdc_data, 0, sizeof(private->rdc_data));
        rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
-                                        &private->rdc_data, 64);
+                                        &temp_rdc_data, 64);
        if (rc) {
                DBF_EVENT(DBF_WARNING,
                          "Read device characteristics failed, rc=%d for "
                          "device: %s", rc, dev_name(&device->cdev->dev));
                goto out_err;
        }
+       spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+       memcpy(&private->rdc_data, &temp_rdc_data, sizeof(temp_rdc_data));
+       spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 
        /* add device to alias management */
        dasd_alias_add_device(device);