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

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