1 /* $NetBSD: esp_mca.c,v 1.20 2009/01/20 20:49:51 christos Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jaromir Dolecek <jdolecek@NetBSD.org>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Driver for NCR 53c90, MCA version, with 86c01 DMA controller chip.
35 * Some of the information used to write this driver was taken
36 * from Tymm Twillman <tymm@computer.org>'s Linux MCA NC53c90 driver,
37 * in drivers/scsi/mca_53c9x.c
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: esp_mca.c,v 1.20 2009/01/20 20:49:51 christos Exp $");
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/errno.h>
48 #include <sys/ioctl.h>
49 #include <sys/device.h>
52 #include <sys/queue.h>
54 #include <dev/scsipi/scsi_all.h>
55 #include <dev/scsipi/scsipi_all.h>
56 #include <dev/scsipi/scsiconf.h>
57 #include <dev/scsipi/scsi_message.h>
62 #include <dev/ic/ncr53c9xreg.h>
63 #include <dev/ic/ncr53c9xvar.h>
65 #include <dev/mca/espvar.h>
66 #include <dev/mca/espreg.h>
68 #include <dev/mca/mcavar.h>
69 #include <dev/mca/mcareg.h>
70 #include <dev/mca/mcadevs.h>
73 #if defined(DEBUG) && !defined(NCR53C9X_DEBUG)
74 #define NCR53C9X_DEBUG
79 static int esp_mca_debug
= 0;
80 #define DPRINTF(x) if (esp_mca_debug) printf x;
85 #define ESP_MCA_IOSIZE 0x20
86 #define ESP_REG_OFFSET 0x10
88 static int esp_mca_match(device_t
, cfdata_t
, void *);
89 static void esp_mca_attach(device_t
, device_t
, void *);
91 CFATTACH_DECL_NEW(esp_mca
, sizeof(struct esp_softc
),
92 esp_mca_match
, esp_mca_attach
, NULL
, NULL
);
95 * Functions and the switch for the MI code.
97 static uint8_t esp_read_reg(struct ncr53c9x_softc
*, int);
98 static void esp_write_reg(struct ncr53c9x_softc
*, int, uint8_t);
99 static int esp_dma_isintr(struct ncr53c9x_softc
*);
100 static void esp_dma_reset(struct ncr53c9x_softc
*);
101 static int esp_dma_intr(struct ncr53c9x_softc
*);
102 static int esp_dma_setup(struct ncr53c9x_softc
*, uint8_t **,
103 size_t *, int, size_t *);
104 static void esp_dma_go(struct ncr53c9x_softc
*);
105 static void esp_dma_stop(struct ncr53c9x_softc
*);
106 static int esp_dma_isactive(struct ncr53c9x_softc
*);
108 static struct ncr53c9x_glue esp_glue
= {
118 NULL
, /* gl_clear_latched_intr */
122 esp_mca_match(device_t parent
, cfdata_t cf
, void *aux
)
124 struct mca_attach_args
*ma
= aux
;
127 case MCA_PRODUCT_NCR53C90
:
135 esp_mca_attach(device_t parent
, device_t self
, void *aux
)
137 struct esp_softc
*esc
= device_private(self
);
138 struct ncr53c9x_softc
*sc
= &esc
->sc_ncr53c9x
;
139 struct mca_attach_args
*ma
= aux
;
141 int scsi_id
, irq
, drq
, error
;
142 bus_space_handle_t ioh
;
143 int pos2
, pos3
, pos5
;
145 static const uint16_t ncrmca_iobase
[] = {
146 0, 0x240, 0x340, 0x400, 0x420, 0x3240, 0x8240, 0xa240
152 * NCR SCSI Adapter (ADF 7f4f)
154 * POS register 2: (adf pos0)
157 * \_/ \___/ \__ enable: 0=adapter disabled, 1=adapter enabled
158 * | \____ I/O base (32B): 001=0x240 010=0x340 011=0x400
159 * | 100=0x420 101=0x3240 110=0x8240 111=0xa240
160 * \__________ IRQ: 00=3 01=5 10=7 11=9
162 * POS register 3: (adf pos1)
167 * \_________ Fairness: 1=enabled 0=disabled
169 * POS register 5: (adf pos3)
173 * | \__ Static Ram: 0xC8000-0xC87FF + XX*0x4000
174 * \___________ Host Adapter ID: 1=7 0=6
177 pos2
= mca_conf_read(ma
->ma_mc
, ma
->ma_slot
, 2);
178 pos3
= mca_conf_read(ma
->ma_mc
, ma
->ma_slot
, 3);
179 pos5
= mca_conf_read(ma
->ma_mc
, ma
->ma_slot
, 5);
181 iobase
= ncrmca_iobase
[(pos2
& 0x0e) >> 1];
182 irq
= 3 + 2 * ((pos2
& 0x30) >> 4);
184 scsi_id
= 6 + ((pos5
& 0x20) ? 1 : 0);
186 aprint_normal(" slot %d irq %d drq %d: NCR SCSI Adapter\n",
187 ma
->ma_slot
+ 1, irq
, drq
);
189 /* Map the 86C01 registers */
190 if (bus_space_map(ma
->ma_iot
, iobase
, ESP_MCA_IOSIZE
, 0, &ioh
)) {
191 aprint_error_dev(sc
->sc_dev
, "can't map i/o space\n");
195 esc
->sc_iot
= ma
->ma_iot
;
198 /* Submap the 'esp' registers */
199 if (bus_space_subregion(ma
->ma_iot
, ioh
, ESP_REG_OFFSET
,
200 ESP_MCA_IOSIZE
-ESP_REG_OFFSET
, &esc
->sc_esp_ioh
)) {
201 aprint_error_dev(sc
->sc_dev
, "can't subregion i/o space\n");
206 esc
->sc_dmat
= ma
->ma_dmat
;
207 if ((error
= mca_dmamap_create(esc
->sc_dmat
, MAXPHYS
,
208 BUS_DMA_NOWAIT
| BUS_DMA_ALLOCNOW
| MCABUS_DMA_IOPORT
,
209 &esc
->sc_xfer
, drq
)) != 0){
210 aprint_error_dev(sc
->sc_dev
,
211 "couldn't create DMA map - error %d\n", error
);
217 sc
->sc_freq
= 25; /* MHz */
219 sc
->sc_glue
= &esp_glue
;
221 sc
->sc_cfg1
= sc
->sc_id
| NCRCFG1_PARENB
; //| NCRCFG1_SLOW;
222 /* No point setting sc_cfg[2345], they won't be used */
224 sc
->sc_rev
= NCR_VARIANT_NCR53C90_86C01
;
228 sc
->sc_maxxfer
= 64 * 1024;
230 /* Establish interrupt */
231 esc
->sc_ih
= mca_intr_establish(ma
->ma_mc
, irq
, IPL_BIO
, ncr53c9x_intr
,
233 if (esc
->sc_ih
== NULL
) {
234 aprint_error_dev(sc
->sc_dev
, "couldn't establish interrupt\n");
239 * Massage the 86C01 chip - setup MCA DMA controller for DMA via
240 * the 86C01 register, and enable 86C01 interrupts.
242 mca_dma_set_ioport(drq
, iobase
+ N86C01_PIO
);
244 bus_space_write_1(esc
->sc_iot
, esc
->sc_ioh
, N86C01_MODE_ENABLE
,
245 bus_space_read_1(esc
->sc_iot
, esc
->sc_ioh
, N86C01_MODE_ENABLE
) |
249 * Now try to attach all the sub-devices
251 sc
->sc_adapter
.adapt_minphys
= minphys
;
252 sc
->sc_adapter
.adapt_request
= ncr53c9x_scsipi_request
;
254 /* Do the common parts of attachment. */
255 printf("%s", device_xname(self
));
264 esp_read_reg(struct ncr53c9x_softc
*sc
, int reg
)
266 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
268 return bus_space_read_1(esc
->sc_iot
, esc
->sc_esp_ioh
, reg
);
272 esp_write_reg(struct ncr53c9x_softc
*sc
, int reg
, uint8_t val
)
274 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
276 bus_space_write_1(esc
->sc_iot
, esc
->sc_esp_ioh
, reg
, val
);
280 esp_dma_isintr(struct ncr53c9x_softc
*sc
)
282 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
284 DPRINTF(("[esp_dma_isintr] "));
285 return bus_space_read_1(esc
->sc_iot
, esc
->sc_ioh
, N86C01_STATUS
) &
290 esp_dma_reset(struct ncr53c9x_softc
*sc
)
292 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
294 DPRINTF(("[esp_dma_reset] "));
296 if (esc
->sc_flags
& ESP_XFER_LOADED
) {
297 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_xfer
);
298 esc
->sc_flags
&= ~ESP_XFER_LOADED
;
301 if (esc
->sc_flags
& ESP_XFER_ACTIVE
) {
302 esc
->sc_flags
&= ~ESP_XFER_ACTIVE
;
308 esp_dma_intr(struct ncr53c9x_softc
*sc
)
310 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
312 DPRINTF(("[esp_dma_intr] "));
314 if ((esc
->sc_flags
& ESP_XFER_ACTIVE
) == 0) {
315 printf("%s: dma_intr--inactive DMA\n",
316 device_xname(sc
->sc_dev
));
320 if ((sc
->sc_espintr
& NCRINTR_BS
) == 0) {
321 esc
->sc_flags
&= ~ESP_XFER_ACTIVE
;
326 sc
->sc_espstat
|= NCRSTAT_TC
; /* XXX */
328 if ((sc
->sc_espstat
& NCRSTAT_TC
) == 0) {
329 printf("%s: DMA not complete?\n", device_xname(sc
->sc_dev
));
333 bus_dmamap_sync(esc
->sc_dmat
, esc
->sc_xfer
, 0, *esc
->sc_xfer_len
,
334 (esc
->sc_flags
& ESP_XFER_READ
) ?
335 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
337 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_xfer
);
338 esc
->sc_flags
&= ~ESP_XFER_LOADED
;
340 *esc
->sc_xfer_addr
+= *esc
->sc_xfer_len
;
341 *esc
->sc_xfer_len
= 0;
343 esc
->sc_flags
&= ~ESP_XFER_ACTIVE
;
350 * Setup DMA transfer.
353 esp_dma_setup(struct ncr53c9x_softc
*sc
, uint8_t **addr
, size_t *len
,
354 int datain
, size_t *dmasize
)
356 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
360 DPRINTF(("[esp_dma_setup] "));
362 if (esc
->sc_flags
& ESP_XFER_LOADED
) {
363 printf("%s: %s: unloading leaked xfer\n",
364 device_xname(sc
->sc_dev
), __func__
);
365 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_xfer
);
366 esc
->sc_flags
&= ~ESP_XFER_LOADED
;
369 /* Load the buffer for DMA transfer. */
370 fl
= (datain
) ? BUS_DMA_READ
: BUS_DMA_WRITE
;
372 if ((error
= bus_dmamap_load(esc
->sc_dmat
, esc
->sc_xfer
, *addr
,
373 *len
, NULL
, BUS_DMA_STREAMING
|fl
))) {
374 printf("%s: %s: unable to load DMA buffer - error %d\n",
375 device_xname(sc
->sc_dev
), __func__
, error
);
379 bus_dmamap_sync(esc
->sc_dmat
, esc
->sc_xfer
, 0, *len
,
380 (datain
) ? BUS_DMASYNC_PREREAD
: BUS_DMASYNC_PREWRITE
);
382 esc
->sc_flags
|= ESP_XFER_LOADED
| (datain
? ESP_XFER_READ
: 0);
383 esc
->sc_xfer_addr
= addr
;
384 esc
->sc_xfer_len
= len
;
390 esp_dma_go(struct ncr53c9x_softc
*sc
)
392 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
393 DPRINTF(("[esp_dma_go] "));
395 esc
->sc_flags
|= ESP_XFER_ACTIVE
;
400 esp_dma_stop(struct ncr53c9x_softc
*sc
)
403 DPRINTF(("[esp_dma_stop] "));
405 panic("%s: stop not yet implemented", device_xname(sc
->sc_dev
));
409 esp_dma_isactive(struct ncr53c9x_softc
*sc
)
411 struct esp_softc
*esc
= (struct esp_softc
*)sc
;
412 DPRINTF(("[esp_dma_isactive] "));
414 return esc
->sc_flags
& ESP_XFER_ACTIVE
;