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 "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 u_long xd_init (u_long mem_start,u_long mem_end)
     /* [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 (mem_start);
 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 mem_start;
 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 (void)
     /* [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(MINOR(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 && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
 220                         block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
 221                         count = CURRENT->nr_sectors;
 222 
 223                         switch (CURRENT->cmd) {
 224                                 case READ:
 225                                 case WRITE:
 226                                         for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
 227                                                 code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 228                                         break;
 229                                 default:
 230                                         printk("do_xd_request: unknown request\n"); break;
 231                         }
 232                 }
 233                 end_request(code);      /* wrap up, 0 = fail, 1 = success */
 234         }
 235 }
 236 
 237 /* xd_ioctl: handle device ioctl's */
 238 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 239 {
 240         XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
 241         int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
 242 
 243         if (inode && (dev < xd_drives))
 244                 switch (cmd) {
 245                         case HDIO_GETGEO:
 246                                 if (arg) {
 247                                         if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
 248                                                 return (err);
 249                                         put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
 250                                         put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
 251                                         put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
 252                                         put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
 253 
 254                                         return (0);
 255                                 }
 256                                 break;
 257                         case BLKRASET:
 258                           if(!suser())  return -EACCES;
 259                           if(!inode->i_rdev) return -EINVAL;
 260                           if(arg > 0xff) return -EINVAL;
 261                           read_ahead[MAJOR(inode->i_rdev)] = arg;
 262                           return 0;
 263                         case BLKGETSIZE:
 264                                 if (arg) {
 265                                         if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
 266                                                 return (err);
 267                                         put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
 268 
 269                                         return (0);
 270                                 }
 271                                 break;
 272                         case BLKFLSBUF:
 273                                 if(!suser())  return -EACCES;
 274                                 if(!inode->i_rdev) return -EINVAL;
 275                                 fsync_dev(inode->i_rdev);
 276                                 invalidate_buffers(inode->i_rdev);
 277                                 return 0;
 278                                 
 279                         case BLKRRPART:
 280                                 return (xd_reread_partitions(inode->i_rdev));
 281                         RO_IOCTLS(inode->i_rdev,arg);
 282                 }
 283         return (-EINVAL);
 284 }
 285 
 286 /* xd_release: release the device */
 287 static void xd_release (struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289         int dev = DEVICE_NR(MINOR(inode->i_rdev));
 290 
 291         if (dev < xd_drives) {
 292                 sync_dev(dev);
 293                 xd_access[dev]--;
 294         }
 295 }
 296 
 297 /* xd_reread_partitions: rereads the partition table from a drive */
 298 static int xd_reread_partitions(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300         int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
 301 
 302         cli(); xd_valid[target] = (xd_access[target] != 1); sti();
 303         if (xd_valid[target])
 304                 return (-EBUSY);
 305 
 306         for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 307                 sync_dev(MAJOR_NR << 8 | start | partition);
 308                 invalidate_inodes(MAJOR_NR << 8 | start | partition);
 309                 invalidate_buffers(MAJOR_NR << 8 | start | partition);
 310                 xd_gendisk.part[start + partition].start_sect = 0;
 311                 xd_gendisk.part[start + partition].nr_sects = 0;
 312         };
 313 
 314         xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
 315         resetup_one_dev(&xd_gendisk,target);
 316 
 317         xd_valid[target] = 1;
 318         wake_up(&xd_wait_open);
 319 
 320         return (0);
 321 }
 322 
 323 /* xd_readwrite: handle a read/write request */
 324 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] */
 325 {
 326         u_char cmdblk[6],sense[4];
 327         u_short track,cylinder;
 328         u_char head,sector,control,mode,temp;
 329         
 330 #ifdef DEBUG_READWRITE
 331         printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 332 #endif /* DEBUG_READWRITE */
 333 
 334         control = xd_info[drive].control;
 335         while (count) {
 336                 temp = count < xd_maxsectors ? count : xd_maxsectors;
 337 
 338                 track = block / xd_info[drive].sectors;
 339                 head = track % xd_info[drive].heads;
 340                 cylinder = track / xd_info[drive].heads;
 341                 sector = block % xd_info[drive].sectors;
 342 
 343 #ifdef DEBUG_READWRITE
 344                 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 345 #endif /* DEBUG_READWRITE */
 346 
 347                 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
 348                 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 349 
 350                 switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
 351                         case 1:
 352                                 printk("xd_readwrite: timeout, recalibrating drive\n");
 353                                 xd_recalibrate(drive);
 354                                 return (0);
 355                         case 2:
 356                                 switch ((sense[0] & 0x30) >> 4) {
 357                                         case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
 358                                         case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
 359                                         case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
 360                                         case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
 361                                 }
 362                                 if (sense[0] & 0x80)
 363                                         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);
 364                                 else
 365                                         printk(" - no valid disk address\n");
 366                                 return (0);
 367                 }
 368                 count -= temp, buffer += temp * 0x200, block += temp;
 369         }
 370         return (1);
 371 }
 372 
 373 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
 374 static void xd_recalibrate (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 375 {
 376         u_char cmdblk[6];
 377         
 378         xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 379         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
 380                 printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
 381 }
 382 
 383 /* xd_interrupt_handler: interrupt service routine */
 384 static void xd_interrupt_handler(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386         if (inb(XD_STATUS) & STAT_INTERRUPT) {                                                  /* check if it was our device */
 387 #ifdef DEBUG_OTHER
 388                 printk("xd_interrupt_handler: interrupt detected\n");
 389 #endif /* DEBUG_OTHER */
 390                 outb(0,XD_CONTROL);                                                             /* acknowledge interrupt */
 391                 wake_up(&xd_wait_int);                                                          /* and wake up sleeping processes */
 392         }
 393         else
 394                 printk("xd_interrupt_handler: unexpected interrupt\n");
 395 }
 396 
 397 /* xd_dma: set up the DMA controller for a data transfer */
 398 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400         if (buffer < ((u_char *) 0x1000000 - count)) {          /* transfer to address < 16M? */
 401                 if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
 402 #ifdef DEBUG_OTHER
 403                         printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 404 #endif /* DEBUG_OTHER */
 405                         return (PIO_MODE);
 406                 }
 407                 disable_dma(xd_dma);
 408                 clear_dma_ff(xd_dma);
 409                 set_dma_mode(xd_dma,mode);
 410                 set_dma_addr(xd_dma,(u_int) buffer);
 411                 set_dma_count(xd_dma,count);
 412 
 413                 return (DMA_MODE);                      /* use DMA and INT */
 414         }
 415 #ifdef DEBUG_OTHER
 416         printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
 417 #endif /* DEBUG_OTHER */
 418         return (PIO_MODE);
 419 }
 420 
 421 /* xd_build: put stuff into an array in a format suitable for the controller */
 422 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] */
 423 {
 424         cmdblk[0] = command;
 425         cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
 426         cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
 427         cmdblk[3] = cylinder & 0xFF;
 428         cmdblk[4] = count;
 429         cmdblk[5] = control;
 430         
 431         return (cmdblk);
 432 }
 433 
 434 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
 435 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] */
 436 {
 437         u_long expiry = jiffies + timeout;
 438 
 439         while (((inb(port) & mask) != flags) && (jiffies < expiry))
 440                 ;
 441 
 442         return (jiffies >= expiry);
 443 }
 444 
 445 /* xd_command: handle all data transfers necessary for a single command */
 446 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] */
 447 {
 448         u_char cmdblk[6],csb,complete = 0;
 449 
 450 #ifdef DEBUG_COMMAND
 451         printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 452 #endif /* DEBUG_COMMAND */
 453 
 454         outb(0,XD_SELECT);
 455         outb(mode,XD_CONTROL);
 456 
 457         if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
 458                 return (1);
 459         
 460         while (!complete) {
 461                 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
 462                         return (1);
 463                 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
 464                         case 0:
 465                                 if (mode == DMA_MODE) {
 466                                         enable_dma(xd_dma);
 467                                         sleep_on(&xd_wait_int);
 468                                         disable_dma(xd_dma);
 469                                 } else
 470                                         outb(outdata ? *outdata++ : 0,XD_DATA);
 471                                 break;
 472                         case STAT_INPUT:
 473                                 if (mode == DMA_MODE) {
 474                                         enable_dma(xd_dma);
 475                                         sleep_on(&xd_wait_int);
 476                                         disable_dma(xd_dma);
 477                                 } else
 478                                         if (indata)
 479                                                 *indata++ = inb(XD_DATA);
 480                                         else
 481                                                 inb(XD_DATA);
 482                                 break;
 483                         case STAT_COMMAND:
 484                                 outb(command ? *command++ : 0,XD_DATA);
 485                                 break;
 486                         case STAT_COMMAND | STAT_INPUT:
 487                                 complete = 1;
 488                                 break;
 489                 }
 490         }
 491         csb = inb(XD_DATA);
 492 
 493         if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                                       /* wait until deselected */
 494                 return (1);
 495 
 496         if (csb & CSB_ERROR) {                                                                  /* read sense data if error */
 497                 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 498                 if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
 499                         printk("xd_command: warning! sense command failed!\n");
 500         }
 501 
 502 #ifdef DEBUG_COMMAND
 503         printk("xd_command: completed with csb = 0x%X\n",csb);
 504 #endif /* DEBUG_COMMAND */
 505 
 506         return (csb & CSB_ERROR);
 507 }
 508 
 509 static u_char xd_initdrives (void (*init_drive)(u_char drive))
     /* [previous][next][first][last][top][bottom][index][help] */
 510 {
 511         u_char cmdblk[6],i,count = 0;
 512 
 513         for (i = 0; i < XD_MAXDRIVES; i++) {
 514                 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 515                 if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
 516                         init_drive(count);
 517                         count++;
 518                 }
 519         }
 520         return (count);
 521 }
 522 
 523 static void xd_dtc_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 524 {
 525         switch ((u_long) address) {
 526                 case 0xC8000:   xd_iobase = 0x320; break;
 527                 case 0xCA000:   xd_iobase = 0x324; break;
 528                 default:        printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
 529                                 xd_iobase = 0x320; break;
 530         }
 531         xd_irq = 5;                     /* the IRQ _can_ be changed on this card, but requires a hardware mod */
 532         xd_dma = 3;
 533         xd_maxsectors = 0x01;           /* my card seems to have trouble doing multi-block transfers? */
 534 
 535         outb(0,XD_RESET);               /* reset the controller */
 536 }
 537 
 538 static void xd_dtc_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 539 {
 540         u_char cmdblk[6],buf[64];
 541 
 542         xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 543         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 544                 xd_info[drive].heads = buf[0x0A];                       /* heads */
 545                 xd_info[drive].cylinders = ((u_short *) (buf))[0x04];   /* cylinders */
 546                 xd_info[drive].sectors = 17;                            /* sectors */
 547 #if 0
 548                 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];  /* reduced write */
 549                 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
 550                 xd_info[drive].ecc = buf[0x0F];                         /* ecc length */
 551 #endif /* 0 */
 552                 xd_info[drive].control = 0;                             /* control byte */
 553 
 554                 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]);
 555                 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 556                 if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 557                         printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive);
 558         }
 559         else
 560                 printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
 561 }
 562 
 563 static void xd_wd_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         switch ((u_long) address) {
 566                 case 0xC8000:   xd_iobase = 0x320; break;
 567                 case 0xCA000:   xd_iobase = 0x324; break;
 568                 case 0xCC000:   xd_iobase = 0x328; break;
 569                 case 0xCE000:   xd_iobase = 0x32C; break;
 570                 case 0xD0000:   xd_iobase = 0x328; break;
 571                 case 0xD8000:   xd_iobase = 0x32C; break;
 572                 default:        printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
 573                                 xd_iobase = 0x320; break;
 574         }
 575         xd_irq = 5;                     /* don't know how to auto-detect this yet */
 576         xd_dma = 3;
 577         xd_maxsectors = 0x01;           /* this one doesn't wrap properly either... */
 578 
 579         /* outb(0,XD_RESET); */         /* reset the controller */
 580 }
 581 
 582 static void xd_wd_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584         u_char cmdblk[6],buf[0x200];
 585 
 586         xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 587         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 588                 xd_info[drive].heads = buf[0x1AF];                              /* heads */
 589                 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];       /* cylinders */
 590                 xd_info[drive].sectors = 17;                                    /* sectors */
 591 #if 0
 592                 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];              /* reduced write */
 593                 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];            /* write precomp */
 594                 xd_info[drive].ecc = buf[0x1B4];                                /* ecc length */
 595 #endif /* 0 */
 596                 xd_info[drive].control = buf[0x1B5];                            /* control byte */
 597 
 598                 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
 599         }
 600         else
 601                 printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);        
 602 }
 603 
 604 static void xd_seagate_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 605 {
 606         switch ((u_long) address) {
 607                 case 0xC8000:   xd_iobase = 0x320; break;
 608                 case 0xD0000:   xd_iobase = 0x324; break;
 609                 case 0xD8000:   xd_iobase = 0x328; break;
 610                 case 0xE0000:   xd_iobase = 0x32C; break;
 611                 default:        printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
 612                                 xd_iobase = 0x320; break;
 613         }
 614         xd_irq = 5;                     /* the IRQ and DMA channel are fixed on the Seagate controllers */
 615         xd_dma = 3;
 616         xd_maxsectors = 0x40;
 617 
 618         outb(0,XD_RESET);               /* reset the controller */
 619 }
 620 
 621 static void xd_seagate_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 622 {
 623         u_char cmdblk[6],buf[0x200];
 624 
 625         xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 626         if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 627                 xd_info[drive].heads = buf[0x04];                               /* heads */
 628                 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03];        /* cylinders */
 629                 xd_info[drive].sectors = buf[0x05];                             /* sectors */
 630                 xd_info[drive].control = 0;                                     /* control byte */
 631         }
 632         else
 633                 printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
 634 }
 635 
 636 /* Omti support courtesy Dirk Melchers */
 637 static void xd_omti_init_controller (u_char *address)
     /* [previous][next][first][last][top][bottom][index][help] */
 638 {
 639         switch ((u_long) address) {
 640                 case 0xC8000:   xd_iobase = 0x320; break;
 641                 case 0xD0000:   xd_iobase = 0x324; break;
 642                 case 0xD8000:   xd_iobase = 0x328; break;
 643                 case 0xE0000:   xd_iobase = 0x32C; break;
 644                 default:        printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
 645                                 xd_iobase = 0x320; break;
 646         }
 647         
 648         xd_irq = 5;                     /* the IRQ and DMA channel are fixed on the Omti controllers */
 649         xd_dma = 3;
 650         xd_maxsectors = 0x40;
 651 
 652         outb(0,XD_RESET);               /* reset the controller */
 653 }
 654 
 655 static void xd_omti_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 656 {
 657         /* gets infos from drive */
 658         xd_override_init_drive(drive);
 659 
 660         /* set other parameters, Hardcoded, not that nice :-) */
 661         xd_info[drive].control = 2;
 662 }
 663 
 664 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
 665    etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
 666 static void xd_override_init_drive (u_char drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 667 {
 668         u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
 669         u_char cmdblk[6],i;
 670 
 671         for (i = 0; i < 3; i++) {
 672                 while (min[i] != max[i] - 1) {
 673                         test[i] = (min[i] + max[i]) / 2;
 674                         xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
 675                         if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 676                                 min[i] = test[i];
 677                         else
 678                                 max[i] = test[i];
 679                 }
 680                 test[i] = min[i];
 681         }
 682         xd_info[drive].heads = (u_char) min[0] + 1;
 683         xd_info[drive].cylinders = (u_short) min[1] + 1;
 684         xd_info[drive].sectors = (u_char) min[2] + 1;
 685         xd_info[drive].control = 0;
 686 }
 687 
 688 /* xd_setup: initialise from command line parameters */
 689 void xd_setup (char *command,int *integers)
     /* [previous][next][first][last][top][bottom][index][help] */
 690 {
 691         xd_override = 1;
 692 
 693         xd_type = integers[1];
 694         xd_irq = integers[2];
 695         xd_iobase = integers[3];
 696         xd_dma = integers[4];
 697 
 698         xd_maxsectors = 0x01;
 699 }
 700 
 701 /* xd_setparam: set the drive characteristics */
 702 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] */
 703 {
 704         u_char cmdblk[14];
 705 
 706         xd_build(cmdblk,command,drive,0,0,0,0,0);
 707         cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
 708         cmdblk[7] = (u_char) (cylinders & 0xFF);
 709         cmdblk[8] = heads & 0x1F;
 710         cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
 711         cmdblk[10] = (u_char) (rwrite & 0xFF);
 712         cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
 713         cmdblk[12] = (u_char) (wprecomp & 0xFF);
 714         cmdblk[13] = ecc;
 715 
 716         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 717                 printk("xd_setparam: error setting characteristics for drive %d\n",drive);
 718 }
 719 

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