1 /* $NetBSD: asc.c,v 1.21 2008/04/13 04:55:52 tsutsui Exp $ */
3 * Copyright (c) 2000 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: asc.c,v 1.21 2008/04/13 04:55:52 tsutsui Exp $");
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
41 #include <sys/malloc.h>
43 #include <uvm/uvm_extern.h>
45 #include <dev/scsipi/scsi_all.h>
46 #include <dev/scsipi/scsipi_all.h>
47 #include <dev/scsipi/scsiconf.h>
48 #include <dev/scsipi/scsi_message.h>
50 #include <machine/cpu.h>
51 #include <machine/autoconf.h>
52 #include <machine/mainboard.h>
53 #include <machine/bus.h>
55 #include <mipsco/obio/rambo.h>
57 #include <dev/ic/ncr53c9xreg.h>
58 #include <dev/ic/ncr53c9xvar.h>
61 struct ncr53c9x_softc sc_ncr53c9x
; /* glue to MI code */
62 struct evcnt sc_intrcnt
; /* Interrupt counter */
63 bus_space_tag_t sc_bst
;
64 bus_space_handle_t sc_bsh
; /* NCR 53c94 registers */
65 bus_space_handle_t dm_bsh
; /* RAMBO registers */
66 bus_dma_tag_t sc_dmat
;
67 bus_dmamap_t sc_dmamap
;
73 #define DMA_PULLUP 0x1
74 #define DMA_ACTIVE 0x2
75 #define DMA_MAPLOADED 0x4
80 static int ascmatch(device_t
, cfdata_t
, void *);
81 static void ascattach(device_t
, device_t
, void *);
83 CFATTACH_DECL_NEW(asc
, sizeof(struct asc_softc
),
84 ascmatch
, ascattach
, NULL
, NULL
);
87 * Functions and the switch for the MI code.
89 static uint8_t asc_read_reg(struct ncr53c9x_softc
*, int);
90 static void asc_write_reg(struct ncr53c9x_softc
*, int, uint8_t);
91 static int asc_dma_isintr(struct ncr53c9x_softc
*);
92 static void asc_dma_reset(struct ncr53c9x_softc
*);
93 static int asc_dma_intr(struct ncr53c9x_softc
*);
94 static int asc_dma_setup(struct ncr53c9x_softc
*, uint8_t **,
95 size_t *, int, size_t *);
96 static void asc_dma_go(struct ncr53c9x_softc
*);
97 static void asc_dma_stop(struct ncr53c9x_softc
*);
98 static int asc_dma_isactive(struct ncr53c9x_softc
*);
100 static struct ncr53c9x_glue asc_glue
= {
110 NULL
, /* gl_clear_latched_intr */
113 static int asc_intr(void *);
115 #define MAX_SCSI_XFER (64 * 1024)
116 #define MAX_DMA_SZ MAX_SCSI_XFER
117 #define DMA_SEGS (MAX_DMA_SZ / PAGE_SIZE)
120 ascmatch(device_t parent
, cfdata_t cf
, void *aux
)
127 ascattach(device_t parent
, device_t self
, void *aux
)
129 struct asc_softc
*esc
= device_private(self
);
130 struct ncr53c9x_softc
*sc
= &esc
->sc_ncr53c9x
;
131 struct confargs
*ca
= aux
;
134 * Set up glue for MI code early; we use some of it here.
137 sc
->sc_glue
= &asc_glue
;
139 esc
->sc_bst
= ca
->ca_bustag
;
140 esc
->sc_dmat
= ca
->ca_dmatag
;
142 if (bus_space_map(ca
->ca_bustag
, ca
->ca_addr
,
143 16 * 4, /* sizeof (ncr53c9xreg) */
144 BUS_SPACE_MAP_LINEAR
,
145 &esc
->sc_bsh
) != 0) {
146 aprint_error(": cannot map registers\n");
150 if (bus_space_map(ca
->ca_bustag
, RAMBO_BASE
, sizeof(struct rambo_ch
),
151 BUS_SPACE_MAP_LINEAR
, &esc
->dm_bsh
) != 0) {
152 aprint_error(": cannot map DMA registers\n");
156 if (bus_dmamap_create(esc
->sc_dmat
, MAX_DMA_SZ
,
157 DMA_SEGS
, MAX_DMA_SZ
, RB_BOUNDRY
, BUS_DMA_WAITOK
,
158 &esc
->sc_dmamap
) != 0) {
159 aprint_error(": failed to create dmamap\n");
163 evcnt_attach_dynamic(&esc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
164 device_xname(self
), "intr");
166 esc
->sc_flags
= DMA_IDLE
;
171 sc
->sc_freq
= 24; /* 24 MHz clock */
174 * Setup for genuine NCR 53C94 SCSI Controller
177 sc
->sc_cfg1
= sc
->sc_id
| NCRCFG1_PARENB
;
178 sc
->sc_cfg2
= NCRCFG2_SCSI2
| NCRCFG2_FE
;
179 sc
->sc_cfg3
= NCRCFG3_CDB
| NCRCFG3_QTE
| NCRCFG3_FSCSI
;
180 sc
->sc_rev
= NCR_VARIANT_NCR53C94
;
182 sc
->sc_minsync
= (1000 / sc
->sc_freq
) * 5 / 4;
183 sc
->sc_maxxfer
= MAX_SCSI_XFER
;
186 if (NCR_READ_REG(sc
, NCR_CFG3
) == 0) {
187 aprint_normal(" [old revision]");
194 sc
->sc_adapter
.adapt_minphys
= minphys
;
195 sc
->sc_adapter
.adapt_request
= ncr53c9x_scsipi_request
;
198 bus_intr_establish(esc
->sc_bst
, SYS_INTR_SCSI
, 0, 0, asc_intr
, esc
);
206 asc_read_reg(struct ncr53c9x_softc
*sc
, int reg
)
208 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
210 return bus_space_read_1(esc
->sc_bst
, esc
->sc_bsh
, reg
* 4 + 3);
214 asc_write_reg(struct ncr53c9x_softc
*sc
, int reg
, uint8_t val
)
216 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
218 bus_space_write_1(esc
->sc_bst
, esc
->sc_bsh
, reg
* 4 + 3, val
);
222 dma_status(struct ncr53c9x_softc
*sc
)
224 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
230 tc
= (asc_read_reg(sc
, NCR_TCM
) << 8) + asc_read_reg(sc
, NCR_TCL
);
231 count
= bus_space_read_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
);
232 stat
= bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
);
233 addr
= (void *)bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_CADDR
);
235 printf("rambo status: cnt=%x addr=%p stat=%08x tc=%04x "
236 "ncr_stat=0x%02x ncr_fifo=0x%02x\n",
237 count
, addr
, stat
, tc
,
238 asc_read_reg(sc
, NCR_STAT
),
239 asc_read_reg(sc
, NCR_FFLAG
));
243 check_fifo(struct asc_softc
*esc
)
247 while (i
&& !(bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
,
248 RAMBO_MODE
) & RB_FIFO_EMPTY
)) {
254 dma_status((void *)esc
);
255 panic("fifo didn't flush");
260 asc_dma_isintr(struct ncr53c9x_softc
*sc
)
263 return NCR_READ_REG(sc
, NCR_STAT
) & NCRSTAT_INT
;
267 asc_dma_reset(struct ncr53c9x_softc
*sc
)
269 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
271 bus_space_write_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
, 0);
272 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
,
273 RB_CLRFIFO
|RB_CLRERROR
);
275 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
, 0);
277 if (esc
->sc_flags
& DMA_MAPLOADED
)
278 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_dmamap
);
280 esc
->sc_flags
= DMA_IDLE
;
284 * Setup a DMA transfer
288 asc_dma_setup(struct ncr53c9x_softc
*sc
, uint8_t **addr
, size_t *len
,
289 int datain
, size_t *dmasize
)
291 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
293 size_t count
, blocks
;
297 if (esc
->sc_flags
& DMA_ACTIVE
) {
303 esc
->sc_dmaaddr
= addr
;
304 esc
->sc_dmalen
= len
;
305 esc
->sc_dmasize
= *dmasize
;
306 esc
->sc_flags
= datain
? DMA_PULLUP
: 0;
308 NCR_DMA(("asc_dma_setup va=%p len=%d datain=%d count=%d\n",
309 *addr
, *len
, datain
, esc
->sc_dmasize
));
311 if (esc
->sc_dmasize
== 0)
314 /* have dmamap for the transfering addresses */
315 if ((err
= bus_dmamap_load(esc
->sc_dmat
, esc
->sc_dmamap
,
316 *esc
->sc_dmaaddr
, esc
->sc_dmasize
, NULL
/* kernel address */, BUS_DMA_NOWAIT
)) != 0)
317 panic("%s: bus_dmamap_load err=%d",
318 device_xname(sc
->sc_dev
), err
);
320 esc
->sc_flags
|= DMA_MAPLOADED
;
322 paddr
= esc
->sc_dmamap
->dm_segs
[0].ds_addr
;
323 count
= esc
->sc_dmamap
->dm_segs
[0].ds_len
;
324 prime
= (uint32_t)paddr
& 0x3f;
325 blocks
= (prime
+ count
+ 63) >> 6;
327 esc
->dm_mode
= datain
? RB_DMA_WR
: RB_DMA_RD
;
329 /* Set transfer direction and disable DMA */
330 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
, esc
->dm_mode
);
332 /* Load DMA transfer address */
333 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_LADDR
, paddr
& ~0x3f);
335 /* Load number of blocks to DMA (1 block = 64 bytes) */
336 bus_space_write_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
, blocks
);
338 /* If non block-aligned transfer prime FIFO manually */
340 /* Enable DMA to prime the FIFO buffer */
341 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
,
342 RAMBO_MODE
, esc
->dm_mode
| RB_DMA_ENABLE
);
344 if (esc
->sc_flags
& DMA_PULLUP
) {
345 /* Read from NCR 53c94 controller*/
348 p
= (uint16_t *)((uint32_t)*esc
->sc_dmaaddr
& ~0x3f);
349 bus_space_write_multi_2(esc
->sc_bst
, esc
->dm_bsh
,
350 RAMBO_FIFO
, p
, prime
>>1);
352 /* Write to NCR 53C94 controller */
354 (void)bus_space_read_2(esc
->sc_bst
, esc
->dm_bsh
,
358 /* Leave DMA disabled while we setup NCR controller */
359 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
,
363 bus_dmamap_sync(esc
->sc_dmat
, esc
->sc_dmamap
, 0, esc
->sc_dmasize
,
364 datain
? BUS_DMASYNC_PREREAD
: BUS_DMASYNC_PREWRITE
);
367 esc
->dm_mode
|= RB_DMA_ENABLE
;
368 if (esc
->sc_dmamap
->dm_nsegs
> 1)
369 esc
->dm_mode
|= RB_INT_ENABLE
; /* Requires DMA chaining */
375 asc_dma_go(struct ncr53c9x_softc
*sc
)
377 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
380 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
, esc
->dm_mode
);
382 esc
->sc_flags
|= DMA_ACTIVE
;
386 asc_dma_intr(struct ncr53c9x_softc
*sc
)
388 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
396 if ((esc
->sc_flags
& DMA_ACTIVE
) == 0) {
398 panic("DMA not active");
403 if ((esc
->sc_flags
& DMA_PULLUP
) == 0 &&
404 (resid
= (NCR_READ_REG(sc
, NCR_FFLAG
) & NCRFIFO_FF
)) != 0) {
405 NCR_DMA(("asc_intr: empty FIFO of %d ", resid
));
409 resid
+= (tcl
= NCR_READ_REG(sc
, NCR_TCL
)) +
410 ((tcm
= NCR_READ_REG(sc
, NCR_TCM
)) << 8);
412 if (esc
->sc_dmasize
== 0) { /* Transfer pad operation */
413 NCR_DMA(("asc_intr: discard %d bytes\n", resid
));
417 trans
= esc
->sc_dmasize
- resid
;
418 if (trans
< 0) { /* transferred < 0 ? */
419 printf("%s: xfer (%d) > req (%d)\n",
420 __func__
, trans
, esc
->sc_dmasize
);
421 trans
= esc
->sc_dmasize
;
424 NCR_DMA(("asc_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
425 tcl
, tcm
, trans
, resid
));
427 status
= bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
);
429 if ((status
& RB_FIFO_EMPTY
) == 0) { /* Data left in RAMBO FIFO */
430 if ((esc
->sc_flags
& DMA_PULLUP
) != 0) { /* SCSI Read */
434 resid
= status
& 0x1f;
436 /* take the address of block to fixed up */
437 ptr
= bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
,
439 /* find the starting address of fractional data */
440 p
= (uint16_t *)MIPS_PHYS_TO_KSEG0(ptr
+ (resid
<< 1));
442 /* duplicate trailing data to FIFO for force flush */
443 len
= RB_BLK_CNT
- resid
;
444 bus_space_write_multi_2(esc
->sc_bst
, esc
->dm_bsh
,
447 } else { /* SCSI Write */
448 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
,
450 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
,
451 RAMBO_MODE
, RB_CLRFIFO
);
455 bus_space_write_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
, 0);
457 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
, 0);
459 bus_dmamap_sync(esc
->sc_dmat
, esc
->sc_dmamap
,
461 (esc
->sc_flags
& DMA_PULLUP
) != 0 ?
462 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
463 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_dmamap
);
465 *esc
->sc_dmaaddr
+= trans
;
466 *esc
->sc_dmalen
-= trans
;
468 esc
->sc_flags
= DMA_IDLE
;
475 asc_dma_stop(struct ncr53c9x_softc
*sc
)
477 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
479 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
, 0);
480 if ((esc
->sc_flags
& DMA_MAPLOADED
) != 0)
481 bus_dmamap_unload(esc
->sc_dmat
, esc
->sc_dmamap
);
482 esc
->sc_flags
= DMA_IDLE
;
486 asc_dma_isactive(struct ncr53c9x_softc
*sc
)
488 struct asc_softc
*esc
= (struct asc_softc
*)sc
;
489 return (esc
->sc_flags
& DMA_ACTIVE
) != 0 ? 1 : 0;
493 rambo_dma_chain(struct asc_softc
*esc
)
496 size_t count
, blocks
;
499 seg
= ++esc
->dm_curseg
;
502 if ((esc
->sc_flags
& DMA_ACTIVE
) == 0 || seg
> esc
->sc_dmamap
->dm_nsegs
)
503 panic("Unexpected DMA chaining intr");
505 /* Interrupt can only occur at terminal count, but double check */
506 if (bus_space_read_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
)) {
507 dma_status((void *)esc
);
508 panic("rambo blkcnt != 0");
512 paddr
= esc
->sc_dmamap
->dm_segs
[seg
].ds_addr
;
513 count
= esc
->sc_dmamap
->dm_segs
[seg
].ds_len
;
514 blocks
= (count
+ 63) >> 6;
516 /* Disable DMA interrupt if last segment */
517 if (seg
+ 1 > esc
->sc_dmamap
->dm_nsegs
) {
518 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
,
519 RAMBO_MODE
, esc
->dm_mode
& ~RB_INT_ENABLE
);
522 /* Load transfer address for next DMA chain */
523 bus_space_write_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_LADDR
, paddr
);
525 /* DMA restarts when we enter a new block count */
526 bus_space_write_2(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_BLKCNT
, blocks
);
533 struct asc_softc
*esc
= arg
;
534 struct ncr53c9x_softc
*sc
= &esc
->sc_ncr53c9x
;
536 esc
->sc_intrcnt
.ev_count
++;
538 /* Check for RAMBO DMA Interrupt */
539 dma_stat
= bus_space_read_4(esc
->sc_bst
, esc
->dm_bsh
, RAMBO_MODE
);
540 if ((dma_stat
& RB_INTR_PEND
) != 0) {
541 rambo_dma_chain(esc
);
543 /* Check for NCR 53c94 interrupt */
544 if (NCR_READ_REG(sc
, NCR_STAT
) & NCRSTAT_INT
) {