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 * ddv.c - Single AP1000 block driver.
11 * This block driver performs io operations to the ddv option
16 #include <linux/errno.h>
17 #include <linux/types.h>
19 #include <linux/ext2_fs.h>
20 #include <linux/kernel.h>
21 #include <linux/major.h>
23 #include <linux/malloc.h>
24 #define __KERNEL_SYSCALLS__
25 #include <linux/unistd.h>
26 #include <linux/sched.h>
27 #include <asm/pgtable.h>
28 #include <asm/uaccess.h>
29 #include <linux/module.h>
30 #include <asm/ap1000/apreg.h>
31 #include <asm/ap1000/DdvReqTable.h>
33 #define MAJOR_NR DDV_MAJOR
35 #include <linux/blk.h>
36 #include <linux/genhd.h>
37 #include <linux/hdreg.h>
42 #define SECTOR_SIZE 512
44 /* we can have lots of partitions */
46 #define NUM_DDVDEVS (1<<PARTN_BITS)
48 #define PARDISK_BASE (1<<5) /* partitions above this number are
49 striped across all the cells */
50 #define STRIPE_SHIFT 6
51 #define STRIPE_SECTORS (1<<STRIPE_SHIFT) /* number of sectors per stripe */
54 #define MAX_REQUEST (TABLE_SIZE - 2)
55 #define REQUEST_LOW 16
56 #define REQUEST_HIGH 4
59 /* we fake up a block size larger than the physical block size to try
60 to make things a bit more efficient */
61 #define SECTOR_BLOCK_SHIFT 9
63 #define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1)
65 /* try to read ahead a bit */
66 #define DDV_READ_AHEAD 64
68 static int have_ddv_board
= 1;
69 static unsigned num_options
= 0;
70 static unsigned this_option
= 0;
72 extern int ddv_get_mlist(unsigned mptr
[],int bnum
);
73 extern int ddv_set_request(struct request
*req
,
74 int request_type
,int bnum
,int mlist
,int len
,int offset
);
75 extern void ddv_load_kernel(char *opcodep
);
76 extern int ddv_restart_cpu(void);
77 extern int ddv_mlist_available(void);
78 static int ddv_revalidate(kdev_t dev
, struct gendisk
*gdev
);
79 static void ddv_geninit(struct gendisk
*ignored
);
80 static void ddv_release(struct inode
* inode
, struct file
* filp
);
81 static void ddv_request1(void);
84 static char *ddv_opcodep
= NULL
;
85 static struct request
*next_request
= NULL
;
87 static DECLARE_WAIT_QUEUE_HEAD(busy_wait
);
89 static int ddv_blocksizes
[NUM_DDVDEVS
]; /* in bytes */
90 int ddv_sect_length
[NUM_DDVDEVS
]; /* in sectors */
91 int ddv_blk_length
[NUM_DDVDEVS
]; /* in blocks */
93 /* these are used by the ddv_daemon, which services remote disk requests */
94 static struct remote_request
*rem_queue
= NULL
;
95 static struct remote_request
*rem_queue_end
;
96 static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait
);
98 static int opiu_kernel_loaded
= 0;
101 unsigned reads
, writes
, blocks
, rq_started
, rq_finished
, errors
;
102 unsigned sectors_read
, sectors_written
;
105 static struct hd_struct partition_tables
[NUM_DDVDEVS
];
107 static struct gendisk ddv_gendisk
= {
108 MAJOR_NR
, /* Major number */
109 DEVICE_NAME
, /* Major name */
110 PARTN_BITS
, /* Bits to shift to get real from partition */
111 1 << PARTN_BITS
, /* Number of partitions per real */
112 1, /* maximum number of real */
114 NULL
, /* called from init_module */
116 ddv_geninit
, /* init function */
118 partition_tables
,/* hd struct */
119 ddv_blk_length
, /* block sizes */
121 (void *) NULL
, /* internal */
126 struct ddv_geometry
{
128 unsigned char sectors
;
129 unsigned short cylinders
;
133 static struct ddv_geometry ddv_geometry
;
136 struct remote_request
{
138 struct remote_request
*next
;
141 unsigned bnum
; /* how many blocks does this contain */
142 struct request
*reqp
; /* pointer to the request on the original cell */
143 unsigned cell
; /* what cell is the request from */
144 struct request req
; /* details of the request */
148 static void ddv_set_optadr(void)
150 unsigned addr
= 0x11000000;
151 OPT_IO(OBASE
) = addr
;
153 ((addr
& 0xff000000)>>16) |
154 ((OPTION_BASE
& 0xf0000000)>>24) |
155 ((OPTION_BASE
+ 0x10000000)>>28);
159 extern struct RequestTable
*RTable
;
160 extern struct OPrintBufArray
*PrintBufs
;
161 extern struct OAlignBufArray
*AlignBufs
;
162 extern struct DiskInfo
*DiskInfo
;
164 static void ddv_release(struct inode
* inode
, struct file
* filp
)
167 printk("ddv_release started\n");
169 sync_dev(inode
->i_rdev
);
171 printk("ddv_release done\n");
176 static unsigned in_request
= 0;
177 static unsigned req_queued
= 0;
179 static void ddv_end_request(int uptodate
,struct request
*req
)
181 struct buffer_head
* bh
;
183 ddv_stats
.rq_finished
++;
185 /* printk("ddv_end_request(%d,%p)\n",uptodate,req); */
189 printk("end_request: I/O error, dev %s, sector %lu\n",
190 kdevname(req
->rq_dev
), req
->sector
);
192 req
->nr_sectors
&= ~SECTOR_MASK
;
193 req
->sector
+= (BLOCK_SIZE
/ SECTOR_SIZE
);
194 req
->sector
&= ~SECTOR_MASK
;
198 if ((bh
= req
->bh
) != NULL
) {
199 req
->bh
= bh
->b_reqnext
;
200 bh
->b_reqnext
= NULL
;
201 mark_buffer_uptodate(bh
, uptodate
);
203 if ((bh
= req
->bh
) != NULL
) {
204 req
->current_nr_sectors
= bh
->b_size
>> 9;
205 if (req
->nr_sectors
< req
->current_nr_sectors
) {
206 req
->nr_sectors
= req
->current_nr_sectors
;
207 printk("end_request: buffer-list destroyed\n");
209 req
->buffer
= bh
->b_data
;
210 printk("WARNING: ddv: more sectors!\n");
215 if (req
->sem
!= NULL
)
217 req
->rq_status
= RQ_INACTIVE
;
218 wake_up(&wait_for_request
);
222 /* check that a request is all OK to process */
223 static int request_ok(struct request
*req
)
228 if (MAJOR(req
->rq_dev
) != MAJOR_NR
)
229 panic(DEVICE_NAME
": bad major number\n");
230 if (!buffer_locked(req
->bh
))
231 panic(DEVICE_NAME
": block not locked");
233 minor
= MINOR(req
->rq_dev
);
234 if (minor
>= NUM_DDVDEVS
) {
235 printk("ddv_request: Invalid minor (%d)\n", minor
);
239 if ((req
->sector
+ req
->current_nr_sectors
) > ddv_sect_length
[minor
]) {
240 printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n",
241 minor
,(int)req
->sector
,(int)req
->current_nr_sectors
,
242 ddv_sect_length
[minor
]);
246 if (req
->cmd
!= READ
&& req
->cmd
!= WRITE
) {
247 printk("unknown request type %d\n",req
->cmd
);
251 /* it seems to be OK */
256 static void complete_request(struct request
*req
,int bnum
)
259 ddv_end_request(1,req
);
265 static int completion_pointer
= 0;
267 static void check_completion(void)
275 (i
=completion_pointer
) != RTable
->ddv_pointer
&&
276 RTable
->async_info
[i
].status
== DDV_REQ_FREE
;
277 completion_pointer
= INC_T(completion_pointer
))
279 req
= (struct request
*)RTable
->async_info
[i
].argv
[7];
280 bnum
= RTable
->async_info
[i
].bnum
;
282 printk("%s(%d)\n",__FILE__
,__LINE__
);
287 RTable
->async_info
[i
].status
= 0;
288 RTable
->async_info
[i
].argv
[7] = 0;
290 complete_request(req
,bnum
);
296 static struct request
*get_request_queue(struct request
*oldq
)
298 struct request
*req
,*req2
;
300 /* skip any non-active or bad requests */
302 if (!(req
= CURRENT
))
305 if (req
->rq_status
!= RQ_ACTIVE
) {
310 if (!request_ok(req
)) {
311 ddv_end_request(0,req
);
316 /* now grab as many as we can */
321 req2
->next
->rq_status
== RQ_ACTIVE
&&
322 request_ok(req2
->next
);
326 /* leave CURRENT pointing at the bad ones */
327 CURRENT
= req2
->next
;
329 /* chop our list at that point */
335 for (req2
=oldq
;req2
->next
;req2
=req2
->next
) ;
343 static void ddv_rem_complete(struct remote_request
*rem
)
346 int bnum
= rem
->bnum
;
347 struct request
*req
= rem
->reqp
;
349 complete_request(req
,bnum
);
352 save_flags(flags
); cli();
354 restore_flags(flags
);
359 * The background ddv daemon. This receives remote disk requests
360 * and processes them via the normal block operations
362 static int ddv_daemon(void *unused
)
364 current
->session
= 1;
366 sprintf(current
->comm
, "ddv_daemon");
367 spin_lock_irq(¤t
->sigmask_lock
);
368 sigfillset(¤t
->blocked
); /* block all signals */
369 recalc_sigpending(current
);
370 spin_unlock_irq(¤t
->sigmask_lock
);
372 /* Give it a realtime priority. */
373 current
->policy
= SCHED_FIFO
;
374 current
->priority
= 32; /* Fixme --- we need to standardise our
375 namings for POSIX.4 realtime scheduling
378 printk("Started ddv_daemon\n");
381 struct remote_request
*rem
;
383 struct buffer_head
*bhlist
[MAX_BNUM
*4];
384 int i
,j
,minor
,len
,shift
,offset
;
386 save_flags(flags
); cli();
389 spin_lock_irq(¤t
->sigmask_lock
);
390 flush_signals(current
);
391 spin_unlock_irq(¤t
->sigmask_lock
);
392 interruptible_sleep_on(&ddv_daemon_wait
);
396 rem_queue
= rem
->u
.next
;
397 restore_flags(flags
);
400 minor
= MINOR(rem
->req
.rq_dev
);
401 len
= rem
->req
.current_nr_sectors
;
402 offset
= rem
->req
.sector
;
404 /* work out the conversion to the local block size from
407 (SECTOR_SIZE
<<shift
) != ddv_blocksizes
[minor
];
411 for (i
=0; len
; i
++) {
412 bhlist
[i
] = getblk(rem
->req
.rq_dev
,
414 ddv_blocksizes
[minor
]);
415 if (!buffer_uptodate(bhlist
[i
]))
416 ll_rw_block(READ
,1,&bhlist
[i
]);
422 if (!buffer_uptodate(bhlist
[j
]))
423 wait_on_buffer(bhlist
[j
]);
429 /* release the buffers */
433 /* tell the originator that its done */
434 rem
->u
.fn
= ddv_rem_complete
;
435 tnet_rpc(rem
->cell
,rem
,sizeof(int)*3,1);
440 /* receive a remote disk request */
441 static void ddv_rem_queue(char *data
,unsigned size
)
444 struct remote_request
*rem
= (struct remote_request
*)
445 kmalloc(size
,GFP_ATOMIC
);
453 memcpy(rem
,data
,size
);
456 save_flags(flags
); cli();
458 /* add it to our remote request queue */
462 rem_queue_end
->u
.next
= rem
;
465 restore_flags(flags
);
467 wake_up(&ddv_daemon_wait
);
471 /* which disk should this request go to */
472 static inline unsigned pardisk_num(struct request
*req
)
474 int minor
= MINOR(req
->rq_dev
);
478 if (minor
< PARDISK_BASE
)
481 stripe
= req
->sector
>> STRIPE_SHIFT
;
482 cell
= stripe
% num_options
;
488 /* check if a 2nd request can be tacked onto the first */
489 static inline int contiguous(struct request
*req1
,struct request
*req2
)
491 if (req2
->cmd
!= req1
->cmd
||
492 req2
->rq_dev
!= req1
->rq_dev
||
493 req2
->sector
!= req1
->sector
+ req1
->current_nr_sectors
||
494 req2
->current_nr_sectors
!= req1
->current_nr_sectors
)
496 if (pardisk_num(req1
) != pardisk_num(req2
))
501 static void ddv_request1(void)
503 struct request
*req
,*req1
,*req2
;
504 unsigned offset
,len
,req_num
,mlist
,bnum
,available
=0;
505 static unsigned mptrs
[MAX_BNUM
];
508 if (in_request
> REQUEST_HIGH
)
511 next_request
= get_request_queue(next_request
);
513 while ((req
= next_request
)) {
516 if (in_request
>= MAX_REQUEST
)
519 if (in_request
>1 && req_queued
<REQUEST_LOW
)
522 /* make sure we have room for a request */
523 available
= ddv_mlist_available();
524 if (available
< 1) return;
525 if (available
> MAX_BNUM
)
526 available
= MAX_BNUM
;
528 offset
= req
->sector
;
529 len
= req
->current_nr_sectors
;
530 minor
= MINOR(req
->rq_dev
);
532 mptrs
[0] = (int)req
->buffer
;
534 for (bnum
=1,req1
=req
,req2
=req
->next
;
535 req2
&& bnum
<available
&& contiguous(req1
,req2
);
536 req1
=req2
,req2
=req2
->next
) {
537 mptrs
[bnum
++] = (int)req2
->buffer
;
544 ddv_stats
.blocks
+= bnum
;
545 ddv_stats
.rq_started
+= bnum
;
547 if (req
->cmd
== READ
) {
549 ddv_stats
.sectors_read
+= len
*bnum
;
552 ddv_stats
.sectors_written
+= len
*bnum
;
555 if (minor
>= PARDISK_BASE
) {
556 /* translate the request to the normal partition */
558 minor
-= PARDISK_BASE
;
560 stripe
= offset
>> STRIPE_SHIFT
;
561 stripe
/= num_options
;
562 offset
= (stripe
<< STRIPE_SHIFT
) +
563 (offset
& ((1<<STRIPE_SHIFT
)-1));
565 /* like an air-guitar :-) */
566 complete_request(req
,bnum
);
571 if ((cell
=pardisk_num(req
)) != this_option
) {
572 /* its a remote request */
573 struct remote_request
*rem
;
575 unsigned size
= sizeof(*rem
) + sizeof(int)*bnum
;
577 rem
= (struct remote_request
*)kmalloc(size
,GFP_ATOMIC
);
579 /* hopefully we can get it on the next go */
582 remlist
= (unsigned *)(rem
+1);
584 rem
->u
.fn
= ddv_rem_queue
;
585 rem
->cell
= this_option
;
589 rem
->req
.rq_dev
= MKDEV(MAJOR_NR
,minor
);
590 rem
->req
.sector
= offset
;
591 memcpy(remlist
,mptrs
,sizeof(mptrs
[0])*bnum
);
593 if (tnet_rpc(cell
,rem
,size
,1) != 0) {
598 /* its a local request */
599 if ((mlist
= ddv_get_mlist(mptrs
,bnum
)) == -1) {
601 panic("ddv: mlist corrupted");
604 req_num
= RTable
->cell_pointer
;
605 RTable
->async_info
[req_num
].status
=
606 req
->cmd
==READ
?DDV_RAWREAD_REQ
:DDV_RAWWRITE_REQ
;
607 RTable
->async_info
[req_num
].bnum
= bnum
;
608 RTable
->async_info
[req_num
].argv
[0] = mlist
;
609 RTable
->async_info
[req_num
].argv
[1] = len
;
610 RTable
->async_info
[req_num
].argv
[2] = offset
+
611 partition_tables
[minor
].start_sect
;
612 RTable
->async_info
[req_num
].argv
[3] = bnum
;
613 RTable
->async_info
[req_num
].argv
[7] = (unsigned)req
;
614 RTable
->cell_pointer
= INC_T(RTable
->cell_pointer
);
623 static void ddv_request(void)
631 static void check_printbufs(void)
635 if (!PrintBufs
) return;
637 while (PrintBufs
->option_counter
!= PrintBufs
->cell_counter
) {
638 i
= PrintBufs
->cell_counter
;
639 printk("opiu (%d): ",i
);
640 if (((unsigned)PrintBufs
->bufs
[i
].fmt
) > 0x100000)
641 printk("Error: bad format in printk at %p\n",
642 PrintBufs
->bufs
[i
].fmt
);
644 printk(PrintBufs
->bufs
[i
].fmt
+ OPIBUS_BASE
,
645 PrintBufs
->bufs
[i
].args
[0],
646 PrintBufs
->bufs
[i
].args
[1],
647 PrintBufs
->bufs
[i
].args
[2],
648 PrintBufs
->bufs
[i
].args
[3],
649 PrintBufs
->bufs
[i
].args
[4],
650 PrintBufs
->bufs
[i
].args
[5]);
651 if (++PrintBufs
->cell_counter
== PRINT_BUFS
)
652 PrintBufs
->cell_counter
= 0;
656 static void ddv_interrupt(int irq
, void *dev_id
, struct pt_regs
*regs
)
659 save_flags(flags
); cli();
660 OPT_IO(IRC1
) = 0x80000000;
666 restore_flags(flags
);
669 static int ddv_open(struct inode
* inode
, struct file
* filp
)
671 int minor
= MINOR(inode
->i_rdev
);
673 if (!have_ddv_board
|| minor
>= NUM_DDVDEVS
)
676 if (minor
>= PARDISK_BASE
) {
677 ddv_sect_length
[minor
] = ddv_sect_length
[minor
- PARDISK_BASE
];
678 ddv_blk_length
[minor
] = ddv_blk_length
[minor
- PARDISK_BASE
];
685 static void ddv_open_reply(struct cap_request
*creq
)
687 int size
= creq
->size
- sizeof(*creq
);
688 ddv_opcodep
= (char *)kmalloc(size
,GFP_ATOMIC
);
689 read_bif(ddv_opcodep
, size
);
691 printk("received opiu kernel of size %d\n",size
);
699 static void ddv_load_opiu(void)
702 struct cap_request creq
;
704 /* if the opiu kernel is already loaded then we don't do anything */
705 if (!have_ddv_board
|| opiu_kernel_loaded
)
708 bif_register_request(REQ_DDVOPEN
,ddv_open_reply
);
710 /* send the open request to the front end */
711 creq
.cid
= mpp_cid();
712 creq
.type
= REQ_DDVOPEN
;
714 creq
.size
= sizeof(creq
);
716 bif_queue(&creq
,0,0);
721 sleep_on(&busy_wait
);
726 ddv_load_kernel(ddv_opcodep
);
731 if (ddv_restart_cpu())
734 ddv_sect_length
[0] = DiskInfo
->blocks
;
735 ddv_blk_length
[0] = DiskInfo
->blocks
>> 1;
736 ddv_blocksizes
[0] = BLOCK_SIZE
;
738 ddv_geometry
.cylinders
= ddv_sect_length
[0] /
739 (ddv_geometry
.heads
*ddv_geometry
.sectors
);
741 ddv_gendisk
.part
[0].start_sect
= 0;
742 ddv_gendisk
.part
[0].nr_sects
= ddv_sect_length
[0];
744 resetup_one_dev(&ddv_gendisk
, 0);
746 for (i
=0;i
<PARDISK_BASE
;i
++) {
747 ddv_sect_length
[i
] = ddv_gendisk
.part
[i
].nr_sects
;
748 ddv_blk_length
[i
] = ddv_gendisk
.part
[i
].nr_sects
>> 1;
751 /* setup the parallel partitions by multiplying the normal
752 partition by the number of options */
753 for (;i
<NUM_DDVDEVS
;i
++) {
754 ddv_sect_length
[i
] = ddv_sect_length
[i
-PARDISK_BASE
]*num_options
;
755 ddv_blk_length
[i
] = ddv_blk_length
[i
-PARDISK_BASE
]*num_options
;
756 ddv_gendisk
.part
[i
].start_sect
= ddv_gendisk
.part
[i
-PARDISK_BASE
].start_sect
;
757 ddv_gendisk
.part
[i
].nr_sects
= ddv_sect_length
[i
];
761 opiu_kernel_loaded
= 1;
766 * This routine is called to flush all partitions and partition tables
767 * for a changed disk, and then re-read the new partition table.
769 static int ddv_revalidate(kdev_t dev
, struct gendisk
*gdev
)
776 target
= DEVICE_NR(dev
);
779 start
= target
<< gdev
->minor_shift
;
781 printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n",
782 dev
,target
,max_p
,start
);
784 for (i
=max_p
- 1; i
>=0 ; i
--) {
785 int minor
= start
+ i
;
786 kdev_t devi
= MKDEV(gdev
->major
, minor
);
788 invalidate_inodes(devi
);
789 invalidate_buffers(devi
);
790 gdev
->part
[minor
].start_sect
= 0;
791 gdev
->part
[minor
].nr_sects
= 0;
794 ddv_sect_length
[start
] = DiskInfo
->blocks
;
795 ddv_blk_length
[start
] = DiskInfo
->blocks
>> 1;
797 gdev
->part
[start
].nr_sects
= ddv_sect_length
[start
];
798 resetup_one_dev(gdev
, target
);
800 printk("sect_length[%d]=%d blk_length[%d]=%d\n",
801 start
,ddv_sect_length
[start
],
802 start
,ddv_blk_length
[start
]);
804 for (i
=0;i
<max_p
;i
++) {
805 ddv_sect_length
[start
+i
] = gdev
->part
[start
+i
].nr_sects
;
806 ddv_blk_length
[start
+i
] = gdev
->part
[start
+i
].nr_sects
>> 1;
807 if (gdev
->part
[start
+i
].nr_sects
)
808 printk("partition[%d] start=%d length=%d\n",i
,
809 (int)gdev
->part
[start
+i
].start_sect
,
810 (int)gdev
->part
[start
+i
].nr_sects
);
819 static int ddv_ioctl(struct inode
*inode
, struct file
*file
,
820 unsigned int cmd
, unsigned long arg
)
823 struct ddv_geometry
*loc
= (struct ddv_geometry
*) arg
;
825 int minor
= MINOR(inode
->i_rdev
);
827 if ((!inode
) || !(inode
->i_rdev
))
829 dev
= DEVICE_NR(inode
->i_rdev
);
831 printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd
, dev
, minor
);
835 printk("\tHDIO_GETGEO\n");
836 if (!loc
) return -EINVAL
;
837 if (put_user(ddv_geometry
.heads
, (char *) &loc
->heads
)) return -EFAULT
;
838 if (put_user(ddv_geometry
.sectors
, (char *) &loc
->sectors
)) return -EFAULT
;
839 if (put_user(ddv_geometry
.cylinders
, (short *) &loc
->cylinders
)) return -EFAULT
;
840 if (put_user(ddv_geometry
.start
, (long *) &loc
->start
)) return -EFAULT
;
843 case HDIO_GET_MULTCOUNT
:
844 printk("\tHDIO_GET_MULTCOUNT\n");
847 case HDIO_GET_IDENTITY
:
848 printk("\tHDIO_GET_IDENTITY\n");
851 case HDIO_GET_NOWERR
:
852 printk("\tHDIO_GET_NOWERR\n");
855 case HDIO_SET_NOWERR
:
856 printk("\tHDIO_SET_NOWERR\n");
860 printk("\tBLKRRPART\n");
861 if (!capable(CAP_SYS_ADMIN
))
863 return ddv_revalidate(inode
->i_rdev
,&ddv_gendisk
);
865 case BLKGETSIZE
: /* Return device size */
866 if (put_user(ddv_sect_length
[minor
],(long *) arg
)) return -EFAULT
;
868 printk("BLKGETSIZE gave %d\n",ddv_sect_length
[minor
]);
873 printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd
, cmd
);
878 static struct file_operations ddv_fops
= {
879 NULL
, /* lseek - default */
880 block_read
, /* read */
881 block_write
, /* write */
882 NULL
, /* readdir - bad */
884 ddv_ioctl
, /* ioctl */
889 block_fsync
/* fsync */
893 static void ddv_status(void)
895 if (!have_ddv_board
) {
896 printk("no ddv board\n");
901 in_request %u req_queued %u
902 MTable: start=%u end=%u
903 Requests: started=%u finished=%u
904 Requests: completion_pointer=%u ddv_pointer=%u cell_pointer=%u
905 PrintBufs: option_counter=%u cell_counter=%u
906 ddv_stats: reads=%u writes=%u blocks=%u
907 ddv_stats: sectors_read=%u sectors_written=%u
908 CURRENT=%p next_request=%p errors=%u
910 in_request
,req_queued
,
911 RTable
->start_mtable
,RTable
->end_mtable
,
912 ddv_stats
.rq_started
,ddv_stats
.rq_finished
,
913 completion_pointer
,RTable
->ddv_pointer
,RTable
->cell_pointer
,
914 PrintBufs
->option_counter
,PrintBufs
->cell_counter
,
915 ddv_stats
.reads
,ddv_stats
.writes
,ddv_stats
.blocks
,
916 ddv_stats
.sectors_read
,ddv_stats
.sectors_written
,
917 CURRENT
,next_request
,
928 if (register_blkdev(MAJOR_NR
,DEVICE_NAME
,&ddv_fops
)) {
929 printk("ap: unable to get major %d for ap block dev\n",
934 printk("ddv_init: register dev %d\n", MAJOR_NR
);
935 blk_dev
[MAJOR_NR
].request_fn
= DEVICE_REQUEST
;
936 read_ahead
[MAJOR_NR
] = DDV_READ_AHEAD
;
938 bif_add_debug_key('d',ddv_status
,"DDV status");
939 ddv_gendisk
.next
= gendisk_head
;
940 gendisk_head
= &ddv_gendisk
;
942 num_options
= mpp_num_cells();
943 this_option
= mpp_cid();
945 kernel_thread(ddv_daemon
, NULL
, 0);
951 static void ddv_geninit(struct gendisk
*ignored
)
957 printk("ddv_geninit already done!\n");
961 printk("ddv_geninit\n");
963 /* request interrupt line 2 */
964 if (request_irq(APOPT0_IRQ
,ddv_interrupt
,SA_INTERRUPT
,"apddv",NULL
)) {
965 printk("Failed to install ddv interrupt handler\n");
968 for (i
=0;i
<NUM_DDVDEVS
;i
++) {
969 ddv_blocksizes
[i
] = BLOCK_SIZE
;
970 ddv_sect_length
[i
] = 0;
971 ddv_blk_length
[i
] = 0;
974 ddv_geometry
.heads
= 32;
975 ddv_geometry
.sectors
= 32;
976 ddv_geometry
.cylinders
= 1;
977 ddv_geometry
.start
= 0;
979 blksize_size
[MAJOR_NR
] = ddv_blocksizes
;
985 /* loadable module support */
989 int init_module(void)
991 int error
= ddv_init();
993 ddv_geninit(&(struct gendisk
) { 0,0,0,0,0,0,0,0,0,0,0 });
994 printk(KERN_INFO
"DDV: Loaded as module.\n");
999 /* Before freeing the module, invalidate all of the protected buffers! */
1000 void cleanup_module(void)
1003 struct gendisk
** gdp
;
1005 for (i
= 0 ; i
< NUM_DDVDEVS
; i
++)
1006 invalidate_buffers(MKDEV(MAJOR_NR
, i
));
1008 /* reset the opiu */
1009 OPT_IO(OPIU_OP
) = OPIU_RESET
;
1010 OPT_IO(PRST
) = PRST_IRST
;
1012 unregister_blkdev( MAJOR_NR
, DEVICE_NAME
);
1013 for (gdp
= &gendisk_head
; *gdp
; gdp
= &((*gdp
)->next
))
1014 if (*gdp
== &ddv_gendisk
)
1017 *gdp
= (*gdp
)->next
;
1018 free_irq(APOPT0_IRQ
, NULL
);
1019 blk_dev
[MAJOR_NR
].request_fn
= 0;