2 * Bogus Block Driver for PowerPC Full System Simulator
4 * (C) Copyright IBM Corporation 2003-2005
8 * Author: Eric Van Hensbegren <ericvh@gmail.com>
10 * inspired by drivers/block/nbd.c
11 * written by Pavel Machek and Steven Whitehouse
13 * Some code is from the IBM Full System Simulator Group in ARL
14 * Author: PAtrick Bohrer <IBM Austin Research Lab>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2, or (at your option)
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to:
28 * Free Software Foundation
29 * 51 Franklin Street, Fifth Floor
30 * Boston, MA 02111-1301 USA
34 #include <linux/major.h>
35 #include <linux/kernel.h>
36 #include <linux/module.h>
37 #include <linux/init.h>
38 #include <linux/sched.h>
40 #include <linux/stat.h>
41 #include <linux/errno.h>
42 #include <linux/file.h>
43 #include <linux/ioctl.h>
44 #include <linux/blkdev.h>
47 #include <asm/systemsim.h>
49 #include <linux/devfs_fs_kernel.h>
51 #include <asm/uaccess.h>
52 #include <asm/types.h>
57 #define MBD_SET_BLKSIZE _IO( 0xab, 1 )
58 #define MBD_SET_SIZE _IO( 0xab, 2 )
59 #define MBD_SET_SIZE_BLOCKS _IO( 0xab, 7 )
60 #define MBD_DISCONNECT _IO( 0xab, 8 )
69 static struct mbd_device mbd_dev[MAX_MBD];
71 #define BD_INFO_SYNC 0
72 #define BD_INFO_STATUS 1
73 #define BD_INFO_BLKSZ 2
74 #define BD_INFO_DEVSZ 3
75 #define BD_INFO_CHANGE 4
77 #define BOGUS_DISK_READ 116
78 #define BOGUS_DISK_WRITE 117
79 #define BOGUS_DISK_INFO 118
82 MamboBogusDiskRead(int devno, void *buf, ulong sect, ulong nrsect)
84 return callthru3(BOGUS_DISK_READ, (unsigned long)buf,
86 (unsigned long)((nrsect << 16) | devno));
90 MamboBogusDiskWrite(int devno, void *buf, ulong sect, ulong nrsect)
92 return callthru3(BOGUS_DISK_WRITE, (unsigned long)buf,
94 (unsigned long)((nrsect << 16) | devno));
97 static inline int MamboBogusDiskInfo(int op, int devno)
99 return callthru2(BOGUS_DISK_INFO, (unsigned long)op,
100 (unsigned long)devno);
103 static int mbd_init_disk(int devno)
105 struct gendisk *disk = mbd_dev[devno].disk;
111 /* check disk configured */
112 if (!MamboBogusDiskInfo(BD_INFO_STATUS, devno)) {
114 "Attempting to open bogus disk before initializaiton\n");
118 mbd_dev[devno].initialized++;
120 sz = MamboBogusDiskInfo(BD_INFO_DEVSZ, devno);
125 printk("Initializing disk %d with devsz %u\n", devno, sz);
127 set_capacity(disk, sz << 1);
132 static void do_mbd_request(request_queue_t * q)
137 while ((req = elv_next_request(q)) != NULL) {
138 int minor = req->rq_disk->first_minor;
140 switch (rq_data_dir(req)) {
142 result = MamboBogusDiskRead(minor,
143 req->buffer, req->sector,
144 req->current_nr_sectors);
147 result = MamboBogusDiskWrite(minor,
148 req->buffer, req->sector,
149 req->current_nr_sectors);
153 end_request(req, 0); /* failure */
155 end_request(req, 1); /* success */
159 static int mbd_release(struct inode *inode, struct file *file)
161 struct mbd_device *lo;
166 dev = inode->i_bdev->bd_disk->first_minor;
169 if (MamboBogusDiskInfo(BD_INFO_SYNC, dev) < 0) {
170 printk(KERN_ALERT "mbd_release: unable to sync\n");
174 printk(KERN_ALERT "mbd_release: refcount(%d) <= 0\n",
180 static int mbd_revalidate(struct gendisk *disk)
182 int devno = disk->first_minor;
184 mbd_init_disk(devno);
189 static int mbd_open(struct inode *inode, struct file *file)
195 dev = inode->i_bdev->bd_disk->first_minor;
199 check_disk_change(inode->i_bdev);
201 if (!mbd_dev[dev].initialized)
202 if (!mbd_init_disk(dev))
205 mbd_dev[dev].refcnt++;
209 static struct block_device_operations mbd_fops = {
213 /* media_changed: mbd_check_change, */
214 revalidate_disk:mbd_revalidate,
217 static spinlock_t mbd_lock = SPIN_LOCK_UNLOCKED;
219 static int __init mbd_init(void)
224 for (i = 0; i < MAX_MBD; i++) {
225 struct gendisk *disk = alloc_disk(1);
228 mbd_dev[i].disk = disk;
230 * The new linux 2.5 block layer implementation requires
231 * every gendisk to have its very own request_queue struct.
232 * These structs are big so we dynamically allocate them.
234 disk->queue = blk_init_queue(do_mbd_request, &mbd_lock);
241 if (register_blkdev(MAJOR_NR, "mbd")) {
246 printk("mambo bogus disk: registered device at major %d\n", MAJOR_NR);
248 printk("mambo bogus disk: compiled in with kernel\n");
251 devfs_mk_dir("mambobd");
252 for (i = 0; i < MAX_MBD; i++) { /* load defaults */
253 struct gendisk *disk = mbd_dev[i].disk;
254 mbd_dev[i].initialized = 0;
255 mbd_dev[i].refcnt = 0;
256 mbd_dev[i].flags = 0;
257 disk->major = MAJOR_NR;
258 disk->first_minor = i;
259 disk->fops = &mbd_fops;
260 disk->private_data = &mbd_dev[i];
261 sprintf(disk->disk_name, "mambobd%d", i);
262 sprintf(disk->devfs_name, "mambobd%d", i);
263 set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */
270 if (mbd_dev[i].disk->queue)
271 blk_cleanup_queue(mbd_dev[i].disk->queue);
272 put_disk(mbd_dev[i].disk);
277 static void __exit mbd_cleanup(void)
279 devfs_remove("mambobd");
281 if (unregister_blkdev(MAJOR_NR, "mbd") != 0)
282 printk("mbd: cleanup_module failed\n");
284 printk("mbd: module cleaned up.\n");
287 module_init(mbd_init);
288 module_exit(mbd_cleanup);
290 MODULE_DESCRIPTION("Mambo Block Device");
291 MODULE_LICENSE("GPL");