patch-2.3.42 linux/drivers/ap1000/ddv.c
Next file: linux/drivers/ap1000/ddv_util.c
Previous file: linux/drivers/ap1000/bif.c
Back to the patch index
Back to the overall index
- Lines: 1009
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.41/linux/drivers/ap1000/ddv.c
- Orig date:
Fri Jan 21 18:19:16 2000
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c
@@ -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 */
-
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)