Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | // SPDX-License-Identifier: GPL-2.0 #include <linux/module.h> #include <linux/io.h> #include <linux/isa.h> #include <scsi/scsi_host.h> #include "fdomain.h" #define MAXBOARDS_PARAM 4 static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; module_param_hw_array(io, int, ioport, NULL, 0); MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)"); static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; module_param_hw_array(irq, int, irq, NULL, 0); MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])"); static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; module_param_hw_array(scsi_id, int, other, NULL, 0); MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)"); static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000, }; #define ADDRESS_COUNT ARRAY_SIZE(addresses) static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; #define PORT_COUNT ARRAY_SIZE(ports) static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; /* 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. These are all 16-bit cards. * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter. * * 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 * * (The cards which do *NOT* work are all 8-bit cards -- although some of * them have a 16-bit form-factor, the upper 8-bits are used only for IRQs * and are *NOT* used for data. You can tell the difference by following * the tracings on the circuit board -- if only the IRQ lines are involved, * you have a "8-bit" card, and should *NOT* use this driver.) */ static struct signature { const char *signature; int offset; int length; int this_id; int base_offset; } signatures[] = { /* 1 2 3 4 5 6 */ /* 123456789012345678901234567890123456789012345678901234567890 */ { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 6, 0x1fcc }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 6, 0x1fcc }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 6, 0x1fa2 }, { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 6, 0x1fa2 }, { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 6, 0x1fa3 }, { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 6, 0 }, { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 7, 0 }, { "IBM F1 P2 BIOS v1.0011/09/92", 5, 28, 7, 0x1ff3 }, { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 7, 0 }, { "Future Domain Corp. V1.0008/18/93", 5, 33, 7, 0 }, { "Future Domain Corp. V2.0108/18/93", 5, 33, 7, 0 }, { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 7, 0 }, { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 7, 0 }, { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 7, 0 }, { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 7, 0 }, }; #define SIGNATURE_COUNT ARRAY_SIZE(signatures) static int fdomain_isa_match(struct device *dev, unsigned int ndev) { struct Scsi_Host *sh; int i, base = 0, irq = 0; unsigned long bios_base = 0; struct signature *sig = NULL; void __iomem *p; static struct signature *saved_sig; int this_id = 7; if (ndev < ADDRESS_COUNT) { /* scan supported ISA BIOS addresses */ p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE); if (!p) return 0; for (i = 0; i < SIGNATURE_COUNT; i++) if (check_signature(p + signatures[i].offset, signatures[i].signature, signatures[i].length)) break; if (i == SIGNATURE_COUNT) /* no signature found */ goto fail_unmap; sig = &signatures[i]; bios_base = addresses[ndev]; /* read I/O base from BIOS area */ if (sig->base_offset) base = readb(p + sig->base_offset) + (readb(p + sig->base_offset + 1) << 8); iounmap(p); if (base) { dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n", bios_base, base); } else { /* no I/O base in BIOS area */ dev_info(dev, "BIOS at 0x%lx\n", bios_base); /* save BIOS signature for later use in port probing */ saved_sig = sig; return 0; } } else /* scan supported I/O ports */ base = ports[ndev - ADDRESS_COUNT]; /* use saved BIOS signature if present */ if (!sig && saved_sig) sig = saved_sig; if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa")) return 0; irq = irqs[(inb(base + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; if (sig) this_id = sig->this_id; sh = fdomain_create(base, irq, this_id, dev); if (!sh) { release_region(base, FDOMAIN_REGION_SIZE); return 0; } dev_set_drvdata(dev, sh); return 1; fail_unmap: iounmap(p); return 0; } static int fdomain_isa_param_match(struct device *dev, unsigned int ndev) { struct Scsi_Host *sh; int irq_ = irq[ndev]; if (!io[ndev]) return 0; if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) { dev_err(dev, "base 0x%x already in use", io[ndev]); return 0; } if (irq_ <= 0) irq_ = irqs[(inb(io[ndev] + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev); if (!sh) { dev_err(dev, "controller not found at base 0x%x", io[ndev]); release_region(io[ndev], FDOMAIN_REGION_SIZE); return 0; } dev_set_drvdata(dev, sh); return 1; } static void fdomain_isa_remove(struct device *dev, unsigned int ndev) { struct Scsi_Host *sh = dev_get_drvdata(dev); int base = sh->io_port; fdomain_destroy(sh); release_region(base, FDOMAIN_REGION_SIZE); dev_set_drvdata(dev, NULL); } static struct isa_driver fdomain_isa_driver = { .match = fdomain_isa_match, .remove = fdomain_isa_remove, .driver = { .name = "fdomain_isa", .pm = FDOMAIN_PM_OPS, }, }; static int __init fdomain_isa_init(void) { int isa_probe_count = ADDRESS_COUNT + PORT_COUNT; if (io[0]) { /* use module parameters if present */ fdomain_isa_driver.match = fdomain_isa_param_match; isa_probe_count = MAXBOARDS_PARAM; } return isa_register_driver(&fdomain_isa_driver, isa_probe_count); } static void __exit fdomain_isa_exit(void) { isa_unregister_driver(&fdomain_isa_driver); } module_init(fdomain_isa_init); module_exit(fdomain_isa_exit); MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver"); MODULE_LICENSE("GPL"); |