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