Merge branch 'for-3.20/core' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / s390 / block / dcssblk.c
index b550c8c..96128cb 100644 (file)
@@ -28,8 +28,8 @@
 static int dcssblk_open(struct block_device *bdev, fmode_t mode);
 static void dcssblk_release(struct gendisk *disk, fmode_t mode);
 static void dcssblk_make_request(struct request_queue *q, struct bio *bio);
-static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
-                                void **kaddr, unsigned long *pfn);
+static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
+                                void **kaddr, unsigned long *pfn, long size);
 
 static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
 
@@ -438,7 +438,13 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
                        pr_info("All DCSSs that map to device %s are "
                                "saved\n", dev_info->segment_name);
                        list_for_each_entry(entry, &dev_info->seg_list, lh) {
-                               segment_save(entry->segment_name);
+                               if (entry->segment_type == SEG_TYPE_EN ||
+                                   entry->segment_type == SEG_TYPE_SN)
+                                       pr_warn("DCSS %s is of type SN or EN"
+                                               " and cannot be saved\n",
+                                               entry->segment_name);
+                               else
+                                       segment_save(entry->segment_name);
                        }
                }  else {
                        // device is busy => we save it when it becomes
@@ -797,7 +803,12 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
                pr_info("Device %s has become idle and is being saved "
                        "now\n", dev_info->segment_name);
                list_for_each_entry(entry, &dev_info->seg_list, lh) {
-                       segment_save(entry->segment_name);
+                       if (entry->segment_type == SEG_TYPE_EN ||
+                           entry->segment_type == SEG_TYPE_SN)
+                               pr_warn("DCSS %s is of type SN or EN and cannot"
+                                       " be saved\n", entry->segment_name);
+                       else
+                               segment_save(entry->segment_name);
                }
                dev_info->save_pending = 0;
        }
@@ -866,25 +877,22 @@ fail:
        bio_io_error(bio);
 }
 
-static int
+static long
 dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
-                       void **kaddr, unsigned long *pfn)
+                       void **kaddr, unsigned long *pfn, long size)
 {
        struct dcssblk_dev_info *dev_info;
-       unsigned long pgoff;
+       unsigned long offset, dev_sz;
 
        dev_info = bdev->bd_disk->private_data;
        if (!dev_info)
                return -ENODEV;
-       if (secnum % (PAGE_SIZE/512))
-               return -EINVAL;
-       pgoff = secnum / (PAGE_SIZE / 512);
-       if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
-               return -ERANGE;
-       *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
+       dev_sz = dev_info->end - dev_info->start;
+       offset = secnum * 512;
+       *kaddr = (void *) (dev_info->start + offset);
        *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
 
-       return 0;
+       return dev_sz - offset;
 }
 
 static void