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
  28. init_module
  29. cleanup_module

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

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