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

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(&current->sigmask_lock);
-	sigfillset(&current->blocked); /* block all signals */
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->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(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock(&current->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)