aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dcssblk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dcssblk.c')
-rw-r--r--drivers/s390/block/dcssblk.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 16ab8d363ac6..6bc27d52326f 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -35,14 +35,17 @@
35static int dcssblk_open(struct inode *inode, struct file *filp); 35static int dcssblk_open(struct inode *inode, struct file *filp);
36static int dcssblk_release(struct inode *inode, struct file *filp); 36static int dcssblk_release(struct inode *inode, struct file *filp);
37static int dcssblk_make_request(struct request_queue *q, struct bio *bio); 37static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
38static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
39 unsigned long *data);
38 40
39static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; 41static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
40 42
41static int dcssblk_major; 43static int dcssblk_major;
42static struct block_device_operations dcssblk_devops = { 44static struct block_device_operations dcssblk_devops = {
43 .owner = THIS_MODULE, 45 .owner = THIS_MODULE,
44 .open = dcssblk_open, 46 .open = dcssblk_open,
45 .release = dcssblk_release, 47 .release = dcssblk_release,
48 .direct_access = dcssblk_direct_access,
46}; 49};
47 50
48static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, 51static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
@@ -641,6 +644,20 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
641 /* Request beyond end of DCSS segment. */ 644 /* Request beyond end of DCSS segment. */
642 goto fail; 645 goto fail;
643 } 646 }
647 /* verify data transfer direction */
648 if (dev_info->is_shared) {
649 switch (dev_info->segment_type) {
650 case SEG_TYPE_SR:
651 case SEG_TYPE_ER:
652 case SEG_TYPE_SC:
653 /* cannot write to these segments */
654 if (bio_data_dir(bio) == WRITE) {
655 PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
656 goto fail;
657 }
658 }
659 }
660
644 index = (bio->bi_sector >> 3); 661 index = (bio->bi_sector >> 3);
645 bio_for_each_segment(bvec, bio, i) { 662 bio_for_each_segment(bvec, bio, i) {
646 page_addr = (unsigned long) 663 page_addr = (unsigned long)
@@ -661,7 +678,26 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
661 bio_endio(bio, bytes_done, 0); 678 bio_endio(bio, bytes_done, 0);
662 return 0; 679 return 0;
663fail: 680fail:
664 bio_io_error(bio, bytes_done); 681 bio_io_error(bio, bio->bi_size);
682 return 0;
683}
684
685static int
686dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
687 unsigned long *data)
688{
689 struct dcssblk_dev_info *dev_info;
690 unsigned long pgoff;
691
692 dev_info = bdev->bd_disk->private_data;
693 if (!dev_info)
694 return -ENODEV;
695 if (secnum % (PAGE_SIZE/512))
696 return -EINVAL;
697 pgoff = secnum / (PAGE_SIZE / 512);
698 if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
699 return -ERANGE;
700 *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);
665 return 0; 701 return 0;
666} 702}
667 703