Index: arc/p_acer_pica_61.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/arc/p_acer_pica_61.c,v retrieving revision 1.3 diff -u -r1.3 p_acer_pica_61.c --- arc/p_acer_pica_61.c 2002/12/28 16:44:44 1.3 +++ arc/p_acer_pica_61.c 2003/01/08 17:03:01 @@ -38,16 +38,6 @@ #include #include -#include "asc.h" -#if NASC > 0 -#include - -struct asc_config asc_acer_pica_61_conf = { - &asc_timing_25mhz, - 0, -}; -#endif - /* ALI PICA 61 and some MAGNUM? */ void p_acer_pica_61_init __P((void)); @@ -106,8 +96,4 @@ /* chipset-dependent jazzio bus configuration */ jazzio_devconfig = acer_pica_61_cpu; - -#if NASC > 0 - asc_conf = &asc_acer_pica_61_conf; -#endif } Index: arc/p_ms_jazz.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/arc/p_ms_jazz.c,v retrieving revision 1.3 diff -u -r1.3 p_ms_jazz.c --- arc/p_ms_jazz.c 2002/12/28 16:44:44 1.3 +++ arc/p_ms_jazz.c 2003/01/08 17:03:02 @@ -39,12 +39,6 @@ #include "com.h" -#include "asc.h" -#if NASC > 0 -#include -#include -#endif - /* MAGNUM. NEC goes here too. */ #ifndef COM_FREQ_MAGNUM @@ -55,15 +49,6 @@ #endif #endif /* COM_FREQ_MAGNUM */ -#if NASC > 0 -struct asc_config asc_ms_jazz_conf = { - &asc_timing_40mhz, - - /* only if EPL is FE (Feature Enable bit for 53CF94) */ - ASC_CNFG3_FCLK, /* clock 40MHz */ -}; -#endif - void p_ms_jazz_init __P((void)); struct platform platform_microsoft_jazz = { @@ -111,10 +96,6 @@ /* jazzio bus configuration */ jazzio_devconfig = mips_magnum_r4000_cpu; - -#if NASC > 0 - asc_conf = &asc_ms_jazz_conf; -#endif #if NCOM > 0 com_freq = COM_FREQ_MAGNUM; Index: conf/files.arc =================================================================== RCS file: /cvsroot/src/sys/arch/arc/conf/files.arc,v retrieving revision 1.41 diff -u -r1.41 files.arc --- conf/files.arc 2002/11/30 19:23:46 1.41 +++ conf/files.arc 2003/01/08 17:03:06 @@ -114,7 +114,7 @@ device jazzio {} attach jazzio at mainbus # optional file arch/arc/jazz/jazzio.c jazzio -file arch/arc/jazz/dma.c # XXX jazzio +#file arch/arc/jazz/dma.c # XXX jazzio file arch/arc/jazz/jazzdmatlb.c # XXX jazzio file arch/arc/jazz/bus_dma_jazz.c # XXX jazzio @@ -160,7 +160,7 @@ include "dev/scsipi/files.scsipi" # Symbios 53C94 SCSI interface driver on Jazz-Internal bus -device asc: scsi +device asc: scsi, ncr53c9x attach asc at jazzio file arch/arc/jazz/asc.c asc needs-flag Index: jazz/asc.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/jazz/asc.c,v retrieving revision 1.9 diff -u -r1.9 asc.c --- jazz/asc.c 2002/12/28 16:25:39 1.9 +++ jazz/asc.c 2003/01/08 17:03:07 @@ -1,13 +1,7 @@ -/* $NetBSD: asc.c,v 1.9 2002/12/28 16:25:39 tsutsui Exp $ */ -/* $OpenBSD: asc.c,v 1.9 1998/03/16 09:38:39 pefo Exp $ */ -/* NetBSD: asc.c,v 1.10 1994/12/05 19:11:12 dean Exp */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ralph Campbell and Rick Macklem. +/* $NetBSD$ */ + +/* + * Copyright (c) 2003 Izumi Tsutsui. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -17,503 +11,101 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)asc.c 8.3 (Berkeley) 7/3/94 - */ - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -/* - * HISTORY - * Log: scsi_53C94_hdw.c,v - * Revision 2.5 91/02/05 17:45:07 mrt - * Added author notices - * [91/02/04 11:18:43 mrt] - * - * Changed to use new Mach copyright - * [91/02/02 12:17:20 mrt] - * - * Revision 2.4 91/01/08 15:48:24 rpd - * Added continuation argument to thread_block. - * [90/12/27 rpd] - * - * Revision 2.3 90/12/05 23:34:48 af - * Recovered from pmax merge.. and from the destruction of a disk. - * [90/12/03 23:40:40 af] - * - * Revision 2.1.1.1 90/11/01 03:39:09 af - * Created, from the DEC specs: - * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" - * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. - * And from the NCR data sheets - * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" - * [90/09/03 af] - */ - -/* - * File: scsi_53C94_hdw.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 9/90 - * - * Bottom layer of the SCSI driver: chip-dependent functions - * - * This file contains the code that is specific to the NCR 53C94 - * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start - * operation, and interrupt routine. - */ - -/* - * This layer works based on small simple 'scripts' that are installed - * at the start of the command and drive the chip to completion. - * The idea comes from the specs of the NCR 53C700 'script' processor. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * There are various reasons for this, mainly - * - Performance: identify the common (successful) path, and follow it; - * at interrupt time no code is needed to find the current status - * - Code size: it should be easy to compact common operations - * - Adaptability: the code skeleton should adapt to different chips without - * terrible complications. - * - Error handling: and it is easy to modify the actions performed - * by the scripts to cope with strange but well identified sequences - * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include -#include -#include -#include -#include -#include #include +#include + +#include +#include + #include -#include #include +#include #include -#include - -#include -#include -#include - #include #include +#include #include -#include -#include -#include - #include - -#define readback(a) { register int foo; foo = (a); } +#include +#include -/* - * In 4ns ticks. - */ -int asc_to_scsi_period[] = { - 32, - 33, - 34, - 35, - 5, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, -}; - -/* - * Internal forward declarations. - */ -struct asc_softc; -static void asc_reset __P((struct asc_softc *, asc_regmap_t *)); -static void asc_startcmd __P((struct asc_softc *, int)); - -#ifdef DEBUG -int asc_debug = 1; -int asc_debug_cmd; -int asc_debug_bn; -int asc_debug_sz; -#define NLOG 16 -struct asc_log { - u_int status; - u_char state; - u_char msg; - int target; - int resid; -} asc_log[NLOG], *asc_logp = asc_log; -#define PACK(unit, status, ss, ir) \ - ((unit << 24) | (status << 16) | (ss << 8) | ir) -#endif - -/* - * Scripts are entries in a state machine table. - * A script has four parts: a pre-condition, an action, a command to the chip, - * and an index into asc_scripts for the next state. The first triggers error - * handling if not satisfied and in our case it is formed by the - * values of the interrupt register and status register, this - * basically captures the phase of the bus and the TC and BS - * bits. The action part is just a function pointer, and the - * command is what the 53C94 should be told to do at the end - * of the action processing. This command is only issued and the - * script proceeds if the action routine returns TRUE. - * See asc_intr() for how and where this is all done. - */ -typedef struct script { - int condition; /* expected state at interrupt time */ - int (*action)(struct asc_softc *, int, int, int); - /* extra operations */ - int command; /* command to the chip */ - struct script *next; /* index into asc_scripts for next state */ -} script_t; - -/* Matching on the condition value */ -#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8)) - - -/* forward decls of script actions */ - /* when nothing needed */ -static int script_nop __P((struct asc_softc *, int, int, int)); - /* all come to an end */ -static int asc_end __P((struct asc_softc *, int, int, int)); - /* get status from target */ -static int asc_get_status __P((struct asc_softc *, int, int, int)); - /* start reading data from target */ -static int asc_dma_in __P((struct asc_softc *, int, int, int)); - /* cleanup after all data is read */ -static int asc_last_dma_in __P((struct asc_softc *, int, int, int)); - /* resume data in after a message */ -static int asc_resume_in __P((struct asc_softc *, int, int, int)); - /* resume DMA after a disconnect */ -static int asc_resume_dma_in __P((struct asc_softc *, int, int, int)); - /* send data to target via dma */ -static int asc_dma_out __P((struct asc_softc *, int, int, int)); - /* cleanup after all data is written */ -static int asc_last_dma_out __P((struct asc_softc *, int, int, int)); - /* resume data out after a message */ -static int asc_resume_out __P((struct asc_softc *, int, int, int)); - /* resume DMA after a disconnect */ -static int asc_resume_dma_out __P((struct asc_softc *, int, int, int)); - /* negotiate sync xfer */ -static int asc_sendsync __P((struct asc_softc *, int, int, int)); - /* negotiate sync xfer */ -static int asc_replysync __P((struct asc_softc *, int, int, int)); - /* process a message byte */ -static int asc_msg_in __P((struct asc_softc *, int, int, int)); - /* process an expected disconnect */ -static int asc_disconnect __P((struct asc_softc *, int, int, int)); - -/* Define the index into asc_scripts for various state transitions */ -#define SCRIPT_DATA_IN 0 -#define SCRIPT_CONTINUE_IN 2 -#define SCRIPT_DATA_OUT 3 -#define SCRIPT_CONTINUE_OUT 5 -#define SCRIPT_SIMPLE 6 -#define SCRIPT_GET_STATUS 7 -#define SCRIPT_DONE 8 -#define SCRIPT_MSG_IN 9 -#define SCRIPT_REPLY_SYNC 11 -#define SCRIPT_TRY_SYNC 12 -#define SCRIPT_DISCONNECT 15 -#define SCRIPT_RESEL 16 -#define SCRIPT_RESUME_IN 17 -#define SCRIPT_RESUME_DMA_IN 18 -#define SCRIPT_RESUME_OUT 19 -#define SCRIPT_RESUME_DMA_OUT 20 -#define SCRIPT_RESUME_NO_DATA 21 - -/* - * Scripts - */ -script_t asc_scripts[] = { - /* start data in */ - {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ - asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_IN + 1]}, - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ - asc_last_dma_in, ASC_CMD_I_COMPLETE, - &asc_scripts[SCRIPT_GET_STATUS]}, - - /* continue data in after a chunk is finished */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ - asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_IN + 1]}, - - /* start data out */ - {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ - asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_OUT + 1]}, - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ - asc_last_dma_out, ASC_CMD_I_COMPLETE, - &asc_scripts[SCRIPT_GET_STATUS]}, - - /* continue data out after a chunk is finished */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ - asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_OUT + 1]}, - - /* simple command with no data transfer */ - {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ - script_nop, ASC_CMD_I_COMPLETE, - &asc_scripts[SCRIPT_GET_STATUS]}, - - /* get status and finish command */ - {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ - asc_get_status, ASC_CMD_MSG_ACPT, - &asc_scripts[SCRIPT_DONE]}, - {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ - asc_end, ASC_CMD_NOP, - &asc_scripts[SCRIPT_DONE]}, - - /* message in */ - {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ - asc_msg_in, ASC_CMD_MSG_ACPT, - &asc_scripts[SCRIPT_MSG_IN + 1]}, - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ - script_nop, ASC_CMD_XFER_INFO, - &asc_scripts[SCRIPT_MSG_IN]}, - - /* send synchonous negotiation reply */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ - asc_replysync, ASC_CMD_XFER_INFO, - &asc_scripts[SCRIPT_REPLY_SYNC]}, - - /* try to negotiate synchonous transfer parameters */ - {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ - asc_sendsync, ASC_CMD_XFER_INFO, - &asc_scripts[SCRIPT_TRY_SYNC + 1]}, - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ - script_nop, ASC_CMD_XFER_INFO, - &asc_scripts[SCRIPT_MSG_IN]}, - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ - script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_RESUME_NO_DATA]}, - - /* handle a disconnect */ - {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ - asc_disconnect, ASC_CMD_ENABLE_SEL, - &asc_scripts[SCRIPT_RESEL]}, - - /* reselect sequence: this is just a placeholder so match fails */ - {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ - script_nop, ASC_CMD_MSG_ACPT, - &asc_scripts[SCRIPT_RESEL]}, - - /* resume data in after a message */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ - asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_IN + 1]}, - - /* resume partial DMA data in after a message */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ - asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_IN + 1]}, - - /* resume data out after a message */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ - asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_OUT + 1]}, - - /* resume partial DMA data out after a message */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ - asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, - &asc_scripts[SCRIPT_DATA_OUT + 1]}, - - /* resume after a message when there is no more data */ - {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ - script_nop, ASC_CMD_I_COMPLETE, - &asc_scripts[SCRIPT_GET_STATUS]}, -}; - -/* - * State kept for each active SCSI device. - */ -typedef struct scsi_state { - script_t *script; /* saved script while processing error */ - struct scsi_generic cmd;/* storage for scsi command */ - int statusByte; /* status byte returned during STATUS_PHASE */ - u_int dmaBufSize; /* DMA buffer size */ - int dmalen; /* amount to transfer in this chunk */ - int dmaresid; /* amount not transfered if chunk suspended */ - int cmdlen; /* length of command in cmd */ - int buflen; /* total remaining amount of data to transfer */ - vaddr_t buf; /* current pointer within scsicmd->buf */ - int flags; /* see below */ - int msglen; /* number of message bytes to read */ - int msgcnt; /* number of message bytes received */ - u_char sync_period; /* DMA synchronous period */ - u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ - u_char msg_out; /* next MSG_OUT byte to send */ - u_char msg_in[16]; /* buffer for multibyte messages */ -} State; - -/* state flags */ -#define DISCONN 0x001 /* true if currently disconnected from bus */ -#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */ -#define DMA_IN 0x004 /* true if reading from SCSI device */ -#define DMA_OUT 0x010 /* true if writing to SCSI device */ -#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */ -#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */ -#define PARITY_ERR 0x080 /* true if parity error seen */ - -/* - * State kept for each active SCSI host interface (53C94). - */ struct asc_softc { - struct device sc_dev; /* use as a device */ - asc_regmap_t *regs; /* chip address */ - dma_softc_t __dma; /* stupid macro..... */ - dma_softc_t *dma; /* dma control structure */ - int sc_id; /* SCSI ID of this interface */ - int myidmask; /* ~(1 << myid) */ - int state; /* current SCSI connection state */ - int target; /* target SCSI ID if busy */ - script_t *script; /* next expected interrupt & action */ - struct scsipi_xfer *cmdq[ASC_NCMD];/* Pointer to queued commands */ - struct scsipi_xfer *cmd[ASC_NCMD];/* Pointer to current active command */ - State st[ASC_NCMD]; /* state info for each active command */ - int min_period; /* Min transfer period clk/byte */ - int max_period; /* Max transfer period clk/byte */ - int ccf; /* CCF, whatever that really is? */ - int timeout_250; /* 250ms timeout */ - int tb_ticks; /* 4ns. ticks/tb channel ticks */ - int is24bit; /* if 53CF94/96-2, 24bit address */ - struct scsipi_channel sc_channel; - struct scsipi_adapter sc_adapter; -}; + struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ -#define ASC_STATE_IDLE 0 /* idle state */ -#define ASC_STATE_BUSY 1 /* selecting or currently connected */ -#define ASC_STATE_TARGET 2 /* currently selected as target */ -#define ASC_STATE_RESEL 3 /* currently waiting for reselect */ - -typedef struct asc_softc *asc_softc_t; - -struct asc_timing { - int min_period; /* Min transfer period clk/byte */ - int max_period; /* Max transfer period clk/byte */ - int ccf; /* CCF, whatever that really is? */ - int timeout_250; /* 250ms timeout */ - int tb_ticks; /* 4ns. ticks/tb channel ticks */ -} asc_timing_40mhz = { - ASC_MIN_PERIOD40, - ASC_MAX_PERIOD40, - ASC_CCF(40), - ASC_TIMEOUT_250(40, 8 /* exception for ASC_CCF(40) (== 0) */), - 6, /* 6.25 */ -}, asc_timing_25mhz = { - ASC_MIN_PERIOD25, - ASC_MAX_PERIOD25, - ASC_CCF(25), - ASC_TIMEOUT_250(25, ASC_CCF(25)), - 10, -}, asc_timing_12mhz = { - ASC_MIN_PERIOD12, - ASC_MAX_PERIOD12, - ASC_CCF(13), - ASC_TIMEOUT_250(13, ASC_CCF(13)), - 20, + bus_space_tag_t sc_iot; /* bus space tag */ + bus_space_handle_t sc_ioh; /* bus space handle */ + bus_space_handle_t sc_dmaioh; /* bus space handle for DMAC */ + + bus_dma_tag_t sc_dmat; /* DMA tag */ + bus_dmamap_t sc_dmamap; /* DMA map for transfers */ + + int sc_active; /* DMA state */ + int sc_datain; /* DMA Data Direction */ + size_t sc_dmasize; /* DMA size */ + char **sc_dmaaddr; /* DMA address */ + size_t *sc_dmalen; /* DMA length */ }; -struct asc_config *asc_conf = NULL; - /* * Autoconfiguration data for config. */ -int ascmatch __P((struct device *, struct cfdata *, void *)); -void ascattach __P((struct device *, struct device *, void *)); - -int asc_doprobe __P((void *, int, int, struct device *)); +int asc_match(struct device *, struct cfdata *, void *); +void asc_attach(struct device *, struct device *, void *); CFATTACH_DECL(asc, sizeof(struct asc_softc), - ascmatch, ascattach, NULL, NULL); + asc_match, asc_attach, NULL, NULL); /* - * Glue to the machine dependent scsi + * Functions and the switch for the MI code. */ -void asc_scsipi_request __P((struct scsipi_channel *, - scsipi_adapter_req_t, void *)); - -static int asc_intr __P((void *)); -static void asc_poll __P((struct asc_softc *, int)); -#ifdef DEBUG -static void asc_DumpLog __P((char *)); -#endif +u_char asc_read_reg(struct ncr53c9x_softc *, int); +void asc_write_reg(struct ncr53c9x_softc *, int, u_char); +int asc_dma_isintr(struct ncr53c9x_softc *); +void asc_dma_reset(struct ncr53c9x_softc *); +int asc_dma_intr(struct ncr53c9x_softc *); +int asc_dma_setup(struct ncr53c9x_softc *, caddr_t *, size_t *, int, size_t *); +void asc_dma_go(struct ncr53c9x_softc *); +void asc_dma_stop(struct ncr53c9x_softc *); +int asc_dma_isactive(struct ncr53c9x_softc *); + +struct ncr53c9x_glue asc_glue = { + asc_read_reg, + asc_write_reg, + asc_dma_isintr, + asc_dma_reset, + asc_dma_intr, + asc_dma_setup, + asc_dma_go, + asc_dma_stop, + asc_dma_isactive, + NULL /* gl_clear_latched_intr */ +}; /* * Match driver based on name */ int -ascmatch(parent, match, aux) +asc_match(parent, match, aux) struct device *parent; struct cfdata *match; void *aux; @@ -526,1530 +118,321 @@ } void -ascattach(parent, self, aux) +asc_attach(parent, self, aux) struct device *parent; struct device *self; void *aux; { struct jazzio_attach_args *ja = aux; - asc_softc_t asc = (void *)self; - asc_regmap_t *regs; - int id, s, i; - int bufsiz; + struct asc_softc *asc = (void *)self; + struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x; + bus_space_tag_t iot; +#if 0 + /* Need info from platform dependent config?? */ if (asc_conf == NULL) panic("asc_conf isn't initialized"); +#endif - /* - * Initialize hw descriptor, cache some pointers - */ - asc->regs = (asc_regmap_t *)ja->ja_addr; /* XXX */ + sc->sc_glue = &asc_glue; - /* - * Set up machine dependencies. - * 1) how to do dma - * 2) timing based on chip clock frequency - */ -#if 1 /*XXX check if code handles 0 as 64k */ - bufsiz = 63 * 1024; -#else - bufsiz = 64 * 1024; -#endif - asc->dma = &asc->__dma; - asc_dma_init(asc->dma); + asc->sc_iot = iot = ja->ja_bust; + asc->sc_dmat = ja->ja_dmat; - /* - * Now for timing. - */ - asc->min_period = asc_conf->ac_timing->min_period; - asc->max_period = asc_conf->ac_timing->max_period; - asc->ccf = asc_conf->ac_timing->ccf; - asc->timeout_250 = asc_conf->ac_timing->timeout_250; - asc->tb_ticks = asc_conf->ac_timing->tb_ticks; + if (bus_space_map(iot, ja->ja_addr, 0x10 /*XXX*/, 0, &asc->sc_ioh)) { + printf(": unable to map I/O space\n"); + return; + } - asc->state = ASC_STATE_IDLE; - asc->target = -1; + if (bus_space_map(iot, R4030_SYS_DMA0_REGS, R4030_DMA_RANGE, + 0, &asc->sc_dmaioh)) { + printf(": unable to map dma I/O space\n"); + goto out1; + } - regs = asc->regs; + if (bus_dmamap_create(asc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0, + BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, &asc->sc_dmamap)) { + printf(": unable to create DMA map\n"); + goto out2; + } /* - * Reset chip, fully. Note that interrupts are already enabled. + * XXX More of this should be in ncr53c9x_attach(), but + * XXX should we really poke around the chip that much in + * XXX the MI code? Think about this more... */ - s = splbio(); - /* preserve our ID for now */ - asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; - asc->myidmask = ~(1 << asc->sc_id); + /* + * Set up static configuration info. + */ + sc->sc_id = 7; /* XXX should be taken from ARC BIOS */ + sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; /* identify 53CF9x-2 or not */ - regs->asc_cmd = ASC_CMD_RESET; - wbflush(); DELAY(25); - regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP; - wbflush(); DELAY(25); - regs->asc_cnfg2 = ASC_CNFG2_FE; - wbflush(); DELAY(25); - regs->asc_cmd = ASC_CMD_DMA | ASC_CMD_NOP; - wbflush(); DELAY(25); - asc->is24bit = regs->asc_id == ASC_ID_53CF94; - - asc_reset(asc, regs); + asc_write_reg(sc, NCR_CMD, NCRCMD_RSTCHIP); + DELAY(25); + asc_write_reg(sc, NCR_CMD, NCRCMD_DMA | NCRCMD_NOP); + DELAY(25); + asc_write_reg(sc, NCR_CFG2, NCRCFG2_FE); + DELAY(25); + asc_write_reg(sc, NCR_CMD, NCRCMD_DMA | NCRCMD_NOP); + DELAY(25); + if (asc_read_reg(sc, NCR_TCH) == 0xa2 /*XXX*/) { + sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE; + sc->sc_cfg3 = NCRF9XCFG3_IDM | NCRF9XCFG3_FCLK; + sc->sc_features = NCR_F_FASTSCSI; + sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI; + sc->sc_freq = 40; /* MHz */ + sc->sc_maxxfer = 16 * 1024 * 1024; + } else { + sc->sc_freq = 25; /* MHz */ + sc->sc_maxxfer = 64 * 1024; + } /* - * Our SCSI id on the bus. - * The user can set this via the prom on 3maxen/picaen. - * If this changes it is easy to fix: make a default that - * can be changed as boot arg. + * XXX minsync and maxxfer _should_ be set up in MI code, + * XXX but it appears to have some dependency on what sort + * XXX of DMA we're hooked up to, etc. */ -#ifdef unneeded - regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | - (scsi_initiator_id[unit] & 0x7); - asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; -#endif - id = asc->sc_id; - splx(s); /* - * Give each target its DMA buffer region. - * The buffer address is the same for all targets, - * the allocated dma viritual scatter/gather space. + * This is the value used to start sync negotiations + * Note that the NCR register "SYNCTP" is programmed + * in "clocks per byte", and has a minimum value of 4. + * The SCSI period used in negotiation is one-fourth + * of the time (in nanoseconds) needed to transfer one byte. + * Since the chip's clock is given in MHz, we have the following + * formula: 4 * period = (1000 / freq) * 4 */ - for (i = 0; i < ASC_NCMD; i++) { - asc->st[i].dmaBufSize = bufsiz; - } + sc->sc_minsync = 1000 / sc->sc_freq; - /* - * Set up interrupt handler. - */ - jazzio_intr_establish(ja->ja_intr, asc_intr, (void *)asc); - - printf(": %s, target %d\n", asc->is24bit ? "NCR53CF9X-2" : "NCR53C94", - id); - - asc->sc_adapter.adapt_dev = &asc->sc_dev; - asc->sc_adapter.adapt_nchannels = 1; - asc->sc_adapter.adapt_openings = 7; - asc->sc_adapter.adapt_max_periph = 1; - asc->sc_adapter.adapt_ioctl = NULL; - asc->sc_adapter.adapt_minphys = minphys; - asc->sc_adapter.adapt_request = asc_scsipi_request; - - memset(&asc->sc_channel, 0, sizeof(asc->sc_channel)); - asc->sc_channel.chan_adapter = &asc->sc_adapter; - asc->sc_channel.chan_bustype = &scsi_bustype; - asc->sc_channel.chan_channel = 0; - asc->sc_channel.chan_ntargets = 8; - asc->sc_channel.chan_nluns = 8; - asc->sc_channel.chan_id = asc->sc_id; + /* establish interrupt */ + jazzio_intr_establish(ja->ja_intr, ncr53c9x_intr, asc); - /* - * Now try to attach all the sub devices. - */ - config_found(self, &asc->sc_channel, scsiprint); + /* Do the common parts of attachment. */ + sc->sc_adapter.adapt_minphys = minphys; + sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; + ncr53c9x_attach(sc); + + /* Turn on target selection using the `dma' method */ + sc->sc_features |= NCR_F_DMASELECT; + return; + + out2: + bus_space_unmap(iot, asc->sc_dmaioh, R4030_DMA_RANGE); + out1: + bus_space_unmap(iot, asc->sc_ioh, 0x20/*XXX*/); } /* - * Start activity on a SCSI device. - * We maintain information on each device separately since devices can - * connect/disconnect during an operation. + * Glue functions. */ -void -asc_scsipi_request(chan, req, arg) - struct scsipi_channel *chan; - scsipi_adapter_req_t req; - void *arg; -{ - struct scsipi_xfer *xs; - struct scsipi_periph *periph; - struct asc_softc *asc = (void *)chan->chan_adapter->adapt_dev; - int dontqueue, s; - - switch (req) { - case ADAPTER_REQ_RUN_XFER: - xs = arg; - periph = xs->xs_periph; - dontqueue = xs->xs_control & XS_CTL_POLL; - - /* - * Flush caches for any data buffer - */ - if(xs->datalen != 0) { - mips_dcache_wbinv_range((vaddr_t)xs->data, xs->datalen); - } - /* - * The hack on the next few lines are to avoid buffers - * mapped to UADDR. Realloc to the kva uarea address. - */ - if((u_int)(xs->data) >= UADDR) { - xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curproc->p_addr); - } - - s = splbio(); - asc->cmd[periph->periph_target] = xs; - - /* - * Going to launch. - * Make a local copy of the command and some pointers. - */ - asc_startcmd(asc, periph->periph_target); +u_char +asc_read_reg(sc, reg) + struct ncr53c9x_softc *sc; + int reg; +{ + struct asc_softc *asc = (struct asc_softc *)sc; - /* - * If in startup, interrupts not usable yet. - */ - if(dontqueue) { - asc_poll(asc,periph->periph_target); - } - splx(s); - return; - case ADAPTER_REQ_GROW_RESOURCES: - /* XXX Not supported. */ - return; - case ADAPTER_REQ_SET_XFER_MODE: - /* XXX Not supported. */ - return; - } + return bus_space_read_1(asc->sc_iot, asc->sc_ioh, reg); } void -asc_poll(asc, target) - struct asc_softc *asc; - int target; +asc_write_reg(sc, reg, val) + struct ncr53c9x_softc *sc; + int reg; + u_char val; { - struct scsipi_xfer *scsicmd = asc->cmd[target]; - int count = scsicmd->timeout * 10; + struct asc_softc *asc = (struct asc_softc *)sc; - while(count) { - if(asc->regs->asc_status &ASC_CSR_INT) { - asc_intr(asc); - } - if(scsicmd->xs_status & XS_STS_DONE) - break; - DELAY(5); - count--; - } - if(count == 0) { - scsicmd->error = XS_TIMEOUT; - asc_end(asc, 0, 0, 0); - } + bus_space_write_1(asc->sc_iot, asc->sc_ioh, reg, val); } -static void -asc_reset(asc, regs) - asc_softc_t asc; - asc_regmap_t *regs; +int +asc_dma_isintr(sc) + struct ncr53c9x_softc *sc; { - /* - * Reset chip and wait till done - */ - regs->asc_cmd = ASC_CMD_RESET; - wbflush(); DELAY(25); - - /* spec says this is needed after reset */ - regs->asc_cmd = ASC_CMD_NOP; - wbflush(); DELAY(25); - - /* - * Set up various chip parameters - */ - regs->asc_ccf = asc->ccf; - wbflush(); DELAY(25); - regs->asc_sel_timo = asc->timeout_250; - /* restore our ID */ - regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK; - /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ - regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; - regs->asc_cnfg3 = asc_conf->ac_cnfg3; - /* zero anything else */ - ASC_TC_PUT(regs, 0, asc->is24bit); - regs->asc_syn_p = asc->min_period; - regs->asc_syn_o = 0; /* async for now */ - wbflush(); + return asc_read_reg(sc, NCR_STAT) & NCRSTAT_INT; } -/* - * Start a SCSI command on a target. - */ -static void -asc_startcmd(asc, target) - asc_softc_t asc; - int target; +void +asc_dma_reset(sc) + struct ncr53c9x_softc *sc; { - asc_regmap_t *regs; - State *state; - struct scsipi_xfer *scsicmd; - int i, len; - - /* - * See if another target is currently selected on this SCSI bus. - */ - if (asc->target >= 0) - return; - - regs = asc->regs; - - /* - * If a reselection is in progress, it is Ok to ignore it since - * the ASC will automatically cancel the command and flush - * the FIFO if the ASC is reselected before the command starts. - * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if - * a reselect occurs before starting the command. - */ - - asc->state = ASC_STATE_BUSY; - asc->target = target; - - /* cache some pointers */ - scsicmd = asc->cmd[target]; - state = &asc->st[target]; - - /* - * Init the chip and target state. - */ - state->flags = state->flags & DID_SYNC; - state->script = (script_t *)0; - state->msg_out = SCSI_NO_OP; - - /* - * Set up for DMA of command output. Also need to flush cache. - */ - bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen); - state->cmdlen = scsicmd->cmdlen; - state->buf = (vaddr_t)scsicmd->data; - state->buflen = scsicmd->datalen; - len = state->cmdlen; - state->dmalen = len; - -#ifdef DEBUG - if (asc_debug > 1) { - printf("asc_startcmd: %s target %d cmd %x len %d\n", - asc->sc_dev.dv_xname, target, - state->cmd.opcode, state->buflen); - } -#endif - - /* check for simple SCSI command with no data transfer */ - if (scsicmd->xs_control & XS_CTL_DATA_OUT) { - asc->script = &asc_scripts[SCRIPT_DATA_OUT]; - state->flags |= DMA_OUT; - } - else if (scsicmd->xs_control & XS_CTL_DATA_IN) { - asc->script = &asc_scripts[SCRIPT_DATA_IN]; - state->flags |= DMA_IN; - } - else if (state->buflen == 0) { - /* check for sync negotiation */ - if ((scsicmd->xs_status & /* SCSICMD_USE_SYNC */ 0) && - !(state->flags & DID_SYNC)) { - asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; - state->flags |= TRY_SYNC; - } else - asc->script = &asc_scripts[SCRIPT_SIMPLE]; - state->buf = (vaddr_t)0; - } - -#ifdef DEBUG - asc_debug_cmd = state->cmd.opcode; - if (state->cmd.opcode == SCSI_READ_EXT) { - asc_debug_bn = (state->cmd.bytes[1] << 24) | - (state->cmd.bytes[2] << 16) | - (state->cmd.bytes[3] << 8) | - state->cmd.bytes[4]; - asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7]; - } - asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd); - asc_logp->target = asc->target; - asc_logp->state = asc->script - asc_scripts; - asc_logp->msg = SCSI_DIS_REC_IDENTIFY; - asc_logp->resid = scsicmd->datalen; - if (++asc_logp >= &asc_log[NLOG]) - asc_logp = asc_log; -#endif - - /* preload the FIFO with the message and command to be sent */ - regs->asc_fifo = SCSI_DIS_REC_IDENTIFY | - (scsicmd->xs_periph->periph_lun & 0x07); + struct asc_softc *asc = (struct asc_softc *)sc; - for( i = 0; i < len; i++ ) { - regs->asc_fifo = ((caddr_t)&state->cmd)[i]; - } - ASC_TC_PUT(regs, 0, asc->is24bit); - readback(regs->asc_cmd); - regs->asc_cmd = ASC_CMD_DMA; - readback(regs->asc_cmd); - - regs->asc_dbus_id = target; - readback(regs->asc_dbus_id); - regs->asc_syn_p = state->sync_period; - readback(regs->asc_syn_p); - regs->asc_syn_o = state->sync_offset; - readback(regs->asc_syn_o); - -/*XXX PEFO */ -/* we are not using sync transfer now, need to check this if we will */ - - if (state->flags & TRY_SYNC) - regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; - else - regs->asc_cmd = ASC_CMD_SEL_ATN; - readback(regs->asc_cmd); + /* halt DMA */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_MODE, 0); } -/* - * Interrupt routine - * Take interrupts from the chip - * - * Implementation: - * Move along the current command's script if - * all is well, invoke error handler if not. - */ int -asc_intr(sc) - void *sc; +asc_dma_intr(sc) + struct ncr53c9x_softc *sc; { - asc_softc_t asc = sc; - asc_regmap_t *regs = asc->regs; - State *state; - script_t *scpt; - int ss, ir, status; - - /* collect ephemeral information */ - status = regs->asc_status; - ss = regs->asc_ss; - - if ((status & ASC_CSR_INT) == 0) /* Make shure it's a real interrupt */ - return(0); - - ir = regs->asc_intr; /* this resets the previous two */ - scpt = asc->script; - -#ifdef DEBUG - asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir); - asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; - asc_logp->state = scpt - asc_scripts; - asc_logp->msg = -1; - asc_logp->resid = 0; - if (++asc_logp >= &asc_log[NLOG]) - asc_logp = asc_log; - if (asc_debug > 2) - printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", - status, ss, ir, scpt - asc_scripts, scpt->condition); -#endif + struct asc_softc *asc = (struct asc_softc *)sc; + int datain, resid, trans; - /* check the expected state */ - if (SCRIPT_MATCH(ir, status) == scpt->condition) { - /* - * Perform the appropriate operation, then proceed. - */ - if ((*scpt->action)(asc, status, ss, ir)) { - regs->asc_cmd = scpt->command; - readback(regs->asc_cmd); - asc->script = scpt->next; - } - goto done; - } + datain = asc->sc_datain; - /* - * Check for parity error. - * Hardware will automatically set ATN - * to request the device for a MSG_OUT phase. - */ - if (status & ASC_CSR_PE) { - printf("%s: SCSI device %d: incomming parity error seen\n", - asc->sc_dev.dv_xname, asc->target); - asc->st[asc->target].flags |= PARITY_ERR; - } - - /* - * Check for gross error. - * Probably a bug in a device driver. - */ - if (status & ASC_CSR_GE) { - printf("%s: SCSI device %d: gross error\n", - asc->sc_dev.dv_xname, asc->target); - goto abort; - } - - /* check for message in or out */ - if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { - register int len, fifo; - - state = &asc->st[asc->target]; - switch (ASC_PHASE(status)) { - case ASC_PHASE_DATAI: - case ASC_PHASE_DATAO: - ASC_TC_GET(regs, len); - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; - printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", - state->buflen, state->dmalen, len, fifo); - goto abort; - - case ASC_PHASE_MSG_IN: - break; - - case ASC_PHASE_MSG_OUT: - /* - * Check for parity error. - * Hardware will automatically set ATN - * to request the device for a MSG_OUT phase. - */ - if (state->flags & PARITY_ERR) { - state->flags &= ~PARITY_ERR; - state->msg_out = SCSI_MESSAGE_PARITY_ERROR; - /* reset message in counter */ - state->msglen = 0; - } else - state->msg_out = SCSI_NO_OP; - regs->asc_fifo = state->msg_out; - regs->asc_cmd = ASC_CMD_XFER_INFO; - readback(regs->asc_cmd); - goto done; - - case ASC_PHASE_STATUS: - /* probably an error in the SCSI command */ - asc->script = &asc_scripts[SCRIPT_GET_STATUS]; - regs->asc_cmd = ASC_CMD_I_COMPLETE; - readback(regs->asc_cmd); - goto done; - - default: - goto abort; - } - - if (state->script) - goto abort; - - /* - * OK, message coming in clean up whatever is going on. - * Get number of bytes left to transfered from byte counter - * counter decrements when data is trf on the SCSI bus - */ - ASC_TC_GET(regs, len); - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; - /* flush any data in the FIFO */ - if (fifo && !(state->flags & DMA_IN_PROGRESS)) { -printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo); - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - DELAY(2); - } - else if (fifo && state->flags & DMA_IN_PROGRESS) { - if (state->flags & DMA_OUT) { - len += fifo; /* Bytes dma'ed but not sent */ - } - else if (state->flags & DMA_IN) { - printf("asc_intr: IN: dmalen %d len %d fifo %d\n", - state->dmalen, len, fifo); /* XXX */ - } - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - DELAY(2); - } - if (len && (state->flags & DMA_IN_PROGRESS)) { - /* save number of bytes still to be sent or received */ - state->dmaresid = len; - state->flags &= ~DMA_IN_PROGRESS; - ASC_TC_PUT(regs, 0, asc->is24bit); -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - /* setup state to resume to */ - if (state->flags & DMA_IN) { - /* - * Since the ASC_CNFG3_SRB bit of the - * cnfg3 register bit is not set, - * we just transferred an extra byte. - * Since we can't resume on an odd byte - * boundary, we copy the valid data out - * and resume DMA at the start address. - */ - if (len & 1) { - printf("asc_intr: msg in len %d (fifo %d)\n", - len, fifo); /* XXX */ - len = state->dmalen - len; - goto do_in; - } - state->script = - &asc_scripts[SCRIPT_RESUME_DMA_IN]; - } else if (state->flags & DMA_OUT) - state->script = - &asc_scripts[SCRIPT_RESUME_DMA_OUT]; - else - state->script = asc->script; - } else if (state->flags & DMA_IN) { - if (len) { -#ifdef DEBUG - printf("asc_intr: 1: bn %d len %d (fifo %d)\n", - asc_debug_bn, len, fifo); /* XXX */ -#endif - goto abort; - } - /* setup state to resume to */ - if (state->flags & DMA_IN_PROGRESS) { - len = state->dmalen; - state->flags &= ~DMA_IN_PROGRESS; - do_in: - DMA_END(asc->dma); - state->buf += len; - state->buflen -= len; - } - if (state->buflen) - state->script = - &asc_scripts[SCRIPT_RESUME_IN]; - else - state->script = - &asc_scripts[SCRIPT_RESUME_NO_DATA]; - } else if (state->flags & DMA_OUT) { - if (len) { - printf("asc_intr: 2: len %d (fifo %d)\n", len, - fifo); /* XXX */ -/* XXX THEO */ -#if 1 - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - DELAY(2); - len = 0; -#else - goto abort; -#endif - } - /* - * If this is the last chunk, the next expected - * state is to get status. - */ - if (state->flags & DMA_IN_PROGRESS) { - state->flags &= ~DMA_IN_PROGRESS; - DMA_END(asc->dma); - len = state->dmalen; - state->buf += len; - state->buflen -= len; - } - if (state->buflen) - state->script = - &asc_scripts[SCRIPT_RESUME_OUT]; - else - state->script = - &asc_scripts[SCRIPT_RESUME_NO_DATA]; - } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) - state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA]; - else - state->script = asc->script; - - /* setup to receive a message */ - asc->script = &asc_scripts[SCRIPT_MSG_IN]; - state->msglen = 0; - regs->asc_cmd = ASC_CMD_XFER_INFO; - readback(regs->asc_cmd); - goto done; - } - - /* check for SCSI bus reset */ - if (ir & ASC_INT_RESET) { - register int i; - - printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname); - /* need to flush any pending commands */ - for (i = 0; i < ASC_NCMD; i++) { - if (!asc->cmd[i]) - continue; - asc->cmd[i]->error = XS_DRIVER_STUFFUP; - asc_end(asc, 0, 0, 0); - } - /* rearbitrate synchronous offset */ - for (i = 0; i < ASC_NCMD; i++) { - asc->st[i].sync_offset = 0; - asc->st[i].flags = 0; - } - asc->target = -1; - return(1); - } - - /* check for command errors */ - if (ir & ASC_INT_ILL) - goto abort; - - /* check for disconnect */ - if (ir & ASC_INT_DISC) { - state = &asc->st[asc->target]; - switch (asc->script - asc_scripts) { - case SCRIPT_DONE: - case SCRIPT_DISCONNECT: - /* - * Disconnects can happen normally when the - * command is complete with the phase being - * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN. - * The SCRIPT_MATCH() only checks for one phase - * so we can wind up here. - * Perform the appropriate operation, then proceed. - */ - if ((*scpt->action)(asc, status, ss, ir)) { - regs->asc_cmd = scpt->command; - readback(regs->asc_cmd); - asc->script = scpt->next; - } - goto done; - - case SCRIPT_TRY_SYNC: - case SCRIPT_SIMPLE: - case SCRIPT_DATA_IN: - case SCRIPT_DATA_OUT: /* one of the starting scripts */ - if (ASC_SS(ss) == 0) { - /* device did not respond */ - if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - } - asc->cmd[asc->target]->error = XS_SELTIMEOUT; - asc_end(asc, status, ss, ir); - return(1); - } - /* FALLTHROUGH */ - - default: - printf("%s: SCSI device %d: unexpected disconnect\n", - asc->sc_dev.dv_xname, asc->target); -#ifdef DEBUG - asc_DumpLog("asc_disc"); -#endif - /* - * On rare occasions my RZ24 does a disconnect during - * data in phase and the following seems to keep it - * happy. - * XXX Should a scsi disk ever do this?? - */ - asc->script = &asc_scripts[SCRIPT_RESEL]; - asc->state = ASC_STATE_RESEL; - state->flags |= DISCONN; - regs->asc_cmd = ASC_CMD_ENABLE_SEL; - readback(regs->asc_cmd); - return(1); - } - } - - /* check for reselect */ - if (ir & ASC_INT_RESEL) { - unsigned fifo, id, msg; - - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; - if (fifo < 2) - goto abort; - /* read unencoded SCSI ID and convert to binary */ - msg = regs->asc_fifo & asc->myidmask; - for (id = 0; (msg & 1) == 0; id++) - msg >>= 1; - /* read identify message */ - msg = regs->asc_fifo; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].msg = msg; - else - asc_logp[-1].msg = msg; +#ifdef DIAGNOSTIC + /* This is an "assertion" :) */ + if (asc->sc_active == 0) + panic("asc_dma_intr: DMA wasn't active"); #endif - asc->state = ASC_STATE_BUSY; - asc->target = id; - state = &asc->st[id]; - asc->script = state->script; - state->script = (script_t *)0; - if (!(state->flags & DISCONN)) - goto abort; - state->flags &= ~DISCONN; - regs->asc_syn_p = state->sync_period; - regs->asc_syn_o = state->sync_offset; - regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(regs->asc_cmd); - goto done; - } - - /* check if we are being selected as a target */ - if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) - goto abort; - /* - * 'ir' must be just ASC_INT_FC. - * This is normal if canceling an ASC_ENABLE_SEL. - */ - -done: - wbflush(); - /* - * If the next interrupt comes in immediatly the interrupt - * dispatcher (which we are returning to) will catch it - * before returning to the interrupted code. - */ - return(1); + /* DMA has stopped */ -abort: -#ifdef DEBUG - asc_DumpLog("asc_intr"); -#endif - panic("asc_intr"); - return(1); -} + asc->sc_active = 0; -/* - * All the many little things that the interrupt - * routine might switch to. - */ + if (asc->sc_dmasize == 0) { + /* A "Transfer Pad" operation complete */ + NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", + NCR_READ_REG(sc, NCR_TCL) | + (NCR_READ_REG(sc, NCR_TCM) << 8), + NCR_READ_REG(sc, NCR_TCL), + NCR_READ_REG(sc, NCR_TCM))); -/* ARGSUSED */ -static int -script_nop(asc, status, ss, ir) - asc_softc_t asc; - int status, ss, ir; -{ - return (1); -} + return 0; + } -/* ARGSUSED */ -static int -asc_get_status(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register int data; + resid = 0; /* - * Get the last two bytes in the FIFO. + * If a transfer onto the SCSI bus gets interrupted by the device + * (e.g. for a SAVEPOINTER message), the data in the FIFO counts + * as residual since the ESP counter registers get decremented as + * bytes are clocked into the FIFO. */ - if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { - printf("asc_get_status: cmdreg %x, fifo cnt %d\n", - regs->asc_cmd, data); /* XXX */ -#ifdef DEBUG - asc_DumpLog("get_status"); /* XXX */ -#endif - if (data < 2) { - asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(asc->regs->asc_cmd); - return (0); - } - do { - data = regs->asc_fifo; - } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); + if (!datain && + (resid = (asc_read_reg(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { + NCR_DMA(("asc_dma_intr: empty asc FIFO of %d ", resid)); } - - /* save the status byte */ - asc->st[asc->target].statusByte = data = regs->asc_fifo; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].msg = data; - else - asc_logp[-1].msg = data; -#endif - - /* get the (presumed) command_complete message */ - if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) - return (1); - -#ifdef DEBUG - printf("asc_get_status: status %x cmd %x\n", - asc->st[asc->target].statusByte, data); - asc_DumpLog("asc_get_status"); -#endif - return (0); -} -/* ARGSUSED */ -static int -asc_end(asc, status, ss, ir) - asc_softc_t asc; - int status, ss, ir; -{ - struct scsipi_xfer *scsicmd; - struct scsipi_periph *periph; - State *state; - int i, target; - - asc->state = ASC_STATE_IDLE; - target = asc->target; - asc->target = -1; - scsicmd = asc->cmd[target]; - periph = scsicmd->xs_periph; - asc->cmd[target] = (struct scsipi_xfer *)0; - state = &asc->st[target]; - -#ifdef DEBUG - if (asc_debug > 1) { - printf("asc_end: %s target %d cmd %x err %d resid %d\n", - asc->sc_dev.dv_xname, target, - state->cmd.opcode, scsicmd->error, state->buflen); +#if 0 + if ((sc->sc_espstat & NCRSTAT_TC) == 0) { + /* XXX need to drain residual data in FIFO? */ } #endif -#ifdef DIAGNOSTIC - if (target < 0 || !scsicmd) - panic("asc_end"); -#endif - /* look for disconnected devices */ - for (i = 0; i < ASC_NCMD; i++) { - if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) - continue; - asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; - readback(asc->regs->asc_cmd); - asc->state = ASC_STATE_RESEL; - asc->script = &asc_scripts[SCRIPT_RESEL]; - break; - } + /* halt DMA */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_COUNT, 0); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_MODE, 0); - if(scsicmd->error == XS_NOERROR) { - if((state->statusByte & ST_MASK) == SCSI_CHECK) { - scsicmd->status = state->statusByte; - scsicmd->error = XS_BUSY; - } - } + bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap, + 0, asc->sc_dmamap->dm_mapsize, + datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap); - scsicmd->resid = state->buflen; + trans = asc->sc_dmasize - resid; - /* - * Look for another device that is ready. - * May want to keep last one started and increment for fairness - * rather than always starting at zero. - */ - for (i = 0; i < ASC_NCMD; i++) { - /* don't restart a disconnected command */ - if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) - continue; - asc_startcmd(asc, i); - break; - } - - /* signal device driver that the command is done */ - scsipi_done(scsicmd); - - return (0); -} - -/* ARGSUSED */ -static int -asc_dma_in(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len; - - /* check for previous chunk in buffer */ - if (state->flags & DMA_IN_PROGRESS) { + if (trans < 0) { /* transfered < 0 ? */ +#if 0 /* - * Only count bytes that have been copied to memory. - * There may be some bytes in the FIFO if synchonous transfers - * are in progress. + * This situation can happen in perfectly normal operation + * if the ESP is reselected while using DMA to select + * another target. As such, don't print the warning. */ - DMA_END(asc->dma); - ASC_TC_GET(regs, len); - len = state->dmalen - len; - state->buf += len; - state->buflen -= len; - } - - /* setup to start reading the next chunk */ - len = state->buflen; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - if (len > state->dmaBufSize) - len = state->dmaBufSize; - state->dmalen = len; - DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); -#endif - - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (len != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; - return (0); - } - return (1); -} - -/* ARGSUSED */ -static int -asc_last_dma_in(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len, fifo; - - DMA_END(asc->dma); - ASC_TC_GET(regs, len); - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", - state->buflen, state->dmalen, len, fifo); -#endif - if (fifo) { - /* device must be trying to send more than we expect */ - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - } - state->flags &= ~DMA_IN_PROGRESS; - len = state->dmalen - len; - state->buflen -= len; - - return (1); -} - -/* ARGSUSED */ -static int -asc_resume_in(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len; - - /* setup to start reading the next chunk */ - len = state->buflen; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - if (len > state->dmaBufSize) - len = state->dmaBufSize; - state->dmalen = len; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_resume_in: buflen %d, len %d\n", state->buflen, - len); -#endif - - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (len != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; - return (0); - } - return (1); -} - -/* ARGSUSED */ -static int -asc_resume_dma_in(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len, off; - - /* setup to finish reading the current chunk */ - len = state->dmaresid; - off = state->dmalen - len; - if ((off & 1) && state->sync_offset) { - printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", - state->dmalen, len, off); /* XXX */ - regs->asc_res_fifo = ((u_char *)state->buf)[off]; -/*XXX Need to flush cache ? */ - } - DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", - state->dmalen, state->buflen, len, off); -#endif - - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (state->dmalen != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; - return (0); - } - return (1); -} - -/* ARGSUSED */ -static int -asc_dma_out(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len, fifo; - - if (state->flags & DMA_IN_PROGRESS) { - /* check to be sure previous chunk was finished */ - ASC_TC_GET(regs, len); - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; - if (len || fifo) - printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", - state->buflen, state->dmalen, len, fifo); /* XXX */ - len += fifo; - len = state->dmalen - len; - state->buf += len; - state->buflen -= len; - } - - /* setup for this chunk */ - len = state->buflen; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - if (len > state->dmaBufSize) - len = state->dmaBufSize; - state->dmalen = len; - DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); + printf("%s: xfer (%d) > req (%d)\n", + sc->sc_dev.dv_xname, trans, asc->sc_dmasize); #endif - - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (len != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; - return (0); + trans = asc->sc_dmasize; } - return (1); -} + NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", + NCR_READ_REG(sc, NCR_TCL), + NCR_READ_REG(sc, NCR_TCM), + (sc->sc_cfg2 & NCRCFG2_FE) ? NCR_READ_REG(sc, NCR_TCH) : 0, + trans, resid)); -/* ARGSUSED */ -static int -asc_last_dma_out(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len, fifo; - - ASC_TC_GET(regs, len); - fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", - state->buflen, state->dmalen, len, fifo); -#endif - if (fifo) { - len += fifo; - regs->asc_cmd = ASC_CMD_FLUSH; - readback(regs->asc_cmd); - } - state->flags &= ~DMA_IN_PROGRESS; - len = state->dmalen - len; - state->buflen -= len; - return (1); -} + *asc->sc_dmalen -= trans; + *asc->sc_dmaaddr += trans; -/* ARGSUSED */ -static int -asc_resume_out(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len; - - /* setup for this chunk */ - len = state->buflen; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - if (len > state->dmaBufSize) - len = state->dmaBufSize; - state->dmalen = len; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].resid = len; - else - asc_logp[-1].resid = len; -#endif - DMA_START(asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_resume_out: buflen %d, len %d\n", state->buflen, - len); -#endif - - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (len != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; - return (0); - } - return (1); + return 0; } -/* ARGSUSED */ -static int -asc_resume_dma_out(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int len, off; - - /* setup to finish writing this chunk */ - len = state->dmaresid; - off = state->dmalen - len; - if (off & 1) { - printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", - state->dmalen, len, off); /* XXX */ - regs->asc_fifo = ((u_char *)state->buf)[off]; -/*XXX Need to flush Cache ? */ - off++; - len--; - } - DMA_START(asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV); - ASC_TC_PUT(regs, len, asc->is24bit); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", - state->dmalen, state->buflen, len, off); -#endif +int +asc_dma_setup(sc, addr, len, datain, dmasize) + struct ncr53c9x_softc *sc; + caddr_t *addr; + size_t *len; + int datain; + size_t *dmasize; +{ + struct asc_softc *asc = (struct asc_softc *)sc; + + /* halt DMA */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_MODE, 0); + + asc->sc_dmaaddr = addr; + asc->sc_dmalen = len; + asc->sc_dmasize = *dmasize; + asc->sc_datain = datain; + + /* + * No need to set up DMA in `Transfer Pad' operation. + */ + if (*dmasize == 0) + return 0; + + bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap, *addr, *len, NULL, + ((sc->sc_nexus->xs->xs_control & XS_CTL_NOSLEEP) ? + BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_STREAMING | + (datain ? BUS_DMA_READ : BUS_DMA_WRITE)); + bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap, + 0, asc->sc_dmamap->dm_mapsize, + datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); - /* check for next chunk */ - state->flags |= DMA_IN_PROGRESS; - if (state->dmalen != state->buflen) { - regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; - return (0); - } - return (1); + return 0; } -/* ARGSUSED */ -static int -asc_sendsync(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; +void +asc_dma_go(sc) + struct ncr53c9x_softc *sc; { - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; + struct asc_softc *asc = (struct asc_softc *)sc; - /* send the extended synchronous negotiation message */ - regs->asc_fifo = SCSI_EXTENDED_MSG; - wbflush(); - regs->asc_fifo = 3; - wbflush(); - regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; - wbflush(); - regs->asc_fifo = SCSI_MIN_PERIOD; - wbflush(); - regs->asc_fifo = ASC_MAX_OFFSET; - /* state to resume after we see the sync reply message */ - state->script = asc->script + 2; - state->msglen = 0; - return (1); -} + /* No DMA transfer in Transfer Pad operation */ + if (asc->sc_dmasize == 0) + return; -/* ARGSUSED */ -static int -asc_replysync(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; -{ - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; + /* load transfer parameters */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, + R4030_DMA_ADDR, asc->sc_dmamap->dm_segs[0].ds_addr); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, + R4030_DMA_COUNT, asc->sc_dmamap->dm_segs[0].ds_len); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, + R4030_DMA_MODE, R4030_DMA_MODE_160NS | R4030_DMA_MODE_16); + + /* start DMA */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, + R4030_DMA_ENAB, R4030_DMA_ENAB_RUN | + (asc->sc_datain ? R4030_DMA_ENAB_READ : R4030_DMA_ENAB_WRITE)); -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_replysync: %x %x\n", - asc_to_scsi_period[state->sync_period] * asc->tb_ticks, - state->sync_offset); -#endif - /* send synchronous transfer in response to a request */ - regs->asc_fifo = SCSI_EXTENDED_MSG; - wbflush(); - regs->asc_fifo = 3; - wbflush(); - regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; - wbflush(); - regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; - wbflush(); - regs->asc_fifo = state->sync_offset; - regs->asc_cmd = ASC_CMD_XFER_INFO; - readback(regs->asc_cmd); - - /* return to the appropriate script */ - if (!state->script) { -#ifdef DEBUG - asc_DumpLog("asc_replsync"); -#endif - panic("asc_replysync"); - } - asc->script = state->script; - state->script = (script_t *)0; - return (0); + asc->sc_active = 1; } -/* ARGSUSED */ -static int -asc_msg_in(asc, status, ss, ir) - register asc_softc_t asc; - register int status, ss, ir; +void +asc_dma_stop(sc) + struct ncr53c9x_softc *sc; { - register asc_regmap_t *regs = asc->regs; - register State *state = &asc->st[asc->target]; - register int msg; - int i; - - /* read one message byte */ - msg = regs->asc_fifo; -#ifdef DEBUG - if (asc_logp == asc_log) - asc_log[NLOG - 1].msg = msg; - else - asc_logp[-1].msg = msg; -#endif - - /* check for multi-byte message */ - if (state->msglen != 0) { - /* first byte is the message length */ - if (state->msglen < 0) { - state->msglen = msg; - return (1); - } - if (state->msgcnt >= state->msglen) - goto abort; - state->msg_in[state->msgcnt++] = msg; - - /* did we just read the last byte of the message? */ - if (state->msgcnt != state->msglen) - return (1); - - /* process an extended message */ -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_msg_in: msg %x %x %x\n", - state->msg_in[0], - state->msg_in[1], - state->msg_in[2]); -#endif - switch (state->msg_in[0]) { - case SCSI_SYNCHRONOUS_XFER: - state->flags |= DID_SYNC; - state->sync_offset = state->msg_in[2]; - - /* convert SCSI period to ASC period */ - i = state->msg_in[1] / asc->tb_ticks; - if (i < asc->min_period) - i = asc->min_period; - else if (i >= asc->max_period) { - /* can't do sync transfer, period too long */ - printf("%s: SCSI device %d: sync xfer period too long (%d)\n", - asc->sc_dev.dv_xname, asc->target, i); - i = asc->max_period; - state->sync_offset = 0; - } - if ((i * asc->tb_ticks) != state->msg_in[1]) - i++; - state->sync_period = i & 0x1F; - - /* - * If this is a request, check minimums and - * send back an acknowledge. - */ - if (!(state->flags & TRY_SYNC)) { - regs->asc_cmd = ASC_CMD_SET_ATN; - readback(regs->asc_cmd); - - if (state->sync_period < asc->min_period) - state->sync_period = - asc->min_period; - if (state->sync_offset > ASC_MAX_OFFSET) - state->sync_offset = - ASC_MAX_OFFSET; - asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; - regs->asc_syn_p = state->sync_period; - readback(regs->asc_syn_p); - regs->asc_syn_o = state->sync_offset; - readback(regs->asc_syn_o); - regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(regs->asc_cmd); - return (0); - } - - regs->asc_syn_p = state->sync_period; - readback(regs->asc_syn_p); - regs->asc_syn_o = state->sync_offset; - readback(regs->asc_syn_o); - goto done; - - default: - printf("%s: SCSI device %d: rejecting extended message 0x%x\n", - asc->sc_dev.dv_xname, asc->target, - state->msg_in[0]); - goto reject; - } - } - - /* process first byte of a message */ -#ifdef DEBUG - if (asc_debug > 2) - printf("asc_msg_in: msg %x\n", msg); -#endif - switch (msg) { -#if 0 - case SCSI_MESSAGE_REJECT: - printf(" did not like SYNCH xfer "); /* XXX */ - state->flags |= DID_SYNC; - regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(regs->asc_cmd); - status = asc_wait(regs, ASC_CSR_INT); - ir = regs->asc_intr; - /* some just break out here, some dont */ - if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { - regs->asc_fifo = SCSI_ABORT; - regs->asc_cmd = ASC_CMD_XFER_INFO; - readback(regs->asc_cmd); - status = asc_wait(regs, ASC_CSR_INT); - ir = regs->asc_intr; - } - if (ir & ASC_INT_DISC) { - asc_end(asc, status, 0, ir); - return (0); - } - goto status; -#endif /* 0 */ - - case SCSI_EXTENDED_MSG: /* read an extended message */ - /* setup to read message length next */ - state->msglen = -1; - state->msgcnt = 0; - return (1); - - case SCSI_NO_OP: - break; - - case SCSI_SAVE_DATA_POINTER: - /* expect another message */ - return (1); - - case SCSI_RESTORE_POINTERS: - /* - * Need to do the following if resuming synchonous data in - * on an odd byte boundary. - regs->asc_cnfg2 |= ASC_CNFG2_RFB; - */ - break; + struct asc_softc *asc = (struct asc_softc *)sc; - case SCSI_DISCONNECT: - if (state->flags & DISCONN) - goto abort; - state->flags |= DISCONN; - regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(regs->asc_cmd); - asc->script = &asc_scripts[SCRIPT_DISCONNECT]; - return (0); - - default: - printf("%s: SCSI device %d: rejecting message 0x%x\n", - asc->sc_dev.dv_xname, asc->target, msg); - reject: - /* request a message out before acknowledging this message */ - state->msg_out = SCSI_MESSAGE_REJECT; - regs->asc_cmd = ASC_CMD_SET_ATN; - readback(regs->asc_cmd); - } + /* halt DMA */ + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(asc->sc_iot, asc->sc_dmaioh, R4030_DMA_MODE, 0); -done: - /* return to original script */ - regs->asc_cmd = ASC_CMD_MSG_ACPT; - readback(regs->asc_cmd); - if (!state->script) { - abort: -#ifdef DEBUG - asc_DumpLog("asc_msg_in"); -#endif - panic("asc_msg_in"); - } - asc->script = state->script; - state->script = (script_t *)0; - return (0); + asc->sc_active = 0; } -/* ARGSUSED */ -static int -asc_disconnect(asc, status, ss, ir) - asc_softc_t asc; - int status, ss, ir; -{ -#ifdef DIAGNOSTIC - if (!(asc->st[asc->target].flags & DISCONN)) { - printf("asc_disconnect: device %d: DISCONN not set!\n", - asc->target); - } -#endif /* DIAGNOSTIC */ - asc->target = -1; - asc->state = ASC_STATE_RESEL; - return (1); -} - -#ifdef DEBUG -/* - * Dump the log buffer. - */ -static void -asc_DumpLog(str) - char *str; +int +asc_dma_isactive(sc) + struct ncr53c9x_softc *sc; { - register struct asc_log *lp; - register u_int status; + struct asc_softc *asc = (struct asc_softc *)sc; - printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, - asc_debug_bn, asc_debug_sz); - lp = asc_logp; - do { - status = lp->status; - printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", - status >> 24, - lp->target, - (status >> 16) & 0xFF, - (status >> 8) & 0xFF, - status & 0XFF, - lp->state, - asc_scripts[lp->state].condition, - lp->msg, lp->resid); - if (++lp >= &asc_log[NLOG]) - lp = asc_log; - } while (lp != asc_logp); + return asc->sc_active; } -#endif /* DEBUG */ Index: jazz/bus_dma_jazz.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/jazz/bus_dma_jazz.c,v retrieving revision 1.4 diff -u -r1.4 bus_dma_jazz.c --- jazz/bus_dma_jazz.c 2001/11/14 18:15:15 1.4 +++ jazz/bus_dma_jazz.c 2003/01/08 17:03:08 @@ -39,11 +39,19 @@ #include #include +typedef struct jazz_tlbmap { + struct jazz_dma_pte *ptebase; + bus_addr_t vaddr; +} *jazz_tlbmap_t; + static int jazz_bus_dmamap_alloc_sgmap __P((bus_dma_tag_t, bus_dma_segment_t *, int, bus_size_t, struct proc *, int)); static void jazz_bus_dmamap_free_sgmap __P((bus_dma_tag_t, bus_dma_segment_t *, int)); +int jazz_bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, + bus_size_t, bus_size_t, int, bus_dmamap_t *)); +void jazz_bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t)); int jazz_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, struct proc *, int)); int jazz_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t, @@ -62,6 +70,8 @@ { _bus_dma_tag_init(t); + t->_dmamap_create = jazz_bus_dmamap_create; + t->_dmamap_destroy = jazz_bus_dmamap_destroy; t->_dmamap_load = jazz_bus_dmamap_load; t->_dmamap_load_mbuf = jazz_bus_dmamap_load_mbuf; t->_dmamap_load_uio = jazz_bus_dmamap_load_uio; @@ -117,6 +127,83 @@ } } + +/* + * function to create a DMA map. If BUS_DMA_ALLOCNOW is specified and + * nsegments is 1, allocate jazzdmatlb here, too. + */ +int +jazz_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp) + bus_dma_tag_t t; + bus_size_t size; + int nsegments; + bus_size_t maxsegsz; + bus_size_t boundary; + int flags; + bus_dmamap_t *dmamp; +{ + struct arc_bus_dmamap *map; + jazz_tlbmap_t tlbmap; + int error, npte; + + if ((flags & BUS_DMA_ALLOCNOW) == 0) + return (_bus_dmamap_create(t, size, nsegments, maxsegsz, + boundary, flags, dmamp)); + + if (nsegments > 1) + /* BUS_DMA_ALLOCNOW is allowd only with one segment for now. */ + return (ENOMEM); + + tlbmap = malloc(sizeof(struct jazz_tlbmap), M_DMAMAP, + (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); + if (tlbmap == NULL) + return (ENOMEM); + + npte = jazz_dma_page_round(maxsegsz) / JAZZ_DMA_PAGE_SIZE + 1; + tlbmap->ptebase = + jazz_dmatlb_alloc(npte, boundary, flags, &tlbmap->vaddr); + if (tlbmap->ptebase == NULL) { + free(tlbmap, M_DMAMAP); + return (ENOMEM); + } + + error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, + flags, dmamp); + if (error != 0) { + jazz_dmatlb_free(tlbmap->vaddr, npte); + free(tlbmap, M_DMAMAP); + return (error); + } + map = *dmamp; + map->_dm_cookie = (void *)tlbmap; + + return (0); +} + +/* + * function to destroy a DMA map. If BUS_DMA_ALLOCNOW is specified, + * free jazzdmatlb, too. + */ +void +jazz_bus_dmamap_destroy(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) { + jazz_tlbmap_t tlbmap; + int npte; + + tlbmap = (jazz_tlbmap_t)map->_dm_cookie; + npte = jazz_dma_page_round(map->_dm_maxsegsz) / + JAZZ_DMA_PAGE_SIZE + 1; + jazz_dmatlb_free(tlbmap->vaddr, npte); + free(tlbmap, M_DMAMAP); + } + + _bus_dmamap_destroy(t, map); +} + /* * function for loading a direct-mapped DMA map with a linear buffer. */ @@ -129,8 +216,26 @@ struct proc *p; int flags; { - int error = _bus_dmamap_load(t, map, buf, buflen, p, flags); + int error; + + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) { + jazz_tlbmap_t tlbmap; + bus_size_t off; + + tlbmap = (jazz_tlbmap_t)map->_dm_cookie; + off = jazz_dma_page_offs(buf); + jazz_dmatlb_map_va(p, (vaddr_t)buf, buflen, tlbmap->ptebase); + + map->dm_segs[0].ds_addr = tlbmap->vaddr + off; + map->dm_segs[0].ds_len = buflen; + map->dm_segs[0]._ds_vaddr = (vaddr_t)buf; + map->dm_mapsize = buflen; + map->dm_nsegs = 1; + return (0); + } + + error = _bus_dmamap_load(t, map, buf, buflen, p, flags); if (error == 0) { error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, map->dm_nsegs, map->_dm_boundary, p, flags); @@ -148,8 +253,12 @@ struct mbuf *m0; int flags; { - int error = _bus_dmamap_load_mbuf(t, map, m0, flags); + int error; + + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) + return (ENODEV); /* XXX which errno is better? */ + error = _bus_dmamap_load_mbuf(t, map, m0, flags); if (error == 0) { error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, map->dm_nsegs, map->_dm_boundary, NULL, flags); @@ -167,8 +276,12 @@ struct uio *uio; int flags; { - int error = jazz_bus_dmamap_load_uio(t, map, uio, flags); + int error; + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) + return (ENODEV); /* XXX which errno is better? */ + + error = jazz_bus_dmamap_load_uio(t, map, uio, flags); if (error == 0) { error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, map->dm_nsegs, map->_dm_boundary, @@ -190,8 +303,12 @@ bus_size_t size; int flags; { - int error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); + int error; + + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) + return (ENODEV); /* XXX which errno is better? */ + error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); if (error == 0) { error = jazz_bus_dmamap_alloc_sgmap(t, map->dm_segs, map->dm_nsegs, map->_dm_boundary, NULL, flags); @@ -207,6 +324,13 @@ bus_dma_tag_t t; bus_dmamap_t map; { + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) != 0) { + map->dm_mapsize = 0; + map->dm_nsegs = 0; + map->_dm_flags &= ~BUS_DMA_ALLOCNOW; + return; + } + jazz_bus_dmamap_free_sgmap(t, map->dm_segs, map->dm_nsegs); _bus_dmamap_unload(t, map); } Index: jazz/dma.h =================================================================== RCS file: /cvsroot/src/sys/arch/arc/jazz/dma.h,v retrieving revision 1.2 diff -u -r1.2 dma.h --- jazz/dma.h 2001/07/24 16:26:53 1.2 +++ jazz/dma.h 2003/01/08 17:03:08 @@ -34,83 +34,34 @@ /* * Hardware dma registers. */ -typedef volatile struct { - int32_t dma_mode; - int32_t pad1; - int32_t dma_enab; - int32_t pad2; - int32_t dma_count; - int32_t pad3; - int32_t dma_addr; - int32_t pad4; -} DmaReg, *pDmaReg; -#define R4030_DMA_MODE_40NS 0x00 /* Device dma timing */ -#define R4030_DMA_MODE_80NS 0x01 /* Device dma timing */ -#define R4030_DMA_MODE_120NS 0x02 /* Device dma timing */ -#define R4030_DMA_MODE_160NS 0x03 /* Device dma timing */ -#define R4030_DMA_MODE_200NS 0x04 /* Device dma timing */ -#define R4030_DMA_MODE_240NS 0x05 /* Device dma timing */ -#define R4030_DMA_MODE_280NS 0x06 /* Device dma timing */ -#define R4030_DMA_MODE_320NS 0x07 /* Device dma timing */ -#define R4030_DMA_MODE_8 0x08 /* Device 8 bit */ -#define R4030_DMA_MODE_16 0x10 /* Device 16 bit */ -#define R4030_DMA_MODE_32 0x18 /* Device 32 bit */ -#define R4030_DMA_MODE_INT 0x20 /* Interrupt when done */ -#define R4030_DMA_MODE_BURST 0x40 /* Burst mode (Rev 2 only) */ -#define R4030_DMA_MODE_FAST 0x80 /* Fast dma cycle (Rev 2 only) */ -#define R4030_DMA_MODE 0xff /* Mode register bits */ -#define DMA_DIR_WRITE 0x100 /* Software direction status */ -#define DMA_DIR_READ 0x000 /* Software direction status */ +#define R4030_DMA_MODE 0x00 +#define R4030_DMA_MODE_40NS 0x00 /* Device dma timing */ +#define R4030_DMA_MODE_80NS 0x01 /* Device dma timing */ +#define R4030_DMA_MODE_120NS 0x02 /* Device dma timing */ +#define R4030_DMA_MODE_160NS 0x03 /* Device dma timing */ +#define R4030_DMA_MODE_200NS 0x04 /* Device dma timing */ +#define R4030_DMA_MODE_240NS 0x05 /* Device dma timing */ +#define R4030_DMA_MODE_280NS 0x06 /* Device dma timing */ +#define R4030_DMA_MODE_320NS 0x07 /* Device dma timing */ +#define R4030_DMA_MODE_8 0x08 /* Device 8 bit */ +#define R4030_DMA_MODE_16 0x10 /* Device 16 bit */ +#define R4030_DMA_MODE_32 0x18 /* Device 32 bit */ +#define R4030_DMA_MODE_INT 0x20 /* Interrupt when done */ +#define R4030_DMA_MODE_BURST 0x40 /* Burst mode (Rev 2 only) */ +#define R4030_DMA_MODE_FAST 0x80 /* Fast dma cycle (Rev 2 only) */ + +#define R4030_DMA_ENAB 0x08 +#define R4030_DMA_ENAB_RUN 0x0001 /* Enable dma */ +#define R4030_DMA_ENAB_READ 0x0000 /* Read from device */ +#define R4030_DMA_ENAB_WRITE 0x0002 /* Write to device */ +#define R4030_DMA_ENAB_TC_IE 0x0100 /* Terminal count int enable */ +#define R4030_DMA_ENAB_ME_IE 0x0200 /* Memory error int enable */ +#define R4030_DMA_ENAB_TL_IE 0x0400 /* Translation limit int enable */ -#define R4030_DMA_ENAB_RUN 0x01 /* Enable dma */ -#define R4030_DMA_ENAB_READ 0x00 /* Read from device */ -#define R4030_DMA_ENAB_WRITE 0x02 /* Write to device */ -#define R4030_DMA_ENAB_TC_IE 0x100 /* Terminal count int enable */ -#define R4030_DMA_ENAB_ME_IE 0x200 /* Memory error int enable */ -#define R4030_DMA_ENAB_TL_IE 0x400 /* Translation limit int enable */ +#define R4030_DMA_COUNT 0x10 +#define R4030_DMA_COUNT_MASK 0x000fffff /* Byte count mask */ -#define R4030_DMA_COUNT_MASK 0x000fffff /* Byte count mask */ +#define R4030_DMA_ADDR 0x18 -/* - * Structure used to control dma. - */ - -typedef struct dma_softc { - struct device sc_dev; /* use as a device */ - struct esp_softc *sc_esp; - bus_addr_t dma_va; /* Viritual address for transfer */ - int mode; /* Mode register value and direction */ - jazz_dma_pte_t *pte_base; /* Pointer to dma tlb array */ - int pte_size; /* Size of pte allocated pte array */ - pDmaReg dma_reg; /* Pointer to dma registers */ - int sc_active; /* Active flag */ - void (*reset)(struct dma_softc *); /* Reset routine pointer */ - void (*enintr)(struct dma_softc *); /* Int enab routine pointer */ - void (*map)(struct dma_softc *, char *, size_t, int); - /* Map a dma viritual area */ - void (*start)(struct dma_softc *, caddr_t, size_t, int); - /* Start routine pointer */ - int (*isintr)(struct dma_softc *); /* Int check routine pointer */ - int (*intr)(struct dma_softc *); /* Interrupt routine pointer */ - void (*end)(struct dma_softc *); /* Interrupt routine pointer */ -} dma_softc_t; - -#define DMA_TO_DEV 0 -#define DMA_FROM_DEV 1 - -#define DMA_RESET(r) ((r->reset)(r)) -#define DMA_START(a, b, c, d) ((a->start)(a, b, c, d)) -#define DMA_MAP(a, b, c, d) ((a->map)(a, b, c, d)) -#define DMA_INTR(r) ((r->intr)(r)) -#define DMA_DRAIN(r) -#define DMA_END(r) ((r->end)(r)) - -void picaDmaInit __P((void)); -void picaDmaTLBAlloc __P((dma_softc_t *)); -void picaDmaTLBFree __P((dma_softc_t *)); -void picaDmaMap __P((struct dma_softc *, char *, size_t, int)); -void picaDmaStart __P((struct dma_softc *, char *, size_t, int)); -void picaDmaFlush __P((struct dma_softc *, char *, size_t, int)); -void asc_dma_init __P((struct dma_softc *)); -void fdc_dma_init __P((struct dma_softc *)); +#define R4030_DMA_RANGE 0x20 Index: jazz/fdc_jazzio.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/jazz/fdc_jazzio.c,v retrieving revision 1.5 diff -u -r1.5 fdc_jazzio.c --- jazz/fdc_jazzio.c 2002/12/28 16:25:39 1.5 +++ jazz/fdc_jazzio.c 2003/01/08 17:03:09 @@ -80,23 +80,15 @@ #include #include #include -#include -#include -#include - #include #include -#include -#include #include #include #include #include -#include "locators.h" - /* controller driver configuration */ int fdc_jazzio_probe(struct device *, struct cfdata *, void *); void fdc_jazzio_attach(struct device *, struct device *, void *); @@ -111,8 +103,11 @@ struct fdc_softc sc_fdc; /* base fdc device */ bus_space_handle_t sc_baseioh; /* base I/O handle */ - struct dma_softc __dma; - struct dma_softc *dma; + + bus_dma_tag_t sc_dmat; /* bus dma tag */ + bus_dmamap_t sc_dmamap; /* bus dma map */ + bus_space_handle_t sc_dmaioh; /* dma I/O handle */ + int sc_datain; /* data direction */ }; CFATTACH_DECL(fdc_jazzio, sizeof(struct fdc_jazzio_softc), @@ -175,13 +170,12 @@ fdc->sc_iot = ja->ja_bust; - fdc->sc_maxiosize = 4096; /* XXX */ + fdc->sc_maxiosize = MAXPHYS; fdc->sc_dma_start = fdc_jazzio_dma_start; fdc->sc_dma_abort = fdc_jazzio_dma_abort; fdc->sc_dma_done = fdc_jazzio_dma_done; - jsc->dma = &jsc->__dma; - fdc_dma_init(jsc->dma); + jsc->sc_dmat = ja->ja_dmat; if (bus_space_map(fdc->sc_iot, ja->ja_addr, FDC_OFFSET + FDC_NPORT, 0, &jsc->sc_baseioh)) { @@ -192,16 +186,32 @@ if (bus_space_subregion(fdc->sc_iot, jsc->sc_baseioh, FDC_OFFSET, FDC_NPORT, &fdc->sc_ioh)) { printf(": unable to subregion I/O space\n"); - bus_space_unmap(fdc->sc_iot, jsc->sc_baseioh, - FDC_OFFSET + FDC_NPORT); - return; + goto out_unmap1; } + if (bus_space_map(fdc->sc_iot, jazzio_conf->jc_fdcdmareg, + R4030_DMA_RANGE, 0, &jsc->sc_dmaioh)) { + printf(": unable to map dma I/O space\n"); + goto out_unmap1; + } + + if (bus_dmamap_create(jsc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0, + BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, &jsc->sc_dmamap)) { + printf(": unable to create DMA map\n"); + goto out_unmap2; + } + printf("\n"); jazzio_intr_establish(ja->ja_intr, fdcintr, fdc); fdcattach(fdc); + return; + + out_unmap2: + bus_space_unmap(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_RANGE); + out_unmap1: + bus_space_unmap(fdc->sc_iot, jsc->sc_baseioh, FDC_OFFSET + FDC_NPORT); } void @@ -213,8 +223,31 @@ { struct fdc_jazzio_softc *jsc = (void *)fdc; - mips_dcache_wbinv_range((vaddr_t)addr, (vsize_t)size); - DMA_START(jsc->dma, addr, size, datain ? DMA_FROM_DEV : DMA_TO_DEV); + /* halt DMA */ + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_MODE, 0); + + jsc->sc_datain = datain; + + bus_dmamap_load(jsc->sc_dmat, jsc->sc_dmamap, addr, size, NULL, + BUS_DMA_NOWAIT | BUS_DMA_STREAMING | + (datain ? BUS_DMA_READ : BUS_DMA_WRITE)); + bus_dmamap_sync(jsc->sc_dmat, jsc->sc_dmamap, + 0, jsc->sc_dmamap->dm_mapsize, + datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); + + /* load new transfer parameters */ + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, + R4030_DMA_ADDR, jsc->sc_dmamap->dm_segs[0].ds_addr); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, + R4030_DMA_COUNT, jsc->sc_dmamap->dm_segs[0].ds_len); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, + R4030_DMA_MODE, R4030_DMA_MODE_160NS | R4030_DMA_MODE_8); + + /* start DMA */ + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, + R4030_DMA_ENAB, R4030_DMA_ENAB_RUN | + (datain ? R4030_DMA_ENAB_READ : R4030_DMA_ENAB_WRITE)); } void @@ -223,7 +256,9 @@ { struct fdc_jazzio_softc *jsc = (void *)fdc; - DMA_RESET(jsc->dma); + /* halt DMA */ + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_MODE, 0); } void @@ -232,5 +267,13 @@ { struct fdc_jazzio_softc *jsc = (void *)fdc; - DMA_END(jsc->dma); + /* halt DMA */ + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_COUNT, 0); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_ENAB, 0); + bus_space_write_4(fdc->sc_iot, jsc->sc_dmaioh, R4030_DMA_MODE, 0); + + bus_dmamap_sync(jsc->sc_dmat, jsc->sc_dmamap, + 0, jsc->sc_dmamap->dm_mapsize, + jsc->sc_datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(jsc->sc_dmat, jsc->sc_dmamap); } Index: jazz/jazzio.c =================================================================== RCS file: /cvsroot/src/sys/arch/arc/jazz/jazzio.c,v retrieving revision 1.8 diff -u -r1.8 jazzio.c --- jazz/jazzio.c 2003/01/01 00:32:05 1.8 +++ jazz/jazzio.c 2003/01/08 17:03:09 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -145,8 +146,8 @@ sc->sc_bus.ab_dv = (struct device *)sc; - /* Initialize PICA Dma */ - picaDmaInit(); + /* Initialize jazzio dma mapping register area and pool */ + jazz_dmatlb_init(&jazzio_bus, jazzio_conf->jc_dmatlbreg); /* Create bus_dma_tag */ jazz_bus_dma_tag_init(&sc->sc_dmat);