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

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