1 /* $NetBSD: asc_tc.c,v 1.33 2008/04/13 04:55:53 tsutsui Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: asc_tc.c,v 1.33 2008/04/13 04:55:53 tsutsui Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
40 #include <dev/scsipi/scsi_all.h>
41 #include <dev/scsipi/scsipi_all.h>
42 #include <dev/scsipi/scsiconf.h>
43 #include <dev/scsipi/scsi_message.h>
47 #include <dev/ic/ncr53c9xreg.h>
48 #include <dev/ic/ncr53c9xvar.h>
50 #include <dev/tc/tcvar.h>
53 struct ncr53c9x_softc sc_ncr53c9x
; /* glue to MI code */
54 bus_space_tag_t sc_bst
;
55 bus_space_handle_t sc_bsh
;
56 bus_dma_tag_t sc_dmat
;
57 bus_dmamap_t sc_dmamap
;
61 int sc_active
; /* DMA active ? */
62 int sc_ispullup
; /* DMA into main memory? */
65 char *sc_base
, *sc_bounce
, *sc_target
;
68 static int asc_tc_match(device_t
, cfdata_t
, void *);
69 static void asc_tc_attach(device_t
, device_t
, void *);
71 CFATTACH_DECL_NEW(asc_tc
, sizeof(struct asc_softc
),
72 asc_tc_match
, asc_tc_attach
, NULL
, NULL
);
74 static uint8_t asc_read_reg(struct ncr53c9x_softc
*, int);
75 static void asc_write_reg(struct ncr53c9x_softc
*, int, uint8_t);
76 static int asc_dma_isintr(struct ncr53c9x_softc
*);
77 static void asc_tc_reset(struct ncr53c9x_softc
*);
78 static int asc_tc_intr(struct ncr53c9x_softc
*);
79 static int asc_tc_setup(struct ncr53c9x_softc
*, uint8_t **,
80 size_t *, int, size_t *);
81 static void asc_tc_go(struct ncr53c9x_softc
*);
82 static void asc_tc_stop(struct ncr53c9x_softc
*);
83 static int asc_dma_isactive(struct ncr53c9x_softc
*);
85 static struct ncr53c9x_glue asc_tc_glue
= {
99 * Parameters specific to PMAZ-A TC option card.
101 #define PMAZ_OFFSET_53C94 0x0 /* from module base */
102 #define PMAZ_OFFSET_DMAR 0x40000 /* DMA Address Register */
103 #define PMAZ_OFFSET_RAM 0x80000 /* 128KB SRAM buffer */
104 #define PMAZ_OFFSET_ROM 0xc0000 /* diagnostic ROM */
106 #define PMAZ_RAM_SIZE 0x20000 /* 128k (32k*32) */
107 #define PER_TGT_DMA_SIZE ((PMAZ_RAM_SIZE / 7) & ~(sizeof(int) - 1))
109 #define PMAZ_DMAR_WRITE 0x80000000 /* DMA direction bit */
110 #define PMAZ_DMAR_MASK 0x1ffff /* 17 bits, 128k */
111 #define PMAZ_DMA_ADDR(x) ((unsigned long)(x) & PMAZ_DMAR_MASK)
114 asc_tc_match(device_t parent
, cfdata_t cfdata
, void *aux
)
116 struct tc_attach_args
*d
= aux
;
118 if (strncmp("PMAZ-AA ", d
->ta_modname
, TC_ROM_LLEN
))
125 asc_tc_attach(device_t parent
, device_t self
, void *aux
)
127 struct asc_softc
*asc
= device_private(self
);
128 struct ncr53c9x_softc
*sc
= &asc
->sc_ncr53c9x
;
129 struct tc_attach_args
*ta
= aux
;
132 * Set up glue for MI code early; we use some of it here.
135 sc
->sc_glue
= &asc_tc_glue
;
136 asc
->sc_bst
= ta
->ta_memt
;
137 asc
->sc_dmat
= ta
->ta_dmat
;
138 if (bus_space_map(asc
->sc_bst
, ta
->ta_addr
,
139 PMAZ_OFFSET_RAM
+ PMAZ_RAM_SIZE
, 0, &asc
->sc_bsh
)) {
140 aprint_error(": unable to map device\n");
143 asc
->sc_base
= (void *)ta
->ta_addr
; /* XXX XXX XXX */
145 tc_intr_establish(parent
, ta
->ta_cookie
, IPL_BIO
, ncr53c9x_intr
, sc
);
148 sc
->sc_freq
= (ta
->ta_busspeed
) ? 25000000 : 12500000;
151 sc
->sc_freq
/= 1000000;
154 * XXX More of this should be in ncr53c9x_attach(), but
155 * XXX should we really poke around the chip that much in
156 * XXX the MI code? Think about this more...
160 * Set up static configuration info.
162 sc
->sc_cfg1
= sc
->sc_id
| NCRCFG1_PARENB
;
163 sc
->sc_cfg2
= NCRCFG2_SCSI2
;
165 sc
->sc_rev
= NCR_VARIANT_NCR53C94
;
168 * XXX minsync and maxxfer _should_ be set up in MI code,
169 * XXX but it appears to have some dependency on what sort
170 * XXX of DMA we're hooked up to, etc.
174 * This is the value used to start sync negotiations
175 * Note that the NCR register "SYNCTP" is programmed
176 * in "clocks per byte", and has a minimum value of 4.
177 * The SCSI period used in negotiation is one-fourth
178 * of the time (in nanoseconds) needed to transfer one byte.
179 * Since the chip's clock is given in MHz, we have the following
180 * formula: 4 * period = (1000 / freq) * 4
182 sc
->sc_minsync
= (1000 / sc
->sc_freq
) * 5 / 4;
184 sc
->sc_maxxfer
= 64 * 1024;
186 /* Do the common parts of attachment. */
187 sc
->sc_adapter
.adapt_minphys
= minphys
;
188 sc
->sc_adapter
.adapt_request
= ncr53c9x_scsipi_request
;
193 asc_tc_reset(struct ncr53c9x_softc
*sc
)
195 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
201 asc_tc_intr(struct ncr53c9x_softc
*sc
)
203 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
207 if (!asc
->sc_ispullup
&&
208 (resid
= (NCR_READ_REG(sc
, NCR_FFLAG
) & NCRFIFO_FF
)) != 0) {
209 NCR_DMA(("asc_tc_intr: empty FIFO of %d ", resid
));
213 resid
+= NCR_READ_REG(sc
, NCR_TCL
);
214 resid
+= NCR_READ_REG(sc
, NCR_TCM
) << 8;
216 trans
= asc
->sc_dmasize
- resid
;
218 if (asc
->sc_ispullup
)
219 memcpy(asc
->sc_target
, asc
->sc_bounce
, trans
);
220 *asc
->sc_dmalen
-= trans
;
221 *asc
->sc_dmaaddr
+= trans
;
228 asc_tc_setup(struct ncr53c9x_softc
*sc
, uint8_t **addr
, size_t *len
,
229 int datain
, size_t *dmasize
)
231 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
235 asc
->sc_dmaaddr
= addr
;
236 asc
->sc_dmalen
= len
;
237 asc
->sc_ispullup
= datain
;
239 NCR_DMA(("asc_tc_setup: start %ld@%p, %s\n", (long)*asc
->sc_dmalen
,
240 *asc
->sc_dmaaddr
, datain
? "IN" : "OUT"));
243 if (size
> PER_TGT_DMA_SIZE
)
244 size
= PER_TGT_DMA_SIZE
;
245 *dmasize
= asc
->sc_dmasize
= size
;
247 NCR_DMA(("asc_tc_setup: dmasize = %ld\n", (long)asc
->sc_dmasize
));
249 asc
->sc_bounce
= asc
->sc_base
+ PMAZ_OFFSET_RAM
;
250 asc
->sc_bounce
+= PER_TGT_DMA_SIZE
*
251 sc
->sc_nexus
->xs
->xs_periph
->periph_target
;
252 asc
->sc_target
= *addr
;
254 if (!asc
->sc_ispullup
)
255 memcpy(asc
->sc_bounce
, asc
->sc_target
, size
);
258 if (asc
->sc_ispullup
)
259 tc_dmar
= PMAZ_DMA_ADDR(asc
->sc_bounce
);
261 tc_dmar
= PMAZ_DMAR_WRITE
| PMAZ_DMA_ADDR(asc
->sc_bounce
);
262 bus_space_write_4(asc
->sc_bst
, asc
->sc_bsh
, PMAZ_OFFSET_DMAR
, tc_dmar
);
269 asc_tc_go(struct ncr53c9x_softc
*sc
)
272 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
275 if (asc
->sc_ispullup
)
276 tc_dmar
= PMAZ_DMA_ADDR(asc
->sc_bounce
);
278 tc_dmar
= PMAZ_DMAR_WRITE
| PMAZ_DMA_ADDR(asc
->sc_bounce
);
279 bus_space_write_4(asc
->sc_bst
, asc
->sc_bsh
, PMAZ_OFFSET_DMAR
, tc_dmar
);
284 /* NEVER CALLED BY MI 53C9x ENGINE INDEED */
286 asc_tc_stop(struct ncr53c9x_softc
*sc
)
289 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
291 if (asc
->sc_ispullup
)
292 memcpy(asc
->sc_target
, asc
->sc_bounce
, asc
->sc_dmasize
);
301 asc_read_reg(struct ncr53c9x_softc
*sc
, int reg
)
303 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
305 return bus_space_read_4(asc
->sc_bst
, asc
->sc_bsh
,
306 reg
* sizeof(uint32_t)) & 0xff;
310 asc_write_reg(struct ncr53c9x_softc
*sc
, int reg
, uint8_t val
)
312 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
314 bus_space_write_4(asc
->sc_bst
, asc
->sc_bsh
,
315 reg
* sizeof(uint32_t), val
);
319 asc_dma_isintr(struct ncr53c9x_softc
*sc
)
322 return (NCR_READ_REG(sc
, NCR_STAT
) & NCRSTAT_INT
) != 0;
326 asc_dma_isactive(struct ncr53c9x_softc
*sc
)
328 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
330 return asc
->sc_active
;