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

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