|
|
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 ! 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.