|
|
1.1 root 1: /* $Id: wd7000.c,v 1.1 1999/04/26 05:55:18 tb 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 <[email protected]> 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 <[email protected]>
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
1.1.1.2 ! root 576: ogmb = (ogmb + 1) % OGMB_CNT;
1.1 root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.