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

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