root/drivers/block/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_dtc_init_controller
  18. xd_dtc_init_drive
  19. xd_wd_init_controller
  20. xd_wd_init_drive
  21. xd_seagate_init_controller
  22. xd_seagate_init_drive
  23. xd_omti_init_controller
  24. xd_omti_init_drive
  25. xd_override_init_drive
  26. xd_setup
  27. xd_setparam

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

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