linux-old/drivers/block/xd.c
<<
>>
Prefs
   1/*
   2 * This file contains the driver for an XT hard disk controller
   3 * (at least the DTC 5150X) for Linux.
   4 *
   5 * Author: Pat Mackinlay, pat@it.com.au
   6 * Date: 29/09/92
   7 * 
   8 * Revised: 01/01/93, ...
   9 *
  10 * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler,
  11 *   kevinf@agora.rain.com)
  12 * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and
  13 *   Wim Van Dorst.
  14 *
  15 * Revised: 04/04/94 by Risto Kankkunen
  16 *   Moved the detection code from xd_init() to xd_geninit() as it needed
  17 *   interrupts enabled and Linus didn't want to enable them in that first
  18 *   phase. xd_geninit() is the place to do these kinds of things anyway,
  19 *   he says.
  20 *
  21 * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
  22 *
  23 * Revised: 13/12/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
  24 *   Fixed some problems with disk initialization and module initiation.
  25 *   Added support for manual geometry setting (except Seagate controllers)
  26 *   in form:
  27 *      xd_geo=<cyl_xda>,<head_xda>,<sec_xda>[,<cyl_xdb>,<head_xdb>,<sec_xdb>]
  28 *   Recovered DMA access. Abridged messages. Added support for DTC5051CX,
  29 *   WD1002-27X & XEBEC controllers. Driver uses now some jumper settings.
  30 *   Extended ioctl() support.
  31 *
  32 * Bugfix: 15/02/01, Paul G. - inform queue layer of tiny xd_maxsect.
  33 *
  34 */
  35
  36#include <linux/module.h>
  37#include <linux/errno.h>
  38#include <linux/sched.h>
  39#include <linux/mm.h>
  40#include <linux/fs.h>
  41#include <linux/kernel.h>
  42#include <linux/timer.h>
  43#include <linux/genhd.h>
  44#include <linux/hdreg.h>
  45#include <linux/ioport.h>
  46#include <linux/init.h>
  47#include <linux/devfs_fs_kernel.h>
  48
  49#include <asm/system.h>
  50#include <asm/io.h>
  51#include <asm/uaccess.h>
  52#include <asm/dma.h>
  53
  54#define MAJOR_NR XT_DISK_MAJOR
  55#include <linux/blk.h>
  56#include <linux/blkpg.h>
  57
  58#include "xd.h"
  59
  60#define XD_DONT_USE_DMA         0  /* Initial value. may be overriden using
  61                                      "nodma" module option */
  62#define XD_INIT_DISK_DELAY      (30*HZ/1000)  /* 30 ms delay during disk initialization */
  63
  64/* Above may need to be increased if a problem with the 2nd drive detection
  65   (ST11M controller) or resetting a controller (WD) appears */
  66
  67XD_INFO xd_info[XD_MAXDRIVES];
  68
  69/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
  70   signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
  71   few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
  72   command. Run DEBUG, and then you can examine your BIOS signature with:
  73
  74        d xxxx:0000
  75
  76   where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
  77   be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
  78   in the table are, in order:
  79
  80        offset                  ; this is the offset (in bytes) from the start of your ROM where the signature starts
  81        signature               ; this is the actual text of the signature
  82        xd_?_init_controller    ; this is the controller init routine used by your controller
  83        xd_?_init_drive         ; this is the drive init routine used by your controller
  84
  85   The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
  86   made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
  87   best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
  88   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>.
  89
  90   NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
  91   should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
  92
  93#include <asm/page.h>
  94#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
  95#define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
  96static char *xd_dma_buffer = 0;
  97
  98static XD_SIGNATURE xd_sigs[] __initdata = {
  99        { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */
 100        { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
 101        { 0x000B,"CRD18A   Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */
 102        { 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 */
 103        { 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1002-27X" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
 104        { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
 105        { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
 106        { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
 107        { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
 108        { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
 109        { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
 110        { 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" },
 111        { 0x0008,"(C) Copyright 1986 Western Digital Corporation", xd_wd_init_controller, xd_wd_init_drive," 1986 Western Digital" }, /* jfree@sovereign.org */
 112};
 113
 114static unsigned int xd_bases[] __initdata =
 115{
 116        0xC8000, 0xCA000, 0xCC000,
 117        0xCE000, 0xD0000, 0xD2000,
 118        0xD4000, 0xD6000, 0xD8000,
 119        0xDA000, 0xDC000, 0xDE000,
 120        0xE0000
 121};
 122
 123static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
 124static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES];
 125static int xd_blocksizes[XD_MAXDRIVES << 6];
 126static int xd_maxsect[XD_MAXDRIVES << 6];
 127
 128extern struct block_device_operations xd_fops;
 129
 130static struct gendisk xd_gendisk = {
 131        major:          MAJOR_NR,
 132        major_name:     "xd",
 133        minor_shift:    6,
 134        max_p:          1 << 6,
 135        part:           xd_struct,
 136        sizes:          xd_sizes,
 137        real_devices:   (void *)xd_info,
 138        fops:           &xd_fops,
 139};
 140
 141static struct block_device_operations xd_fops = {
 142        owner:          THIS_MODULE,
 143        open:           xd_open,
 144        release:        xd_release,
 145        ioctl:          xd_ioctl,
 146};
 147
 148static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 149static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
 150static u8 xd_valid[XD_MAXDRIVES] = { 0,0 };
 151static u8 xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
 152static u8 xd_override __initdata = 0, xd_type __initdata = 0;
 153static u16 xd_iobase = 0x320;
 154static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
 155
 156static volatile int xdc_busy;
 157
 158static struct timer_list xd_watchdog_int;
 159
 160static volatile u8 xd_error;
 161static int nodma = XD_DONT_USE_DMA;
 162
 163static devfs_handle_t devfs_handle = NULL;
 164
 165/* xd_init: register the block device number and set up pointer tables */
 166int __init xd_init(void)
 167{
 168        init_timer (&xd_watchdog_int); 
 169        xd_watchdog_int.function = xd_watchdog;
 170
 171        if (!xd_dma_buffer)
 172                xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
 173        if (!xd_dma_buffer)
 174        {
 175                printk(KERN_ERR "xd: Out of memory.\n");
 176                return -ENOMEM;
 177        }
 178
 179        if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 180                printk(KERN_ERR "xd: Unable to get major number %d\n",MAJOR_NR);
 181                return -1;
 182        }
 183        devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL);
 184        blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
 185        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
 186        add_gendisk(&xd_gendisk);
 187        xd_geninit();
 188
 189        return 0;
 190}
 191
 192/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
 193
 194static u8 __init xd_detect (u8 *controller, unsigned int *address)
 195{
 196        u8 i,j,found = 0;
 197
 198        if (xd_override)
 199        {
 200                *controller = xd_type;
 201                *address = 0;
 202                return(1);
 203        }
 204
 205        for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
 206                for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
 207                        if (isa_check_signature(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
 208                                *controller = j;
 209                                xd_type = j;
 210                                *address = xd_bases[i];
 211                                found++;
 212                        }
 213        return (found);
 214}
 215
 216/* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 217/* and set up the "raw" device entries in the table */
 218
 219static void __init xd_geninit (void)
 220{
 221        u8 i,controller;
 222        unsigned int address;
 223
 224        for(i=0;i<(XD_MAXDRIVES << 6);i++)
 225                xd_blocksizes[i] = 1024;
 226                
 227        blksize_size[MAJOR_NR] = xd_blocksizes;
 228
 229        if (xd_detect(&controller,&address)) {
 230                printk(KERN_INFO "Detected a%s controller (type %d) at address %06x\n",
 231                        xd_sigs[controller].name,controller,address);
 232                if (!request_region(xd_iobase,4, "xd")) {
 233                        printk(KERN_ERR "xd: Ports at 0x%x are not available\n", xd_iobase);
 234                        return;
 235                }
 236                if (controller)
 237                        xd_sigs[controller].init_controller(address);
 238                xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
 239                
 240                printk(KERN_INFO "Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
 241                        xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
 242                for (i = 0; i < xd_drives; i++)
 243                        printk(KERN_INFO " xd%c: CHS=%d/%d/%d\n",'a'+i,
 244                                xd_info[i].cylinders,xd_info[i].heads,
 245                                xd_info[i].sectors);
 246
 247        }
 248        if (xd_drives) {
 249                if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
 250                        if (request_dma(xd_dma,"xd")) {
 251                                printk(KERN_ERR "xd: unable to get DMA%d\n",xd_dma);
 252                                free_irq(xd_irq, NULL);
 253                        }
 254                }
 255                else
 256                        printk(KERN_ERR "xd: unable to get IRQ%d\n",xd_irq);
 257        }
 258
 259        /* xd_maxsectors depends on controller - so set after detection */
 260        for(i=0; i<(XD_MAXDRIVES << 6); i++) xd_maxsect[i] = xd_maxsectors;
 261        max_sectors[MAJOR_NR] = xd_maxsect;
 262
 263        for (i = 0; i < xd_drives; i++) {
 264                xd_valid[i] = 1;
 265                register_disk(&xd_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6, &xd_fops,
 266                                xd_info[i].heads * xd_info[i].cylinders *
 267                                xd_info[i].sectors);
 268        }
 269
 270        xd_gendisk.nr_real = xd_drives;
 271
 272}
 273
 274/* xd_open: open a device */
 275static int xd_open (struct inode *inode,struct file *file)
 276{
 277        int dev = DEVICE_NR(inode->i_rdev);
 278
 279        if (dev < xd_drives) {
 280                while (!xd_valid[dev])
 281                        sleep_on(&xd_wait_open);
 282                xd_access[dev]++;
 283                return (0);
 284        }
 285
 286        return -ENXIO;
 287}
 288
 289/* do_xd_request: handle an incoming request */
 290static void do_xd_request (request_queue_t * q)
 291{
 292        unsigned int block,count,retry;
 293        int code;
 294
 295        if (xdc_busy)
 296                return;
 297                
 298        while (code = 0, !QUEUE_EMPTY) {
 299                INIT_REQUEST;   /* do some checking on the request structure */
 300
 301                if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
 302                        block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect;
 303                        count = CURRENT->nr_sectors;
 304
 305                        switch (CURRENT->cmd) {
 306                                case READ:
 307                                case WRITE:
 308                                        for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
 309                                                code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
 310                                        break;
 311                                default:
 312                                        BUG();
 313                        }
 314                }
 315                end_request(code);      /* wrap up, 0 = fail, 1 = success */
 316        }
 317}
 318
 319/* xd_ioctl: handle device ioctl's */
 320
 321static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
 322{
 323        int dev;
 324
 325        if ((!inode) || !(inode->i_rdev))
 326                return -EINVAL;
 327        dev = DEVICE_NR(inode->i_rdev);
 328
 329        if (dev >= xd_drives) return -EINVAL;
 330        switch (cmd) {
 331                case HDIO_GETGEO:
 332                {
 333                        struct hd_geometry g;
 334                        struct hd_geometry *geometry = (struct hd_geometry *) arg;
 335                        g.heads = xd_info[dev].heads;
 336                        g.sectors = xd_info[dev].sectors;
 337                        g.cylinders = xd_info[dev].cylinders;
 338                        g.start = xd_struct[MINOR(inode->i_rdev)].start_sect;
 339                        return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0;
 340                }
 341                case HDIO_SET_DMA:
 342                        if (!capable(CAP_SYS_ADMIN))
 343                                return -EACCES;
 344                        if (xdc_busy)
 345                                return -EBUSY;
 346                                
 347                        nodma = !arg;
 348                        
 349                        if (nodma && xd_dma_buffer) {
 350                                xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
 351                                xd_dma_buffer = 0;
 352                        } else if (!nodma && !xd_dma_buffer) {
 353                                xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
 354                                if (!xd_dma_buffer)
 355                                {
 356                                        nodma = XD_DONT_USE_DMA;
 357                                        return -ENOMEM;
 358                                }
 359                        }
 360                        return 0;
 361                case HDIO_GET_DMA:
 362                        return put_user(!nodma, (long *) arg);
 363                case HDIO_GET_MULTCOUNT:
 364                        return put_user(xd_maxsectors, (long *) arg);
 365                case BLKRRPART:
 366                        if (!capable(CAP_SYS_ADMIN)) 
 367                                return -EACCES;
 368                        return xd_reread_partitions(inode->i_rdev);
 369                case BLKGETSIZE:
 370                case BLKGETSIZE64:
 371                case BLKFLSBUF:
 372                case BLKROSET:
 373                case BLKROGET:
 374                case BLKRASET:
 375                case BLKRAGET:
 376                case BLKPG:
 377                        return blk_ioctl(inode->i_rdev, cmd, arg);
 378                default:
 379                        return -EINVAL;
 380        }
 381}
 382
 383/* xd_release: release the device */
 384static int xd_release (struct inode *inode, struct file *file)
 385{
 386        int target = DEVICE_NR(inode->i_rdev);
 387        if (target < xd_drives)
 388                xd_access[target]--;
 389        return 0;
 390}
 391
 392/* xd_reread_partitions: rereads the partition table from a drive */
 393static int xd_reread_partitions(kdev_t dev)
 394{
 395        int target;
 396        int start;
 397        int partition;
 398        
 399        target = DEVICE_NR(dev);
 400        start = target << xd_gendisk.minor_shift;
 401
 402        cli();
 403        xd_valid[target] = (xd_access[target] != 1);
 404        sti();
 405        if (xd_valid[target])
 406                return -EBUSY;
 407
 408        for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 409                int minor = (start | partition);
 410                invalidate_device(MKDEV(MAJOR_NR, minor), 1);
 411                xd_gendisk.part[minor].start_sect = 0;
 412                xd_gendisk.part[minor].nr_sects = 0;
 413        };
 414
 415        grok_partitions(&xd_gendisk, target, 1<<6,
 416                        xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors);
 417
 418        xd_valid[target] = 1;
 419        wake_up(&xd_wait_open);
 420
 421        return 0;
 422}
 423
 424/* xd_readwrite: handle a read/write request */
 425static int xd_readwrite (u8 operation,u8 drive,char *buffer,unsigned int block,unsigned int count)
 426{
 427        u8 cmdblk[6],sense[4];
 428        u16 track,cylinder;
 429        u8 head,sector,control,mode = PIO_MODE,temp;
 430        char **real_buffer;
 431        
 432#ifdef DEBUG_READWRITE
 433        printk(KERN_DEBUG "xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
 434#endif /* DEBUG_READWRITE */
 435
 436        spin_unlock_irq(&io_request_lock);
 437
 438        control = xd_info[drive].control;
 439        while (count) {
 440                temp = count < xd_maxsectors ? count : xd_maxsectors;
 441
 442                track = block / xd_info[drive].sectors;
 443                head = track % xd_info[drive].heads;
 444                cylinder = track / xd_info[drive].heads;
 445                sector = block % xd_info[drive].sectors;
 446
 447#ifdef DEBUG_READWRITE
 448                printk(KERN_DEBUG "xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
 449#endif /* DEBUG_READWRITE */
 450
 451                if (xd_dma_buffer) {
 452                        mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u8 *)(xd_dma_buffer),temp * 0x200);
 453                        real_buffer = &xd_dma_buffer;
 454                        memcpy(xd_dma_buffer, buffer, temp * 0x200);
 455                }
 456                else
 457                        real_buffer = &buffer;
 458
 459                xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
 460
 461                switch (xd_command(cmdblk,mode,(u8 *)(*real_buffer),(u8 *)(*real_buffer),sense,XD_TIMEOUT)) 
 462                {
 463                        case 1:
 464                                printk(KERN_WARNING "xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
 465                                xd_recalibrate(drive);
 466                                goto fail;
 467                        case 2:
 468                                if (sense[0] & 0x30) {
 469                                        printk(KERN_ERR "xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
 470                                        switch ((sense[0] & 0x30) >> 4) {
 471                                        case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
 472                                                break;
 473                                        case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
 474                                                break;
 475                                        case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
 476                                                break;
 477                                        case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
 478                                                break;
 479                                        }
 480                                }
 481                                if (sense[0] & 0x80)
 482                                        printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
 483                                /*      reported drive number = (sense[1] & 0xE0) >> 5 */
 484                                else
 485                                        printk(" - no valid disk address\n");
 486                                goto fail;
 487                }
 488                if (xd_dma_buffer)
 489                        memcpy(buffer, xd_dma_buffer, (temp * 0x200));
 490
 491                count -= temp, buffer += temp * 0x200, block += temp;
 492        }
 493        spin_lock_irq(&io_request_lock);
 494        return 1;
 495
 496fail:
 497        spin_lock_irq(&io_request_lock);
 498        return 0;
 499
 500}
 501
 502/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
 503static void xd_recalibrate (u8 drive)
 504{
 505        u8 cmdblk[6];
 506        
 507        xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
 508        if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
 509                printk(KERN_WARNING "xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
 510}
 511
 512/* xd_interrupt_handler: interrupt service routine */
 513static void xd_interrupt_handler(int irq, void *dev_id, struct pt_regs * regs)
 514{
 515        if (inb(XD_STATUS) & STAT_INTERRUPT) {                                                  /* check if it was our device */
 516#ifdef DEBUG_OTHER
 517                printk(KERN_DEBUG "xd_interrupt_handler: interrupt detected\n");
 518#endif /* DEBUG_OTHER */
 519                outb(0,XD_CONTROL);                                                             /* acknowledge interrupt */
 520                wake_up(&xd_wait_int);                                                          /* and wake up sleeping processes */
 521        }
 522        else
 523                printk(KERN_DEBUG "xd: unexpected interrupt\n");
 524}
 525
 526/* xd_setup_dma: set up the DMA controller for a data transfer */
 527static u8 xd_setup_dma (u8 mode,u8 *buffer,unsigned int count)
 528{
 529        unsigned long f;
 530        
 531        if (nodma)
 532                return (PIO_MODE);
 533        if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
 534#ifdef DEBUG_OTHER
 535                printk(KERN_DEBUG "xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
 536#endif /* DEBUG_OTHER */
 537                return PIO_MODE;
 538        }
 539        
 540        f=claim_dma_lock();
 541        disable_dma(xd_dma);
 542        clear_dma_ff(xd_dma);
 543        set_dma_mode(xd_dma,mode);
 544        set_dma_addr(xd_dma, (unsigned long) buffer);
 545        set_dma_count(xd_dma,count);
 546        
 547        release_dma_lock(f);
 548
 549        return DMA_MODE;                        /* use DMA and INT */
 550}
 551
 552/* xd_build: put stuff into an array in a format suitable for the controller */
 553static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control)
 554{
 555        cmdblk[0] = command;
 556        cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
 557        cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
 558        cmdblk[3] = cylinder & 0xFF;
 559        cmdblk[4] = count;
 560        cmdblk[5] = control;
 561        
 562        return cmdblk;
 563}
 564
 565/* xd_wakeup is called from timer interrupt */
 566static void xd_watchdog (unsigned long unused)
 567{
 568        xd_error = 1;
 569        wake_up(&xd_wait_int);
 570}
 571
 572/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
 573static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout)
 574{
 575        unsigned long expiry = jiffies + timeout;
 576        int success;
 577
 578        xdc_busy = 1;
 579        while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) {
 580                set_current_state(TASK_UNINTERRUPTIBLE);
 581                schedule_timeout(1);
 582        }
 583        xdc_busy = 0;
 584        return (success);
 585}
 586
 587static inline unsigned int xd_wait_for_IRQ (void)
 588{
 589        unsigned long flags;
 590        xd_watchdog_int.expires = jiffies + 8 * HZ;
 591        add_timer(&xd_watchdog_int);
 592        
 593        flags=claim_dma_lock();
 594        enable_dma(xd_dma);
 595        release_dma_lock(flags);
 596        
 597        sleep_on(&xd_wait_int);
 598        del_timer_sync(&xd_watchdog_int);
 599        xdc_busy = 0;
 600        
 601        flags=claim_dma_lock();
 602        disable_dma(xd_dma);
 603        release_dma_lock(flags);
 604        
 605        if (xd_error) {
 606                printk(KERN_DEBUG "xd: missed IRQ - command aborted\n");
 607                xd_error = 0;
 608                return (1);
 609        }
 610        return (0);
 611}
 612
 613/* xd_command: handle all data transfers necessary for a single command */
 614static unsigned int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout)
 615{
 616        u8 cmdblk[6];
 617        u8 csb,complete = 0;
 618
 619#ifdef DEBUG_COMMAND
 620        printk(KERN_DEBUG "xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
 621#endif /* DEBUG_COMMAND */
 622
 623        outb(0,XD_SELECT);
 624        outb(mode,XD_CONTROL);
 625
 626        if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
 627                return (1);
 628
 629        while (!complete) {
 630                if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
 631                        return (1);
 632
 633                switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
 634                        case 0:
 635                                if (mode == DMA_MODE) {
 636                                        if (xd_wait_for_IRQ())
 637                                                return (1);
 638                                } else
 639                                        outb(outdata ? *outdata++ : 0,XD_DATA);
 640                                break;
 641                        case STAT_INPUT:
 642                                if (mode == DMA_MODE) {
 643                                        if (xd_wait_for_IRQ())
 644                                                return (1);
 645                                } else
 646                                        if (indata)
 647                                                *indata++ = inb(XD_DATA);
 648                                        else
 649                                                inb(XD_DATA);
 650                                break;
 651                        case STAT_COMMAND:
 652                                outb(command ? *command++ : 0,XD_DATA);
 653                                break;
 654                        case STAT_COMMAND | STAT_INPUT:
 655                                complete = 1;
 656                                break;
 657                }
 658        }
 659        csb = inb(XD_DATA);
 660
 661        if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                                       /* wait until deselected */
 662                return (1);
 663
 664        if (csb & CSB_ERROR) {                                                                  /* read sense data if error */
 665                xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
 666                if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
 667                        printk(KERN_DEBUG "xd: warning! sense command failed!\n");
 668        }
 669
 670#ifdef DEBUG_COMMAND
 671        printk(KERN_DEBUG "xd_command: completed with csb = 0x%X\n",csb);
 672#endif /* DEBUG_COMMAND */
 673
 674        return (csb & CSB_ERROR);
 675}
 676
 677static u8 __init xd_initdrives (void (*init_drive)(u8 drive))
 678{
 679        u8 cmdblk[6],i,count = 0;
 680
 681        for (i = 0; i < XD_MAXDRIVES; i++) {
 682                xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
 683                if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
 684                        set_current_state(TASK_INTERRUPTIBLE);
 685                        schedule_timeout(XD_INIT_DISK_DELAY);
 686
 687                        init_drive(count);
 688                        count++;
 689
 690                        set_current_state(TASK_INTERRUPTIBLE);
 691                        schedule_timeout(XD_INIT_DISK_DELAY);
 692                }
 693        }
 694        return (count);
 695}
 696
 697static void __init xd_manual_geo_set (u8 drive)
 698{
 699        xd_info[drive].heads    = xd_geo[3 * drive + 1];
 700        xd_info[drive].cylinders= xd_geo[3 * drive];
 701        xd_info[drive].sectors =  xd_geo[3 * drive + 2];
 702}
 703
 704static void __init xd_dtc_init_controller (unsigned int address)
 705{
 706        switch (address) {
 707                case 0x00000:
 708                case 0xC8000:
 709                        break;                  /*initial: 0x320 */
 710                case 0xCA000:
 711                        xd_iobase = 0x324; 
 712                case 0xD0000:                   /*5150CX*/
 713                case 0xD8000:
 714                        break;                  /*5150CX & 5150XL*/
 715                default:        
 716                        printk(KERN_ERR "xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
 717                        break;
 718        }
 719        xd_maxsectors = 0x01;           /* my card seems to have trouble doing multi-block transfers? */
 720
 721        outb(0,XD_RESET);               /* reset the controller */
 722}
 723
 724
 725static void __init xd_dtc5150cx_init_drive (u8 drive)
 726{
 727        /* values from controller's BIOS - BIOS chip may be removed */
 728        static u16 geometry_table[][4] = {
 729                {0x200,8,0x200,0x100},
 730                {0x267,2,0x267,0x267},
 731                {0x264,4,0x264,0x80},
 732                {0x132,4,0x132,0x0},
 733                {0x132,2,0x80, 0x132},
 734                {0x177,8,0x177,0x0},
 735                {0x132,8,0x84, 0x0},
 736                {},  /* not used */
 737                {0x132,6,0x80, 0x100},
 738                {0x200,6,0x100,0x100},
 739                {0x264,2,0x264,0x80},
 740                {0x280,4,0x280,0x100},
 741                {0x2B9,3,0x2B9,0x2B9},
 742                {0x2B9,5,0x2B9,0x2B9},
 743                {0x280,6,0x280,0x100},
 744                {0x132,4,0x132,0x0}};
 745        u8 n;
 746
 747        n = inb(XD_JUMPER);
 748        n = (drive ? n : (n >> 2)) & 0x33;
 749        n = (n | (n >> 2)) & 0x0F;
 750        if (xd_geo[3*drive])
 751                xd_manual_geo_set(drive);
 752        else
 753                if (n != 7) {   
 754                        xd_info[drive].heads = (u8)(geometry_table[n][1]);                      /* heads */
 755                        xd_info[drive].cylinders = geometry_table[n][0];        /* cylinders */
 756                        xd_info[drive].sectors = 17;                            /* sectors */
 757#if 0
 758                        xd_info[drive].rwrite = geometry_table[n][2];   /* reduced write */
 759                        xd_info[drive].precomp = geometry_table[n][3]           /* write precomp */
 760                        xd_info[drive].ecc = 0x0B;                              /* ecc length */
 761#endif /* 0 */
 762                }
 763                else {
 764                        printk(KERN_WARNING "xd%c: undetermined drive geometry\n",'a'+drive);
 765                        return;
 766                }
 767        xd_info[drive].control = 5;                             /* control byte */
 768        xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
 769        xd_recalibrate(drive);
 770}
 771
 772static void __init xd_dtc_init_drive (u8 drive)
 773{
 774        u8 cmdblk[6],buf[64];
 775
 776        xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
 777        if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 778                xd_info[drive].heads = buf[0x0A];                       /* heads */
 779                xd_info[drive].cylinders = ((u16 *) (buf))[0x04];       /* cylinders */
 780                xd_info[drive].sectors = 17;                            /* sectors */
 781                if (xd_geo[3*drive])
 782                        xd_manual_geo_set(drive);
 783#if 0
 784                xd_info[drive].rwrite = ((u16 *) (buf + 1))[0x05];      /* reduced write */
 785                xd_info[drive].precomp = ((u16 *) (buf + 1))[0x06];     /* write precomp */
 786                xd_info[drive].ecc = buf[0x0F];                         /* ecc length */
 787#endif /* 0 */
 788                xd_info[drive].control = 0;                             /* control byte */
 789
 790                xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u16 *) (buf + 1))[0x05],((u16 *) (buf + 1))[0x06],buf[0x0F]);
 791                xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
 792                if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
 793                        printk(KERN_WARNING "xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
 794        }
 795        else
 796                printk(KERN_WARNING "xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
 797}
 798
 799static void __init xd_wd_init_controller (unsigned int address)
 800{
 801        switch (address) {
 802                case 0x00000:
 803                case 0xC8000:   break;                  /*initial: 0x320 */
 804                case 0xCA000:   xd_iobase = 0x324; break;
 805                case 0xCC000:   xd_iobase = 0x328; break;
 806                case 0xCE000:   xd_iobase = 0x32C; break;
 807                case 0xD0000:   xd_iobase = 0x328; break; /* ? */
 808                case 0xD8000:   xd_iobase = 0x32C; break; /* ? */
 809                default:        printk(KERN_ERR "xd_wd_init_controller: unsupported BIOS address %06x\n",address);
 810                                break;
 811        }
 812        xd_maxsectors = 0x01;           /* this one doesn't wrap properly either... */
 813
 814        outb(0,XD_RESET);               /* reset the controller */
 815
 816        set_current_state(TASK_UNINTERRUPTIBLE);
 817        schedule_timeout(XD_INIT_DISK_DELAY);
 818}
 819
 820static void __init xd_wd_init_drive (u8 drive)
 821{
 822        /* values from controller's BIOS - BIOS may be disabled */
 823        static u16 geometry_table[][4] = {
 824                {0x264,4,0x1C2,0x1C2},   /* common part */
 825                {0x132,4,0x099,0x0},
 826                {0x267,2,0x1C2,0x1C2},
 827                {0x267,4,0x1C2,0x1C2},
 828
 829                {0x334,6,0x335,0x335},   /* 1004 series RLL */
 830                {0x30E,4,0x30F,0x3DC},
 831                {0x30E,2,0x30F,0x30F},
 832                {0x267,4,0x268,0x268},
 833
 834                {0x3D5,5,0x3D6,0x3D6},   /* 1002 series RLL */
 835                {0x3DB,7,0x3DC,0x3DC},
 836                {0x264,4,0x265,0x265},
 837                {0x267,4,0x268,0x268}};
 838
 839        u8 cmdblk[6],buf[0x200];
 840        u8 n = 0,rll,jumper_state,use_jumper_geo;
 841        u8 wd_1002 = (xd_sigs[xd_type].string[7] == '6');
 842        
 843        jumper_state = ~(inb(0x322));
 844        if (jumper_state & 0x40)
 845                xd_irq = 9;
 846        rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
 847        xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
 848        if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 849                xd_info[drive].heads = buf[0x1AF];                              /* heads */
 850                xd_info[drive].cylinders = ((u16 *) (buf + 1))[0xD6];   /* cylinders */
 851                xd_info[drive].sectors = 17;                                    /* sectors */
 852                if (xd_geo[3*drive])
 853                        xd_manual_geo_set(drive);
 854#if 0
 855                xd_info[drive].rwrite = ((u16 *) (buf))[0xD8];          /* reduced write */
 856                xd_info[drive].wprecomp = ((u16 *) (buf))[0xDA];                /* write precomp */
 857                xd_info[drive].ecc = buf[0x1B4];                                /* ecc length */
 858#endif /* 0 */
 859                xd_info[drive].control = buf[0x1B5];                            /* control byte */
 860                use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
 861                if (xd_geo[3*drive]) {
 862                        xd_manual_geo_set(drive);
 863                        xd_info[drive].control = rll ? 7 : 5;
 864                }
 865                else if (use_jumper_geo) {
 866                        n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
 867                        xd_info[drive].cylinders = geometry_table[n][0];
 868                        xd_info[drive].heads = (u8)(geometry_table[n][1]);
 869                        xd_info[drive].control = rll ? 7 : 5;
 870#if 0
 871                        xd_info[drive].rwrite = geometry_table[n][2];
 872                        xd_info[drive].wprecomp = geometry_table[n][3];
 873                        xd_info[drive].ecc = 0x0B;
 874#endif /* 0 */
 875                }
 876                if (!wd_1002) {
 877                        if (use_jumper_geo)
 878                                xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
 879                                        geometry_table[n][2],geometry_table[n][3],0x0B);
 880                        else
 881                                xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
 882                                        ((u16 *) (buf))[0xD8],((u16 *) (buf))[0xDA],buf[0x1B4]);
 883                }
 884        /* 1002 based RLL controller requests converted addressing, but reports physical 
 885           (physical 26 sec., logical 17 sec.) 
 886           1004 based ???? */
 887                if (rll & wd_1002) {
 888                        if ((xd_info[drive].cylinders *= 26,
 889                             xd_info[drive].cylinders /= 17) > 1023)
 890                                xd_info[drive].cylinders = 1023;  /* 1024 ? */
 891#if 0
 892                        xd_info[drive].rwrite *= 26; 
 893                        xd_info[drive].rwrite /= 17;
 894                        xd_info[drive].wprecomp *= 26
 895                        xd_info[drive].wprecomp /= 17;
 896#endif /* 0 */
 897                }
 898        }
 899        else
 900                printk(KERN_WARNING "xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);   
 901
 902}
 903
 904static void __init xd_seagate_init_controller (unsigned int address)
 905{
 906        switch (address) {
 907                case 0x00000:
 908                case 0xC8000:   break;                  /*initial: 0x320 */
 909                case 0xD0000:   xd_iobase = 0x324; break;
 910                case 0xD8000:   xd_iobase = 0x328; break;
 911                case 0xE0000:   xd_iobase = 0x32C; break;
 912                default:        printk(KERN_ERR "xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
 913                                break;
 914        }
 915        xd_maxsectors = 0x40;
 916
 917        outb(0,XD_RESET);               /* reset the controller */
 918}
 919
 920static void __init xd_seagate_init_drive (u8 drive)
 921{
 922        u8 cmdblk[6],buf[0x200];
 923
 924        xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
 925        if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
 926                xd_info[drive].heads = buf[0x04];                               /* heads */
 927                xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03];        /* cylinders */
 928                xd_info[drive].sectors = buf[0x05];                             /* sectors */
 929                xd_info[drive].control = 0;                                     /* control byte */
 930        }
 931        else
 932                printk(KERN_WARNING "xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
 933}
 934
 935/* Omti support courtesy Dirk Melchers */
 936static void __init xd_omti_init_controller (unsigned int address)
 937{
 938        switch (address) {
 939                case 0x00000:
 940                case 0xC8000:   break;                  /*initial: 0x320 */
 941                case 0xD0000:   xd_iobase = 0x324; break;
 942                case 0xD8000:   xd_iobase = 0x328; break;
 943                case 0xE0000:   xd_iobase = 0x32C; break;
 944                default:        printk(KERN_ERR "xd_omti_init_controller: unsupported BIOS address %06x\n",address);
 945                                break;
 946        }
 947        
 948        xd_maxsectors = 0x40;
 949
 950        outb(0,XD_RESET);               /* reset the controller */
 951}
 952
 953static void __init xd_omti_init_drive (u8 drive)
 954{
 955        /* gets infos from drive */
 956        xd_override_init_drive(drive);
 957
 958        /* set other parameters, Hardcoded, not that nice :-) */
 959        xd_info[drive].control = 2;
 960}
 961
 962/* Xebec support (AK) */
 963static void __init xd_xebec_init_controller (unsigned int address)
 964{
 965/* iobase may be set manually in range 0x300 - 0x33C
 966      irq may be set manually to 2(9),3,4,5,6,7
 967      dma may be set manually to 1,2,3
 968        (How to detect them ???)
 969BIOS address may be set manually in range 0x0 - 0xF8000
 970If you need non-standard settings use the xd=... command */
 971
 972        switch (address) {
 973                case 0x00000:
 974                case 0xC8000:   /* initially: xd_iobase==0x320 */
 975                case 0xD0000:
 976                case 0xD2000:
 977                case 0xD4000:
 978                case 0xD6000:
 979                case 0xD8000:
 980                case 0xDA000:
 981                case 0xDC000:
 982                case 0xDE000:
 983                case 0xE0000:   break;
 984                default:        printk(KERN_ERR "xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
 985                                break;
 986                }
 987
 988        xd_maxsectors = 0x01;
 989        outb(0,XD_RESET);               /* reset the controller */
 990
 991        set_current_state(TASK_UNINTERRUPTIBLE);
 992        schedule_timeout(XD_INIT_DISK_DELAY);
 993}
 994
 995static void __init xd_xebec_init_drive (u8 drive)
 996{
 997        /* values from controller's BIOS - BIOS chip may be removed */
 998        static u16 geometry_table[][5] = {
 999                {0x132,4,0x080,0x080,0x7},
1000                {0x132,4,0x080,0x080,0x17},
1001                {0x264,2,0x100,0x100,0x7},
1002                {0x264,2,0x100,0x100,0x17},
1003                {0x132,8,0x080,0x080,0x7},
1004                {0x132,8,0x080,0x080,0x17},
1005                {0x264,4,0x100,0x100,0x6},
1006                {0x264,4,0x100,0x100,0x17},
1007                {0x2BC,5,0x2BC,0x12C,0x6},
1008                {0x3A5,4,0x3A5,0x3A5,0x7},
1009                {0x26C,6,0x26C,0x26C,0x7},
1010                {0x200,8,0x200,0x100,0x17},
1011                {0x400,5,0x400,0x400,0x7},
1012                {0x400,6,0x400,0x400,0x7},
1013                {0x264,8,0x264,0x200,0x17},
1014                {0x33E,7,0x33E,0x200,0x7}};
1015        u8 n;
1016
1017        n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry 
1018                                        is assumed for BOTH drives */
1019        if (xd_geo[3*drive])
1020                xd_manual_geo_set(drive);
1021        else {
1022                xd_info[drive].heads = (u8)(geometry_table[n][1]);                      /* heads */
1023                xd_info[drive].cylinders = geometry_table[n][0];        /* cylinders */
1024                xd_info[drive].sectors = 17;                            /* sectors */
1025#if 0
1026                xd_info[drive].rwrite = geometry_table[n][2];   /* reduced write */
1027                xd_info[drive].precomp = geometry_table[n][3]           /* write precomp */
1028                xd_info[drive].ecc = 0x0B;                              /* ecc length */
1029#endif /* 0 */
1030        }
1031        xd_info[drive].control = geometry_table[n][4];                  /* control byte */
1032        xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
1033        xd_recalibrate(drive);
1034}
1035
1036/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
1037   etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
1038static void __init xd_override_init_drive (u8 drive)
1039{
1040        u16 min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
1041        u8 cmdblk[6],i;
1042
1043        if (xd_geo[3*drive])
1044                xd_manual_geo_set(drive);
1045        else {
1046                for (i = 0; i < 3; i++) {
1047                        while (min[i] != max[i] - 1) {
1048                                test[i] = (min[i] + max[i]) / 2;
1049                                xd_build(cmdblk,CMD_SEEK,drive,(u8) test[0],(u16) test[1],(u8) test[2],0,0);
1050                                if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
1051                                        min[i] = test[i];
1052                                else
1053                                        max[i] = test[i];
1054                        }
1055                        test[i] = min[i];
1056                }
1057                xd_info[drive].heads = (u8) min[0] + 1;
1058                xd_info[drive].cylinders = (u16) min[1] + 1;
1059                xd_info[drive].sectors = (u8) min[2] + 1;
1060        }
1061        xd_info[drive].control = 0;
1062}
1063
1064/* xd_setup: initialise controller from command line parameters */
1065void __init do_xd_setup (int *integers)
1066{
1067        switch (integers[0]) {
1068                case 4: if (integers[4] < 0)
1069                                nodma = 1;
1070                        else if (integers[4] < 8)
1071                                xd_dma = integers[4];
1072                case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1073                                xd_iobase = integers[3];
1074                case 2: if ((integers[2] > 0) && (integers[2] < 16))
1075                                xd_irq = integers[2];
1076                case 1: xd_override = 1;
1077                        if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
1078                                xd_type = integers[1];
1079                case 0: break;
1080                default:printk(KERN_ERR "xd: too many parameters for xd\n");
1081        }
1082        xd_maxsectors = 0x01;
1083}
1084
1085/* xd_setparam: set the drive characteristics */
1086static void __init xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc)
1087{
1088        u8 cmdblk[14];
1089
1090        xd_build(cmdblk,command,drive,0,0,0,0,0);
1091        cmdblk[6] = (u8) (cylinders >> 8) & 0x03;
1092        cmdblk[7] = (u8) (cylinders & 0xFF);
1093        cmdblk[8] = heads & 0x1F;
1094        cmdblk[9] = (u8) (rwrite >> 8) & 0x03;
1095        cmdblk[10] = (u8) (rwrite & 0xFF);
1096        cmdblk[11] = (u8) (wprecomp >> 8) & 0x03;
1097        cmdblk[12] = (u8) (wprecomp & 0xFF);
1098        cmdblk[13] = ecc;
1099
1100        /* Some controllers require geometry info as data, not command */
1101
1102        if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2))
1103                printk(KERN_WARNING "xd: error setting characteristics for xd%c\n", 'a'+drive);
1104}
1105
1106
1107#ifdef MODULE
1108static int xd[5] = { -1,-1,-1,-1, };
1109
1110MODULE_PARM(xd, "1-4i");
1111MODULE_PARM(xd_geo, "3-6i");
1112MODULE_PARM(nodma, "i");
1113
1114MODULE_LICENSE("GPL");
1115
1116static void xd_done (void)
1117{
1118        blksize_size[MAJOR_NR] = NULL;
1119        blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1120        blk_size[MAJOR_NR] = NULL;
1121        hardsect_size[MAJOR_NR] = NULL;
1122        read_ahead[MAJOR_NR] = 0;
1123        del_gendisk(&xd_gendisk);
1124        release_region(xd_iobase,4);
1125}
1126
1127int init_module(void)
1128{
1129        int i,count = 0;
1130        int error;
1131
1132        for (i = 4; i > 0; i--)
1133                if(((xd[i] = xd[i-1]) >= 0) && !count)
1134                        count = i;
1135        if((xd[0] = count))
1136                do_xd_setup(xd);
1137
1138        error = xd_init();
1139        if (error) return error;
1140
1141        printk(KERN_INFO "XD: Loaded as a module.\n");
1142        if (!xd_drives) {
1143                /* no drives detected - unload module */
1144                devfs_unregister_blkdev(MAJOR_NR, "xd");
1145                xd_done();
1146                return (-1);
1147        }
1148        
1149        return 0;
1150}
1151
1152void cleanup_module(void)
1153{
1154        devfs_unregister_blkdev(MAJOR_NR, "xd");
1155        xd_done();
1156        devfs_unregister(devfs_handle);
1157        if (xd_drives) {
1158                free_irq(xd_irq, NULL);
1159                free_dma(xd_dma);
1160                if (xd_dma_buffer)
1161                        xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1162        }
1163}
1164#else
1165
1166static int __init xd_setup (char *str)
1167{
1168        int ints[5];
1169        get_options (str, ARRAY_SIZE (ints), ints);
1170        do_xd_setup (ints);
1171        return 1;
1172}
1173
1174/* xd_manual_geo_init: initialise drive geometry from command line parameters
1175   (used only for WD drives) */
1176static int __init xd_manual_geo_init (char *str)
1177{
1178        int i, integers[1 + 3*XD_MAXDRIVES];
1179
1180        get_options (str, ARRAY_SIZE (integers), integers);
1181        if (integers[0]%3 != 0) {
1182                printk(KERN_ERR "xd: incorrect number of parameters for xd_geo\n");
1183                return 1;
1184        }
1185        for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1186                xd_geo[i] = integers[i+1];
1187        return 1;
1188}
1189
1190__setup ("xd=", xd_setup);
1191__setup ("xd_geo=", xd_manual_geo_init);
1192
1193#endif /* MODULE */
1194
1195
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.