root/kernel/blk_drv/xd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xd_init
  2. xd_detect
  3. xd_geninit
  4. xd_open
  5. do_xd_request
  6. xd_ioctl
  7. xd_release
  8. xd_reread_partitions
  9. xd_readwrite
  10. xd_recalibrate
  11. xd_interrupt_handler
  12. xd_setup_dma
  13. xd_build
  14. xd_waitport
  15. xd_command
  16. xd_initdrives
  17. xd_dtc5150x_init_controller
  18. xd_dtc5150x_init_drive
  19. xd_wd1004a27x_init_controller
  20. xd_wd1004a27x_init_drive
  21. xd_seagate11_init_controller
  22. xd_seagate11_init_drive
  23. xd_override_init_controller
  24. xd_override_init_drive
  25. xd_setparam

   1 /*
   2  * This file contains the driver for an XT hard disk controller (at least the DTC 5150X) for Linux.
   3  *
   4  * Author: Pat Mackinlay, smackinla@cc.curtin.edu.au
   5  * Date: 29/09/92
   6  * 
   7  * Revised: 01/01/93, ...
   8  *
   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.
  11  */
  12 
  13 #include <linux/config.h>
  14 #ifdef CONFIG_BLK_DEV_XD
  15 
  16 #include <linux/errno.h>
  17 #include <linux/sched.h>
  18 #include <linux/fs.h>
  19 #include <linux/kernel.h>
  20 #include <linux/genhd.h>
  21 #include <linux/xd.h>
  22 
  23 #include <asm/system.h>
  24 #include <asm/io.h>
  25 #include <asm/segment.h>
  26 #include <asm/dma.h>
  27 
  28 #define MAJOR_NR 13
  29 #include "blk.h"
  30 
  31 XD_INFO xd_info[XD_MAXDRIVES];
  32 
  33 /* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
  34    signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
  35    few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
  36    command. Run DEBUG, and then you can examine your BIOS signature with:
  37 
  38         d xxxx:0000
  39 
  40    where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
  41    be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
  42    in the table are, in order:
  43 
  44         offset                  ; this is the offset (in bytes) from the start of your ROM where the signature starts
  45         signature               ; this is the actual text of the signature
  46         xd_?_init_controller    ; this is the controller init routine used by your controller
  47         xd_?_init_drive         ; this is the drive init routine used by your controller
  48 
  49    The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
  50    made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
  51    best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
  52    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>. */
  53 
  54 static XD_SIGNATURE xd_sigs[] = {
  55         { 0x0000,"Override geometry handler",xd_override_init_controller,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
  56 #ifndef XD_OVERRIDE
  57         { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc5150x_init_controller,xd_dtc5150x_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_wd1004a27x_init_controller,xd_wd1004a27x_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_wd1004a27x_init_controller,xd_wd1004a27x_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
  60         { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
  61         { 0x0010,"ST11R BIOS",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
  62 #endif XD_OVERRIDE
  63 };
  64 #ifndef XD_OVERRIDE
  65 static u_char *xd_bases[] = { (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xD0000,(u_char *) 0xD8000,(u_char *) 0xE0000 };
  66 #endif XD_OVERRIDE
  67 
  68 static struct hd_struct xd[XD_MAXDRIVES << 6];
  69 static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
  70 static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL };
  71 static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release };
  72 
  73 static struct wait_queue *xd_wait_exclusive = NULL,*xd_wait_int = NULL,*xd_wait_open = NULL;
  74 static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
  75 static u_char xd_busy = 0,xd_drives = 0;
  76 static u_char xd_irq,xd_dma,xd_maxsectors;
  77 static u_short xd_iobase;
  78 
  79 /* xd_init: grab the IRQ and DMA channel and initialise the drives */
  80 u_long xd_init (u_long mem_start,u_long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         u_char i,controller,*address;
  83         
  84         if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
  85                 printk("xd_init: unable to get major number %d\n",MAJOR_NR);
  86                 return (mem_start);
  87         }
  88         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  89         read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
  90         xd_gendisk.next = gendisk_head;
  91         gendisk_head = &xd_gendisk;
  92 
  93         if (xd_detect(&controller,&address)) {
  94 
  95                 printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
  96                 xd_sigs[controller].init_controller(address);
  97                 xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
  98                 
  99                 printk("xd_init: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
 100                 for (i = 0; i < xd_drives; i++)
 101                         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);
 102 
 103                 if (!request_irq(xd_irq,xd_interrupt_handler)) {
 104                         if (request_dma(xd_dma)) {
 105                                 printk("xd_init: unable to get DMA%d\n",xd_dma);
 106                                 free_irq(xd_irq);
 107                         }
 108                 }
 109                 else
 110                         printk("xd_init: unable to get IRQ%d\n",xd_irq);
 111         }
 112         return mem_start;
 113 }
 114 
 115 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
 116 static u_char xd_detect (u_char *controller,u_char **address)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118 #ifndef XD_OVERRIDE
 119         u_char i,j,found = 0;
 120 
 121         for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
 122                 for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
 123                         if (!memcmp((u_char *) (xd_bases[i] + xd_sigs[j].offset),xd_sigs[j].string,strlen(xd_sigs[j].string))) {
 124                                 *controller = j;
 125                                 *address = xd_bases[i];
 126                                 found++;
 127                         }
 128         return (found);
 129 #else
 130         *controller = 0;
 131         *address = NULL;
 132         return (1);
 133 #endif XD_OVERRIDE
 134 }
 135 
 136 /* xd_geninit: set up the "raw" device entries in the table */
 137 static void xd_geninit (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139         u_char i;
 140 
 141         for (i = 0; i < xd_drives; i++) {
 142                 xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
 143                 xd_valid[i] = 1;
 144         }
 145 
 146         xd_gendisk.nr_real = xd_drives;
 147 }
 148 
 149 /* xd_open: open a device */
 150 static int xd_open (struct inode *inode,struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         int dev = DEVICE_NR(MINOR(inode->i_rdev));
 153 
 154         if (dev < xd_drives) {
 155                 while (!xd_valid[dev])
 156                         sleep_on(&xd_wait_open);
 157 
 158                 xd_access[dev]++;
 159 
 160                 return (0);
 161         }
 162         else
 163                 return (-ENODEV);
 164 }
 165 
 166 /* do_xd_request: handle an incoming request */
 167 static void do_xd_request (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         u_int block,count,retry;
 170         int code;
 171 
 172         sti();
 173         while (code = 0, CURRENT) {
 174                 INIT_REQUEST;   /* do some checking on the request structure */
 175 
 176                 if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
 177                         block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
 178                         count = CURRENT->nr_sectors;
 179 
 180                         switch (CURRENT->cmd) {
 181                                 case READ:
 182                                 case WRITE:     for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
 183                                                         code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 184                                                 break;
 185                                 default:        printk("do_xd_request: unknown request\n"); break;
 186                         }
 187                 }
 188                 end_request(code);      /* wrap up, 0 = fail, 1 = success */
 189         }
 190 }
 191 
 192 /* xd_ioctl: handle device ioctl's */
 193 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
 196         int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
 197 
 198         if (inode && (dev < xd_drives))
 199                 switch (cmd) {
 200                         case HDIO_GETGEO:       if (arg) {
 201                                                         if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
 202                                                                 return (err);
 203                                                         put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
 204                                                         put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
 205                                                         put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
 206                                                         put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
 207 
 208                                                         return (0);
 209                                                 }
 210                                                 break;
 211                         case BLKGETSIZE:        if (arg) {
 212                                                         if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
 213                                                                 return (err);
 214                                                         put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 215 
 216                                                         return (0);
 217                                                 }
 218                                                 break;
 219                         case BLKRRPART:         return (xd_reread_partitions(inode->i_rdev));
 220                         RO_IOCTLS(inode->i_rdev,arg);
 221                 }
 222         return (-EINVAL);
 223 }
 224 
 225 /* xd_release: release the device */
 226 static void xd_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         int dev = DEVICE_NR(MINOR(inode->i_rdev));
 229 
 230         if (dev < xd_drives) {
 231                 sync_dev(dev);
 232                 xd_access[dev]--;
 233         }
 234 }
 235 
 236 /* xd_reread_partitions: rereads the partition table from a drive */
 237 
 238 /* xd_reread_partitions: rereads the partition table from a drive */
 239 static int xd_reread_partitions(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241         int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
 242 
 243         cli(); xd_valid[target] = (xd_access[target] != 1); sti();
 244         if (xd_valid[target])
 245                 return (-EBUSY);
 246 
 247         for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 248                 sync_dev(MAJOR_NR << 8 | start | partition);
 249                 invalidate_inodes(MAJOR_NR << 8 | start | partition);
 250                 invalidate_buffers(MAJOR_NR << 8 | start | partition);
 251                 xd_gendisk.part[start + partition].start_sect = 0;
 252                 xd_gendisk.part[start + partition].nr_sects = 0;
 253         };
 254 
 255         xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
 256         resetup_one_dev(&xd_gendisk,target);
 257 
 258         xd_valid[target] = 1;
 259         wake_up(&xd_wait_open);
 260 
 261         return (0);
 262 }
 263 
 264 /* xd_readwrite: handle a read/write request */
 265 static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267         u_char cmdblk[6],sense[4];
 268         u_short track,cylinder;
 269         u_char head,sector,control,mode,temp;
 270         
 271 #ifdef DEBUG_READWRITE
 272         printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 273 #endif DEBUG_READWRITE
 274 
 275         control = xd_info[drive].control;
 276         while (count) {
 277                 temp = count < xd_maxsectors ? count : xd_maxsectors;
 278 
 279                 track = block / xd_info[drive].sectors;
 280                 head = track % xd_info[drive].heads;
 281                 cylinder = track / xd_info[drive].heads;
 282                 sector = block % xd_info[drive].sectors;
 283 
 284 #ifdef DEBUG_READWRITE
 285                 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 286 #endif DEBUG_READWRITE
 287 
 288                 if (xd_busy)                            /* get exclusive access to the controller */
 289                         sleep_on(&xd_wait_exclusive);
 290                 xd_busy = 1;
 291 
 292                 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,buffer,temp * 0x200);
 293                 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 294 
 295                 switch (xd_command(cmdblk,mode,buffer,buffer,sense,XD_TIMEOUT)) {
 296                         case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); xd_busy = 0; wake_up(&xd_wait_exclusive); return (0);
 297                         case 2: switch ((sense[0] & 0x30) >> 4) {
 298                                         case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
 299                                         case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
 300                                         case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
 301                                         case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
 302                                 }
 303                                 if (sense[0] & 0x80)
 304                                         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);
 305                                 else
 306                                         printk(" - no valid disk address\n");
 307                                 xd_busy = 0; wake_up(&xd_wait_exclusive);
 308                                 return (0);
 309                 }
 310                 count -= temp, buffer += temp * 0x200, block += temp;
 311 
 312                 xd_busy = 0; wake_up(&xd_wait_exclusive);
 313         }
 314         return (1);
 315 }
 316 
 317 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
 318 static void xd_recalibrate (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 319 {
 320         u_char cmdblk[6];
 321         
 322         xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 323         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
 324                 printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
 325 }
 326 
 327 /* xd_interrupt_handler: interrupt service routine */
 328 static void xd_interrupt_handler (int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330         if (inb(XD_STATUS) & STAT_INTERRUPT) {                                                  /* check if it was our device */
 331 #ifdef DEBUG_OTHER
 332                 printk("xd_interrupt_handler: interrupt detected\n");
 333 #endif DEBUG_OTHER
 334                 outb(0,XD_CONTROL);                                                             /* acknowledge interrupt */
 335                 wake_up(&xd_wait_int);                                                          /* and wake up sleeping processes */
 336         }
 337         else
 338                 printk("xd_interrupt_handler: unexpected interrupt\n");
 339 }
 340 
 341 /* xd_dma: set up the DMA controller for a data transfer */
 342 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         if (buffer < ((u_char *) 0x1000000 - count)) {          /* transfer to address < 16M? */
 345                 if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
 346 #ifdef DEBUG_OTHER
 347                         printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 348 #endif DEBUG_OTHER
 349                         return (PIO_MODE);
 350                 }
 351                 disable_dma(xd_dma);
 352                 clear_dma_ff(xd_dma);
 353                 set_dma_mode(xd_dma,mode);
 354                 set_dma_addr(xd_dma,(u_int) buffer);
 355                 set_dma_count(xd_dma,count);
 356 
 357                 return (DMA_MODE);                      /* use DMA and INT */
 358         }
 359 #ifdef DEBUG_OTHER
 360         printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
 361 #endif DEBUG_OTHER
 362         return (PIO_MODE);
 363 }
 364 
 365 /* xd_build: put stuff into an array in a format suitable for the controller */
 366 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 367 {
 368         cmdblk[0] = command;
 369         cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
 370         cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
 371         cmdblk[3] = cylinder & 0xFF;
 372         cmdblk[4] = count;
 373         cmdblk[5] = control;
 374         
 375         return (cmdblk);
 376 }
 377 
 378 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
 379 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381         u_long expiry = jiffies + timeout;
 382 
 383         while (((inb(port) & mask) != flags) && (jiffies < expiry))
 384                 ;
 385 
 386         return (jiffies >= expiry);
 387 }
 388 
 389 /* xd_command: handle all data transfers necessary for a single command */
 390 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 391 {
 392         u_char cmdblk[6],csb,complete = 0;
 393 
 394 #ifdef DEBUG_COMMAND
 395         printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 396 #endif DEBUG_COMMAND
 397 
 398         outb(0,XD_SELECT);
 399         outb(mode,XD_CONTROL);
 400 
 401         if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
 402                 return (1);
 403         
 404         while (!complete) {
 405                 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
 406                         return (1);
 407                 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
 408                         case 0:                 if (mode == DMA_MODE) {
 409                                                         enable_dma(xd_dma);
 410                                                         sleep_on(&xd_wait_int);
 411                                                         disable_dma(xd_dma);
 412                                                 }
 413                                                 else
 414                                                         outb(outdata ? *outdata++ : 0,XD_DATA);
 415                                                 break;
 416                         case STAT_INPUT:        if (mode == DMA_MODE) {
 417                                                         enable_dma(xd_dma);
 418                                                         sleep_on(&xd_wait_int);
 419                                                         disable_dma(xd_dma);
 420                                                 }
 421                                                 else
 422                                                         if (indata)
 423                                                                 *indata++ = inb(XD_DATA);
 424                                                         else
 425                                                                 inb(XD_DATA);
 426                                                 break;
 427                         case STAT_COMMAND:      outb(command ? *command++ : 0,XD_DATA); break;
 428                         case STAT_COMMAND
 429                              | STAT_INPUT:      complete = 1; break;
 430                 }
 431         }
 432         csb = inb(XD_DATA);
 433 
 434         if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                                       /* wait until deselected */
 435                 return (1);
 436 
 437         if (csb & CSB_ERROR) {                                                                  /* read sense data if error */
 438                 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 439                 if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
 440                         printk("xd_command: warning! sense command failed!\n");
 441         }
 442 
 443 #ifdef DEBUG_COMMAND
 444         printk("xd_command: completed with csb = 0x%X\n",csb);
 445 #endif DEBUG_COMMAND
 446 
 447         return (csb & CSB_ERROR);
 448 }
 449 
 450 static u_char xd_initdrives (void (*init_drive)(u_char drive))
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452         u_char cmdblk[6],i,count = 0;
 453 
 454         for (i = 0; i < XD_MAXDRIVES; i++) {
 455                 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 456                 if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
 457                         init_drive(count);
 458                         count++;
 459                 }
 460         }
 461         return (count);
 462 }
 463 
 464 #ifndef XD_OVERRIDE
 465 static void xd_dtc5150x_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 466 {
 467         switch ((u_long) address) {
 468                 case 0xC8000:   xd_iobase = 0x320; break;
 469                 case 0xCA000:   xd_iobase = 0x324; break;
 470         }
 471         xd_irq = 5;                     /* the IRQ _can_ be changed on this card, but requires a hardware mod */
 472         xd_dma = 3;
 473         xd_maxsectors = 0x01;           /* my card seems to have trouble doing multi-block transfers? */
 474 
 475         outb(0,XD_RESET);               /* reset the controller */
 476 }
 477 
 478 static void xd_dtc5150x_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480         u_char cmdblk[6],buf[64];
 481 
 482         xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 483         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 484                 xd_info[drive].heads = buf[0x0A];                       /* heads */
 485                 xd_info[drive].cylinders = ((u_short *) (buf))[0x04];   /* cylinders */
 486                 xd_info[drive].sectors = 17;                            /* sectors */
 487 #if 0
 488                 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];  /* reduced write */
 489                 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
 490                 xd_info[drive].ecc = buf[0x0F];                         /* ecc length */
 491 #endif 0
 492                 xd_info[drive].control = 0;                             /* control byte */
 493 
 494                 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]);
 495                 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 496                 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 497                         printk("xd_dtc5150x_init_drive: error setting step rate for drive %d\n",drive);
 498         }
 499         else
 500                 printk("xd_dtc5150x_init_drive: error reading geometry for drive %d\n",drive);
 501 }
 502 
 503 static void xd_wd1004a27x_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 504 {
 505         switch ((u_long) address) {
 506                 case 0xC8000:   xd_iobase = 0x320; break;
 507                 case 0xCA000:   xd_iobase = 0x324; break;
 508                 case 0xD0000:   xd_iobase = 0x328; break;
 509                 case 0xD8000:   xd_iobase = 0x32C; break;
 510         }
 511         xd_irq = 5;                     /* don't know how to auto-detect this yet */
 512         xd_dma = 3;
 513         xd_maxsectors = 0x01;           /* this one doesn't wrap properly either... */
 514 
 515         outb(0,XD_RESET);               /* reset the controller */
 516 }
 517 
 518 static void xd_wd1004a27x_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 519 {
 520         u_char cmdblk[6],buf[0x200];
 521 
 522         xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 523         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 524                 xd_info[drive].heads = buf[0x1AF];                              /* heads */
 525                 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];       /* cylinders */
 526                 xd_info[drive].sectors = 17;                                    /* sectors */
 527 #if 0
 528                 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];              /* reduced write */
 529                 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];            /* write precomp */
 530                 xd_info[drive].ecc = buf[0x1B4];                                /* ecc length */
 531 #endif 0
 532                 xd_info[drive].control = buf[0x1B5];                            /* control byte */
 533 
 534                 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
 535         }
 536         else
 537                 printk("xd_wd1004a27x_init_drive: error reading geometry for drive %d\n",drive);        
 538 }
 539 
 540 static void xd_seagate11_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 541 {
 542         switch ((u_long) address) {
 543                 case 0xC8000:   xd_iobase = 0x320; break;
 544                 case 0xD0000:   xd_iobase = 0x324; break;
 545                 case 0xD8000:   xd_iobase = 0x328; break;
 546                 case 0xE0000:   xd_iobase = 0x32C; break;
 547         }
 548         xd_irq = 5;                     /* the IRQ and DMA channel are fixed on the Seagate controllers */
 549         xd_dma = 3;
 550         xd_maxsectors = 0x40;
 551 
 552         outb(0,XD_RESET);               /* reset the controller */
 553 }
 554 
 555 static void xd_seagate11_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 556 {
 557         u_char cmdblk[6],buf[0x200];
 558 
 559         xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 560         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 561                 xd_info[drive].heads = buf[0x04];                               /* heads */
 562                 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03];        /* cylinders */
 563                 xd_info[drive].sectors = buf[0x05];                             /* sectors */
 564                 xd_info[drive].control = 0;                                     /* control byte */
 565         }
 566         else
 567                 printk("xd_seagate11_init_drive: error reading geometry from drive %d\n",drive);
 568 }
 569 #endif XD_OVERRIDE
 570 
 571 /* xd_override_init_controller: sets appropriate values for unknown controllers. */
 572 static void xd_override_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 573 {
 574         xd_iobase = 0x320;              /* standard setting */
 575         xd_irq = 5;                     /* ditto */
 576         xd_dma = 3;                     /* ditto */
 577         xd_maxsectors = 0x01;
 578 
 579         outb(0,XD_RESET);               /* reset the controller */
 580 }
 581 
 582 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
 583    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
 584 static void xd_override_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 585 {
 586         u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 587         u_char cmdblk[6],i;
 588 
 589         for (i = 0; i < 3; i++) {
 590                 while (min[i] != max[i] - 1) {
 591                         test[i] = (min[i] + max[i]) / 2;
 592                         xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
 593                         if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 594                                 min[i] = test[i];
 595                         else
 596                                 max[i] = test[i];
 597                 }
 598                 test[i] = min[i];
 599         }
 600         xd_info[drive].heads = (u_char) min[0] + 1;
 601         xd_info[drive].cylinders = (u_short) min[1] + 1;
 602         xd_info[drive].sectors = (u_char) min[2] + 1;
 603         xd_info[drive].control = 0;
 604 }
 605 
 606 #ifndef XD_OVERRIDE
 607 /* xd_setparam: set the drive characteristics */
 608 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 609 {
 610         u_char cmdblk[14];
 611 
 612         xd_build(cmdblk,command,drive,0,0,0,0,0);
 613         cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
 614         cmdblk[7] = (u_char) (cylinders & 0xFF);
 615         cmdblk[8] = heads & 0x1F;
 616         cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
 617         cmdblk[10] = (u_char) (rwrite & 0xFF);
 618         cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
 619         cmdblk[12] = (u_char) (wprecomp & 0xFF);
 620         cmdblk[13] = ecc;
 621 
 622         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 623                 printk("xd_setparam: error setting characteristics for drive %d\n",drive);
 624 }
 625 #endif XD_OVERRIDE
 626 
 627 #endif CONFIG_BLK_DEV_XD

/* [previous][next][first][last][top][bottom][index][help] */