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_submit_bio(struct bio
*bio
)
64 struct nfhd_device
*dev
= bio
->bi_disk
->private_data
;
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 .submit_bio
= nfhd_submit_bio
,
97 .getgeo
= nfhd_getgeo
,
100 static int __init
nfhd_init_one(int id
, u32 blocks
, u32 bsize
)
102 struct nfhd_device
*dev
;
103 int dev_id
= id
- NFHD_DEV_OFFSET
;
105 pr_info("nfhd%u: found device with %u blocks (%u bytes)\n", dev_id
,
108 if (bsize
< 512 || (bsize
& (bsize
- 1))) {
109 pr_warn("nfhd%u: invalid block size\n", dev_id
);
113 dev
= kmalloc(sizeof(struct nfhd_device
), GFP_KERNEL
);
118 dev
->blocks
= blocks
;
120 dev
->bshift
= ffs(bsize
) - 10;
122 dev
->queue
= blk_alloc_queue(NUMA_NO_NODE
);
123 if (dev
->queue
== NULL
)
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)
160 nfhd_id
= nf_get_id("XHDI");
164 ret
= register_blkdev(major_num
, "nfhd");
166 pr_warn("nfhd: unable to get major number\n");
173 for (i
= NFHD_DEV_OFFSET
; i
< 24; i
++) {
174 if (nfhd_get_capacity(i
, 0, &blocks
, &bsize
))
176 nfhd_init_one(i
, blocks
, bsize
);
182 static void __exit
nfhd_exit(void)
184 struct nfhd_device
*dev
, *next
;
186 list_for_each_entry_safe(dev
, next
, &nfhd_list
, list
) {
187 list_del(&dev
->list
);
188 del_gendisk(dev
->disk
);
190 blk_cleanup_queue(dev
->queue
);
193 unregister_blkdev(major_num
, "nfhd");
196 module_init(nfhd_init
);
197 module_exit(nfhd_exit
);
199 MODULE_LICENSE("GPL");