esp_mca.c revision 1.6 1 /* $NetBSD: esp_mca.c,v 1.6 2002/10/02 16:34:09 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jaromir Dolecek <jdolecek (at) NetBSD.org>.
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 * Driver for NCR 53c90, MCA version, with 86c01 DMA controller chip.
41 *
42 * Some of the information used to write this driver was taken
43 * from Tymm Twillman <tymm (at) computer.org>'s Linux MCA NC53c90 driver,
44 * in drivers/scsi/mca_53c9x.c
45 */
46
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/errno.h>
52 #include <sys/ioctl.h>
53 #include <sys/device.h>
54 #include <sys/buf.h>
55 #include <sys/proc.h>
56 #include <sys/user.h>
57 #include <sys/queue.h>
58
59 #include <dev/scsipi/scsi_all.h>
60 #include <dev/scsipi/scsipi_all.h>
61 #include <dev/scsipi/scsiconf.h>
62 #include <dev/scsipi/scsi_message.h>
63
64 #include <machine/bus.h>
65 #include <machine/cpu.h>
66
67 #include <dev/ic/ncr53c9xreg.h>
68 #include <dev/ic/ncr53c9xvar.h>
69
70 #include <dev/mca/espvar.h>
71 #include <dev/mca/espreg.h>
72
73 #include <dev/mca/mcavar.h>
74 #include <dev/mca/mcareg.h>
75 #include <dev/mca/mcadevs.h>
76
77 #if 0
78 #if defined(DEBUG) && !defined(NCR53C9X_DEBUG)
79 #define NCR53C9X_DEBUG
80 #endif
81 #endif
82
83 #ifdef NCR53C9X_DEBUG
84 static int esp_mca_debug = 0;
85 #define DPRINTF(x) if (esp_mca_debug) printf x;
86 #else
87 #define DPRINTF(x)
88 #endif
89
90 #define ESP_MCA_IOSIZE 0x20
91 #define ESP_REG_OFFSET 0x10
92
93 static void esp_mca_attach __P((struct device *, struct device *, void *));
94 static int esp_mca_match __P((struct device *, struct cfdata *, void *));
95
96 CFATTACH_DECL(esp_mca, sizeof(struct esp_softc),
97 esp_mca_match, esp_mca_attach, NULL, NULL);
98
99 /*
100 * Functions and the switch for the MI code.
101 */
102 static u_char esp_read_reg __P((struct ncr53c9x_softc *, int));
103 static void esp_write_reg __P((struct ncr53c9x_softc *, int, u_char));
104 static int esp_dma_isintr __P((struct ncr53c9x_softc *));
105 static void esp_dma_reset __P((struct ncr53c9x_softc *));
106 static int esp_dma_intr __P((struct ncr53c9x_softc *));
107 static int esp_dma_setup __P((struct ncr53c9x_softc *, caddr_t *,
108 size_t *, int, size_t *));
109 static void esp_dma_go __P((struct ncr53c9x_softc *));
110 static void esp_dma_stop __P((struct ncr53c9x_softc *));
111 static int esp_dma_isactive __P((struct ncr53c9x_softc *));
112
113 static struct ncr53c9x_glue esp_glue = {
114 esp_read_reg,
115 esp_write_reg,
116 esp_dma_isintr,
117 esp_dma_reset,
118 esp_dma_intr,
119 esp_dma_setup,
120 esp_dma_go,
121 esp_dma_stop,
122 esp_dma_isactive,
123 NULL, /* gl_clear_latched_intr */
124 };
125
126 static int
127 esp_mca_match(parent, cf, aux)
128 struct device *parent;
129 struct cfdata *cf;
130 void *aux;
131 {
132 struct mca_attach_args *ma = aux;
133
134 switch (ma->ma_id) {
135 case MCA_PRODUCT_NCR53C90:
136 return 1;
137 }
138
139 return 0;
140 }
141
142 static void
143 esp_mca_attach(parent, self, aux)
144 struct device *parent, *self;
145 void *aux;
146 {
147 struct mca_attach_args *ma = aux;
148 struct esp_softc *esc = (void *)self;
149 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
150 u_int16_t iobase;
151 int scsi_id, irq, drq, error;
152 bus_space_handle_t ioh;
153 int pos2, pos3, pos5;
154
155 static const u_int16_t ncrmca_iobase[] = {
156 0, 0x240, 0x340, 0x400, 0x420, 0x3240, 0x8240, 0xa240
157 };
158
159 /*
160 * NCR SCSI Adapter (ADF 7f4f)
161 *
162 * POS register 2: (adf pos0)
163 *
164 * 7 6 5 4 3 2 1 0
165 * \_/ \___/ \__ enable: 0=adapter disabled, 1=adapter enabled
166 * | \____ I/O base (32B): 001=0x240 010=0x340 011=0x400
167 * | 100=0x420 101=0x3240 110=0x8240 111=0xa240
168 * \__________ IRQ: 00=3 01=5 10=7 11=9
169 *
170 * POS register 3: (adf pos1)
171 *
172 * 7 6 5 4 3 2 1 0
173 * 1 1 1 | \_____/
174 * | \__ DMA level
175 * \_________ Fairness: 1=enabled 0=disabled
176 *
177 * POS register 5: (adf pos3)
178 *
179 * 7 6 5 4 3 2 1 0
180 * 1 | \___/
181 * | \__ Static Ram: 0xC8000-0xC87FF + XX*0x4000
182 * \___________ Host Adapter ID: 1=7 0=6
183 */
184
185 pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2);
186 pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
187 pos5 = mca_conf_read(ma->ma_mc, ma->ma_slot, 5);
188
189 iobase = ncrmca_iobase[(pos2 & 0x0e) >> 1];
190 irq = 3 + 2*((pos2 & 0x30) >> 4);
191 drq = (pos3 & 0x0f);
192 scsi_id = 6 + ((pos5 & 0x20) ? 1 : 0);
193
194 printf(" slot %d irq %d drq %d: NCR SCSI Adapter\n",
195 ma->ma_slot + 1, irq, drq);
196
197 /* Map the 86C01 registers */
198 if (bus_space_map(ma->ma_iot, iobase, ESP_MCA_IOSIZE, 0, &ioh)) {
199 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
200 return;
201 }
202
203 esc->sc_iot = ma->ma_iot;
204 esc->sc_ioh = ioh;
205
206 /* Submap the 'esp' registers */
207 if (bus_space_subregion(ma->ma_iot, ioh, ESP_REG_OFFSET,
208 ESP_MCA_IOSIZE-ESP_REG_OFFSET, &esc->sc_esp_ioh)) {
209 printf("%s: can't subregion i/o space\n", sc->sc_dev.dv_xname);
210 return;
211 }
212
213 /* Setup DMA map */
214 esc->sc_dmat = ma->ma_dmat;
215 if ((error = mca_dmamap_create(esc->sc_dmat, MAXPHYS,
216 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | MCABUS_DMA_IOPORT,
217 &esc->sc_xfer, drq)) != 0){
218 printf("%s: couldn't create DMA map - error %d\n",
219 sc->sc_dev.dv_xname, error);
220 return;
221 }
222
223 /* MI code glue */
224 sc->sc_id = scsi_id;
225 sc->sc_freq = 25; /* Mhz */
226
227 sc->sc_glue = &esp_glue;
228
229 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; //| NCRCFG1_SLOW;
230 /* No point setting sc_cfg[2345], they won't be used */
231
232 sc->sc_rev = NCR_VARIANT_NCR53C90_86C01;
233 sc->sc_minsync = 0;
234
235 /* max 64KB DMA */
236 sc->sc_maxxfer = 64 * 1024;
237
238 /* Establish interrupt */
239 esc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_BIO, ncr53c9x_intr,
240 esc);
241 if (esc->sc_ih == NULL) {
242 printf("%s: couldn't establish interrupt\n",
243 sc->sc_dev.dv_xname);
244 return;
245 }
246
247 /*
248 * Massage the 86C01 chip - setup MCA DMA controller for DMA via
249 * the 86C01 register, and enable 86C01 interrupts.
250 */
251 mca_dma_set_ioport(drq, iobase + N86C01_PIO);
252
253 bus_space_write_1(esc->sc_iot, esc->sc_ioh, N86C01_MODE_ENABLE,
254 bus_space_read_1(esc->sc_iot, esc->sc_ioh, N86C01_MODE_ENABLE)
255 | N86C01_INTR_ENABLE);
256
257 /*
258 * Now try to attach all the sub-devices
259 */
260 sc->sc_adapter.adapt_minphys = minphys;
261 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
262
263 /* Do the common parts of attachment. */
264 printf("%s", sc->sc_dev.dv_xname);
265 ncr53c9x_attach(sc);
266 }
267
268 /*
269 * Glue functions.
270 */
271
272 static u_char
273 esp_read_reg(sc, reg)
274 struct ncr53c9x_softc *sc;
275 int reg;
276 {
277 struct esp_softc *esc = (struct esp_softc *)sc;
278
279 return (bus_space_read_1(esc->sc_iot, esc->sc_esp_ioh, reg));
280 }
281
282 static void
283 esp_write_reg(sc, reg, val)
284 struct ncr53c9x_softc *sc;
285 int reg;
286 u_char val;
287 {
288 struct esp_softc *esc = (struct esp_softc *)sc;
289
290 bus_space_write_1(esc->sc_iot, esc->sc_esp_ioh, reg, val);
291 }
292
293 static int
294 esp_dma_isintr(sc)
295 struct ncr53c9x_softc *sc;
296 {
297 struct esp_softc *esc = (struct esp_softc *)sc;
298
299 DPRINTF(("[esp_dma_isintr] "));
300 return (bus_space_read_1(esc->sc_iot, esc->sc_ioh,
301 N86C01_STATUS) & N86C01_IRQ_PEND);
302 }
303
304 static void
305 esp_dma_reset(sc)
306 struct ncr53c9x_softc *sc;
307 {
308 struct esp_softc *esc = (struct esp_softc *)sc;
309
310 DPRINTF(("[esp_dma_reset] "));
311
312 if (esc->sc_flags & ESP_XFER_LOADED) {
313 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer);
314 esc->sc_flags &= ~ESP_XFER_LOADED;
315 }
316
317 if (esc->sc_flags & ESP_XFER_ACTIVE) {
318 esc->sc_flags &= ~ESP_XFER_ACTIVE;
319 mca_disk_unbusy();
320 }
321 }
322
323 static int
324 esp_dma_intr(sc)
325 struct ncr53c9x_softc *sc;
326 {
327 struct esp_softc *esc = (struct esp_softc *) sc;
328 DPRINTF(("[esp_dma_intr] "));
329
330 if ((esc->sc_flags & ESP_XFER_ACTIVE) == 0) {
331 printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
332 return (-1);
333 }
334
335 if ((sc->sc_espintr & NCRINTR_BS) == 0) {
336 esc->sc_flags &= ~ESP_XFER_ACTIVE;
337 mca_disk_unbusy();
338 return (0);
339 }
340
341 sc->sc_espstat |= NCRSTAT_TC; /* XXX */
342
343 if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
344 printf("%s: DMA not complete?\n", sc->sc_dev.dv_xname);
345 return (1);
346 }
347
348 bus_dmamap_sync(esc->sc_dmat, esc->sc_xfer, 0,
349 *esc->sc_xfer_len,
350 (esc->sc_flags & ESP_XFER_READ)
351 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
352
353 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer);
354 esc->sc_flags &= ~ESP_XFER_LOADED;
355
356 *esc->sc_xfer_addr += *esc->sc_xfer_len;
357 *esc->sc_xfer_len = 0;
358
359 esc->sc_flags &= ~ESP_XFER_ACTIVE;
360 mca_disk_unbusy();
361
362 return (0);
363 }
364
365 /*
366 * Setup DMA transfer.
367 */
368 static int
369 esp_dma_setup(sc, addr, len, datain, dmasize)
370 struct ncr53c9x_softc *sc;
371 caddr_t *addr;
372 size_t *len;
373 int datain;
374 size_t *dmasize;
375 {
376 struct esp_softc *esc = (struct esp_softc *) sc;
377 int error;
378 int fl;
379
380 DPRINTF(("[esp_dma_setup] "));
381
382 if (esc->sc_flags & ESP_XFER_LOADED) {
383 printf("%s: esp_dma_setup: unloading leaked xfer\n",
384 sc->sc_dev.dv_xname);
385 bus_dmamap_unload(esc->sc_dmat, esc->sc_xfer);
386 esc->sc_flags &= ~ESP_XFER_LOADED;
387 }
388
389 /* Load the buffer for DMA transfer. */
390 fl = (datain) ? BUS_DMA_READ : BUS_DMA_WRITE;
391
392 if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_xfer, *addr,
393 *len, NULL, BUS_DMA_STREAMING|fl))) {
394 printf("%s: esp_dma_setup: unable to load DMA buffer - error %d\n",
395 sc->sc_dev.dv_xname, error);
396 return (error);
397 }
398
399 bus_dmamap_sync(esc->sc_dmat, esc->sc_xfer, 0,
400 *len, (datain) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
401
402 esc->sc_flags |= ESP_XFER_LOADED | (datain ? ESP_XFER_READ : 0);
403 esc->sc_xfer_addr = addr;
404 esc->sc_xfer_len = len;
405
406 return (0);
407 }
408
409 static void
410 esp_dma_go(sc)
411 struct ncr53c9x_softc *sc;
412 {
413 struct esp_softc *esc = (struct esp_softc *) sc;
414 DPRINTF(("[esp_dma_go] "));
415
416 esc->sc_flags |= ESP_XFER_ACTIVE;
417 mca_disk_busy();
418 }
419
420 static void
421 esp_dma_stop(sc)
422 struct ncr53c9x_softc *sc;
423 {
424 DPRINTF(("[esp_dma_stop] "));
425
426 panic("%s: stop not yet implemented", sc->sc_dev.dv_xname);
427 }
428
429 static int
430 esp_dma_isactive(sc)
431 struct ncr53c9x_softc *sc;
432 {
433 struct esp_softc *esc = (struct esp_softc *) sc;
434 DPRINTF(("[esp_dma_isactive] "));
435
436 return (esc->sc_flags & ESP_XFER_ACTIVE);
437 }
438