diff options
Diffstat (limited to 'drivers/ap1000/ddv.c')
-rw-r--r-- | drivers/ap1000/ddv.c | 1008 |
1 files changed, 0 insertions, 1008 deletions
diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c deleted file mode 100644 index 3e32c9c83..000000000 --- a/drivers/ap1000/ddv.c +++ /dev/null @@ -1,1008 +0,0 @@ - /* - * Copyright 1996 The Australian National University. - * Copyright 1996 Fujitsu Laboratories Limited - * - * This software may be distributed under the terms of the Gnu - * Public License version 2 or later - */ -/* - * ddv.c - Single AP1000 block driver. - * - * This block driver performs io operations to the ddv option - * board. (Hopefully:) - * - */ - -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/fs.h> -#include <linux/ext2_fs.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/mm.h> -#include <linux/malloc.h> -#define __KERNEL_SYSCALLS__ -#include <linux/unistd.h> -#include <linux/sched.h> -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <linux/module.h> -#include <asm/ap1000/apreg.h> -#include <asm/ap1000/DdvReqTable.h> - -#define MAJOR_NR DDV_MAJOR - -#include <linux/blk.h> -#include <linux/genhd.h> -#include <linux/hdreg.h> - -#define DDV_DEBUG 0 -#define AIR_DISK 1 - -#define SECTOR_SIZE 512 - -/* we can have lots of partitions */ -#define PARTN_BITS 6 -#define NUM_DDVDEVS (1<<PARTN_BITS) - -#define PARDISK_BASE (1<<5) /* partitions above this number are - striped across all the cells */ -#define STRIPE_SHIFT 6 -#define STRIPE_SECTORS (1<<STRIPE_SHIFT) /* number of sectors per stripe */ - -#define MAX_BNUM 16 -#define MAX_REQUEST (TABLE_SIZE - 2) -#define REQUEST_LOW 16 -#define REQUEST_HIGH 4 - - -/* we fake up a block size larger than the physical block size to try - to make things a bit more efficient */ -#define SECTOR_BLOCK_SHIFT 9 - -#define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1) - -/* try to read ahead a bit */ -#define DDV_READ_AHEAD 64 - -static int have_ddv_board = 1; -static unsigned num_options = 0; -static unsigned this_option = 0; - -extern int ddv_get_mlist(unsigned mptr[],int bnum); -extern int ddv_set_request(struct request *req, - int request_type,int bnum,int mlist,int len,int offset); -extern void ddv_load_kernel(char *opcodep); -extern int ddv_restart_cpu(void); -extern int ddv_mlist_available(void); -static int ddv_revalidate(kdev_t dev, struct gendisk *gdev); -static void ddv_geninit(void); -static void ddv_release(struct inode * inode, struct file * filp); -static void ddv_request1(void); - - -static char *ddv_opcodep = NULL; -static struct request *next_request = NULL; - -static DECLARE_WAIT_QUEUE_HEAD(busy_wait); - -static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */ -int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */ -int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */ - -/* these are used by the ddv_daemon, which services remote disk requests */ -static struct remote_request *rem_queue = NULL; -static struct remote_request *rem_queue_end; -static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait); - -static int opiu_kernel_loaded = 0; - -static struct { - unsigned reads, writes, blocks, rq_started, rq_finished, errors; - unsigned sectors_read, sectors_written; -} ddv_stats; - -static struct hd_struct partition_tables[NUM_DDVDEVS]; - -static struct gendisk ddv_gendisk = { - MAJOR_NR, /* Major number */ - DEVICE_NAME, /* Major name */ - PARTN_BITS, /* Bits to shift to get real from partition */ - 1 << PARTN_BITS, /* Number of partitions per real */ - partition_tables,/* hd struct */ - ddv_blk_length, /* block sizes */ - 1, /* number */ - (void *) NULL, /* internal */ - NULL /* next */ -}; - -struct ddv_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; - -static struct ddv_geometry ddv_geometry; - - -struct remote_request { - union { - struct remote_request *next; - void (*fn)(void); - } u; - unsigned bnum; /* how many blocks does this contain */ - struct request *reqp; /* pointer to the request on the original cell */ - unsigned cell; /* what cell is the request from */ - struct request req; /* details of the request */ -}; - - -static void ddv_set_optadr(void) -{ - unsigned addr = 0x11000000; - OPT_IO(OBASE) = addr; - MSC_IO(MSC_OPTADR) = - ((addr & 0xff000000)>>16) | - ((OPTION_BASE & 0xf0000000)>>24) | - ((OPTION_BASE + 0x10000000)>>28); - OPT_IO(PRST) = 0; -} - -extern struct RequestTable *RTable; -extern struct OPrintBufArray *PrintBufs; -extern struct OAlignBufArray *AlignBufs; -extern struct DiskInfo *DiskInfo; - -static void ddv_release(struct inode * inode, struct file * filp) -{ -#if DEBUG - printk("ddv_release started\n"); -#endif -#if DEBUG - printk("ddv_release done\n"); -#endif -} - - -static unsigned in_request = 0; -static unsigned req_queued = 0; - -static void ddv_end_request(int uptodate,struct request *req) -{ - struct buffer_head * bh; - - ddv_stats.rq_finished++; - -/* printk("ddv_end_request(%d,%p)\n",uptodate,req); */ - - req->errors = 0; - if (!uptodate) { - printk("end_request: I/O error, dev %s, sector %lu\n", - kdevname(req->rq_dev), req->sector); - req->nr_sectors--; - req->nr_sectors &= ~SECTOR_MASK; - req->sector += (BLOCK_SIZE / SECTOR_SIZE); - req->sector &= ~SECTOR_MASK; - ddv_stats.errors++; - } - - if ((bh = req->bh) != NULL) { - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); - if ((bh = req->bh) != NULL) { - req->current_nr_sectors = bh->b_size >> 9; - if (req->nr_sectors < req->current_nr_sectors) { - req->nr_sectors = req->current_nr_sectors; - printk("end_request: buffer-list destroyed\n"); - } - req->buffer = bh->b_data; - printk("WARNING: ddv: more sectors!\n"); - ddv_stats.errors++; - return; - } - } - if (req->sem != NULL) - up(req->sem); - req->rq_status = RQ_INACTIVE; - wake_up(&wait_for_request); -} - - -/* check that a request is all OK to process */ -static int request_ok(struct request *req) -{ - int minor; - if (!req) return 0; - - if (MAJOR(req->rq_dev) != MAJOR_NR) - panic(DEVICE_NAME ": bad major number\n"); - if (!buffer_locked(req->bh)) - panic(DEVICE_NAME ": block not locked"); - - minor = MINOR(req->rq_dev); - if (minor >= NUM_DDVDEVS) { - printk("ddv_request: Invalid minor (%d)\n", minor); - return 0; - } - - if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) { - printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n", - minor,(int)req->sector,(int)req->current_nr_sectors, - ddv_sect_length[minor]); - return 0; - } - - if (req->cmd != READ && req->cmd != WRITE) { - printk("unknown request type %d\n",req->cmd); - return 0; - } - - /* it seems to be OK */ - return 1; -} - - -static void complete_request(struct request *req,int bnum) -{ - while (bnum--) { - ddv_end_request(1,req); - req = req->next; - } -} - - -static int completion_pointer = 0; - -static void check_completion(void) -{ - int i,bnum; - struct request *req; - - if (!RTable) return; - - for (; - (i=completion_pointer) != RTable->ddv_pointer && - RTable->async_info[i].status == DDV_REQ_FREE; - completion_pointer = INC_T(completion_pointer)) - { - req = (struct request *)RTable->async_info[i].argv[7]; - bnum = RTable->async_info[i].bnum; - if (!req || !bnum) { - printk("%s(%d)\n",__FILE__,__LINE__); - ddv_stats.errors++; - continue; - } - - RTable->async_info[i].status = 0; - RTable->async_info[i].argv[7] = 0; - - complete_request(req,bnum); - in_request--; - } -} - - -static struct request *get_request_queue(struct request *oldq) -{ - struct request *req,*req2; - - /* skip any non-active or bad requests */ - skip1: - if (!(req = CURRENT)) - return oldq; - - if (req->rq_status != RQ_ACTIVE) { - CURRENT = req->next; - goto skip1; - } - - if (!request_ok(req)) { - ddv_end_request(0,req); - CURRENT = req->next; - goto skip1; - } - - /* now grab as many as we can */ - req_queued++; - - for (req2 = req; - req2->next && - req2->next->rq_status == RQ_ACTIVE && - request_ok(req2->next); - req2 = req2->next) - req_queued++; - - /* leave CURRENT pointing at the bad ones */ - CURRENT = req2->next; - - /* chop our list at that point */ - req2->next = NULL; - - if (!oldq) - return req; - - for (req2=oldq;req2->next;req2=req2->next) ; - - req2->next = req; - - return oldq; -} - - -static void ddv_rem_complete(struct remote_request *rem) -{ - unsigned flags; - int bnum = rem->bnum; - struct request *req = rem->reqp; - - complete_request(req,bnum); - in_request--; - - save_flags(flags); cli(); - ddv_request1(); - restore_flags(flags); -} - - -/* - * The background ddv daemon. This receives remote disk requests - * and processes them via the normal block operations - */ -static int ddv_daemon(void *unused) -{ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "ddv_daemon"); - spin_lock_irq(¤t->sigmask_lock); - sigfillset(¤t->blocked); /* block all signals */ - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - /* Give it a realtime priority. */ - current->policy = SCHED_FIFO; - current->priority = 32; /* Fixme --- we need to standardise our - namings for POSIX.4 realtime scheduling - priorities. */ - - printk("Started ddv_daemon\n"); - - while (1) { - struct remote_request *rem; - unsigned flags; - struct buffer_head *bhlist[MAX_BNUM*4]; - int i,j,minor,len,shift,offset; - - save_flags(flags); cli(); - - while (!rem_queue) { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&ddv_daemon_wait); - __sti(); cli(); - } - - rem = rem_queue; - rem_queue = rem->u.next; - restore_flags(flags); - - - minor = MINOR(rem->req.rq_dev); - len = rem->req.current_nr_sectors; - offset = rem->req.sector; - - /* work out the conversion to the local block size from - sectors */ - for (shift=0; - (SECTOR_SIZE<<shift) != ddv_blocksizes[minor]; - shift++) ; - - /* do the request */ - for (i=0; len; i++) { - bhlist[i] = getblk(rem->req.rq_dev, - offset >> shift, - ddv_blocksizes[minor]); - if (!buffer_uptodate(bhlist[i])) - ll_rw_block(READ,1,&bhlist[i]); - offset += 1<<shift; - len -= 1<<shift; - } - - for (j=0;j<i;j++) - if (!buffer_uptodate(bhlist[j])) - wait_on_buffer(bhlist[j]); - - - /* put() the data */ - - - /* release the buffers */ - for (j=0;j<i;j++) - brelse(bhlist[j]); - - /* tell the originator that its done */ - rem->u.fn = ddv_rem_complete; - tnet_rpc(rem->cell,rem,sizeof(int)*3,1); - } -} - - -/* receive a remote disk request */ -static void ddv_rem_queue(char *data,unsigned size) -{ - unsigned flags; - struct remote_request *rem = (struct remote_request *) - kmalloc(size,GFP_ATOMIC); - - if (!rem) { - /* oh bugger! */ - ddv_stats.errors++; - return; - } - - memcpy(rem,data,size); - rem->u.next = NULL; - - save_flags(flags); cli(); - - /* add it to our remote request queue */ - if (!rem_queue) - rem_queue = rem; - else - rem_queue_end->u.next = rem; - rem_queue_end = rem; - - restore_flags(flags); - - wake_up(&ddv_daemon_wait); -} - - -/* which disk should this request go to */ -static inline unsigned pardisk_num(struct request *req) -{ - int minor = MINOR(req->rq_dev); - unsigned stripe; - unsigned cell; - - if (minor < PARDISK_BASE) - return this_option; - - stripe = req->sector >> STRIPE_SHIFT; - cell = stripe % num_options; - - return cell; -} - - -/* check if a 2nd request can be tacked onto the first */ -static inline int contiguous(struct request *req1,struct request *req2) -{ - if (req2->cmd != req1->cmd || - req2->rq_dev != req1->rq_dev || - req2->sector != req1->sector + req1->current_nr_sectors || - req2->current_nr_sectors != req1->current_nr_sectors) - return 0; - if (pardisk_num(req1) != pardisk_num(req2)) - return 0; - return 1; -} - -static void ddv_request1(void) -{ - struct request *req,*req1,*req2; - unsigned offset,len,req_num,mlist,bnum,available=0; - static unsigned mptrs[MAX_BNUM]; - unsigned cell; - - if (in_request > REQUEST_HIGH) - return; - - next_request = get_request_queue(next_request); - - while ((req = next_request)) { - int minor; - - if (in_request >= MAX_REQUEST) - return; - - if (in_request>1 && req_queued<REQUEST_LOW) - return; - - /* make sure we have room for a request */ - available = ddv_mlist_available(); - if (available < 1) return; - if (available > MAX_BNUM) - available = MAX_BNUM; - - offset = req->sector; - len = req->current_nr_sectors; - minor = MINOR(req->rq_dev); - - mptrs[0] = (int)req->buffer; - - for (bnum=1,req1=req,req2=req->next; - req2 && bnum<available && contiguous(req1,req2); - req1=req2,req2=req2->next) { - mptrs[bnum++] = (int)req2->buffer; - } - - next_request = req2; - - - req_queued -= bnum; - ddv_stats.blocks += bnum; - ddv_stats.rq_started += bnum; - - if (req->cmd == READ) { - ddv_stats.reads++; - ddv_stats.sectors_read += len*bnum; - } else { - ddv_stats.writes++; - ddv_stats.sectors_written += len*bnum; - } - - if (minor >= PARDISK_BASE) { - /* translate the request to the normal partition */ - unsigned stripe; - minor -= PARDISK_BASE; - - stripe = offset >> STRIPE_SHIFT; - stripe /= num_options; - offset = (stripe << STRIPE_SHIFT) + - (offset & ((1<<STRIPE_SHIFT)-1)); -#if AIR_DISK - /* like an air-guitar :-) */ - complete_request(req,bnum); - continue; -#endif - } - - if ((cell=pardisk_num(req)) != this_option) { - /* its a remote request */ - struct remote_request *rem; - unsigned *remlist; - unsigned size = sizeof(*rem) + sizeof(int)*bnum; - - rem = (struct remote_request *)kmalloc(size,GFP_ATOMIC); - if (!rem) { - /* hopefully we can get it on the next go */ - return; - } - remlist = (unsigned *)(rem+1); - - rem->u.fn = ddv_rem_queue; - rem->cell = this_option; - rem->bnum = bnum; - rem->req = *req; - rem->reqp = req; - rem->req.rq_dev = MKDEV(MAJOR_NR,minor); - rem->req.sector = offset; - memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum); - - if (tnet_rpc(cell,rem,size,1) != 0) { - kfree_s(rem,size); - return; - } - } else { - /* its a local request */ - if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) { - ddv_stats.errors++; - panic("ddv: mlist corrupted"); - } - - req_num = RTable->cell_pointer; - RTable->async_info[req_num].status = - req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ; - RTable->async_info[req_num].bnum = bnum; - RTable->async_info[req_num].argv[0] = mlist; - RTable->async_info[req_num].argv[1] = len; - RTable->async_info[req_num].argv[2] = offset + - partition_tables[minor].start_sect; - RTable->async_info[req_num].argv[3] = bnum; - RTable->async_info[req_num].argv[7] = (unsigned)req; - RTable->cell_pointer = INC_T(RTable->cell_pointer); - - } - - in_request++; - } -} - - -static void ddv_request(request_queue_t * q) -{ - cli(); - ddv_request1(); - sti(); -} - - -static void check_printbufs(void) -{ - int i; - - if (!PrintBufs) return; - - while (PrintBufs->option_counter != PrintBufs->cell_counter) { - i = PrintBufs->cell_counter; - printk("opiu (%d): ",i); - if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000) - printk("Error: bad format in printk at %p\n", - PrintBufs->bufs[i].fmt); - else - printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE, - PrintBufs->bufs[i].args[0], - PrintBufs->bufs[i].args[1], - PrintBufs->bufs[i].args[2], - PrintBufs->bufs[i].args[3], - PrintBufs->bufs[i].args[4], - PrintBufs->bufs[i].args[5]); - if (++PrintBufs->cell_counter == PRINT_BUFS) - PrintBufs->cell_counter = 0; - } -} - -static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - save_flags(flags); cli(); - OPT_IO(IRC1) = 0x80000000; - - check_printbufs(); - check_completion(); - - ddv_request1(); - restore_flags(flags); -} - -static int ddv_open(struct inode * inode, struct file * filp) -{ - int minor = MINOR(inode->i_rdev); - - if (!have_ddv_board || minor >= NUM_DDVDEVS) - return -ENODEV; - - if (minor >= PARDISK_BASE) { - ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE]; - ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE]; - } - - return 0; -} - - -static void ddv_open_reply(struct cap_request *creq) -{ - int size = creq->size - sizeof(*creq); - ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC); - read_bif(ddv_opcodep, size); -#if DEBUG - printk("received opiu kernel of size %d\n",size); -#endif - if (size == 0) - have_ddv_board = 0; - wake_up(&busy_wait); -} - -extern struct block_device_operations ddv_fops; - -static void ddv_load_opiu(void) -{ - int i; - struct cap_request creq; - - /* if the opiu kernel is already loaded then we don't do anything */ - if (!have_ddv_board || opiu_kernel_loaded) - return; - - bif_register_request(REQ_DDVOPEN,ddv_open_reply); - - /* send the open request to the front end */ - creq.cid = mpp_cid(); - creq.type = REQ_DDVOPEN; - creq.header = 0; - creq.size = sizeof(creq); - - bif_queue(&creq,0,0); - - ddv_set_optadr(); - - while (!ddv_opcodep) - sleep_on(&busy_wait); - - if (!have_ddv_board) - return; - - ddv_load_kernel(ddv_opcodep); - - kfree(ddv_opcodep); - ddv_opcodep = NULL; - - if (ddv_restart_cpu()) - return; - - ddv_sect_length[0] = DiskInfo->blocks; - ddv_blk_length[0] = DiskInfo->blocks >> 1; - ddv_blocksizes[0] = BLOCK_SIZE; - - ddv_geometry.cylinders = ddv_sect_length[0] / - (ddv_geometry.heads*ddv_geometry.sectors); - - register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<<PARTN_BITS, - &ddv_fops, ddv_sect_length[0]); - - /* FIXME. The crap below is, well, crap. Pseudo-RAID and unsafe one */ - for (i=0;i<PARDISK_BASE;i++) { - ddv_sect_length[i] = ddv_gendisk.part[i].nr_sects; - ddv_blk_length[i] = ddv_gendisk.part[i].nr_sects >> 1; - } - - /* setup the parallel partitions by multiplying the normal - partition by the number of options */ - for (;i<NUM_DDVDEVS;i++) { - ddv_sect_length[i] = ddv_sect_length[i-PARDISK_BASE]*num_options; - ddv_blk_length[i] = ddv_blk_length[i-PARDISK_BASE]*num_options; - ddv_gendisk.part[i].start_sect = ddv_gendisk.part[i-PARDISK_BASE].start_sect; - ddv_gendisk.part[i].nr_sects = ddv_sect_length[i]; - } - - - opiu_kernel_loaded = 1; -} - - -/* - * This routine is called to flush all partitions and partition tables - * for a changed disk, and then re-read the new partition table. - */ -static int ddv_revalidate(kdev_t dev, struct gendisk *gdev) -{ - int target; - int max_p; - int start; - int i; - - target = DEVICE_NR(dev); - - max_p = gdev->max_p; - start = target << gdev->minor_shift; - - printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n", - dev,target,max_p,start); - - for (i=max_p - 1; i >=0 ; i--) { - int minor = start + i; - kdev_t devi = MKDEV(gdev->major, minor); - sync_dev(devi); - invalidate_inodes(devi); - invalidate_buffers(devi); - gdev->part[minor].start_sect = 0; - gdev->part[minor].nr_sects = 0; - }; - - ddv_sect_length[start] = DiskInfo->blocks; - ddv_blk_length[start] = DiskInfo->blocks >> 1; - - grok_partitions(gdev, target, 1<<PARTN_BITS, ddv_sect_length[start]); - - printk("sect_length[%d]=%d blk_length[%d]=%d\n", - start,ddv_sect_length[start], - start,ddv_blk_length[start]); - - for (i=0;i<max_p;i++) { - ddv_sect_length[start+i] = gdev->part[start+i].nr_sects; - ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1; - if (gdev->part[start+i].nr_sects) - printk("partition[%d] start=%d length=%d\n",i, - (int)gdev->part[start+i].start_sect, - (int)gdev->part[start+i].nr_sects); - } - - return 0; -} - - - - -static int ddv_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int err; - struct ddv_geometry *loc = (struct ddv_geometry *) arg; - int dev; - int minor = MINOR(inode->i_rdev); - - if ((!inode) || !(inode->i_rdev)) - return -EINVAL; - dev = DEVICE_NR(inode->i_rdev); -#if DEBUG - printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor); -#endif - switch (cmd) { - case HDIO_GETGEO: - printk("\tHDIO_GETGEO\n"); - if (!loc) return -EINVAL; - if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT; - if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT; - if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT; - if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT; - return 0; - - case HDIO_GET_MULTCOUNT : - printk("\tHDIO_GET_MULTCOUNT\n"); - return -EINVAL; - - case HDIO_GET_IDENTITY : - printk("\tHDIO_GET_IDENTITY\n"); - return -EINVAL; - - case HDIO_GET_NOWERR : - printk("\tHDIO_GET_NOWERR\n"); - return -EINVAL; - - case HDIO_SET_NOWERR : - printk("\tHDIO_SET_NOWERR\n"); - return -EINVAL; - - case BLKRRPART: - printk("\tBLKRRPART\n"); - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - return ddv_revalidate(inode->i_rdev,&ddv_gendisk); - - case BLKGETSIZE: /* Return device size */ - if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT; -#if DEBUG - printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]); -#endif - return 0; - - default: - printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd); - return -EINVAL; - }; -} - -static struct block_device_operations ddv_fops = { - open: ddv_open, - release: ddv_release, - ioctl: ddv_ioctl, -}; - - -static void ddv_status(void) -{ - if (!have_ddv_board) { - printk("no ddv board\n"); - return; - } - - printk(" -in_request %u req_queued %u -MTable: start=%u end=%u -Requests: started=%u finished=%u -Requests: completion_pointer=%u ddv_pointer=%u cell_pointer=%u -PrintBufs: option_counter=%u cell_counter=%u -ddv_stats: reads=%u writes=%u blocks=%u -ddv_stats: sectors_read=%u sectors_written=%u -CURRENT=%p next_request=%p errors=%u -", - in_request,req_queued, - RTable->start_mtable,RTable->end_mtable, - ddv_stats.rq_started,ddv_stats.rq_finished, - completion_pointer,RTable->ddv_pointer,RTable->cell_pointer, - PrintBufs->option_counter,PrintBufs->cell_counter, - ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks, - ddv_stats.sectors_read,ddv_stats.sectors_written, - CURRENT,next_request, - ddv_stats.errors); -} - - -int ddv_init(void) -{ - int cid; - - cid = mpp_cid(); - - if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) { - printk("ap: unable to get major %d for ap block dev\n", - MAJOR_NR); - return -1; - } - - printk("ddv_init: register dev %d\n", MAJOR_NR); - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); - read_ahead[MAJOR_NR] = DDV_READ_AHEAD; - - bif_add_debug_key('d',ddv_status,"DDV status"); - ddv_gendisk.next = gendisk_head; - gendisk_head = &ddv_gendisk; - - num_options = mpp_num_cells(); - this_option = mpp_cid(); - - kernel_thread(ddv_daemon, NULL, 0); - - ddv_geninit(); - - return(0); -} - - -static void ddv_geninit(void) -{ - int i; - static int done = 0; - - if (done) - printk("ddv_geninit already done!\n"); - - done = 1; - - printk("ddv_geninit\n"); - - /* request interrupt line 2 */ - if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) { - printk("Failed to install ddv interrupt handler\n"); - } - - for (i=0;i<NUM_DDVDEVS;i++) { - ddv_blocksizes[i] = BLOCK_SIZE; - ddv_sect_length[i] = 0; - ddv_blk_length[i] = 0; - } - - ddv_geometry.heads = 32; - ddv_geometry.sectors = 32; - ddv_geometry.cylinders = 1; - ddv_geometry.start = 0; - - blksize_size[MAJOR_NR] = ddv_blocksizes; - - ddv_load_opiu(); -} - - -/* loadable module support */ - -#ifdef MODULE - -int init_module(void) -{ - int error = ddv_init(); - if (!error) - printk(KERN_INFO "DDV: Loaded as module.\n"); - return error; -} - -/* Before freeing the module, invalidate all of the protected buffers! */ -void cleanup_module(void) -{ - int i; - struct gendisk ** gdp; - - for (i = 0 ; i < NUM_DDVDEVS; i++) - invalidate_buffers(MKDEV(MAJOR_NR, i)); - - /* reset the opiu */ - OPT_IO(OPIU_OP) = OPIU_RESET; - OPT_IO(PRST) = PRST_IRST; - - unregister_blkdev( MAJOR_NR, DEVICE_NAME ); - for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) - if (*gdp == &ddv_gendisk) - break; - if (*gdp) - *gdp = (*gdp)->next; - free_irq(APOPT0_IRQ, NULL); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); -} - -#endif /* MODULE */ - - |