2 * ARAnyM block device driver
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive
9 #include <linux/module.h>
10 #include <linux/moduleparam.h>
11 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/types.h>
16 #include <linux/genhd.h>
17 #include <linux/blkdev.h>
18 #include <linux/hdreg.h>
19 #include <linux/slab.h>
21 #include <asm/natfeat.h>
26 /* emulation entry points */
28 NFHD_GET_CAPACITY
= 14,
30 /* skip ACSI devices */
34 static inline s32
nfhd_read_write(u32 major
, u32 minor
, u32 rwflag
, u32 recno
,
37 return nf_call(nfhd_id
+ NFHD_READ_WRITE
, major
, minor
, rwflag
, recno
,
41 static inline s32
nfhd_get_capacity(u32 major
, u32 minor
, u32
*blocks
,
44 return nf_call(nfhd_id
+ NFHD_GET_CAPACITY
, major
, minor
,
45 virt_to_phys(blocks
), virt_to_phys(blocksize
));
48 static LIST_HEAD(nfhd_list
);
51 module_param(major_num
, int, 0);
54 struct list_head list
;
58 struct request_queue
*queue
;
62 static blk_qc_t
nfhd_make_request(struct request_queue
*queue
, struct bio
*bio
)
64 struct nfhd_device
*dev
= queue
->queuedata
;
66 struct bvec_iter iter
;
68 sector_t sec
= bio
->bi_iter
.bi_sector
;
70 dir
= bio_data_dir(bio
);
72 bio_for_each_segment(bvec
, bio
, iter
) {
75 nfhd_read_write(dev
->id
, 0, dir
, sec
>> shift
, len
>> shift
,
76 page_to_phys(bvec
.bv_page
) + bvec
.bv_offset
);
83 static int nfhd_getgeo(struct block_device
*bdev
, struct hd_geometry
*geo
)
85 struct nfhd_device
*dev
= bdev
->bd_disk
->private_data
;
87 geo
->cylinders
= dev
->blocks
>> (6 - dev
->bshift
);
94 static const struct block_device_operations nfhd_ops
= {
96 .getgeo
= nfhd_getgeo
,
99 static int __init
nfhd_init_one(int id
, u32 blocks
, u32 bsize
)
101 struct nfhd_device
*dev
;
102 int dev_id
= id
- NFHD_DEV_OFFSET
;
104 pr_info("nfhd%u: found device with %u blocks (%u bytes)\n", dev_id
,
107 if (bsize
< 512 || (bsize
& (bsize
- 1))) {
108 pr_warn("nfhd%u: invalid block size\n", dev_id
);
112 dev
= kmalloc(sizeof(struct nfhd_device
), GFP_KERNEL
);
117 dev
->blocks
= blocks
;
119 dev
->bshift
= ffs(bsize
) - 10;
121 dev
->queue
= blk_alloc_queue(GFP_KERNEL
);
122 if (dev
->queue
== NULL
)
125 dev
->queue
->queuedata
= dev
;
126 blk_queue_make_request(dev
->queue
, nfhd_make_request
);
127 blk_queue_logical_block_size(dev
->queue
, bsize
);
129 dev
->disk
= alloc_disk(16);
133 dev
->disk
->major
= major_num
;
134 dev
->disk
->first_minor
= dev_id
* 16;
135 dev
->disk
->fops
= &nfhd_ops
;
136 dev
->disk
->private_data
= dev
;
137 sprintf(dev
->disk
->disk_name
, "nfhd%u", dev_id
);
138 set_capacity(dev
->disk
, (sector_t
)blocks
* (bsize
/ 512));
139 dev
->disk
->queue
= dev
->queue
;
143 list_add_tail(&dev
->list
, &nfhd_list
);
148 blk_cleanup_queue(dev
->queue
);
155 static int __init
nfhd_init(void)
161 nfhd_id
= nf_get_id("XHDI");
165 ret
= register_blkdev(major_num
, "nfhd");
167 pr_warn("nfhd: unable to get major number\n");
174 for (i
= NFHD_DEV_OFFSET
; i
< 24; i
++) {
175 if (nfhd_get_capacity(i
, 0, &blocks
, &bsize
))
177 nfhd_init_one(i
, blocks
, bsize
);
183 static void __exit
nfhd_exit(void)
185 struct nfhd_device
*dev
, *next
;
187 list_for_each_entry_safe(dev
, next
, &nfhd_list
, list
) {
188 list_del(&dev
->list
);
189 del_gendisk(dev
->disk
);
191 blk_cleanup_queue(dev
->queue
);
194 unregister_blkdev(major_num
, "nfhd");
197 module_init(nfhd_init
);
198 module_exit(nfhd_exit
);
200 MODULE_LICENSE("GPL");