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

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