2 * Copyright 1996 The Australian National University.
3 * Copyright 1996 Fujitsu Laboratories Limited
5 * This software may be distributed under the terms of the Gnu
6 * Public License version 2 or later
9 * ap.c - Single AP1000 block driver.
11 * (C) dwalsh, Pious project, DCS, ANU 1996
13 * This block driver is designed to simply to perform
14 * io operations to the hosts file system.
16 * Heavily modified by tridge
20 #include <linux/errno.h>
21 #include <linux/types.h>
23 #include <linux/ext2_fs.h>
24 #include <linux/kernel.h>
25 #include <linux/major.h>
26 #include <linux/module.h>
27 #include <asm/uaccess.h>
28 #include <asm/ap1000/apservice.h>
32 #define MAJOR_NR APBLOCK_MAJOR
34 #include <linux/blk.h>
37 #define MAX_REQUESTS 1
39 static struct wait_queue
* busy_wait
= NULL
;
41 static int ap_blocksizes
[NUM_APDEVS
];
42 static int ap_length
[NUM_APDEVS
];
43 static int ap_fds
[NUM_APDEVS
];
45 #define SECTOR_BLOCK_SHIFT 9
46 #define AP_BLOCK_SHIFT 12 /* 4k blocks */
47 #define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
49 static volatile int request_count
= 0;
51 static void ap_release(struct inode
* inode
, struct file
* filp
)
56 static void ap_request(void)
58 struct cap_request creq
;
63 if (request_count
>= MAX_REQUESTS
) return;
71 if (MAJOR(CURRENT
->rq_dev
) != MAJOR_NR
) {
72 panic(DEVICE_NAME
": request list destroyed");
75 if (!buffer_locked(CURRENT
->bh
)) {
76 panic(DEVICE_NAME
": block not locked");
82 minor
= MINOR(req
->rq_dev
);
84 if (minor
>= NUM_APDEVS
) {
85 printk("apblock: request for invalid minor %d\n",minor
);
91 len
= req
->current_nr_sectors
;
93 if ((offset
+ len
) > ap_length
[minor
]) {
94 printk("apblock: request for invalid sectors %d -> %d\n",
100 if (ap_fds
[minor
] == -1) {
101 printk("apblock: minor %d not open\n",minor
);
106 /* convert to our units */
107 offset
<<= SECTOR_BLOCK_SHIFT
;
108 len
<<= SECTOR_BLOCK_SHIFT
;
110 /* setup a request for the host */
111 creq
.cid
= mpp_cid();
112 creq
.size
= sizeof(creq
);
114 creq
.data
[0] = (int)(req
);
115 creq
.data
[1] = ap_fds
[minor
];
116 creq
.data
[2] = offset
;
122 printk("apblock: read req=0x%x len=%d offset=%d\n",
125 creq
.type
= REQ_BREAD
;
126 if (bif_queue(&creq
,0,0)) {
133 printk("apblock: write req=0x%x len=%d offset=%d\n",
136 creq
.type
= REQ_BWRITE
;
138 if (bif_queue_nocopy(&creq
,req
->buffer
,creq
.size
- sizeof(creq
))) {
144 printk("apblock: unknown ap op %d\n",req
->cmd
);
149 if (++request_count
< MAX_REQUESTS
)
153 /* this is called by ap1000/bif.c when a read/write has completed */
154 void ap_complete(struct cap_request
*creq
)
157 struct request
*req
= (struct request
*)(creq
->data
[0]);
159 printk("request 0x%x complete\n",req
);
167 /* this is called by ap1000/bif.c to find a buffer to put a BREAD into
169 char *ap_buffer(struct cap_request
*creq
)
171 struct request
*req
= (struct request
*)(creq
->data
[0]);
177 static int ap_open(struct inode
* inode
, struct file
* filp
)
179 struct cap_request creq
;
181 minor
= DEVICE_NR(inode
->i_rdev
);
184 printk("ap_open: minor=%x\n", minor
);
187 if (minor
>= NUM_APDEVS
)
190 /* if its already open then don't do anything */
191 if (ap_fds
[minor
] != -1)
194 /* send the open request to the front end */
195 creq
.cid
= mpp_cid();
196 creq
.type
= REQ_BOPEN
;
198 creq
.size
= sizeof(creq
);
199 creq
.data
[0] = minor
;
201 bif_queue(&creq
,0,0);
203 /* wait for the reply */
204 while (ap_fds
[minor
] == -1)
205 sleep_on(&busy_wait
);
211 static int ap_ioctl(struct inode
*inode
, struct file
*file
,
212 unsigned int cmd
, unsigned long arg
)
214 if (!inode
|| !inode
->i_rdev
)
218 case BLKGETSIZE
: /* Return device size */
219 if (put_user(ap_length
[MINOR(inode
->i_rdev
)],(long *) arg
))
231 /* this is called by ap1000/bif.c when a open reply comes in */
232 void ap_open_reply(struct cap_request
*creq
)
234 int minor
= creq
->data
[0];
236 ap_fds
[minor
] = creq
->data
[1];
237 ap_length
[minor
] = creq
->data
[2] >> SECTOR_BLOCK_SHIFT
;
240 printk("ap opened minor %d length=%d fd=%d\n",
241 minor
,ap_length
[minor
],ap_fds
[minor
]);
247 static struct file_operations ap_fops
= {
248 NULL
, /* lseek - default */
249 block_read
, /* read - general block-dev read */
250 block_write
, /* write - general block-dev write */
251 NULL
, /* readdir - bad */
253 ap_ioctl
, /* ioctl */
257 ap_release
, /* module needs to decrement use count */
258 block_fsync
, /* fsync */
269 if (register_blkdev(MAJOR_NR
,"apblock",&ap_fops
)) {
270 printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR
);
273 printk("ap_init: register dev %d\n", MAJOR_NR
);
274 blk_dev
[MAJOR_NR
].request_fn
= &ap_request
;
276 for (i
=0;i
<NUM_APDEVS
;i
++) {
277 ap_blocksizes
[i
] = AP_BLOCK_SIZE
;
282 blksize_size
[MAJOR_NR
] = ap_blocksizes
;
284 read_ahead
[MAJOR_NR
] = 32; /* 16k read ahead */
289 /* loadable module support */
293 int init_module(void)
295 int error
= ap_init();
297 printk(KERN_INFO
"APBLOCK: Loaded as module.\n");
301 /* Before freeing the module, invalidate all of the protected buffers! */
302 void cleanup_module(void)
306 for (i
= 0 ; i
< NUM_APDEVS
; i
++)
307 invalidate_buffers(MKDEV(MAJOR_NR
, i
));
309 unregister_blkdev( MAJOR_NR
, "apblock" );
310 blk_dev
[MAJOR_NR
].request_fn
= 0;