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         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
  85         if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
  86                 printk("xd_init: unable to get major number %d\n",MAJOR_NR);
  87                 return (mem_start);
  88         }
  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 target = DEVICE_NR(MINOR(inode->i_rdev));
 153 
 154         while (!xd_valid[target])
 155                 sleep_on(&xd_wait_open);
 156 
 157         xd_access[target]++;
 158 
 159         return (0);
 160 }
 161 
 162 /* do_xd_request: handle an incoming request */
 163 static void do_xd_request (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165         u_int block,count,retry;
 166         int code;
 167 
 168         sti();
 169         while (code = 0, CURRENT) {
 170                 INIT_REQUEST;   /* do some checking on the request structure */
 171 
 172                 if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
 173                         block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
 174                         count = CURRENT->nr_sectors;
 175 
 176                         switch (CURRENT->cmd) {
 177                                 case READ:
 178                                 case WRITE:     for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
 179                                                         code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 180                                                 break;
 181                                 default:        printk("do_xd_request: unknown request\n"); break;
 182                         }
 183                 }
 184                 end_request(code);      /* wrap up, 0 = fail, 1 = success */
 185         }
 186 }
 187 
 188 /* xd_ioctl: handle device ioctl's */
 189 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
 192         int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
 193 
 194         if (inode && (dev < xd_drives))
 195                 switch (cmd) {
 196                         case HDIO_GETGEO:       if (arg) {
 197                                                         if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
 198                                                                 return (err);
 199                                                         put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
 200                                                         put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
 201                                                         put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
 202                                                         put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
 203 
 204                                                         return (0);
 205                                                 }
 206                                                 break;
 207                         case BLKGETSIZE:        if (arg) {
 208                                                         if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
 209                                                                 return (err);
 210                                                         put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 211 
 212                                                         return (0);
 213                                                 }
 214                                                 break;
 215                         case BLKRRPART:         return (xd_reread_partitions(inode->i_rdev));
 216                         RO_IOCTLS(inode->i_rdev,arg);
 217                 }
 218         return (-EINVAL);
 219 }
 220 
 221 /* xd_release: release the device */
 222 static void xd_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         sync_dev(inode->i_rdev);
 225         xd_access[DEVICE_NR(MINOR(inode->i_rdev))]--;
 226 }
 227 
 228 /* xd_reread_partitions: rereads the partition table from a drive */
 229 
 230 /* xd_reread_partitions: rereads the partition table from a drive */
 231 static int xd_reread_partitions(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 232 {
 233         int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
 234 
 235         cli(); xd_valid[target] = (xd_access[target] != 1); sti();
 236         if (xd_valid[target])
 237                 return (-EBUSY);
 238 
 239         for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 240                 sync_dev(MAJOR_NR << 8 | start | partition);
 241                 invalidate_inodes(MAJOR_NR << 8 | start | partition);
 242                 invalidate_buffers(MAJOR_NR << 8 | start | partition);
 243                 xd_gendisk.part[start + partition].start_sect = 0;
 244                 xd_gendisk.part[start + partition].nr_sects = 0;
 245         };
 246 
 247         xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
 248         resetup_one_dev(&xd_gendisk,target);
 249 
 250         xd_valid[target] = 1;
 251         wake_up(&xd_wait_open);
 252 
 253         return (0);
 254 }
 255 
 256 /* xd_readwrite: handle a read/write request */
 257 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] */
 258 {
 259         u_char cmdblk[6],sense[4];
 260         u_short track,cylinder;
 261         u_char head,sector,control,mode,temp;
 262         
 263 #ifdef DEBUG_READWRITE
 264         printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 265 #endif DEBUG_READWRITE
 266 
 267         control = xd_info[drive].control;
 268         while (count) {
 269                 temp = count < xd_maxsectors ? count : xd_maxsectors;
 270 
 271                 track = block / xd_info[drive].sectors;
 272                 head = track % xd_info[drive].heads;
 273                 cylinder = track / xd_info[drive].heads;
 274                 sector = block % xd_info[drive].sectors;
 275 
 276 #ifdef DEBUG_READWRITE
 277                 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 278 #endif DEBUG_READWRITE
 279 
 280                 if (xd_busy)                            /* get exclusive access to the controller */
 281                         sleep_on(&xd_wait_exclusive);
 282                 xd_busy = 1;
 283 
 284                 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,buffer,temp * 0x200);
 285                 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 286 
 287                 switch (xd_command(cmdblk,mode,buffer,buffer,sense,XD_TIMEOUT)) {
 288                         case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); xd_busy = 0; wake_up(&xd_wait_exclusive); return (0);
 289                         case 2: switch ((sense[0] & 0x30) >> 4) {
 290                                         case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
 291                                         case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
 292                                         case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
 293                                         case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
 294                                 }
 295                                 if (sense[0] & 0x80)
 296                                         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);
 297                                 else
 298                                         printk(" - no valid disk address\n");
 299                                 xd_busy = 0; wake_up(&xd_wait_exclusive);
 300                                 return (0);
 301                 }
 302                 count -= temp, buffer += temp * 0x200, block += temp;
 303 
 304                 xd_busy = 0; wake_up(&xd_wait_exclusive);
 305         }
 306         return (1);
 307 }
 308 
 309 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
 310 static void xd_recalibrate (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312         u_char cmdblk[6];
 313         
 314         xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 315         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
 316                 printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
 317 }
 318 
 319 /* xd_interrupt_handler: interrupt service routine */
 320 static void xd_interrupt_handler (int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 321 {
 322         if (inb(XD_STATUS) & STAT_INTERRUPT) {                                                  /* check if it was our device */
 323 #ifdef DEBUG_OTHER
 324                 printk("xd_interrupt_handler: interrupt detected\n");
 325 #endif DEBUG_OTHER
 326                 outb(0,XD_CONTROL);                                                             /* acknowledge interrupt */
 327                 wake_up(&xd_wait_int);                                                          /* and wake up sleeping processes */
 328         }
 329         else
 330                 printk("xd_interrupt_handler: unexpected interrupt\n");
 331 }
 332 
 333 /* xd_dma: set up the DMA controller for a data transfer */
 334 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336         if (buffer < ((u_char *) 0x1000000 - count)) {          /* transfer to address < 16M? */
 337                 if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
 338 #ifdef DEBUG_OTHER
 339                         printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 340 #endif DEBUG_OTHER
 341                         return (PIO_MODE);
 342                 }
 343                 disable_dma(xd_dma);
 344                 clear_dma_ff(xd_dma);
 345                 set_dma_mode(xd_dma,mode);
 346                 set_dma_addr(xd_dma,(u_int) buffer);
 347                 set_dma_count(xd_dma,count);
 348 
 349                 return (DMA_MODE);                      /* use DMA and INT */
 350         }
 351 #ifdef DEBUG_OTHER
 352         printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
 353 #endif DEBUG_OTHER
 354         return (PIO_MODE);
 355 }
 356 
 357 /* xd_build: put stuff into an array in a format suitable for the controller */
 358 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] */
 359 {
 360         cmdblk[0] = command;
 361         cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
 362         cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
 363         cmdblk[3] = cylinder & 0xFF;
 364         cmdblk[4] = count;
 365         cmdblk[5] = control;
 366         
 367         return (cmdblk);
 368 }
 369 
 370 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
 371 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] */
 372 {
 373         u_long expiry = jiffies + timeout;
 374 
 375         while (((inb(port) & mask) != flags) && (jiffies < expiry))
 376                 ;
 377 
 378         return (jiffies >= expiry);
 379 }
 380 
 381 /* xd_command: handle all data transfers necessary for a single command */
 382 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] */
 383 {
 384         u_char cmdblk[6],csb,complete = 0;
 385 
 386 #ifdef DEBUG_COMMAND
 387         printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 388 #endif DEBUG_COMMAND
 389 
 390         outb(0,XD_SELECT);
 391         outb(mode,XD_CONTROL);
 392 
 393         if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
 394                 return (1);
 395         
 396         while (!complete) {
 397                 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
 398                         return (1);
 399                 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
 400                         case 0:                 if (mode == DMA_MODE) {
 401                                                         enable_dma(xd_dma);
 402                                                         sleep_on(&xd_wait_int);
 403                                                         disable_dma(xd_dma);
 404                                                 }
 405                                                 else
 406                                                         outb(outdata ? *outdata++ : 0,XD_DATA);
 407                                                 break;
 408                         case STAT_INPUT:        if (mode == DMA_MODE) {
 409                                                         enable_dma(xd_dma);
 410                                                         sleep_on(&xd_wait_int);
 411                                                         disable_dma(xd_dma);
 412                                                 }
 413                                                 else
 414                                                         if (indata)
 415                                                                 *indata++ = inb(XD_DATA);
 416                                                         else
 417                                                                 inb(XD_DATA);
 418                                                 break;
 419                         case STAT_COMMAND:      outb(command ? *command++ : 0,XD_DATA); break;
 420                         case STAT_COMMAND
 421                              | STAT_INPUT:      complete = 1; break;
 422                 }
 423         }
 424         csb = inb(XD_DATA);
 425 
 426         if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                                       /* wait until deselected */
 427                 return (1);
 428 
 429         if (csb & CSB_ERROR) {                                                                  /* read sense data if error */
 430                 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 431                 if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
 432                         printk("xd_command: warning! sense command failed!\n");
 433         }
 434 
 435 #ifdef DEBUG_COMMAND
 436         printk("xd_command: completed with csb = 0x%X\n",csb);
 437 #endif DEBUG_COMMAND
 438 
 439         return (csb & CSB_ERROR);
 440 }
 441 
 442 static u_char xd_initdrives (void (*init_drive)(u_char drive))
     /* [previous][next][first][last][top][bottom][index][help] */
 443 {
 444         u_char cmdblk[6],i,count = 0;
 445 
 446         for (i = 0; i < XD_MAXDRIVES; i++) {
 447                 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 448                 if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
 449                         init_drive(count);
 450                         count++;
 451                 }
 452         }
 453         return (count);
 454 }
 455 
 456 #ifndef XD_OVERRIDE
 457 static void xd_dtc5150x_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459         switch ((u_long) address) {
 460                 case 0xC8000:   xd_iobase = 0x320; break;
 461                 case 0xCA000:   xd_iobase = 0x324; break;
 462         }
 463         xd_irq = 5;                     /* the IRQ _can_ be changed on this card, but requires a hardware mod */
 464         xd_dma = 3;
 465         xd_maxsectors = 0x01;           /* my card seems to have trouble doing multi-block transfers? */
 466 
 467         outb(0,XD_RESET);               /* reset the controller */
 468 }
 469 
 470 static void xd_dtc5150x_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 471 {
 472         u_char cmdblk[6],buf[64];
 473 
 474         xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 475         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 476                 xd_info[drive].heads = buf[0x0A];                       /* heads */
 477                 xd_info[drive].cylinders = ((u_short *) (buf))[0x04];   /* cylinders */
 478                 xd_info[drive].sectors = 17;                            /* sectors */
 479 #if 0
 480                 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];  /* reduced write */
 481                 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
 482                 xd_info[drive].ecc = buf[0x0F];                         /* ecc length */
 483 #endif 0
 484                 xd_info[drive].control = 0;                             /* control byte */
 485 
 486                 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]);
 487                 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 488                 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 489                         printk("xd_dtc5150x_init_drive: error setting step rate for drive %d\n",drive);
 490         }
 491         else
 492                 printk("xd_dtc5150x_init_drive: error reading geometry for drive %d\n",drive);
 493 }
 494 
 495 static void xd_wd1004a27x_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 496 {
 497         switch ((u_long) address) {
 498                 case 0xC8000:   xd_iobase = 0x320; break;
 499                 case 0xCA000:   xd_iobase = 0x324; break;
 500                 case 0xD0000:   xd_iobase = 0x328; break;
 501                 case 0xD8000:   xd_iobase = 0x32C; break;
 502         }
 503         xd_irq = 5;                     /* don't know how to auto-detect this yet */
 504         xd_dma = 3;
 505         xd_maxsectors = 0x01;           /* this one doesn't wrap properly either... */
 506 
 507         outb(0,XD_RESET);               /* reset the controller */
 508 }
 509 
 510 static void xd_wd1004a27x_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 511 {
 512         u_char cmdblk[6],buf[0x200];
 513 
 514         xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 515         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 516                 xd_info[drive].heads = buf[0x1AF];                              /* heads */
 517                 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];       /* cylinders */
 518                 xd_info[drive].sectors = 17;                                    /* sectors */
 519 #if 0
 520                 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];              /* reduced write */
 521                 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];            /* write precomp */
 522                 xd_info[drive].ecc = buf[0x1B4];                                /* ecc length */
 523 #endif 0
 524                 xd_info[drive].control = buf[0x1B5];                            /* control byte */
 525 
 526                 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
 527         }
 528         else
 529                 printk("xd_wd1004a27x_init_drive: error reading geometry for drive %d\n",drive);        
 530 }
 531 
 532 static void xd_seagate11_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534         switch ((u_long) address) {
 535                 case 0xC8000:   xd_iobase = 0x320; break;
 536                 case 0xD0000:   xd_iobase = 0x324; break;
 537                 case 0xD8000:   xd_iobase = 0x328; break;
 538                 case 0xE0000:   xd_iobase = 0x32C; break;
 539         }
 540         xd_irq = 5;                     /* the IRQ and DMA channel are fixed on the Seagate controllers */
 541         xd_dma = 3;
 542         xd_maxsectors = 0x40;
 543 
 544         outb(0,XD_RESET);               /* reset the controller */
 545 }
 546 
 547 static void xd_seagate11_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 548 {
 549         u_char cmdblk[6],buf[0x200];
 550 
 551         xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 552         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 553                 xd_info[drive].heads = buf[0x04];                               /* heads */
 554                 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03];        /* cylinders */
 555                 xd_info[drive].sectors = buf[0x05];                             /* sectors */
 556                 xd_info[drive].control = 0;                                     /* control byte */
 557         }
 558         else
 559                 printk("xd_seagate11_init_drive: error reading geometry from drive %d\n",drive);
 560 }
 561 #endif XD_OVERRIDE
 562 
 563 /* xd_override_init_controller: sets appropriate values for unknown controllers. */
 564 static void xd_override_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566         xd_iobase = 0x320;              /* standard setting */
 567         xd_irq = 5;                     /* ditto */
 568         xd_dma = 3;                     /* ditto */
 569         xd_maxsectors = 0x01;
 570 
 571         outb(0,XD_RESET);               /* reset the controller */
 572 }
 573 
 574 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
 575    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
 576 static void xd_override_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 577 {
 578         u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 579         u_char cmdblk[6],i;
 580 
 581         for (i = 0; i < 3; i++) {
 582                 while (min[i] != max[i] - 1) {
 583                         test[i] = (min[i] + max[i]) / 2;
 584                         xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
 585                         if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 586                                 min[i] = test[i];
 587                         else
 588                                 max[i] = test[i];
 589                 }
 590                 test[i] = min[i];
 591         }
 592         xd_info[drive].heads = (u_char) min[0] + 1;
 593         xd_info[drive].cylinders = (u_short) min[1] + 1;
 594         xd_info[drive].sectors = (u_char) min[2] + 1;
 595         xd_info[drive].control = 0;
 596 }
 597 
 598 #ifndef XD_OVERRIDE
 599 /* xd_setparam: set the drive characteristics */
 600 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] */
 601 {
 602         u_char cmdblk[14];
 603 
 604         xd_build(cmdblk,command,drive,0,0,0,0,0);
 605         cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
 606         cmdblk[7] = (u_char) (cylinders & 0xFF);
 607         cmdblk[8] = heads & 0x1F;
 608         cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
 609         cmdblk[10] = (u_char) (rwrite & 0xFF);
 610         cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
 611         cmdblk[12] = (u_char) (wprecomp & 0xFF);
 612         cmdblk[13] = ecc;
 613 
 614         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 615                 printk("xd_setparam: error setting characteristics for drive %d\n",drive);
 616 }
 617 #endif XD_OVERRIDE
 618 
 619 #endif CONFIG_BLK_DEV_XD

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