* add p cc
[mascara-docs.git] / i386 / linux / linux-0.99 / drivers / block / xd.c
blob07a4a42454e2bc84faf23f665bb3c9bae85d392f
1 /*
2 * This file contains the driver for an XT hard disk controller (at least the DTC 5150X) for Linux.
4 * Author: Pat Mackinlay, smackinla@cc.curtin.edu.au
5 * Date: 29/09/92
6 *
7 * Revised: 01/01/93, ...
9 * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
10 * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/fs.h>
17 #include <linux/kernel.h>
18 #include <linux/genhd.h>
19 #include <linux/xd.h>
21 #include <asm/system.h>
22 #include <asm/io.h>
23 #include <asm/segment.h>
24 #include <asm/dma.h>
26 #define MAJOR_NR XT_DISK_MAJOR
27 #include "blk.h"
29 XD_INFO xd_info[XD_MAXDRIVES];
31 /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
32 signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
33 few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
34 command. Run DEBUG, and then you can examine your BIOS signature with:
36 d xxxx:0000
38 where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
39 be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
40 in the table are, in order:
42 offset ; this is the offset (in bytes) from the start of your ROM where the signature starts
43 signature ; this is the actual text of the signature
44 xd_?_init_controller ; this is the controller init routine used by your controller
45 xd_?_init_drive ; this is the drive init routine used by your controller
47 The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
48 made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
49 best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
50 may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>.
52 NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
53 should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
55 static XD_SIGNATURE xd_sigs[] = {
56 { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
57 { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
58 { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
59 { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
60 { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
61 { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
62 { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
64 static u_char *xd_bases[] =
66 (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xCC000,
67 (u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD8000,
68 (u_char *) 0xE0000
71 static struct hd_struct xd[XD_MAXDRIVES << 6];
72 static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
73 static int xd_blocksizes[XD_MAXDRIVES << 6];
74 static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL };
75 static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release,block_fsync };
77 static struct wait_queue *xd_wait_int = NULL,*xd_wait_open = NULL;
78 static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
79 static u_char xd_drives = 0,xd_irq = 0,xd_dma = 0,xd_maxsectors,xd_override = 0,xd_type = 0;
80 static u_short xd_iobase = 0;
82 /* xd_init: grab the IRQ and DMA channel and initialise the drives */
83 u_long xd_init (u_long mem_start,u_long mem_end)
85 u_char i,controller,*address;
87 if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
88 printk("xd_init: unable to get major number %d\n",MAJOR_NR);
89 return (mem_start);
91 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
92 read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
93 xd_gendisk.next = gendisk_head;
94 gendisk_head = &xd_gendisk;
96 if (xd_detect(&controller,&address)) {
98 printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
99 if (controller)
100 xd_sigs[controller].init_controller(address);
101 xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
103 printk("xd_init: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
104 for (i = 0; i < xd_drives; i++)
105 printk("xd_init: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
107 if (!request_irq(xd_irq,xd_interrupt_handler)) {
108 if (request_dma(xd_dma)) {
109 printk("xd_init: unable to get DMA%d\n",xd_dma);
110 free_irq(xd_irq);
113 else
114 printk("xd_init: unable to get IRQ%d\n",xd_irq);
116 return mem_start;
119 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
120 static u_char xd_detect (u_char *controller,u_char **address)
122 u_char i,j,found = 0;
124 if (xd_override)
126 *controller = xd_type;
127 *address = NULL;
128 return(1);
131 for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
132 for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
133 if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
134 *controller = j;
135 *address = xd_bases[i];
136 found++;
138 return (found);
141 /* xd_geninit: set up the "raw" device entries in the table */
142 static void xd_geninit (void)
144 u_char i;
146 for (i = 0; i < xd_drives; i++) {
147 xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
148 xd_valid[i] = 1;
151 xd_gendisk.nr_real = xd_drives;
153 for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024;
154 blksize_size[MAJOR_NR] = xd_blocksizes;
157 /* xd_open: open a device */
158 static int xd_open (struct inode *inode,struct file *file)
160 int dev = DEVICE_NR(MINOR(inode->i_rdev));
162 if (dev < xd_drives) {
163 while (!xd_valid[dev])
164 sleep_on(&xd_wait_open);
166 xd_access[dev]++;
168 return (0);
170 else
171 return (-ENODEV);
174 /* do_xd_request: handle an incoming request */
175 static void do_xd_request (void)
177 u_int block,count,retry;
178 int code;
180 sti();
181 while (code = 0, CURRENT) {
182 INIT_REQUEST; /* do some checking on the request structure */
184 if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
185 block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
186 count = CURRENT->nr_sectors;
188 switch (CURRENT->cmd) {
189 case READ:
190 case WRITE: for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
191 code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
192 break;
193 default: printk("do_xd_request: unknown request\n"); break;
196 end_request(code); /* wrap up, 0 = fail, 1 = success */
200 /* xd_ioctl: handle device ioctl's */
201 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
203 XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
204 int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
206 if (inode && (dev < xd_drives))
207 switch (cmd) {
208 case HDIO_GETGEO: if (arg) {
209 if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
210 return (err);
211 put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
212 put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
213 put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
214 put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
216 return (0);
218 break;
219 case BLKGETSIZE: if (arg) {
220 if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
221 return (err);
222 put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
224 return (0);
226 break;
227 case BLKFLSBUF:
228 if(!suser()) return -EACCES;
229 if(!inode->i_rdev) return -EINVAL;
230 fsync_dev(inode->i_rdev);
231 invalidate_buffers(inode->i_rdev);
232 return 0;
234 case BLKRRPART: return (xd_reread_partitions(inode->i_rdev));
235 RO_IOCTLS(inode->i_rdev,arg);
237 return (-EINVAL);
240 /* xd_release: release the device */
241 static void xd_release (struct inode *inode, struct file *file)
243 int dev = DEVICE_NR(MINOR(inode->i_rdev));
245 if (dev < xd_drives) {
246 sync_dev(dev);
247 xd_access[dev]--;
251 /* xd_reread_partitions: rereads the partition table from a drive */
252 static int xd_reread_partitions(int dev)
254 int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
256 cli(); xd_valid[target] = (xd_access[target] != 1); sti();
257 if (xd_valid[target])
258 return (-EBUSY);
260 for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
261 sync_dev(MAJOR_NR << 8 | start | partition);
262 invalidate_inodes(MAJOR_NR << 8 | start | partition);
263 invalidate_buffers(MAJOR_NR << 8 | start | partition);
264 xd_gendisk.part[start + partition].start_sect = 0;
265 xd_gendisk.part[start + partition].nr_sects = 0;
268 xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
269 resetup_one_dev(&xd_gendisk,target);
271 xd_valid[target] = 1;
272 wake_up(&xd_wait_open);
274 return (0);
277 /* xd_readwrite: handle a read/write request */
278 static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
280 u_char cmdblk[6],sense[4];
281 u_short track,cylinder;
282 u_char head,sector,control,mode,temp;
284 #ifdef DEBUG_READWRITE
285 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
286 #endif /* DEBUG_READWRITE */
288 control = xd_info[drive].control;
289 while (count) {
290 temp = count < xd_maxsectors ? count : xd_maxsectors;
292 track = block / xd_info[drive].sectors;
293 head = track % xd_info[drive].heads;
294 cylinder = track / xd_info[drive].heads;
295 sector = block % xd_info[drive].sectors;
297 #ifdef DEBUG_READWRITE
298 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
299 #endif /* DEBUG_READWRITE */
301 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
302 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
304 switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
305 case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); return (0);
306 case 2: switch ((sense[0] & 0x30) >> 4) {
307 case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
308 case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
309 case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
310 case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
312 if (sense[0] & 0x80)
313 printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
314 else
315 printk(" - no valid disk address\n");
316 return (0);
318 count -= temp, buffer += temp * 0x200, block += temp;
320 return (1);
323 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
324 static void xd_recalibrate (u_char drive)
326 u_char cmdblk[6];
328 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
329 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
330 printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
333 /* xd_interrupt_handler: interrupt service routine */
334 static void xd_interrupt_handler (int unused)
336 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
337 #ifdef DEBUG_OTHER
338 printk("xd_interrupt_handler: interrupt detected\n");
339 #endif /* DEBUG_OTHER */
340 outb(0,XD_CONTROL); /* acknowledge interrupt */
341 wake_up(&xd_wait_int); /* and wake up sleeping processes */
343 else
344 printk("xd_interrupt_handler: unexpected interrupt\n");
347 /* xd_dma: set up the DMA controller for a data transfer */
348 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
350 if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */
351 if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
352 #ifdef DEBUG_OTHER
353 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
354 #endif /* DEBUG_OTHER */
355 return (PIO_MODE);
357 disable_dma(xd_dma);
358 clear_dma_ff(xd_dma);
359 set_dma_mode(xd_dma,mode);
360 set_dma_addr(xd_dma,(u_int) buffer);
361 set_dma_count(xd_dma,count);
363 return (DMA_MODE); /* use DMA and INT */
365 #ifdef DEBUG_OTHER
366 printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
367 #endif /* DEBUG_OTHER */
368 return (PIO_MODE);
371 /* xd_build: put stuff into an array in a format suitable for the controller */
372 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
374 cmdblk[0] = command;
375 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
376 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
377 cmdblk[3] = cylinder & 0xFF;
378 cmdblk[4] = count;
379 cmdblk[5] = control;
381 return (cmdblk);
384 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
385 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
387 u_long expiry = jiffies + timeout;
389 while (((inb(port) & mask) != flags) && (jiffies < expiry))
392 return (jiffies >= expiry);
395 /* xd_command: handle all data transfers necessary for a single command */
396 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
398 u_char cmdblk[6],csb,complete = 0;
400 #ifdef DEBUG_COMMAND
401 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
402 #endif /* DEBUG_COMMAND */
404 outb(0,XD_SELECT);
405 outb(mode,XD_CONTROL);
407 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
408 return (1);
410 while (!complete) {
411 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
412 return (1);
413 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
414 case 0: if (mode == DMA_MODE) {
415 enable_dma(xd_dma);
416 sleep_on(&xd_wait_int);
417 disable_dma(xd_dma);
419 else
420 outb(outdata ? *outdata++ : 0,XD_DATA);
421 break;
422 case STAT_INPUT: if (mode == DMA_MODE) {
423 enable_dma(xd_dma);
424 sleep_on(&xd_wait_int);
425 disable_dma(xd_dma);
427 else
428 if (indata)
429 *indata++ = inb(XD_DATA);
430 else
431 inb(XD_DATA);
432 break;
433 case STAT_COMMAND: outb(command ? *command++ : 0,XD_DATA); break;
434 case STAT_COMMAND
435 | STAT_INPUT: complete = 1; break;
438 csb = inb(XD_DATA);
440 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
441 return (1);
443 if (csb & CSB_ERROR) { /* read sense data if error */
444 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
445 if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
446 printk("xd_command: warning! sense command failed!\n");
449 #ifdef DEBUG_COMMAND
450 printk("xd_command: completed with csb = 0x%X\n",csb);
451 #endif /* DEBUG_COMMAND */
453 return (csb & CSB_ERROR);
456 static u_char xd_initdrives (void (*init_drive)(u_char drive))
458 u_char cmdblk[6],i,count = 0;
460 for (i = 0; i < XD_MAXDRIVES; i++) {
461 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
462 if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
463 init_drive(count);
464 count++;
467 return (count);
470 static void xd_dtc_init_controller (u_char *address)
472 switch ((u_long) address) {
473 case 0xC8000: xd_iobase = 0x320; break;
474 case 0xCA000: xd_iobase = 0x324; break;
475 default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
476 xd_iobase = 0x320; break;
478 xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
479 xd_dma = 3;
480 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
482 outb(0,XD_RESET); /* reset the controller */
485 static void xd_dtc_init_drive (u_char drive)
487 u_char cmdblk[6],buf[64];
489 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
490 if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
491 xd_info[drive].heads = buf[0x0A]; /* heads */
492 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
493 xd_info[drive].sectors = 17; /* sectors */
494 #if 0
495 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
496 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
497 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
498 #endif /* 0 */
499 xd_info[drive].control = 0; /* control byte */
501 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
502 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
503 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
504 printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive);
506 else
507 printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
510 static void xd_wd_init_controller (u_char *address)
512 switch ((u_long) address) {
513 case 0xC8000: xd_iobase = 0x320; break;
514 case 0xCA000: xd_iobase = 0x324; break;
515 case 0xCC000: xd_iobase = 0x328; break;
516 case 0xCE000: xd_iobase = 0x32C; break;
517 case 0xD0000: xd_iobase = 0x328; break;
518 case 0xD8000: xd_iobase = 0x32C; break;
519 default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
520 xd_iobase = 0x320; break;
522 xd_irq = 5; /* don't know how to auto-detect this yet */
523 xd_dma = 3;
524 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
526 /* outb(0,XD_RESET); */ /* reset the controller */
529 static void xd_wd_init_drive (u_char drive)
531 u_char cmdblk[6],buf[0x200];
533 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
534 if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
535 xd_info[drive].heads = buf[0x1AF]; /* heads */
536 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
537 xd_info[drive].sectors = 17; /* sectors */
538 #if 0
539 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
540 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
541 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
542 #endif /* 0 */
543 xd_info[drive].control = buf[0x1B5]; /* control byte */
545 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
547 else
548 printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
551 static void xd_seagate_init_controller (u_char *address)
553 switch ((u_long) address) {
554 case 0xC8000: xd_iobase = 0x320; break;
555 case 0xD0000: xd_iobase = 0x324; break;
556 case 0xD8000: xd_iobase = 0x328; break;
557 case 0xE0000: xd_iobase = 0x32C; break;
558 default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
559 xd_iobase = 0x320; break;
561 xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
562 xd_dma = 3;
563 xd_maxsectors = 0x40;
565 outb(0,XD_RESET); /* reset the controller */
568 static void xd_seagate_init_drive (u_char drive)
570 u_char cmdblk[6],buf[0x200];
572 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
573 if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
574 xd_info[drive].heads = buf[0x04]; /* heads */
575 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
576 xd_info[drive].sectors = buf[0x05]; /* sectors */
577 xd_info[drive].control = 0; /* control byte */
579 else
580 printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
583 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
584 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
585 static void xd_override_init_drive (u_char drive)
587 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
588 u_char cmdblk[6],i;
590 for (i = 0; i < 3; i++) {
591 while (min[i] != max[i] - 1) {
592 test[i] = (min[i] + max[i]) / 2;
593 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
594 if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
595 min[i] = test[i];
596 else
597 max[i] = test[i];
599 test[i] = min[i];
601 xd_info[drive].heads = (u_char) min[0] + 1;
602 xd_info[drive].cylinders = (u_short) min[1] + 1;
603 xd_info[drive].sectors = (u_char) min[2] + 1;
604 xd_info[drive].control = 0;
607 /* xd_setup: initialise from command line parameters */
608 void xd_setup (char *command,int *integers)
610 xd_override = 1;
612 xd_type = integers[1];
613 xd_irq = integers[2];
614 xd_iobase = integers[3];
615 xd_dma = integers[4];
617 xd_maxsectors = 0x01;
620 /* xd_setparam: set the drive characteristics */
621 static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
623 u_char cmdblk[14];
625 xd_build(cmdblk,command,drive,0,0,0,0,0);
626 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
627 cmdblk[7] = (u_char) (cylinders & 0xFF);
628 cmdblk[8] = heads & 0x1F;
629 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
630 cmdblk[10] = (u_char) (rwrite & 0xFF);
631 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
632 cmdblk[12] = (u_char) (wprecomp & 0xFF);
633 cmdblk[13] = ecc;
635 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
636 printk("xd_setparam: error setting characteristics for drive %d\n",drive);