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 <asm/uaccess.h>
50 #include <asm/types.h>
55 #define MBD_SET_BLKSIZE _IO( 0xab, 1 )
56 #define MBD_SET_SIZE _IO( 0xab, 2 )
57 #define MBD_SET_SIZE_BLOCKS _IO( 0xab, 7 )
58 #define MBD_DISCONNECT _IO( 0xab, 8 )
67 static struct mbd_device mbd_dev[MAX_MBD];
69 #define BD_INFO_SYNC 0
70 #define BD_INFO_STATUS 1
71 #define BD_INFO_BLKSZ 2
72 #define BD_INFO_DEVSZ 3
73 #define BD_INFO_CHANGE 4
75 #define BOGUS_DISK_READ 116
76 #define BOGUS_DISK_WRITE 117
77 #define BOGUS_DISK_INFO 118
80 MamboBogusDiskRead(int devno, void *buf, ulong sect, ulong nrsect)
82 return callthru3(BOGUS_DISK_READ, (unsigned long)buf,
84 (unsigned long)((nrsect << 16) | devno));
88 MamboBogusDiskWrite(int devno, void *buf, ulong sect, ulong nrsect)
90 return callthru3(BOGUS_DISK_WRITE, (unsigned long)buf,
92 (unsigned long)((nrsect << 16) | devno));
95 static inline int MamboBogusDiskInfo(int op, int devno)
97 return callthru2(BOGUS_DISK_INFO, (unsigned long)op,
98 (unsigned long)devno);
101 static int mbd_init_disk(int devno)
103 struct gendisk *disk = mbd_dev[devno].disk;
109 /* check disk configured */
110 if (!MamboBogusDiskInfo(BD_INFO_STATUS, devno)) {
112 "Attempting to open bogus disk before initializaiton\n");
116 mbd_dev[devno].initialized++;
118 sz = MamboBogusDiskInfo(BD_INFO_DEVSZ, devno);
123 printk("Initializing disk %d with devsz %u\n", devno, sz);
125 set_capacity(disk, sz << 1);
130 static void do_mbd_request(request_queue_t * q)
135 while ((req = elv_next_request(q)) != NULL) {
136 int minor = req->rq_disk->first_minor;
138 switch (rq_data_dir(req)) {
140 result = MamboBogusDiskRead(minor,
141 req->buffer, req->sector,
142 req->current_nr_sectors);
145 result = MamboBogusDiskWrite(minor,
146 req->buffer, req->sector,
147 req->current_nr_sectors);
151 end_request(req, 0); /* failure */
153 end_request(req, 1); /* success */
157 static int mbd_release(struct inode *inode, struct file *file)
159 struct mbd_device *lo;
164 dev = inode->i_bdev->bd_disk->first_minor;
167 if (MamboBogusDiskInfo(BD_INFO_SYNC, dev) < 0) {
168 printk(KERN_ALERT "mbd_release: unable to sync\n");
172 printk(KERN_ALERT "mbd_release: refcount(%d) <= 0\n",
178 static int mbd_revalidate(struct gendisk *disk)
180 int devno = disk->first_minor;
182 mbd_init_disk(devno);
187 static int mbd_open(struct inode *inode, struct file *file)
193 dev = inode->i_bdev->bd_disk->first_minor;
197 check_disk_change(inode->i_bdev);
199 if (!mbd_dev[dev].initialized)
200 if (!mbd_init_disk(dev))
203 mbd_dev[dev].refcnt++;
207 static struct block_device_operations mbd_fops = {
211 /* media_changed: mbd_check_change, */
212 revalidate_disk:mbd_revalidate,
215 static spinlock_t mbd_lock = SPIN_LOCK_UNLOCKED;
217 static int __init mbd_init(void)
222 for (i = 0; i < MAX_MBD; i++) {
223 struct gendisk *disk = alloc_disk(1);
226 mbd_dev[i].disk = disk;
228 * The new linux 2.5 block layer implementation requires
229 * every gendisk to have its very own request_queue struct.
230 * These structs are big so we dynamically allocate them.
232 disk->queue = blk_init_queue(do_mbd_request, &mbd_lock);
239 if (register_blkdev(MAJOR_NR, "mbd")) {
244 printk("mambo bogus disk: registered device at major %d\n", MAJOR_NR);
246 printk("mambo bogus disk: compiled in with kernel\n");
249 for (i = 0; i < MAX_MBD; i++) { /* load defaults */
250 struct gendisk *disk = mbd_dev[i].disk;
251 mbd_dev[i].initialized = 0;
252 mbd_dev[i].refcnt = 0;
253 mbd_dev[i].flags = 0;
254 disk->major = MAJOR_NR;
255 disk->first_minor = i;
256 disk->fops = &mbd_fops;
257 disk->private_data = &mbd_dev[i];
258 sprintf(disk->disk_name, "mambobd%d", i);
259 set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */
266 if (mbd_dev[i].disk->queue)
267 blk_cleanup_queue(mbd_dev[i].disk->queue);
268 put_disk(mbd_dev[i].disk);
273 static void __exit mbd_cleanup(void)
275 if (unregister_blkdev(MAJOR_NR, "mbd") != 0)
276 printk("mbd: cleanup_module failed\n");
278 printk("mbd: module cleaned up.\n");
281 module_init(mbd_init);
282 module_exit(mbd_cleanup);
284 MODULE_DESCRIPTION("Mambo Block Device");
285 MODULE_LICENSE("GPL");