OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [scsi/] [wd7000.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/* $Id: wd7000.c,v 1.1 2005-12-20 10:17:46 jcastillo Exp $
2
 *  linux/drivers/scsi/wd7000.c
3
 *
4
 *  Copyright (C) 1992  Thomas Wuensche
5
 *      closely related to the aha1542 driver from Tommy Thorn
6
 *      ( as close as different hardware allows on a lowlevel-driver :-) )
7
 *
8
 *  Revised (and renamed) by John Boyd <boyd@cis.ohio-state.edu> to
9
 *  accommodate Eric Youngdale's modifications to scsi.c.  Nov 1992.
10
 *
11
 *  Additional changes to support scatter/gather.  Dec. 1992.  tw/jb
12
 *
13
 *  No longer tries to reset SCSI bus at boot (it wasn't working anyway).
14
 *  Rewritten to support multiple host adapters.
15
 *  Miscellaneous cleanup.
16
 *  So far, still doesn't do reset or abort correctly, since I have no idea
17
 *  how to do them with this board (8^(.                      Jan 1994 jb
18
 *
19
 * This driver now supports both of the two standard configurations (per
20
 * the 3.36 Owner's Manual, my latest reference) by the same method as
21
 * before; namely, by looking for a BIOS signature.  Thus, the location of
22
 * the BIOS signature determines the board configuration.  Until I have
23
 * time to do something more flexible, users should stick to one of the
24
 * following:
25
 *
26
 * Standard configuration for single-adapter systems:
27
 *    - BIOS at CE00h
28
 *    - I/O base address 350h
29
 *    - IRQ level 15
30
 *    - DMA channel 6
31
 * Standard configuration for a second adapter in a system:
32
 *    - BIOS at C800h
33
 *    - I/O base address 330h
34
 *    - IRQ level 11
35
 *    - DMA channel 5
36
 *
37
 * Anyone who can recompile the kernel is welcome to add others as need
38
 * arises, but unpredictable results may occur if there are conflicts.
39
 * In any event, if there are multiple adapters in a system, they MUST
40
 * use different I/O bases, IRQ levels, and DMA channels, since they will be
41
 * indistinguishable (and in direct conflict) otherwise.
42
 *
43
 *   As a point of information, the NO_OP command toggles the CMD_RDY bit
44
 * of the status port, and this fact could be used as a test for the I/O
45
 * base address (or more generally, board detection).  There is an interrupt
46
 * status port, so IRQ probing could also be done.  I suppose the full
47
 * DMA diagnostic could be used to detect the DMA channel being used.  I
48
 * haven't done any of this, though, because I think there's too much of
49
 * a chance that such explorations could be destructive, if some other
50
 * board's resources are used inadvertently.  So, call me a wimp, but I
51
 * don't want to try it.  The only kind of exploration I trust is memory
52
 * exploration, since it's more certain that reading memory won't be
53
 * destructive.
54
 *
55
 * More to my liking would be a LILO boot command line specification, such
56
 * as is used by the aha152x driver (and possibly others).  I'll look into
57
 * it, as I have time...
58
 *
59
 *   I get mail occasionally from people who either are using or are
60
 * considering using a WD7000 with Linux.  There is a variety of
61
 * nomenclature describing WD7000's.  To the best of my knowledge, the
62
 * following is a brief summary (from an old WD doc - I don't work for
63
 * them or anything like that):
64
 *
65
 * WD7000-FASST2: This is a WD7000 board with the real-mode SST ROM BIOS
66
 *        installed.  Last I heard, the BIOS was actually done by Columbia
67
 *        Data Products.  The BIOS is only used by this driver (and thus
68
 *        by Linux) to identify the board; none of it can be executed under
69
 *        Linux.
70
 *
71
 * WD7000-ASC: This is the original adapter board, with or without BIOS.
72
 *        The board uses a WD33C93 or WD33C93A SBIC, which in turn is
73
 *        controlled by an onboard Z80 processor.  The board interface
74
 *        visible to the host CPU is defined effectively by the Z80's
75
 *        firmware, and it is this firmware's revision level that is
76
 *        determined and reported by this driver.  (The version of the
77
 *        on-board BIOS is of no interest whatsoever.)  The host CPU has
78
 *        no access to the SBIC; hence the fact that it is a WD33C93 is
79
 *        also of no interest to this driver.
80
 *
81
 * WD7000-AX:
82
 * WD7000-MX:
83
 * WD7000-EX: These are newer versions of the WD7000-ASC.  The -ASC is
84
 *        largely built from discrete components; these boards use more
85
 *        integration.  The -AX is an ISA bus board (like the -ASC),
86
 *        the -MX is an MCA (i.e., PS/2) bus board), and the -EX is an
87
 *        EISA bus board.
88
 *
89
 *  At the time of my documentation, the -?X boards were "future" products,
90
 *  and were not yet available.  However, I vaguely recall that Thomas
91
 *  Wuensche had an -AX, so I believe at least it is supported by this
92
 *  driver.  I have no personal knowledge of either -MX or -EX boards.
93
 *
94
 *  P.S. Just recently, I've discovered (directly from WD and Future
95
 *  Domain) that all but the WD7000-EX have been out of production for
96
 *  two years now.  FD has production rights to the 7000-EX, and are
97
 *  producing it under a new name, and with a new BIOS.  If anyone has
98
 *  one of the FD boards, it would be nice to come up with a signature
99
 *  for it.
100
 *                                                           J.B. Jan 1994.
101
 *
102
 *
103
 *  Revisions by Miroslav Zagorac <zaga@fly.cc.fer.hr>
104
 *
105
 * -- 08/24/1996. --------------------------------------------------------------
106
 *    Enhancement for wd7000_detect function has been made, so you don't have
107
 *    to enter BIOS ROM address in initialisation data (see struct Config).
108
 *    We cannot detect IRQ, DMA and I/O base address for now, so we have to
109
 *    enter them as arguments while wd_7000 is detected.  If someone has IRQ,
110
 *    DMA or an I/O base address set to some other value, he can enter them in
111
 *    a configuration without any problem.
112
 *    Also I wrote a function wd7000_setup, so now you can enter WD-7000
113
 *    definition as kernel arguments, as in lilo.conf:
114
 *
115
 *       append="wd7000=IRQ,DMA,IO"
116
 *
117
 *   PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize
118
 *       adapter, unlike the old one.  Anyway, BIOS ROM from WD7000 adapter is
119
 *       useless for Linux. B^)
120
 *
121
 * -- 09/06/1996. --------------------------------------------------------------
122
 *    Auto detecting of an I/O base address from wd7000_detect function is
123
 *    removed, some little bugs too...
124
 *
125
 *    Thanks to Roger Scott for driver debugging.
126
 *
127
 * -- 06/07/1997. --------------------------------------------------------------
128
 *    Added support for /proc file system (/proc/scsi/wd7000/[0...] files).
129
 *    Now, the driver can handle hard disks with capacity >1GB.
130
 *
131
 * -- 01/15/1998. --------------------------------------------------------------
132
 *    Added support for BUS_ON and BUS_OFF parameters in config line.
133
 *    Miscellaneous cleanups.  Syntax of the append line is changed to:
134
 *
135
 *       append="wd7000=IRQ,DMA,IO[,BUS_ON[,BUS_OFF]]"
136
 *
137
 *    , where BUS_ON and BUS_OFF are time in nanoseconds.
138
 *
139
 * -- 03/01/1998. --------------------------------------------------------------
140
 *    The WD7000 driver now works on kernels' >= 2.1.x
141
 *
142
 * -- 06/11/1998. --------------------------------------------------------------
143
 *    Ugly init_scbs, alloc_scbs and free_scb functions are changed with
144
 *    scbs_init, scb_alloc and scb_free.  Now, source code is identical on
145
 *    2.0.xx and 2.1.xx kernels.
146
 *    WD7000 specific definitions are moved from this file to wd7000.h.
147
 *
148
 */
149
#ifdef MODULE
150
#  include <linux/module.h>
151
#endif
152
 
153
#if (LINUX_VERSION_CODE >= 0x020100)
154
#  include <asm/spinlock.h>
155
#endif
156
 
157
#include <stdarg.h>
158
#include <linux/kernel.h>
159
#include <linux/head.h>
160
#include <linux/types.h>
161
#include <linux/string.h>
162
#include <linux/sched.h>
163
#include <linux/malloc.h>
164
#include <asm/system.h>
165
#include <asm/dma.h>
166
#include <asm/io.h>
167
#include <linux/ioport.h>
168
#include <linux/proc_fs.h>
169
#include <linux/blk.h>
170
#include <linux/version.h>
171
#include <linux/stat.h>
172
#include "scsi.h"
173
#include "hosts.h"
174
#include "sd.h"
175
#include <scsi/scsicam.h>
176
 
177
#undef WD7000_DEBUG     /* general debug         */
178
#define WD7000_DEFINES  /* This must be defined! */
179
 
180
#include "wd7000.h"
181
 
182
 
183
struct proc_dir_entry proc_scsi_wd7000 =
184
{
185
    PROC_SCSI_7000FASST,
186
    6,
187
    "wd7000",
188
    S_IFDIR | S_IRUGO | S_IXUGO,
189
    2
190
};
191
 
192
/*
193
 * (linear) base address for ROM BIOS
194
 */
195
static const long wd7000_biosaddr[] = {
196
    0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
197
    0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
198
};
199
#define NUM_ADDRS       (sizeof (wd7000_biosaddr) / sizeof (long))
200
 
201
static const ushort wd7000_iobase[] = {
202
    0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
203
    0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
204
    0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
205
    0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
206
};
207
#define NUM_IOPORTS     (sizeof (wd7000_iobase) / sizeof (ushort))
208
 
209
static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
210
#define NUM_IRQS        (sizeof (wd7000_irq) / sizeof (short))
211
 
212
static const short wd7000_dma[] = { 5, 6, 7 };
213
#define NUM_DMAS        (sizeof (wd7000_dma) / sizeof (short))
214
 
215
/*
216
 * The following is set up by wd7000_detect, and used thereafter by
217
 * wd7000_intr_handle to map the irq level to the corresponding Adapter.
218
 * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be
219
 * changed to pick up the IRQ level correctly.
220
 */
221
static struct Scsi_Host *wd7000_host[IRQS];
222
 
223
/*
224
 * Add here your configuration...
225
 */
226
static Config configs[] =
227
{
228
    { 15,  6, 0x350, BUS_ON, BUS_OFF }, /* defaults for single adapter */
229
    { 11,  5, 0x320, BUS_ON, BUS_OFF }, /* defaults for second adapter */
230
    {  7,  6, 0x350, BUS_ON, BUS_OFF }, /* My configuration (Zaga)     */
231
    { -1, -1, 0x0,   BUS_ON, BUS_OFF }  /* Empty slot                  */
232
};
233
#define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
234
 
235
static const Signature signatures[] =
236
{
237
    {"SSTBIOS", 0x0000d, 7}     /* "SSTBIOS" @ offset 0x0000d */
238
};
239
#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
240
 
241
/*
242
 *  Driver SCB structure pool.
243
 *
244
 *  The SCBs declared here are shared by all host adapters; hence, this
245
 *  structure is not part of the Adapter structure.
246
 */
247
static Scb scbs[MAX_SCBS];
248
 
249
 
250
/*
251
 *  END of data/declarations - code follows.
252
 */
253
static void setup_error (char *mesg, int *ints)
254
{
255
    if (ints[0] == 3)
256
        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
257
                ints[1], ints[2], ints[3], mesg);
258
    else if (ints[0] == 4)
259
        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
260
                ints[1], ints[2], ints[3], ints[4], mesg);
261
    else
262
        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
263
                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
264
}
265
 
266
 
267
/*
268
 * Note: You can now set these options from the kernel's "command line".
269
 * The syntax is:
270
 *
271
 *     wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]
272
 *
273
 * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values
274
 * are 8000ns for BUS_ON and 1875ns for BUS_OFF.
275
 *
276
 * eg:
277
 *     wd7000=7,6,0x350
278
 *
279
 * will configure the driver for a WD-7000 controller
280
 * using IRQ 15 with a DMA channel 6, at IO base address 0x350.
281
 */
282
void wd7000_setup (char *str, int *ints)
283
{
284
    static short wd7000_card_num = 0;
285
    short i, j;
286
 
287
    if (wd7000_card_num >= NUM_CONFIGS) {
288
        printk ("%s: Too many \"wd7000=\" configurations in "
289
                "command line!\n", __FUNCTION__);
290
        return;
291
    }
292
 
293
    if ((ints[0] < 3) || (ints[0] > 5))
294
        printk ("%s: Error in command line!  "
295
                "Usage: wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]\n",
296
                __FUNCTION__);
297
    else {
298
        for (i = 0; i < NUM_IRQS; i++)
299
            if (ints[1] == wd7000_irq[i])
300
                break;
301
 
302
        if (i == NUM_IRQS) {
303
            setup_error ("invalid IRQ.", ints);
304
            return;
305
        }
306
        else
307
            configs[wd7000_card_num].irq = ints[1];
308
 
309
        for (i = 0; i < NUM_DMAS; i++)
310
            if (ints[2] == wd7000_dma[i])
311
                break;
312
 
313
        if (i == NUM_DMAS) {
314
            setup_error ("invalid DMA channel.", ints);
315
            return;
316
        }
317
        else
318
            configs[wd7000_card_num].dma = ints[2];
319
 
320
        for (i = 0; i < NUM_IOPORTS; i++)
321
            if (ints[3] == wd7000_iobase[i])
322
                break;
323
 
324
        if (i == NUM_IOPORTS) {
325
            setup_error ("invalid I/O base address.", ints);
326
            return;
327
        }
328
        else
329
            configs[wd7000_card_num].iobase = ints[3];
330
 
331
        if (ints[0] > 3) {
332
            if ((ints[4] < 500) || (ints[4] > 31875)) {
333
                setup_error ("BUS_ON value is out of range (500 to 31875 nanoseconds)!",
334
                             ints);
335
                configs[wd7000_card_num].bus_on = BUS_ON;
336
            }
337
            else
338
                configs[wd7000_card_num].bus_on = ints[4] / 125;
339
        }
340
        else
341
            configs[wd7000_card_num].bus_on = BUS_ON;
342
 
343
        if (ints[0] > 4) {
344
            if ((ints[5] < 500) || (ints[5] > 31875)) {
345
                setup_error ("BUS_OFF value is out of range (500 to 31875 nanoseconds)!",
346
                             ints);
347
                configs[wd7000_card_num].bus_off = BUS_OFF;
348
            }
349
            else
350
                configs[wd7000_card_num].bus_off = ints[5] / 125;
351
        }
352
        else
353
            configs[wd7000_card_num].bus_off = BUS_OFF;
354
 
355
        if (wd7000_card_num) {
356
            for (i = 0; i < (wd7000_card_num - 1); i++)
357
                for (j = i + 1; j < wd7000_card_num; j++)
358
                    if (configs[i].irq == configs[j].irq) {
359
                        setup_error ("duplicated IRQ!", ints);
360
                        return;
361
                    }
362
                    else if (configs[i].dma == configs[j].dma) {
363
                        setup_error ("duplicated DMA channel!", ints);
364
                        return;
365
                    }
366
                    else if (configs[i].iobase == configs[j].iobase) {
367
                        setup_error ("duplicated I/O base address!", ints);
368
                        return;
369
                    }
370
        }
371
 
372
#ifdef WD7000_DEBUG
373
        printk ("%s: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
374
                __FUNCTION__,
375
                configs[wd7000_card_num].irq,
376
                configs[wd7000_card_num].dma,
377
                configs[wd7000_card_num].iobase,
378
                configs[wd7000_card_num].bus_on * 125,
379
                configs[wd7000_card_num].bus_off * 125);
380
#endif
381
 
382
        wd7000_card_num++;
383
    }
384
}
385
 
386
 
387
/*
388
 * Since they're used a lot, I've redone the following from the macros
389
 * formerly in wd7000.h, hopefully to speed them up by getting rid of
390
 * all the shifting (it may not matter; GCC might have done as well anyway).
391
 *
392
 * xany2scsi and xscsi2int were not being used, and are no longer defined.
393
 * (They were simply 4-byte versions of these routines).
394
 */
395
static inline void any2scsi (unchar *scsi, int any)
396
{
397
    *scsi++ = ((i_u) any).u[2];
398
    *scsi++ = ((i_u) any).u[1];
399
    *scsi   = ((i_u) any).u[0];
400
}
401
 
402
 
403
static inline int scsi2int (unchar *scsi)
404
{
405
    i_u result;
406
 
407
    result.i = 0;                /* clears unused bytes */
408
    result.u[2] = *scsi++;
409
    result.u[1] = *scsi++;
410
    result.u[0] = *scsi;
411
 
412
    return (result.i);
413
}
414
 
415
 
416
static inline void wd7000_enable_intr (Adapter *host)
417
{
418
    host->control |= INT_EN;
419
    outb (host->control, host->iobase + ASC_CONTROL);
420
}
421
 
422
 
423
static inline void wd7000_enable_dma (Adapter *host)
424
{
425
    host->control |= DMA_EN;
426
    outb (host->control, host->iobase + ASC_CONTROL);
427
    set_dma_mode (host->dma, DMA_MODE_CASCADE);
428
    enable_dma (host->dma);
429
}
430
 
431
 
432
static inline short WAIT (uint port, uint mask, uint allof, uint noneof)
433
{
434
    register uint WAITbits;
435
    register ulong WAITtimeout = jiffies + WAITnexttimeout;
436
 
437
    while (jiffies <= WAITtimeout) {
438
        WAITbits = inb (port) & mask;
439
 
440
        if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
441
            return (0);
442
    }
443
 
444
    return (1);
445
}
446
 
447
 
448
static inline void delay (uint how_long)
449
{
450
    register ulong time = jiffies + how_long;
451
 
452
    while (jiffies < time);
453
}
454
 
455
 
456
static inline int wd7000_command_out (Adapter *host, unchar *cmd, int len)
457
{
458
    if (! WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
459
        for ( ; len--; cmd++)
460
            do {
461
                outb (*cmd, host->iobase + ASC_COMMAND);
462
                WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
463
            } while (inb (host->iobase + ASC_STAT) & CMD_REJ);
464
 
465
        return (1);
466
    }
467
 
468
    printk ("%s: WAIT failed (%d)\n", __FUNCTION__, len + 1);
469
 
470
    return (0);
471
}
472
 
473
 
474
static inline void scbs_init (void)
475
{
476
    short i;
477
 
478
    for (i = 0; i < MAX_SCBS; i++)
479
        memset ((void *) &(scbs[i]), 0, sizeof (Scb));
480
}
481
 
482
 
483
static inline Scb *scb_alloc (void)
484
{
485
    Scb *scb = NULL;
486
    ulong flags;
487
    short i;
488
#ifdef WD7000_DEBUG
489
    short free_scbs = 0;
490
#endif
491
 
492
    save_flags (flags);
493
    cli ();
494
 
495
    for (i = 0; i < MAX_SCBS; i++)
496
        if (! scbs[i].used) {
497
            scbs[i].used = 1;
498
            scb = &(scbs[i]);
499
 
500
            break;
501
        }
502
 
503
#ifdef WD7000_DEBUG
504
    for (i = 0; i < MAX_SCBS; i++)
505
        free_scbs += scbs[i].used ? 0 : 1;
506
 
507
    printk ("wd7000_%s: allocating scb (0x%08x), %d scbs free\n",
508
            __FUNCTION__, (int) scb, free_scbs);
509
#endif
510
 
511
    restore_flags (flags);
512
 
513
    return (scb);
514
}
515
 
516
 
517
static inline void scb_free (Scb *scb)
518
{
519
    short i;
520
    ulong flags;
521
 
522
    save_flags (flags);
523
    cli ();
524
 
525
    for (i = 0; i < MAX_SCBS; i++)
526
        if (&(scbs[i]) == scb) {
527
            memset ((void *) &(scbs[i]), 0, sizeof (Scb));
528
 
529
            break;
530
        }
531
 
532
    if (i == MAX_SCBS)
533
        printk ("wd7000_%s: trying to free alien scb (0x%08x)...\n",
534
                __FUNCTION__, (int) scb);
535
#ifdef WD7000_DEBUG
536
    else
537
        printk ("wd7000_%s: freeing scb (0x%08x)\n", __FUNCTION__, (int) scb);
538
#endif
539
 
540
    restore_flags (flags);
541
}
542
 
543
 
544
static int mail_out (Adapter *host, Scb *scbptr)
545
/*
546
 *  Note: this can also be used for ICBs; just cast to the parm type.
547
 */
548
{
549
    register int i, ogmb;
550
    ulong flags;
551
    unchar start_ogmb;
552
    Mailbox *ogmbs = host->mb.ogmb;
553
    int *next_ogmb = &(host->next_ogmb);
554
 
555
#ifdef WD7000_DEBUG
556
    printk ("wd7000_%s: 0x%08x", __FUNCTION__, (int) scbptr);
557
#endif
558
 
559
    /* We first look for a free outgoing mailbox */
560
    save_flags (flags);
561
    cli ();
562
 
563
    ogmb = *next_ogmb;
564
    for (i = 0; i < OGMB_CNT; i++) {
565
        if (ogmbs[ogmb].status == 0) {
566
#ifdef WD7000_DEBUG
567
            printk (" using OGMB 0x%x", ogmb);
568
#endif
569
            ogmbs[ogmb].status = 1;
570
            any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
571
 
572
            *next_ogmb = (ogmb + 1) % OGMB_CNT;
573
            break;
574
        }
575
        else
576
            ogmb = (++ogmb) % OGMB_CNT;
577
    }
578
 
579
    restore_flags (flags);
580
 
581
#ifdef WD7000_DEBUG
582
    printk (", scb is 0x%08x", (int) scbptr);
583
#endif
584
 
585
    if (i >= OGMB_CNT) {
586
        /*
587
         *  Alternatively, we might issue the "interrupt on free OGMB",
588
         *  and sleep, but it must be ensured that it isn't the init
589
         *  task running.  Instead, this version assumes that the caller
590
         *  will be persistent, and try again.  Since it's the adapter
591
         *  that marks OGMB's free, waiting even with interrupts off
592
         *  should work, since they are freed very quickly in most cases.
593
         */
594
#ifdef WD7000_DEBUG
595
        printk (", no free OGMBs.\n");
596
#endif
597
        return (0);
598
    }
599
 
600
    wd7000_enable_intr (host);
601
 
602
    start_ogmb = START_OGMB | ogmb;
603
    wd7000_command_out (host, &start_ogmb, 1);
604
 
605
#ifdef WD7000_DEBUG
606
    printk (", awaiting interrupt.\n");
607
#endif
608
 
609
    return (1);
610
}
611
 
612
 
613
int make_code (uint hosterr, uint scsierr)
614
{
615
#ifdef WD7000_DEBUG
616
    int in_error = hosterr;
617
#endif
618
 
619
    switch ((hosterr >> 8) & 0xff) {
620
        case 0:  /* Reserved */
621
                 hosterr = DID_ERROR;
622
                 break;
623
 
624
        case 1:  /* Command Complete, no errors */
625
                 hosterr = DID_OK;
626
                 break;
627
 
628
        case 2:  /* Command complete, error logged in scb status (scsierr) */
629
                 hosterr = DID_OK;
630
                 break;
631
 
632
        case 4:  /* Command failed to complete - timeout */
633
                 hosterr = DID_TIME_OUT;
634
                 break;
635
 
636
        case 5:  /* Command terminated; Bus reset by external device */
637
                 hosterr = DID_RESET;
638
                 break;
639
 
640
        case 6:  /* Unexpected Command Received w/ host as target */
641
                 hosterr = DID_BAD_TARGET;
642
                 break;
643
 
644
        case 80: /* Unexpected Reselection */
645
        case 81: /* Unexpected Selection */
646
                 hosterr = DID_BAD_INTR;
647
                 break;
648
 
649
        case 82: /* Abort Command Message  */
650
                 hosterr = DID_ABORT;
651
                 break;
652
 
653
        case 83: /* SCSI Bus Software Reset */
654
        case 84: /* SCSI Bus Hardware Reset */
655
                 hosterr = DID_RESET;
656
                 break;
657
 
658
        default: /* Reserved */
659
                 hosterr = DID_ERROR;
660
    }
661
 
662
#ifdef WD7000_DEBUG
663
    if (scsierr || hosterr)
664
        printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
665
                scsierr, in_error, hosterr);
666
#endif
667
 
668
    return (scsierr | (hosterr << 16));
669
}
670
 
671
 
672
static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
673
{
674
#ifdef WD7000_DEBUG
675
    printk ("%s: 0x%08x\n", __FUNCTION__, (int) SCpnt);
676
#endif
677
 
678
    SCpnt->SCp.phase = 0;
679
}
680
 
681
 
682
static inline void wd7000_intr_ack (Adapter *host)
683
{
684
    outb (0, host->iobase + ASC_INTR_ACK);
685
}
686
 
687
 
688
void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
689
{
690
    register int flag, icmb, errstatus, icmb_status;
691
    register int host_error, scsi_error;
692
    register Scb *scb;          /* for SCSI commands */
693
    register IcbAny *icb;       /* for host commands */
694
    register Scsi_Cmnd *SCpnt;
695
    Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata;   /* This MUST be set!!! */
696
    Mailbox *icmbs = host->mb.icmb;
697
 
698
    host->int_counter++;
699
 
700
#ifdef WD7000_DEBUG
701
    printk ("%s: irq = %d, host = 0x%08x\n", __FUNCTION__, irq, (int) host);
702
#endif
703
 
704
    flag = inb (host->iobase + ASC_INTR_STAT);
705
 
706
#ifdef WD7000_DEBUG
707
    printk ("%s: intr stat = 0x%02x\n", __FUNCTION__, flag);
708
#endif
709
 
710
    if (! (inb (host->iobase + ASC_STAT) & INT_IM)) {
711
        /* NB: these are _very_ possible if IRQ 15 is being used, since
712
         * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
713
         * any interrupt signal into the 8259 which can't be identified
714
         * comes out as 7 from the 8259, which is 15 to the host.  Thus, it
715
         * is a good thing the WD7000 has an interrupt status port, so we
716
         * can sort these out.  Otherwise, electrical noise and other such
717
         * problems would be indistinguishable from valid interrupts...
718
         */
719
#ifdef WD7000_DEBUG
720
        printk ("%s: phantom interrupt...\n", __FUNCTION__);
721
#endif
722
        wd7000_intr_ack (host);
723
        return;
724
    }
725
 
726
    if (flag & MB_INTR) {
727
        /* The interrupt is for a mailbox */
728
        if (! (flag & IMB_INTR)) {
729
#ifdef WD7000_DEBUG
730
            printk ("%s: free outgoing mailbox\n", __FUNCTION__);
731
#endif
732
            /*
733
             * If sleep_on() and the "interrupt on free OGMB" command are
734
             * used in mail_out(), wake_up() should correspondingly be called
735
             * here.  For now, we don't need to do anything special.
736
             */
737
            wd7000_intr_ack (host);
738
            return;
739
        }
740
        else {
741
            /* The interrupt is for an incoming mailbox */
742
            icmb = flag & MB_MASK;
743
            icmb_status = icmbs[icmb].status;
744
 
745
            if (icmb_status & 0x80) {   /* unsolicited - result in ICMB */
746
#ifdef WD7000_DEBUG
747
                printk ("%s: unsolicited interrupt 0x%02x\n",
748
                        __FUNCTION__, icmb_status);
749
#endif
750
                wd7000_intr_ack (host);
751
                return;
752
            }
753
 
754
            /* Aaaargh! (Zaga) */
755
            scb = (Scb *) bus_to_virt (scsi2int ((unchar *) icmbs[icmb].scbptr));
756
 
757
            icmbs[icmb].status = 0;
758
            if (!(scb->op & ICB_OP_MASK)) {     /* an SCB is done */
759
                SCpnt = scb->SCpnt;
760
                if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
761
                    host_error = scb->vue | (icmb_status << 8);
762
                    scsi_error = scb->status;
763
                    errstatus = make_code (host_error, scsi_error);
764
                    SCpnt->result = errstatus;
765
 
766
                    scb_free (scb);
767
 
768
                    SCpnt->scsi_done (SCpnt);
769
                }
770
            }
771
            else {              /* an ICB is done */
772
                icb = (IcbAny *) scb;
773
                icb->status = icmb_status;
774
                icb->phase = 0;
775
            }
776
        }                       /* incoming mailbox */
777
    }
778
 
779
    wd7000_intr_ack (host);
780
 
781
#ifdef WD7000_DEBUG
782
    printk ("%s: return from interrupt handler\n", __FUNCTION__);
783
#endif
784
}
785
 
786
 
787
void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
788
{
789
#if (LINUX_VERSION_CODE >= 0x020100)
790
    ulong flags;
791
 
792
    spin_lock_irqsave (&io_request_lock, flags);
793
#endif
794
 
795
    wd7000_intr_handle (irq, dev_id, regs);
796
 
797
#if (LINUX_VERSION_CODE >= 0x020100)
798
    spin_unlock_irqrestore (&io_request_lock, flags);
799
#endif
800
}
801
 
802
 
803
int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
804
{
805
    register Scb *scb;
806
    register Sgb *sgb;
807
    register Adapter *host = (Adapter *) SCpnt->host->hostdata;
808
 
809
    if ((scb = scb_alloc ()) == NULL) {
810
        printk ("%s: Cannot allocate SCB!\n", __FUNCTION__);
811
        return (0);
812
    }
813
 
814
    SCpnt->scsi_done = done;
815
    SCpnt->SCp.phase = 1;
816
    SCpnt->host_scribble = (unchar *) scb;
817
    scb->idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
818
    scb->direc = 0x40;          /* Disable direction check */
819
    scb->SCpnt = SCpnt;         /* so we can find stuff later */
820
    scb->host = host;
821
    memcpy (scb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
822
 
823
    if (SCpnt->use_sg) {
824
        struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
825
        uint i;
826
 
827
        if (SCpnt->host->sg_tablesize == SG_NONE)
828
            panic ("%s: scatter/gather not supported.\n", __FUNCTION__);
829
#ifdef WD7000_DEBUG
830
        else
831
            printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
832
#endif
833
 
834
        sgb = scb->sgb;
835
        scb->op = 1;
836
        any2scsi (scb->dataptr, (int) sgb);
837
        any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb));
838
 
839
        for (i = 0; i < SCpnt->use_sg; i++) {
840
            any2scsi (sgb[i].ptr, (int) sg[i].address);
841
            any2scsi (sgb[i].len, sg[i].length);
842
        }
843
    }
844
    else {
845
        scb->op = 0;
846
        any2scsi (scb->dataptr, (int) SCpnt->request_buffer);
847
        any2scsi (scb->maxlen, SCpnt->request_bufflen);
848
    }
849
 
850
    while (! mail_out (host, scb));     /* keep trying */
851
 
852
    return (1);
853
}
854
 
855
 
856
int wd7000_command (Scsi_Cmnd *SCpnt)
857
{
858
    if (! wd7000_queuecommand (SCpnt, wd7000_scsi_done))
859
        return (-1);
860
 
861
    while (SCpnt->SCp.phase > 0)
862
        barrier ();             /* phase counts scbs down to 0 */
863
 
864
    return (SCpnt->result);
865
}
866
 
867
 
868
int wd7000_diagnostics (Adapter *host, int code)
869
{
870
    static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
871
    static unchar buf[256];
872
    ulong timeout;
873
 
874
    /*
875
     * This routine is only called at init, so there should be OGMBs
876
     * available.  I'm assuming so here.  If this is going to
877
     * fail, I can just let the timeout catch the failure.
878
     */
879
    icb.type = code;
880
    any2scsi (icb.len, sizeof (buf));
881
    any2scsi (icb.ptr, (int) &buf);
882
    icb.phase = 1;
883
 
884
    mail_out (host, (Scb *) &icb);
885
 
886
    /*
887
     * Wait up to 2 seconds for completion.
888
     */
889
    for (timeout = jiffies + WAITnexttimeout; icb.phase && (jiffies < timeout); )
890
        barrier ();
891
 
892
    if (icb.phase) {
893
        printk ("%s: timed out.\n", __FUNCTION__);
894
        return (0);
895
    }
896
 
897
    if (make_code (icb.vue | (icb.status << 8), 0)) {
898
        printk ("%s: failed (0x%02x,0x%02x)\n", __FUNCTION__, icb.vue, icb.status);
899
        return (0);
900
    }
901
 
902
    return (1);
903
}
904
 
905
 
906
int wd7000_init (Adapter *host)
907
{
908
    InitCmd init_cmd =
909
    {
910
        INITIALIZATION,
911
        7,
912
        host->bus_on,
913
        host->bus_off,
914
        0,
915
        { 0, 0, 0 },
916
        OGMB_CNT,
917
        ICMB_CNT
918
    };
919
    int diag;
920
 
921
    /*
922
     *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
923
     *  and we need to do this just so we control the mailboxes, etc.
924
     */
925
    outb (ASC_RES, host->iobase + ASC_CONTROL);
926
    delay (1);                  /* reset pulse: this is 10ms, only need 25us */
927
    outb (0, host->iobase + ASC_CONTROL);
928
    host->control = 0;           /* this must always shadow ASC_CONTROL */
929
 
930
    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
931
        printk ("%s: WAIT timed out.\n", __FUNCTION__);
932
        return (0);              /* 0 = not ok */
933
    }
934
 
935
    if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {
936
        printk ("%s: ", __FUNCTION__);
937
 
938
        switch (diag) {
939
            case 2:  printk ("RAM failure.\n");
940
                     break;
941
 
942
            case 3:  printk ("FIFO R/W failed\n");
943
                     break;
944
 
945
            case 4:  printk ("SBIC register R/W failed\n");
946
                     break;
947
 
948
            case 5:  printk ("Initialization D-FF failed.\n");
949
                     break;
950
 
951
            case 6:  printk ("Host IRQ D-FF failed.\n");
952
                     break;
953
 
954
            case 7:  printk ("ROM checksum error.\n");
955
                     break;
956
 
957
            default: printk ("diagnostic code 0x%02Xh received.\n", diag);
958
        }
959
 
960
        return (0);
961
    }
962
 
963
    /* Clear mailboxes */
964
    memset (&(host->mb), 0, sizeof (host->mb));
965
 
966
    /* Execute init command */
967
    any2scsi ((unchar *) &(init_cmd.mailboxes), (int) &(host->mb));
968
 
969
    if (! wd7000_command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {
970
        printk ("%s: adapter initialization failed.\n", __FUNCTION__);
971
        return (0);
972
    }
973
 
974
    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
975
        printk ("%s: WAIT timed out.\n", __FUNCTION__);
976
        return (0);
977
    }
978
 
979
    if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) {
980
        printk ("%s: can't get IRQ %d.\n", __FUNCTION__, host->irq);
981
        return (0);
982
    }
983
 
984
    if (request_dma (host->dma, "wd7000")) {
985
        printk ("%s: can't get DMA channel %d.\n", __FUNCTION__, host->dma);
986
        free_irq (host->irq, NULL);
987
        return (0);
988
    }
989
 
990
    wd7000_enable_dma (host);
991
    wd7000_enable_intr (host);
992
 
993
    if (! wd7000_diagnostics (host, ICB_DIAG_FULL)) {
994
        free_dma (host->dma);
995
        free_irq (host->irq, NULL);
996
        return (0);
997
    }
998
 
999
    return (1);
1000
}
1001
 
1002
 
1003
void wd7000_revision (Adapter *host)
1004
{
1005
    static IcbRevLvl icb = { ICB_OP_GET_REVISION };
1006
 
1007
    /*
1008
     * Like diagnostics, this is only done at init time, in fact, from
1009
     * wd7000_detect, so there should be OGMBs available.  If it fails,
1010
     * the only damage will be that the revision will show up as 0.0,
1011
     * which in turn means that scatter/gather will be disabled.
1012
     */
1013
    icb.phase = 1;
1014
    mail_out (host, (Scb *) &icb);
1015
 
1016
    while (icb.phase)
1017
        barrier ();             /* wait for completion */
1018
 
1019
    host->rev1 = icb.primary;
1020
    host->rev2 = icb.secondary;
1021
}
1022
 
1023
 
1024
#undef SPRINTF
1025
#define SPRINTF(args...)        { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
1026
 
1027
int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host)
1028
{
1029
    ulong flags;
1030
 
1031
    save_flags (flags);
1032
    cli ();
1033
 
1034
#ifdef WD7000_DEBUG
1035
    printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
1036
#endif
1037
 
1038
    /*
1039
     * Currently this is a no-op
1040
     */
1041
    printk ("Sorry, this function is currently out of order...\n");
1042
 
1043
    restore_flags (flags);
1044
 
1045
    return (length);
1046
}
1047
 
1048
 
1049
int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
1050
{
1051
    struct Scsi_Host *host = NULL;
1052
    Scsi_Device *scd;
1053
    Adapter *adapter;
1054
    ulong flags;
1055
    char *pos = buffer;
1056
    short i;
1057
 
1058
#ifdef WD7000_DEBUG
1059
    Mailbox *ogmbs, *icmbs;
1060
    short count;
1061
#endif
1062
 
1063
    /*
1064
     * Find the specified host board.
1065
     */
1066
    for (i = 0; i < IRQS; i++)
1067
        if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
1068
            host = wd7000_host[i];
1069
 
1070
            break;
1071
        }
1072
 
1073
    /*
1074
     * Host not found!
1075
     */
1076
    if (! host)
1077
        return (-ESRCH);
1078
 
1079
    /*
1080
     * Has data been written to the file ?
1081
     */
1082
    if (inout)
1083
        return (wd7000_set_info (buffer, length, host));
1084
 
1085
    adapter = (Adapter *) host->hostdata;
1086
 
1087
    save_flags (flags);
1088
    cli ();
1089
 
1090
    SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
1091
    SPRINTF ("  IO base:      0x%x\n", adapter->iobase);
1092
    SPRINTF ("  IRQ:          %d\n", adapter->irq);
1093
    SPRINTF ("  DMA channel:  %d\n", adapter->dma);
1094
    SPRINTF ("  Interrupts:   %d\n", adapter->int_counter);
1095
    SPRINTF ("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);
1096
    SPRINTF ("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
1097
 
1098
#ifdef WD7000_DEBUG
1099
    ogmbs = adapter->mb.ogmb;
1100
    icmbs = adapter->mb.icmb;
1101
 
1102
    SPRINTF ("\nControl port value: 0x%x\n", adapter->control);
1103
    SPRINTF ("Incoming mailbox:\n");
1104
    SPRINTF ("  size: %d\n", ICMB_CNT);
1105
    SPRINTF ("  queued messages: ");
1106
 
1107
    for (i = count = 0; i < ICMB_CNT; i++)
1108
        if (icmbs[i].status) {
1109
            count++;
1110
            SPRINTF ("0x%x ", i);
1111
        }
1112
 
1113
    SPRINTF (count ? "\n" : "none\n");
1114
 
1115
    SPRINTF ("Outgoing mailbox:\n");
1116
    SPRINTF ("  size: %d\n", OGMB_CNT);
1117
    SPRINTF ("  next message: 0x%x\n", adapter->next_ogmb);
1118
    SPRINTF ("  queued messages: ");
1119
 
1120
    for (i = count = 0; i < OGMB_CNT; i++)
1121
        if (ogmbs[i].status) {
1122
            count++;
1123
            SPRINTF ("0x%x ", i);
1124
        }
1125
 
1126
    SPRINTF (count ? "\n" : "none\n");
1127
#endif
1128
 
1129
    /*
1130
     * Display driver information for each device attached to the board.
1131
     */
1132
#if (LINUX_VERSION_CODE >= 0x020100)
1133
    scd = host->host_queue;
1134
#else
1135
    scd = scsi_devices;
1136
#endif
1137
 
1138
    SPRINTF ("\nAttached devices: %s\n", scd ? "" : "none");
1139
 
1140
    for ( ; scd; scd = scd->next)
1141
        if (scd->host->host_no == hostno) {
1142
            SPRINTF ("  [Channel: %02d, Id: %02d, Lun: %02d]  ",
1143
                     scd->channel, scd->id, scd->lun);
1144
            SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
1145
                     scsi_device_types[(short) scd->type] : "Unknown device");
1146
 
1147
            for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
1148
                SPRINTF ("%c", scd->vendor[i]);
1149
            SPRINTF (" ");
1150
 
1151
            for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
1152
                SPRINTF ("%c", scd->model[i]);
1153
            SPRINTF ("\n");
1154
        }
1155
 
1156
    SPRINTF ("\n");
1157
 
1158
    restore_flags (flags);
1159
 
1160
    /*
1161
     * Calculate start of next buffer, and return value.
1162
     */
1163
    *start = buffer + offset;
1164
 
1165
    if ((pos - buffer) < offset)
1166
        return (0);
1167
    else if ((pos - buffer - offset) < length)
1168
        return (pos - buffer - offset);
1169
    else
1170
        return (length);
1171
}
1172
 
1173
 
1174
/*
1175
 *  Returns the number of adapters this driver is supporting.
1176
 *
1177
 *  The source for hosts.c says to wait to call scsi_register until 100%
1178
 *  sure about an adapter.  We need to do it a little sooner here; we
1179
 *  need the storage set up by scsi_register before wd7000_init, and
1180
 *  changing the location of an Adapter structure is more trouble than
1181
 *  calling scsi_unregister.
1182
 *
1183
 */
1184
int wd7000_detect (Scsi_Host_Template *tpnt)
1185
{
1186
    short present = 0, biosaddr_ptr, sig_ptr, i, pass;
1187
    short biosptr[NUM_CONFIGS];
1188
    uint iobase;
1189
    Adapter *host = NULL;
1190
    struct Scsi_Host *sh;
1191
 
1192
#ifdef WD7000_DEBUG
1193
    printk ("%s: started\n", __FUNCTION__);
1194
#endif
1195
 
1196
    /*
1197
     * Set up SCB free list, which is shared by all adapters
1198
     */
1199
    scbs_init ();
1200
 
1201
    for (i = 0; i < IRQS; wd7000_host[i++] = NULL);
1202
    for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
1203
 
1204
    tpnt->proc_dir = &proc_scsi_wd7000;
1205
    tpnt->proc_info = &wd7000_proc_info;
1206
 
1207
    for (pass = 0; pass < NUM_CONFIGS; pass++) {
1208
        short bios_match = 1;
1209
 
1210
#ifdef WD7000_DEBUG
1211
        printk ("%s: pass %d\n", __FUNCTION__, pass + 1);
1212
#endif
1213
 
1214
        /*
1215
         * First, search for BIOS SIGNATURE...
1216
         */
1217
        for (biosaddr_ptr = 0; bios_match && (biosaddr_ptr < NUM_ADDRS); biosaddr_ptr++)
1218
            for (sig_ptr = 0; bios_match && (sig_ptr < NUM_SIGNATURES); sig_ptr++) {
1219
                for (i = 0; i < pass; i++)
1220
                    if (biosptr[i] == biosaddr_ptr)
1221
                        break;
1222
 
1223
                if (i == pass) {
1224
#if (LINUX_VERSION_CODE >= 0x020100)
1225
                    char *biosaddr = (char *) ioremap (wd7000_biosaddr[biosaddr_ptr] +
1226
                                                        signatures[sig_ptr].ofs,
1227
                                                        signatures[sig_ptr].len);
1228
#else
1229
                    char *biosaddr = (char *) (wd7000_biosaddr[biosaddr_ptr] +
1230
                                                signatures[sig_ptr].ofs);
1231
#endif
1232
                    bios_match = memcmp (biosaddr, signatures[sig_ptr].sig,
1233
                                                signatures[sig_ptr].len);
1234
 
1235
#if (LINUX_VERSION_CODE >= 0x020100)
1236
                    iounmap (biosaddr);
1237
#else
1238
#endif
1239
                    if (! bios_match) {
1240
                        /*
1241
                         * BIOS SIGNATURE has been found.
1242
                         */
1243
                        biosptr[pass] = biosaddr_ptr;
1244
#ifdef WD7000_DEBUG
1245
                        printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
1246
                                wd7000_biosaddr[biosaddr_ptr]);
1247
#endif
1248
                    }
1249
                }
1250
            }
1251
 
1252
#ifdef WD7000_DEBUG
1253
        if (bios_match)
1254
            printk ("WD-7000 SST BIOS not detected...\n");
1255
#endif
1256
 
1257
        if (configs[pass].irq < 0)
1258
            continue;
1259
 
1260
        iobase = configs[pass].iobase;
1261
 
1262
#ifdef WD7000_DEBUG
1263
        printk ("%s: check IO 0x%x region...\n", __FUNCTION__, iobase);
1264
#endif
1265
 
1266
        if (! check_region (iobase, 4)) {
1267
#ifdef WD7000_DEBUG
1268
            printk ("%s: ASC reset (IO 0x%x) ...", __FUNCTION__, iobase);
1269
#endif
1270
            /*
1271
             * ASC reset...
1272
             */
1273
            outb (ASC_RES, iobase + ASC_CONTROL);
1274
            delay (1);
1275
            outb (0, iobase + ASC_CONTROL);
1276
 
1277
            if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
1278
#ifdef WD7000_DEBUG
1279
            {
1280
                printk ("failed!\n");
1281
                continue;
1282
            }
1283
            else
1284
                printk ("ok!\n");
1285
#else
1286
                continue;
1287
#endif
1288
 
1289
            if (inb (iobase + ASC_INTR_STAT) == 1) {
1290
                /*
1291
                 *  We register here, to get a pointer to the extra space,
1292
                 *  which we'll use as the Adapter structure (host) for
1293
                 *  this adapter.  It is located just after the registered
1294
                 *  Scsi_Host structure (sh), and is located by the empty
1295
                 *  array hostdata.
1296
                 */
1297
                sh = scsi_register (tpnt, sizeof (Adapter));
1298
                host = (Adapter *) sh->hostdata;
1299
 
1300
#ifdef WD7000_DEBUG
1301
                printk ("%s: adapter allocated at 0x%x\n", __FUNCTION__, (int) host);
1302
#endif
1303
 
1304
                memset (host, 0, sizeof (Adapter));
1305
 
1306
                host->irq = configs[pass].irq;
1307
                host->dma = configs[pass].dma;
1308
                host->iobase = iobase;
1309
                host->int_counter = 0;
1310
                host->bus_on = configs[pass].bus_on;
1311
                host->bus_off = configs[pass].bus_off;
1312
                host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
1313
 
1314
#ifdef WD7000_DEBUG
1315
                printk ("%s: Trying to init WD-7000 card at IO 0x%x, IRQ %d, DMA %d...\n",
1316
                        __FUNCTION__, host->iobase, host->irq, host->dma);
1317
#endif
1318
 
1319
                if (! wd7000_init (host)) {     /* Initialization failed */
1320
                    scsi_unregister (sh);
1321
                    continue;
1322
                }
1323
 
1324
                /*
1325
                 *  OK from here - we'll use this adapter/configuration.
1326
                 */
1327
                wd7000_revision (host);         /* important for scatter/gather */
1328
 
1329
                /*
1330
                 * Register our ports.
1331
                 */
1332
                request_region (host->iobase, 4, "wd7000");
1333
 
1334
                /*
1335
                 *  For boards before rev 6.0, scatter/gather isn't supported.
1336
                 */
1337
                if (host->rev1 < 6)
1338
                    sh->sg_tablesize = SG_NONE;
1339
 
1340
                present++;      /* count it */
1341
 
1342
                printk ("Western Digital WD-7000 (rev %d.%d) ",
1343
                        host->rev1, host->rev2);
1344
                printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
1345
                        host->iobase, host->irq, host->dma);
1346
                printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
1347
                        host->bus_on * 125, host->bus_off * 125);
1348
            }
1349
        }
1350
 
1351
#ifdef WD7000_DEBUG
1352
        else
1353
            printk ("%s: IO 0x%x region is already allocated!\n", __FUNCTION__, iobase);
1354
#endif
1355
 
1356
    }
1357
 
1358
    if (! present)
1359
        printk ("Failed initialization of WD-7000 SCSI card!\n");
1360
 
1361
    return (present);
1362
}
1363
 
1364
 
1365
/*
1366
 *  I have absolutely NO idea how to do an abort with the WD7000...
1367
 */
1368
int wd7000_abort (Scsi_Cmnd *SCpnt)
1369
{
1370
    Adapter *host = (Adapter *) SCpnt->host->hostdata;
1371
 
1372
    if (inb (host->iobase + ASC_STAT) & INT_IM) {
1373
        printk ("%s: lost interrupt\n", __FUNCTION__);
1374
        wd7000_intr_handle (host->irq, NULL, NULL);
1375
 
1376
        return (SCSI_ABORT_SUCCESS);
1377
    }
1378
 
1379
    return (SCSI_ABORT_SNOOZE);
1380
}
1381
 
1382
 
1383
/*
1384
 *  I also have no idea how to do a reset...
1385
 */
1386
int wd7000_reset (Scsi_Cmnd *SCpnt, uint flags)
1387
{
1388
    return (SCSI_RESET_PUNT);
1389
}
1390
 
1391
 
1392
/*
1393
 *  This was borrowed directly from aha1542.c. (Zaga)
1394
 */
1395
int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
1396
{
1397
#ifdef WD7000_DEBUG
1398
    printk ("%s: dev=%s, size=%d, ", __FUNCTION__, kdevname (dev), disk->capacity);
1399
#endif
1400
 
1401
    /*
1402
     * try default translation
1403
     */
1404
    ip[0] = 64;
1405
    ip[1] = 32;
1406
    ip[2] = disk->capacity / (64 * 32);
1407
 
1408
    /*
1409
     * for disks >1GB do some guessing
1410
     */
1411
    if (ip[2] >= 1024) {
1412
        int info[3];
1413
 
1414
        /*
1415
         * try to figure out the geometry from the partition table
1416
         */
1417
        if ((scsicam_bios_param (disk, dev, info) < 0) ||
1418
            !(((info[0] == 64) && (info[1] == 32)) ||
1419
              ((info[0] == 255) && (info[1] == 63)))) {
1420
            printk ("%s: unable to verify geometry for disk with >1GB.\n"
1421
                    "                  using extended translation.\n",
1422
                    __FUNCTION__);
1423
 
1424
            ip[0] = 255;
1425
            ip[1] = 63;
1426
            ip[2] = disk->capacity / (255 * 63);
1427
        }
1428
        else {
1429
            ip[0] = info[0];
1430
            ip[1] = info[1];
1431
            ip[2] = info[2];
1432
 
1433
            if (info[0] == 255)
1434
                printk ("%s: current partition table is using extended translation.\n",
1435
                        __FUNCTION__);
1436
        }
1437
    }
1438
 
1439
#ifdef WD7000_DEBUG
1440
    printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
1441
    printk ("WARNING: check, if the bios geometry is correct.\n");
1442
#endif
1443
 
1444
    return (0);
1445
}
1446
 
1447
#ifdef MODULE
1448
/* Eventually this will go into an include file, but this will be later */
1449
Scsi_Host_Template driver_template = WD7000;
1450
 
1451
#include "scsi_module.c"
1452
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.