Root/drivers/block/xd.c

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

Archive Download this file



interactive