Commit | Line | Data |
---|---|---|
e5207cf0 OZ |
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(addresses[ndev], FDOMAIN_BIOS_SIZE); | |
98 | if (!p) | |
99 | return 0; | |
100 | for (i = 0; i < SIGNATURE_COUNT; i++) | |
101 | if (check_signature(p + signatures[i].offset, | |
102 | signatures[i].signature, | |
103 | 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(p + sig->base_offset) + | |
112 | (readb(p + sig->base_offset + 1) << 8); | |
113 | iounmap(p); | |
255937d7 | 114 | if (base) { |
e5207cf0 OZ |
115 | dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n", |
116 | bios_base, base); | |
255937d7 | 117 | } else { /* no I/O base in BIOS area */ |
e5207cf0 | 118 | dev_info(dev, "BIOS at 0x%lx\n", bios_base); |
e5207cf0 OZ |
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 | ||
22d5aa3a | 133 | irq = irqs[(inb(base + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; |
e5207cf0 OZ |
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, sh); | |
145 | return 1; | |
146 | fail_unmap: | |
147 | iounmap(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) | |
22d5aa3a | 165 | irq_ = irqs[(inb(io[ndev] + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; |
e5207cf0 OZ |
166 | |
167 | sh = fdomain_create(io[ndev], irq_, 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, sh); | |
175 | return 1; | |
176 | } | |
177 | ||
30e88d01 | 178 | static void fdomain_isa_remove(struct device *dev, unsigned int ndev) |
e5207cf0 OZ |
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); | |
e5207cf0 OZ |
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"); |