nca_isa.c revision 1.3 1 /* $NetBSD: nca_isa.c,v 1.3 2000/03/18 16:13:27 mycroft Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by John M. Ruschmeyer.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * FreeBSD generic NCR-5380/NCR-53C400 SCSI driver
41 *
42 * Copyright (C) 1994 Serge Vakulenko (vak (at) cronyx.ru)
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/device.h>
69 #include <sys/buf.h>
70
71 #include <machine/bus.h>
72 #include <machine/intr.h>
73
74 #include <dev/scsipi/scsi_all.h>
75 #include <dev/scsipi/scsipi_all.h>
76 #include <dev/scsipi/scsiconf.h>
77
78 #include <dev/isa/isavar.h>
79 #include <dev/isa/isadmavar.h>
80
81 #include <dev/ic/ncr5380reg.h>
82 #include <dev/ic/ncr5380var.h>
83 #include <dev/ic/ncr53c400reg.h>
84
85 #include <dev/isa/nca_isavar.h>
86
87 int nca_isa_find __P((bus_space_tag_t, bus_space_handle_t, bus_size_t,
88 struct nca_isa_probe_data *));
89 int nca_isa_match __P((struct device *, struct cfdata *, void *));
90 void nca_isa_attach __P((struct device *, struct device *, void *));
91 int nca_isa_test __P((bus_space_tag_t, bus_space_handle_t, bus_size_t));
92
93 struct cfattach nca_isa_ca = {
94 sizeof(struct nca_isa_softc), nca_isa_match, nca_isa_attach
95 };
96
97 struct scsipi_device nca_isa_dev = {
98 NULL, /* Use default error handler */
99 NULL, /* have a queue, served by this */
100 NULL, /* have no async handler */
101 NULL, /* Use default 'done' routine */
102 };
103
104
105 /* Supported controller types */
106 #define MAX_NCA_CONTROLLER 3
107 #define CTLR_NCR_5380 1
108 #define CTLR_NCR_53C400 2
109 #define CTLR_PAS16 3
110
111 #define NCA_ISA_IOSIZE 16
112 #define MIN_DMA_LEN 128
113
114 /* Options for disconnect/reselect, DMA, and interrupts. */
115 #define NCA_NO_DISCONNECT 0xff
116 #define NCA_NO_PARITY_CHK 0xff00
117 #define NCA_FORCE_POLLING 0x10000
118
119
120 /*
121 * Initialization and test function used by nca_isa_find()
122 */
123 int
124 nca_isa_test(iot, ioh, reg_offset)
125 bus_space_tag_t iot;
126 bus_space_handle_t ioh;
127 bus_size_t reg_offset;
128 {
129 /* Reset the SCSI bus. */
130 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, SCI_ICMD_RST);
131 bus_space_write_1(iot, ioh, reg_offset + C80_ODR, 0);
132 /* Hold reset for at least 25 microseconds. */
133 delay(500);
134 /* Check that status cleared. */
135 if (bus_space_read_1(iot, ioh, reg_offset + C80_CSBR) != SCI_BUS_RST) {
136 #ifdef DEBUG
137 printf("nca_isa_find: reset status not cleared [0x%x]\n",
138 bus_space_read_1(iot, ioh, reg_offset+C80_CSBR));
139 #endif
140 bus_space_write_1(iot, ioh, reg_offset+C80_ICR, 0);
141 return 0;
142 }
143 /* Clear reset. */
144 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, 0);
145 /* Wait a Bus Clear Delay (800 ns + bus free delay 800 ns). */
146 delay(16000);
147
148 /* Read RPI port, resetting parity/interrupt state. */
149 bus_space_read_1(iot, ioh, reg_offset + C80_RPIR);
150
151 /* Test BSR: parity error, interrupt request and busy loss state
152 * should be cleared. */
153 if (bus_space_read_1(iot, ioh, reg_offset + C80_BSR) & (SCI_CSR_PERR |
154 SCI_CSR_INT | SCI_CSR_DISC)) {
155 #ifdef DEBUG
156 printf("nca_isa_find: Parity/Interrupt/Busy not cleared [0x%x]\n",
157 bus_space_read_1(iot, ioh, reg_offset+C80_BSR));
158 #endif
159 return 0;
160 }
161
162 /* We must have found one */
163 return 1;
164 }
165
166
167 /*
168 * Look for the board
169 */
170 int
171 nca_isa_find(iot, ioh, max_offset, epd)
172 bus_space_tag_t iot;
173 bus_space_handle_t ioh;
174 bus_size_t max_offset;
175 struct nca_isa_probe_data *epd;
176 {
177 /*
178 * We check for the existence of a board by trying to initialize it,
179 * Then sending the commands to reset the SCSI bus.
180 * (Unfortunately, this duplicates code which is already in the MI
181 * driver. Unavoidable as that code is not suited to this task.)
182 * This is largely stolen from FreeBSD.
183 */
184
185 int cont_type;
186 bus_size_t base_offset, reg_offset = 0;
187
188 /*
189 * Some notes:
190 * In the case of a port-mapped board, we should be pointing
191 * right at the chip registers (if they are there at all).
192 * For a memory-mapped card, we loop through the 16K paragraph,
193 * 8 bytes at a time, until we either find it or run out
194 * of region. This means we will probably be doing things like
195 * trying to write to ROMS, etc. Hopefully, this is not a problem.
196 */
197
198 for (base_offset = 0; base_offset < max_offset; base_offset += 0x08) {
199 #ifdef DEBUG
200 printf("nca_isa_find: testing offset 0x%x\n", (int)base_offset);
201 #endif
202
203 /* See if anything is there */
204 if (bus_space_read_1(iot, ioh, base_offset) == 0xff)
205 continue;
206
207 /* Loop around for each board type */
208 for (cont_type = 1; cont_type <= MAX_NCA_CONTROLLER; cont_type++) {
209 /* Per-controller initialization */
210 switch (cont_type) {
211 case CTLR_NCR_5380:
212 /* No special inits */
213 reg_offset = 0;
214 break;
215 case CTLR_NCR_53C400:
216 /* Reset into 5380-compat. mode */
217 bus_space_write_1(iot, ioh,
218 base_offset + C400_CSR,
219 C400_CSR_5380_ENABLE);
220 reg_offset = C400_5380_REG_OFFSET;
221 break;
222 case CTLR_PAS16:
223 /* Not currently supported */
224 reg_offset = 0;
225 cont_type = 0;
226 continue;
227 }
228
229 /* Initialize controller and bus */
230 if (nca_isa_test(iot, ioh, base_offset+reg_offset)) {
231 epd->sc_reg_offset = base_offset;
232 epd->sc_host_type = cont_type;
233 return cont_type; /* This must be it */
234 }
235 }
236 }
237
238 /* If we got here, we didn't find one */
239 return 0;
240 }
241
242
243 /*
244 * See if there is anything at the config'd address.
245 * If so, call the real probe to see what it is.
246 */
247 int
248 nca_isa_match(parent, match, aux)
249 struct device *parent;
250 struct cfdata *match;
251 void *aux;
252 {
253 struct isa_attach_args *ia = aux;
254 bus_space_tag_t iot = ia->ia_iot;
255 bus_space_tag_t memt = ia->ia_memt;
256 bus_space_handle_t ioh;
257 struct nca_isa_probe_data epd;
258 int rv = 0;
259
260 /* See if we are looking for a port- or memory-mapped adapter */
261 if (ia->ia_iobase != -1) {
262 /* Port-mapped card */
263 if (bus_space_map(iot, ia->ia_iobase, NCA_ISA_IOSIZE, 0, &ioh))
264 return 0;
265
266 /* See if a 53C80/53C400 is there */
267 rv = nca_isa_find(iot, ioh, 0x07, &epd);
268
269 bus_space_unmap(iot, ioh, NCA_ISA_IOSIZE);
270 } else {
271 /* Memory-mapped card */
272 if (bus_space_map(memt, ia->ia_maddr, 0x4000, 0, &ioh))
273 return 0;
274
275 /* See if a 53C80/53C400 is somewhere in this para. */
276 rv = nca_isa_find(memt, ioh, 0x03ff0, &epd);
277
278 bus_space_unmap(memt, ioh, 0x04000);
279 }
280
281 /* Adjust the attachment args if we found one */
282 if (rv) {
283 if (ia->ia_iobase != -1) {
284 /* Port-mapped */
285 ia->ia_iosize = NCA_ISA_IOSIZE;
286 } else {
287 /* Memory-mapped */
288 ia->ia_maddr += epd.sc_reg_offset;
289 ia->ia_msize = NCA_ISA_IOSIZE;
290 ia->ia_iosize = 0;
291 }
292 }
293
294 return rv;
295 }
296
297 /*
298 * Attach this instance, and then all the sub-devices
299 */
300 void
301 nca_isa_attach(parent, self, aux)
302 struct device *parent, *self;
303 void *aux;
304 {
305 struct isa_attach_args *ia = aux;
306 struct nca_isa_softc *esc = (void *)self;
307 struct ncr5380_softc *sc = &esc->sc_ncr5380;
308 bus_space_tag_t iot = ia->ia_iot;
309 bus_space_handle_t ioh;
310 struct nca_isa_probe_data epd;
311 isa_chipset_tag_t ic = ia->ia_ic;
312
313 printf("\n");
314
315 if (ia->ia_iobase != -1) {
316 iot = ia->ia_iot;
317 if (bus_space_map(iot, ia->ia_iobase, NCA_ISA_IOSIZE, 0, &ioh)) {
318 printf("%s: can't map i/o space\n",
319 sc->sc_dev.dv_xname);
320 return;
321 }
322 } else {
323 iot = ia->ia_memt;
324 if (bus_space_map(iot, ia->ia_maddr, NCA_ISA_IOSIZE, 0, &ioh)) {
325 printf("%s: can't map mem space\n",
326 sc->sc_dev.dv_xname);
327 return;
328 }
329 }
330
331 switch (nca_isa_find(iot, ioh, NCA_ISA_IOSIZE, &epd)) {
332 case 0:
333 /* Not found- must have gone away */
334 printf("%s: nca_isa_find failed\n", sc->sc_dev.dv_xname);
335 return;
336 case CTLR_NCR_5380:
337 printf("%s: NCR 53C80 detected\n", sc->sc_dev.dv_xname);
338 sc->sci_r0 = 0;
339 sc->sci_r1 = 1;
340 sc->sci_r2 = 2;
341 sc->sci_r3 = 3;
342 sc->sci_r4 = 4;
343 sc->sci_r5 = 5;
344 sc->sci_r6 = 6;
345 sc->sci_r7 = 7;
346 break;
347 case CTLR_NCR_53C400:
348 printf("%s: NCR 53C400 detected\n", sc->sc_dev.dv_xname);
349 sc->sci_r0 = C400_5380_REG_OFFSET + 0;
350 sc->sci_r1 = C400_5380_REG_OFFSET + 1;
351 sc->sci_r2 = C400_5380_REG_OFFSET + 2;
352 sc->sci_r3 = C400_5380_REG_OFFSET + 3;
353 sc->sci_r4 = C400_5380_REG_OFFSET + 4;
354 sc->sci_r5 = C400_5380_REG_OFFSET + 5;
355 sc->sci_r6 = C400_5380_REG_OFFSET + 6;
356 sc->sci_r7 = C400_5380_REG_OFFSET + 7;
357 break;
358 case CTLR_PAS16:
359 printf("%s: ProAudio Spectrum 16 detected\n", sc->sc_dev.dv_xname);
360 break;
361 }
362
363
364 /*
365 * MD function pointers used by the MI code.
366 */
367 sc->sc_pio_out = ncr5380_pio_out;
368 sc->sc_pio_in = ncr5380_pio_in;
369 sc->sc_dma_alloc = NULL;
370 sc->sc_dma_free = NULL;
371 sc->sc_dma_setup = NULL;
372 sc->sc_dma_start = NULL;
373 sc->sc_dma_poll = NULL;
374 sc->sc_dma_eop = NULL;
375 sc->sc_dma_stop = NULL;
376 sc->sc_intr_on = NULL;
377 sc->sc_intr_off = NULL;
378
379 if (ia->ia_irq != IRQUNK) {
380 esc->sc_ih = isa_intr_establish(ic, ia->ia_irq, IST_EDGE,
381 IPL_BIO, (int (*)(void *))ncr5380_intr, esc);
382 if (esc->sc_ih == NULL) {
383 printf("nca: couldn't establish interrupt\n");
384 return;
385 }
386 } else
387 sc->sc_flags |= NCR5380_FORCE_POLLING;
388
389
390 /*
391 * Support the "options" (config file flags).
392 * Disconnect/reselect is a per-target mask.
393 * Interrupts and DMA are per-controller.
394 */
395 #if 0
396 esc->sc_options = 0x00000; /* no options */
397 #else
398 esc->sc_options = 0x0ffff; /* all options except force poll */
399 #endif
400
401 sc->sc_no_disconnect =
402 (esc->sc_options & NCA_NO_DISCONNECT);
403 sc->sc_parity_disable =
404 (esc->sc_options & NCA_NO_PARITY_CHK) >> 8;
405 if (esc->sc_options & NCA_FORCE_POLLING)
406 sc->sc_flags |= NCR5380_FORCE_POLLING;
407 sc->sc_min_dma_len = MIN_DMA_LEN;
408
409
410 /*
411 * Initialize fields used by the MI code
412 */
413 sc->sc_regt = iot;
414 sc->sc_regh = ioh;
415
416 sc->sc_link.scsipi_scsi.adapter_target = 7;
417 sc->sc_adapter.scsipi_minphys = minphys;
418
419 /*
420 * Initialize nca board itself.
421 */
422 ncr5380_attach(sc);
423 }
424