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 void 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
,
82 static int nfhd_getgeo(struct block_device
*bdev
, struct hd_geometry
*geo
)
84 struct nfhd_device
*dev
= bdev
->bd_disk
->private_data
;
86 geo
->cylinders
= dev
->blocks
>> (6 - dev
->bshift
);
93 static const struct block_device_operations nfhd_ops
= {
95 .getgeo
= nfhd_getgeo
,
98 static int __init
nfhd_init_one(int id
, u32 blocks
, u32 bsize
)
100 struct nfhd_device
*dev
;
101 int dev_id
= id
- NFHD_DEV_OFFSET
;
103 pr_info("nfhd%u: found device with %u blocks (%u bytes)\n", dev_id
,
106 if (bsize
< 512 || (bsize
& (bsize
- 1))) {
107 pr_warn("nfhd%u: invalid block size\n", dev_id
);
111 dev
= kmalloc(sizeof(struct nfhd_device
), GFP_KERNEL
);
116 dev
->blocks
= blocks
;
118 dev
->bshift
= ffs(bsize
) - 10;
120 dev
->queue
= blk_alloc_queue(GFP_KERNEL
);
121 if (dev
->queue
== NULL
)
124 dev
->queue
->queuedata
= dev
;
125 blk_queue_make_request(dev
->queue
, nfhd_make_request
);
126 blk_queue_logical_block_size(dev
->queue
, bsize
);
128 dev
->disk
= alloc_disk(16);
132 dev
->disk
->major
= major_num
;
133 dev
->disk
->first_minor
= dev_id
* 16;
134 dev
->disk
->fops
= &nfhd_ops
;
135 dev
->disk
->private_data
= dev
;
136 sprintf(dev
->disk
->disk_name
, "nfhd%u", dev_id
);
137 set_capacity(dev
->disk
, (sector_t
)blocks
* (bsize
/ 512));
138 dev
->disk
->queue
= dev
->queue
;
142 list_add_tail(&dev
->list
, &nfhd_list
);
147 blk_cleanup_queue(dev
->queue
);
154 static int __init
nfhd_init(void)
159 nfhd_id
= nf_get_id("XHDI");
163 major_num
= register_blkdev(major_num
, "nfhd");
164 if (major_num
<= 0) {
165 pr_warn("nfhd: unable to get major number\n");
169 for (i
= NFHD_DEV_OFFSET
; i
< 24; i
++) {
170 if (nfhd_get_capacity(i
, 0, &blocks
, &bsize
))
172 nfhd_init_one(i
, blocks
, bsize
);
178 static void __exit
nfhd_exit(void)
180 struct nfhd_device
*dev
, *next
;
182 list_for_each_entry_safe(dev
, next
, &nfhd_list
, list
) {
183 list_del(&dev
->list
);
184 del_gendisk(dev
->disk
);
186 blk_cleanup_queue(dev
->queue
);
189 unregister_blkdev(major_num
, "nfhd");
192 module_init(nfhd_init
);
193 module_exit(nfhd_exit
);
195 MODULE_LICENSE("GPL");