📄 fdomain.c
字号:
extern void fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs );static void *addresses[] = { (void *)0xc8000, (void *)0xca000, (void *)0xce000, (void *)0xde000, (void *)0xcc000, /* Extra addresses for PCI boards */ (void *)0xd0000, (void *)0xe0000,};#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };/* READ THIS BEFORE YOU ADD A SIGNATURE! READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! READ EVERY WORD, ESPECIALLY THE WORD *NOT* This driver works *ONLY* for Future Domain cards using the TMC-1800, TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, and 1680. The following BIOS signature signatures are for boards which do *NOT* work with this driver (these TMC-8xx and TMC-9xx boards may work with the Seagate driver): FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92*/struct signature { const char *signature; int sig_offset; int sig_length; int major_bios_version; int minor_bios_version; int flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */} signatures[] = { /* 1 2 3 4 5 6 */ /* 123456789012345678901234567890123456789012345678901234567890 */ { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 2, 0, 3 }, { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 2, 0, 4 }, { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 3, -1, 0 }, { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, { "Future Domain Corp. V1.0008/18/93", 26, 33, 3, 4, 1 }, { "Adaptec AHA-2920 PCI-SCSI Card", 42, 31, 3, -1, 1 }, { "IBM F1 P264/32", 5, 14, 3, -1, 1 }, /* This next signature may not be a 3.5 bios */ { "Future Domain Corp. V2.0108/18/93", 5, 33, 3, 5, 0 }, { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 3, 5, 0 }, { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 3, 5, 0 }, { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 3, 6, 0 }, { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 3, 6, 0 }, { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1, 0 }, /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE Also, fix the disk geometry code for your signature and send your changes for faith@cs.unc.edu. Above all, do *NOT* change any old signatures! Note that the last line will match a "generic" 18XX bios. Because Future Domain has changed the host SCSI ID and/or the location of the geometry information in the on-board RAM area for each of the first three BIOS's, it is still important to enter a fully qualified signature in the table for any new BIOS's (after the host SCSI ID and geometry location are verified). */};#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))static void print_banner( struct Scsi_Host *shpnt ){ if (!shpnt) return; /* This won't ever happen */ if (bios_major < 0 && bios_minor < 0) { printk( "scsi%d <fdomain>: No BIOS; using scsi id %d\n", shpnt->host_no, shpnt->this_id ); } else { printk( "scsi%d <fdomain>: BIOS version ", shpnt->host_no ); if (bios_major >= 0) printk( "%d.", bios_major ); else printk( "?." ); if (bios_minor >= 0) printk( "%d", bios_minor ); else printk( "?." ); printk( " at 0x%x using scsi id %d\n", (unsigned)bios_base, shpnt->this_id ); } /* If this driver works for later FD PCI boards, we will have to modify banner for additional PCI cards, but for now if it's PCI it's a TMC-3260 - JTM */ printk( "scsi%d <fdomain>: %s chip at 0x%x irq ", shpnt->host_no, chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")), port_base ); if (interrupt_level) printk( "%d", interrupt_level ); else printk( "<none>" ); printk( "\n" );}void fdomain_setup( char *str, int *ints ){ if (setup_called++ || ints[0] < 2 || ints[0] > 3) { printk( "fdomain: usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n" ); printk( "fdomain: bad LILO parameters?\n" ); } port_base = ints[0] >= 1 ? ints[1] : 0; interrupt_level = ints[0] >= 2 ? ints[2] : 0; this_id = ints[0] >= 3 ? ints[3] : 0; bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */}static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */{ unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ while (jiffies < the_time);}inline static void fdomain_make_bus_idle( void ){ outb( 0, SCSI_Cntl_port ); outb( 0, SCSI_Mode_Cntl_port ); if (chip == tmc18c50 || chip == tmc18c30) outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */ else outb( 0x01 | PARITY_MASK, TMC_Cntl_port );}static int fdomain_is_valid_port( int port ){#if DEBUG_DETECT printk( " (%x%x),", inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );#endif /* The MCA ID is a unique id for each MCA compatible board. We are using ISA boards, but Future Domain provides the MCA ID anyway. We can use this ID to ensure that this is a Future Domain TMC-1660/TMC-1680. */ if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ if (inb( port + LSB_ID_Code ) != 0x27) return 0; if (inb( port + MSB_ID_Code ) != 0x61) return 0; chip = tmc1800; } else { /* test for 0xe960 id */ if (inb( port + MSB_ID_Code ) != 0x60) return 0; chip = tmc18c50;#if 0 /* Try to toggle 32-bit mode. This only works on an 18c30 chip. (User reports say this works, so we should switch to it in the near future.) */ outb( 0x80, port + IO_Control ); if ((inb( port + Configuration2 ) & 0x80) == 0x80) { outb( 0x00, port + IO_Control ); if ((inb( port + Configuration2 ) & 0x80) == 0x00) { chip = tmc18c30; FIFO_Size = 0x800; /* 2k FIFO */ } }#else /* That should have worked, but appears to have problems. Let's assume it is an 18c30 if the RAM is disabled. */ if (inb( port + Configuration2 ) & 0x02) { chip = tmc18c30; FIFO_Size = 0x800; /* 2k FIFO */ }#endif /* If that failed, we are an 18c50. */ } return 1;}static int fdomain_test_loopback( void ){ int i; int result; for (i = 0; i < 255; i++) { outb( i, port_base + Write_Loopback ); result = inb( port_base + Read_Loopback ); if (i != result) return 1; } return 0;}/* fdomain_get_irq assumes that we have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the bios_base matches these ports. If someone was unlucky enough to have purchased more than one Future Domain board, then they will have to modify this code, as we only detect one board here. [The one with the lowest bios_base.] Note that this routine is only used for systems without a PCI BIOS32 (e.g., ISA bus). For PCI bus systems, this routine will likely fail unless one of the IRQs listed in the ints array is used by the board. Sometimes it is possible to use the computer's BIOS setup screen to configure a PCI system so that one of these IRQs will be used by the Future Domain card. */static int fdomain_get_irq( int base ){ int options = inb( base + Configuration1 );#if DEBUG_DETECT printk( " Options = %x\n", options );#endif /* Check for board with lowest bios_base -- this isn't valid for the 18c30 or for boards on the PCI bus, so just assume we have the right board. */ if (chip != tmc18c30 && !PCI_bus && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0; return ints[ (options & 0x0e) >> 1 ];}static int fdomain_isa_detect( int *irq, int *iobase ){ int i; int base; int flag = 0; if (bios_major == 2) { /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. Assuming the ROM is enabled (otherwise we wouldn't have been able to read the ROM signature :-), then the ROM sets up the RAM area with some magic numbers, such as a list of port base addresses and a list of the disk "geometry" reported to DOS (this geometry has nothing to do with physical geometry). */ switch (Quantum) { case 2: /* ISA_200S */ case 3: /* ISA_250MG */ base = *((char *)bios_base + 0x1fa2) + (*((char *)bios_base + 0x1fa3) << 8); break; case 4: /* ISA_200S (another one) */ base = *((char *)bios_base + 0x1fa3) + (*((char *)bios_base + 0x1fa4) << 8); break; default: base = *((char *)bios_base + 0x1fcc) + (*((char *)bios_base + 0x1fcd) << 8); break; } #if DEBUG_DETECT printk( " %x,", base );#endif for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { if (base == ports[i]) ++flag; } if (flag && fdomain_is_valid_port( base )) { *irq = fdomain_get_irq( base ); *iobase = base; return 1; } /* This is a bad sign. It usually means that someone patched the BIOS signature list (the signatures variable) to contain a BIOS signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ #if DEBUG_DETECT printk( " RAM FAILED, " );#endif } /* Anyway, the alternative to finding the address in the RAM is to just search through every possible port address for one that is attached to the Future Domain card. Don't panic, though, about reading all these random port addresses -- there are rumors that the Future Domain BIOS does something very similar. Do not, however, check ports which the kernel knows are being used by another driver. */ for (i = 0; i < PORT_COUNT; i++) { base = ports[i]; if (check_region( base, 0x10 )) {#if DEBUG_DETECT printk( " (%x inuse),", base );#endif continue; }#if DEBUG_DETECT printk( " %x,", base );#endif if ((flag = fdomain_is_valid_port( base ))) break; } if (!flag) return 0; /* iobase not found */ *irq = fdomain_get_irq( base ); *iobase = base; return 1; /* success */}static int fdomain_pci_nobios_detect( int *irq, int *iobase ){ int i; int flag = 0; /* The proper way of doing this is to use ask the PCI bus for the device IRQ and interrupt level. But we can't do that if PCI BIOS32 support isn't compiled into the kernel, or if a PCI BIOS32 isn't present. Instead, we scan down a bunch of addresses (Future Domain tech support says we will probably find the address before we get to 0xf800). This works fine on some systems -- other systems may have to scan more addresses. If you have to modify this section for your installation, please send mail to faith@cs.unc.edu. */ for (i = 0xfff8; i > 0xe000; i -= 8) { if (check_region( i, 0x10 )) {#if DEBUG_DETECT printk( " (%x inuse)," , i );#endif continue; } if ((flag = fdomain_is_valid_port( i ))) break; } if (!flag) return 0; /* iobase not found */ *irq = fdomain_get_irq( i ); *iobase = i; return 1; /* success */}/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int* iobase) This function gets the Interrupt Level and I/O base address from the PCI configuration registers. The I/O base address is masked with 0xfff8 since on my card the address read from the PCI config registers is off by one from the actual I/O base address necessary for accessing the status and control registers on the card (PCI config register gives 0xf801, actual address is 0xf800). This is likely a bug in the FD config code that writes to the PCI registers, however using a mask should be safe since I think the scan done by the card to determine the I/O base is done in increments of 8 (i.e., 0xf800, 0xf808, ...), at least the old scan code we used to use to get the I/O base did... Also, the device ID from the PCI config registers is 0x0 and should be 0x60e9 as it is in the status registers (offset 5 from I/O base). If this is changed in future hardware/BIOS changes it will need to be fixed in this detection function. Comments, bug reports, etc... on this function should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley. */#ifdef CONFIG_PCIstatic int fdomain_pci_bios_detect( int *irq, int *iobase )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -