Complete overhaul of WD33c93 SCSI driver

- Full support for SCSI-2 Tagged commands (enabled by default)
 - Implement save and restore datapointer messages
 - Formalize interface between MI and MD drivers.
 - decouple interface between MD driver and DMA routines
 - Use scsipi layer where appropriate (Tags, Sync Negotiations etc)
 - control blocks stored using kernel pool(9) functions
 - evcnt(9) compliant counters
 - Enable advanced features on later WD33c93 chips.
   (Identify message out phase is hardware assisted)
 - Improved timeout support (one per active control block)
 - Improved MESG_IN and MESG_OUT handling
 - Start to tidy up debugging output
 - Numerous bug fixes and cleanups throughout

Changes are based largely on the NCR53c9x MI driver for ideas on
how to DTRT.
This commit is contained in:
wdk 2001-11-10 07:32:42 +00:00
parent 9a07d795e3
commit de81761c50
5 changed files with 2346 additions and 2343 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: hpcdma.h,v 1.1 2001/08/19 03:16:21 wdk Exp $ */
/* $NetBSD: hpcdma.h,v 1.2 2001/11/10 07:32:42 wdk Exp $ */
/*
* Copyright (c) 2001 Wayne Knowles
@ -36,8 +36,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SGIMIPS_BUS_DMA_H
#define _SGIMIPS_BUS_DMA_H
#ifndef _SGIMIPS_HPC_DMA_H
#define _SGIMIPS_HPC_DMA_H
#include <machine/bus.h>
@ -47,13 +47,15 @@ struct hpc_dma_softc {
bus_dma_tag_t sc_dmat;
u_int32_t sc_flags;
#define HPC_DMA_ACTIVE 0x80
#define HPC_DMA_READ 0x20
#define HPCDMA_READ 0x20 /* direction of transfer */
#define HPCDMA_LOADED 0x40 /* bus_dmamap loaded */
#define HPCDMA_ACTIVE 0x80 /* DMA engine is busy */
u_int32_t sc_dmacmd;
int sc_ndesc;
bus_dmamap_t sc_dmamap;
struct hpc_dma_desc *sc_desc_kva; /* Virtual address */
struct hpc_dma_desc *sc_desc_pa; /* Physical address */
ssize_t sc_dlen; /* number of bytes transfered */
};
@ -62,4 +64,4 @@ void hpcdma_sglist_create(struct hpc_dma_softc *, bus_dmamap_t);
void hpcdma_cntl(struct hpc_dma_softc *, u_int32_t);
void hpcdma_flush(struct hpc_dma_softc *);
#endif
#endif /* _SGIMIPS_HPC_DMA_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbicreg.h,v 1.1 2001/08/19 03:16:22 wdk Exp $ */
/* $NetBSD: sbicreg.h,v 1.2 2001/11/10 07:32:42 wdk Exp $ */
/*
* Copyright (c) 2001 Wayne Knowles
@ -84,6 +84,9 @@
#define SBIC_csr 23
#define SBIC_cmd 24
#define SBIC_data 25
#define SBIC_queue_tag 26
#define SBIC_aux_status 27
/* sbic_asr is addressed directly */
/*
@ -107,9 +110,10 @@
*/
#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */
/* 11 Mhz is invalid */
/* 11 Mhz is invalid */
#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */
#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */
#define SBIC_ID_RAF 0x20 /* */
#define SBIC_ID_EHP 0x10 /* Enable host parity */
#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */
#define SBIC_ID_MASK 0x07
@ -304,6 +308,21 @@
#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */
#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */
#define PHASE_MASK 0x07 /* mask for psns/pctl phase */
#define DATA_OUT_PHASE 0x00
#define DATA_IN_PHASE 0x01
#define CMD_PHASE 0x02
#define STATUS_PHASE 0x03
#define BUS_FREE_PHASE 0x04
#define ARB_SEL_PHASE 0x05 /* Fuji chip combines bus arb with sel. */
#define MESG_OUT_PHASE 0x06
#define MESG_IN_PHASE 0x07
#define SCSI_PHASE(reg) ((reg) & PHASE_MASK)
#define SCSI_STATUS_MASK 0x3e /* Mask unused bits in status byte */
/* approximate, but we won't do SBT on selects */
#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
@ -387,6 +406,8 @@ typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
#define GET_SBIC_cmd(sc,val) sbic_read_reg(sc,SBIC_cmd,val)
#define SET_SBIC_data(sc,val) sbic_write_reg(sc,SBIC_data,val)
#define GET_SBIC_data(sc,val) sbic_read_reg(sc,SBIC_data,val)
#define SET_SBIC_queue_tag(sc,val) sbic_write_reg(sc,SBIC_queue_tag,val)
#define GET_SBIC_queue_tag(sc,val) sbic_read_reg(sc,SBIC_queue_tag,val)
#define SBIC_TC_PUT(sc,val) \
do { \
@ -411,12 +432,12 @@ typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
int n = (cmdsize) - 1; \
char *ptr = (char *)(cmd); \
sbic_write_reg(regs, SBIC_cdb1, *ptr++); \
while(n-- > 0) /* (regs)->sbic_value = *ptr++; */ \
while(n-- > 0) \
bus_space_write_1((sc)->sc_regt, (sc)->sc_regh, \
SBIC_VAL, *ptr++); /* XXX write_multi */ \
} while (0)
#define GET_SBIC_asr(sc,val) /* (val) = (regs)->sbic_asr */ \
#define GET_SBIC_asr(sc,val) \
do { \
(val) = bus_space_read_1((sc)->sc_regt,(sc)->sc_regh,SBIC_ASR); \
} while (0)
@ -424,7 +445,6 @@ typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
#define WAIT_CIP(sc) \
do { \
/* while ((regs)->sbic_asr & SBIC_ASR_CIP) */ \
while (bus_space_read_1((sc)->sc_regt,(sc)->sc_regh, \
SBIC_ASR) & SBIC_ASR_CIP) \
/*nop*/; \
@ -432,7 +452,7 @@ typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
/*
* transmit a byte in programmed I/O mode
**/
*/
#define SEND_BYTE(sc, ch) \
do { \
WAIT_CIP(sc); \

View File

@ -1,4 +1,4 @@
/* $NetBSD: sbicvar.h,v 1.1 2001/08/19 03:16:22 wdk Exp $ */
/* $NetBSD: sbicvar.h,v 1.2 2001/11/10 07:32:43 wdk Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@ -42,37 +42,43 @@
#include <sys/callout.h>
#include <sys/malloc.h>
/*
* DMA chains are used for Scatter-Gather DMA.
*/
struct dma_chain {
int dc_count;
char *dc_addr;
};
#define SBIC_NTARG 8
#define SBIC_NLUN 8
#define SBIC_NTAGS 256
#define SBIC_MAX_MSGLEN 8
#define SBIC_ABORT_TIMEOUT 2000 /* time to wait for abort */
#define SBIC_SENSE_TIMEOUT 1000 /* time to wait for sense */
/*
* ACB. Holds additional information for each SCSI command Comments: We
* need a separate scsi command block because we may need to overwrite it
* with a request sense command. Basicly, we refrain from fiddling with
* with a request sense command. Basically, we refrain from fiddling with
* the scsi_xfer struct (except do the expected updating of return values).
* We'll generally update: xs->{flags,resid,error,sense,status} and
* occasionally xs->retries.
*/
struct sbic_acb {
TAILQ_ENTRY(sbic_acb) chain;
struct scsipi_xfer *xs; /* SCSI xfer ctrl block from above */
int flags; /* Status */
#define ACB_FREE 0x00
#define ACB_ACTIVE 0x01
#define ACB_DONE 0x04
#define ACB_BBUF 0x10 /* DMA input needs to be copied from bounce */
#define ACB_DATAIN 0x20 /* DMA direction flag */
TAILQ_ENTRY(sbic_acb) chain;
struct scsipi_xfer *xs; /* SCSI xfer ctrl block from above */
int flags; /* Status */
#define ACB_FREE 0x00
#define ACB_ACTIVE 0x01
#define ACB_READY 0x02 /* ACB is on ready list */
#define ACB_DONE 0x04
#define ACB_SENSE 0x08 /* ACB Requesting sense */
#define ACB_COMPLETE 0x10 /* Disconnected at end of xfer */
#define ACB_RESET 0x20 /* Require Reset */
#define ACB_ABORT 0x40 /* Require Abort */
struct scsi_generic cmd; /* SCSI command block */
int clen;
struct dma_chain sc_kv; /* Virtual address of whole DMA */
u_long sc_tcnt; /* number of bytes for this DMA */
u_short sc_usedma; /* Internal data for this DMA */
int timeout;
struct scsi_generic cmd; /* SCSI command block */
int clen;
char *daddr; /* kva for data */
size_t dleft; /* bytes remaining */
u_char tag_type; /* TAG Type (0x20-0x22, 0=No Tags) */
u_char tag_id; /* TAG id number */
};
/*
@ -80,127 +86,173 @@ struct sbic_acb {
* probably have been a "per target+lunit" structure, but we'll leave it at
* this for now. Is there a way to reliably hook it up to sc->fordriver??
*/
struct sbic_tinfo {
int cmds; /* #commands processed */
int dconns; /* #disconnects */
int lubusy; /* What local units/subr. are busy? */
} tinfo_t;
struct sbic_softc {
struct device sc_dev;
struct target_sync {
u_char state;
u_char period;
u_char offset;
} sc_sync[8];
u_char target; /* Currently active target */
u_char lun;
struct scsipi_channel sc_channel; /* proto for sub devices */
struct scsipi_adapter sc_adapter;
/* HPC registers */
bus_space_tag_t sc_hpct;
bus_space_handle_t sc_hpch;
/* HPC external ethernet registers: aka Seeq 8003 registers */
bus_space_tag_t sc_regt;
bus_space_handle_t sc_regh;
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmamap; /* DMA Map for this transfer */
void *sc_driver; /* driver specific field */
struct callout sc_timo_ch;
/* Lists of command blocks */
TAILQ_HEAD(acb_list, sbic_acb) free_list,
ready_list,
nexus_list;
struct sbic_acb *sc_nexus; /* current command */
struct sbic_acb sc_acb[8]; /* the real command blocks */
struct sbic_tinfo sc_tinfo[8];
struct scsipi_xfer *sc_xs; /* transfer from high level code */
u_int32_t sc_flags;
u_char sc_stat[2];
u_char sc_msg[7];
u_long sc_clkfreq;
u_long sc_tcnt; /* number of bytes transfered */
u_short sc_usedma; /* used by dma drivers */
#ifdef DEBUG
u_short sc_dmatimo; /* dma timeout */
#endif
int (*sc_dmasetup) __P((struct sbic_softc *, bus_dmamap_t, int));
int (*sc_dmago) __P((struct sbic_softc *));
void (*sc_enintr) __P((struct sbic_softc *));
void (*sc_dmastop) __P((struct sbic_softc *));
struct sbic_linfo {
LIST_ENTRY(sbic_linfo) link;
time_t last_used;
int lun;
int used; /* # slots in use */
int avail; /* where to start scanning */
u_char state;
#define L_STATE_IDLE 0
#define L_STATE_BUSY 1
#define L_STATE_ESTAT 2
struct sbic_acb *untagged;
struct sbic_acb *queued[SBIC_NTAGS];
};
/*
* sc_flags
*/
#define SBICF_ALIVE 0x01 /* controller initialized */
#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */
#define SBICF_SELECTED 0x04 /* bus is in selected state. */
#define SBICF_ICMD 0x08 /* Immediate command in execution */
#define SBICF_BADDMA 0x10 /* controller can only DMA */
#define SBICF_DMALOADED 0x20 /* bus_dmamap loaded */
#define SBICF_INTR 0x40 /* SBICF interrupt expected */
#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */
struct sbic_tinfo {
int cmds; /* # of commands processed */
int dconns; /* # of disconnects */
/*
* sync states
*/
#define SYNC_START 0 /* no sync handshake started */
#define SYNC_SENT 1 /* we sent sync request, no answer yet */
#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
or it rejected the request and we stay async */
u_char flags;
#define T_NEED_RESET 0x01 /* Should send a BUS_DEV_RESET */
#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */
#define T_BUSY 0x04 /* Target is busy */
#define T_SYNCMODE 0x08 /* SYNC mode has been negotiated */
#define T_NOSYNC 0x10 /* Force ASYNC mode */
#define T_NODISC 0x20 /* Don't allow disconnect */
#define T_TAG 0x40 /* Turn on TAG QUEUEs */
u_char period; /* Period suggestion */
u_char offset; /* Offset suggestion */
u_char nextag; /* Next available tag */
struct sbic_linfo *lun[SBIC_NLUN]; /* LUN list for this target */
} tinfo_t;
#define PHASE 0x07 /* mask for psns/pctl phase */
#define DATA_OUT_PHASE 0x00
#define DATA_IN_PHASE 0x01
#define CMD_PHASE 0x02
#define STATUS_PHASE 0x03
#define BUS_FREE_PHASE 0x04
#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */
#define MESG_OUT_PHASE 0x06
#define MESG_IN_PHASE 0x07
/* Look up a lun in a tinfo */
#define TINFO_LUN(t, l) ((t)->lun[(l)])
#define MSG_CMD_COMPLETE 0x00
#define MSG_EXT_MESSAGE 0x01
#define MSG_SAVE_DATA_PTR 0x02
#define MSG_RESTORE_PTR 0x03
#define MSG_DISCONNECT 0x04
#define MSG_INIT_DETECT_ERROR 0x05
#define MSG_ABORT 0x06
#define MSG_REJECT 0x07
#define MSG_NOOP 0x08
#define MSG_PARITY_ERROR 0x09
#define MSG_BUS_DEVICE_RESET 0x0C
#define MSG_IDENTIFY 0x80
#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
#define MSG_SYNC_REQ 0x01
struct sbic_softc {
struct device sc_dev;
#define MSG_ISIDENTIFY(x) ((x) & MSG_IDENTIFY)
struct scsipi_channel sc_channel; /* proto for sub devices */
struct scsipi_adapter sc_adapter;
struct device *sc_child; /* attached scsibus, if any */
struct callout sc_watchdog;
void *sc_driver; /* driver specific field */
int target; /* Currently active target */
int lun; /* Currently active LUN */
/* WD33c93 registers */
bus_space_tag_t sc_regt;
bus_space_handle_t sc_regh;
#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
#define STS_BUSY 0x08
#define STS_INTERMED 0x10 /* Intermediate status sent */
#define STS_EXT 0x80 /* Extended status valid */
/* Data about the current nexus (updated for every cmd switch) */
caddr_t sc_daddr; /* Current data pointer */
size_t sc_dleft; /* Data left to transfer */
ssize_t sc_tcnt; /* number of bytes transfered */
/* Lists of command blocks */
TAILQ_HEAD(acb_list, sbic_acb) ready_list;
struct sbic_acb *sc_nexus; /* current command */
struct sbic_tinfo sc_tinfo[8];
u_short sc_state;
u_short sc_status;
int sc_disc; /* current # of active nexus's */
int sc_flags;
/* Message stuff */
u_short sc_msgify; /* Last IDENTIFY message */
u_short sc_msgout; /* Current message out */
u_short sc_msgpriq; /* mesg_out queue (bitmap) */
u_short sc_msgoutq; /* mesg_out queue */
u_char sc_imsg[SBIC_MAX_MSGLEN];
u_char sc_omsg[SBIC_MAX_MSGLEN];
u_char sc_imsglen;
u_char sc_omsglen;
/* Static hardware attributes */
int sc_id; /* SCSI ID for controller */
int sc_clkfreq; /* wd33c93 clk freq * 10Mhz */
int sc_chip; /* Chip variation */
int sc_rev; /* Chip revision */
int sc_cfflags; /* Copy of config flags */
int sc_maxxfer; /* Maximum transfer size */
int sc_minsync; /* Minimum sync period (4ns units) */
int sc_maxoffset; /* Maximum sync ofset (bytes) */
int (*sc_dmasetup) __P((struct sbic_softc *,caddr_t *,
size_t *,int,size_t *));
int (*sc_dmago) __P((struct sbic_softc *));
void (*sc_dmastop) __P((struct sbic_softc *));
};
/* values for sc_flags */
#define SBICF_SELECTED 0x01 /* bus is in selected state. */
#define SBICF_NODMA 0x02 /* Polled transfer */
#define SBICF_INDMA 0x04 /* DMA I/O in progress */
#define SBICF_SYNCNEGO 0x08 /* Sync negotiation in progress */
#define SBICF_ABORTING 0x10 /* Aborting */
/* values for sc_state */
#define SBIC_UNINITIALIZED 0 /* Driver not initialized */
#define SBIC_IDLE 1 /* waiting for something to do */
#define SBIC_SELECTING 2 /* SCSI command is arbiting */
#define SBIC_RESELECTED 3 /* Has been reselected */
#define SBIC_IDENTIFIED 4 /* Has gotten IFY but not TAG */
#define SBIC_CONNECTED 5 /* Actively using the SCSI bus */
#define SBIC_DISCONNECT 6 /* MSG_DISCONNECT received */
#define SBIC_CMDCOMPLETE 7 /* MSG_CMDCOMPLETE received */
#define SBIC_ERROR 8 /* Error has occured */
#define SBIC_SELTIMEOUT 9 /* Select Timeout */
#define SBIC_CLEANING 10 /* Scrubbing ACB's */
#define SBIC_BUSRESET 11 /* SCSI RST has been issued */
/* values for sc_msgout */
#define SEND_DEV_RESET 0x0001
#define SEND_PARITY_ERROR 0x0002
#define SEND_INIT_DET_ERR 0x0004
#define SEND_REJECT 0x0008
#define SEND_IDENTIFY 0x0010
#define SEND_ABORT 0x0020
#define SEND_WDTR 0x0040
#define SEND_SDTR 0x0080
#define SEND_TAG 0x0100
/* WD33c93 chipset revisions - values for sc_rev */
#define SBIC_CHIP_UNKNOWN 0
#define SBIC_CHIP_WD33C93 1
#define SBIC_CHIP_WD33C93A 2
#define SBIC_CHIP_WD33C93B 3
#define SBIC_CHIP_LIST {"UNKNOWN", "WD33C93", "WD33C93A", "WD33C93B"}
/*
* States returned by our state machine
*/
#define SBIC_STATE_ERROR -1
#define SBIC_STATE_DONE 0
#define SBIC_STATE_RUNNING 1
#define SBIC_STATE_DISCONNECT 2
#define SBIC_STATE_ERROR -1
#define SBIC_STATE_DONE 0
#define SBIC_STATE_RUNNING 1
#define SBIC_STATE_DISCONNECT 2
#define DEBUG_ACBS 0x01
#define DEBUG_INTS 0x02
#define DEBUG_CMDS 0x04
#define DEBUG_MISC 0x08
#define DEBUG_TRAC 0x10
#define DEBUG_RSEL 0x20
#define DEBUG_PHASE 0x40
#define DEBUG_DMA 0x80
#define DEBUG_CCMDS 0x100
#define DEBUG_MSGS 0x200
#define DEBUG_TAGS 0x400
#define DEBUG_SYNC 0x800
#ifdef DEBUG
extern int sbic_debug_flags;
#define SBIC_DEBUG(level, str) \
do { \
if (sbic_debug & __CONCAT(DEBUG_,level)) \
printf str; \
} while (0)
#else
#define SBIC_DEBUG(level, str)
#endif
struct buf;
struct scsipi_xfer;
@ -208,7 +260,7 @@ struct scsipi_xfer;
void sbic_minphys __P((struct buf *bp));
void sbic_scsi_request __P((struct scsipi_channel *,
scsipi_adapter_req_t, void *));
void sbicinit __P((struct sbic_softc *));
int sbicintr __P((struct sbic_softc *));
void sbic_attach __P((struct sbic_softc *));
int sbic_intr __P((struct sbic_softc *));
#endif /* _SBICVAR_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdsc.c,v 1.1 2001/08/19 03:16:22 wdk Exp $ */
/* $NetBSD: wdsc.c,v 1.2 2001/11/10 07:32:43 wdk Exp $ */
/*
* Copyright (c) 2001 Wayne Knowles
@ -38,13 +38,7 @@
/*
* TODO:
*
* Support for 2nd SCSI controller
* evcnt(9) hooks
* remove struct dma_chain
* dma{setup,stop,go} API similar to NCR93c9x MI driver
* improve hpcdma functions
* cleanup softc stuff
*/
#include <sys/param.h>
@ -68,9 +62,17 @@
#include <sgimips/hpc/sbicreg.h>
#include <sgimips/hpc/sbicvar.h>
#include <opt_kgdb.h>
#include <sys/kgdb.h>
struct wdsc_softc {
struct sbic_softc sc_sbic; /* Must be first */
struct evcnt sc_intrcnt; /* Interrupt counter */
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmamap;
int sc_flags;
#define WDSC_DMA_ACTIVE 0x1
#define WDSC_DMA_MAPLOADED 0x2
struct hpc_dma_softc sc_hpcdma;
};
@ -84,8 +86,8 @@ struct cfattach wdsc_ca = {
extern struct cfdriver wdsc_cd;
void wdsc_enintr __P((struct sbic_softc *));
int wdsc_dmasetup __P((struct sbic_softc *, bus_dmamap_t, int));
int wdsc_dmasetup __P((struct sbic_softc *, caddr_t *,size_t *,
int, size_t *));
int wdsc_dmago __P((struct sbic_softc *));
void wdsc_dmastop __P((struct sbic_softc *));
int wdsc_dmaintr __P((void *));
@ -101,15 +103,15 @@ int wdsc_scsiintr __P((void *));
*/
int
wdsc_match(pdp, cf, auxp)
struct device *pdp;
struct cfdata *cf;
void *auxp;
struct device *pdp;
struct cfdata *cf;
void *auxp;
{
struct hpc_attach_args *haa = auxp;
struct hpc_attach_args *haa = auxp;
if (strcmp(haa->ha_name, wdsc_cd.cd_name))
return (0);
return (1);
if (strcmp(haa->ha_name, wdsc_cd.cd_name))
return (0);
return (1);
}
/*
@ -117,134 +119,102 @@ wdsc_match(pdp, cf, auxp)
*/
void
wdsc_attach(pdp, dp, auxp)
struct device *pdp, *dp;
void *auxp;
struct device *pdp, *dp;
void *auxp;
{
struct sbic_softc *sc = (void *)dp;
struct wdsc_softc *wdsc = (void *)dp;
struct hpc_attach_args *haa = auxp;
int err;
struct sbic_softc *sc = (void *)dp;
struct wdsc_softc *wsc = (void *)dp;
struct hpc_attach_args *haa = auxp;
int err;
sc->sc_regt = haa->ha_iot;
sc->sc_dmat = haa->ha_dmat;
sc->sc_regt = haa->ha_iot;
wsc->sc_dmat = haa->ha_dmat;
if ((err = bus_space_subregion(haa->ha_iot, haa->ha_ioh,
if ((err = bus_space_subregion(haa->ha_iot, haa->ha_ioh,
HPC_SCSI0_DEVREGS,
HPC_SCSI0_DEVREGS_SIZE,
&sc->sc_regh)) != 0) {
printf(": unable to map WD33C93 regs, err=%d\n", err);
goto fail;
}
printf(": unable to map regs, err=%d\n", err);
return;
}
if (bus_dmamap_create(sc->sc_dmat, MAX_DMA_SZ,
if (bus_dmamap_create(wsc->sc_dmat, MAX_DMA_SZ,
DMA_SEGS, MAX_SEG_SZ, MAX_SEG_SZ,
BUS_DMA_WAITOK,
&sc->sc_dmamap) != 0) {
&wsc->sc_dmamap) != 0) {
printf(": failed to create dmamap\n");
goto fail;
}
return;
}
hpcdma_init(haa, &wdsc->sc_hpcdma, DMA_SEGS);
sc->sc_dmasetup = wdsc_dmasetup;
sc->sc_dmago = wdsc_dmago;
sc->sc_dmastop = wdsc_dmastop;
sc->sc_enintr = wdsc_enintr;
sc->sc_dmasetup = wdsc_dmasetup;
sc->sc_dmago = wdsc_dmago;
sc->sc_dmastop = wdsc_dmastop;
sc->sc_adapter.adapt_request = sbic_scsi_request;
sc->sc_adapter.adapt_minphys = minphys;
sc->sc_adapter.adapt_dev = &sc->sc_dev;
sc->sc_adapter.adapt_nchannels = 1;
sc->sc_adapter.adapt_openings = 7;
sc->sc_adapter.adapt_max_periph = 1;
sc->sc_adapter.adapt_ioctl = NULL;
sc->sc_adapter.adapt_minphys = minphys;
sc->sc_adapter.adapt_request = sbic_scsi_request;
sc->sc_channel.chan_adapter = &sc->sc_adapter;
sc->sc_channel.chan_bustype = &scsi_bustype;
sc->sc_channel.chan_channel = 0;
sc->sc_channel.chan_ntargets = 8;
sc->sc_channel.chan_nluns = 8;
sc->sc_channel.chan_id = 7;
sc->sc_id = 7; /* Host ID = 7 */
sc->sc_clkfreq = 200; /* 20MHz Clock */
printf(": WD33C93 SCSI, target %d\n", sc->sc_channel.chan_id);
evcnt_attach_dynamic(&wsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
sc->sc_dev.dv_xname, "intr");
/*
* Controller clock frequency * 10
*/
sc->sc_clkfreq = 200;
/*
* Initialise the hardware
*/
sbicinit(sc);
/* XXX: 1 = IRQ_LOCAL0 + 1 */
if ((cpu_intr_establish(1, IPL_BIO, wdsc_scsiintr, sc)) == NULL) {
/* XXX: 1 = IRQ_LOCAL0 + 1 */
if ((cpu_intr_establish(1, IPL_BIO, wdsc_scsiintr, sc)) == NULL) {
printf(": unable to establish interrupt!\n");
goto fail;
}
return;
}
(void)config_found(dp, &sc->sc_channel, scsiprint);
fail:
return;
}
/*
* Enable DMA interrupts
*/
void
wdsc_enintr(dev)
struct sbic_softc *dev;
{
dev->sc_flags |= SBICF_INTR;
hpcdma_init(haa, &wsc->sc_hpcdma, DMA_SEGS);
sbic_attach(sc);
return;
}
/*
* Prime the hardware for a DMA transfer
*
* Requires splbio() interrupts to be disabled by the caller
*/
int
wdsc_dmasetup(dev, dmamap, flags)
struct sbic_softc *dev;
bus_dmamap_t dmamap;
int flags;
wdsc_dmasetup(dev, addr, len, datain, dmasize)
struct sbic_softc *dev;
caddr_t *addr;
size_t *len;
int datain;
size_t *dmasize;
{
struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma;
struct sbic_acb *acb = dev->sc_nexus;
int s;
int count, err;
void *vaddr;
struct wdsc_softc *wsc = (void *)dev;
struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
int count, err;
void *vaddr;
KASSERT((dsc->sc_flags & HPC_DMA_ACTIVE) == 0);
KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
vaddr = acb->sc_kv.dc_addr;
count = acb->sc_kv.dc_count;
vaddr = *addr;
count = dsc->sc_dlen = *len;
if (count) {
KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0);
if (count) {
s = splbio();
/* have dmamap for the transfering addresses */
if ((err=bus_dmamap_load(dev->sc_dmat, dev->sc_dmamap,
/* Build list of physical addresses for this transfer */
if ((err=bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap,
vaddr, count,
NULL /* kernel address */,
BUS_DMA_NOWAIT)) != 0)
panic("%s: bus_dmamap_load err=%d",
dev->sc_dev.dv_xname, err);
dev->sc_flags |= SBICF_DMALOADED; /* XXX - Move to MD */
dev->sc_flags |= SBICF_INTR;
panic("%s: bus_dmamap_load err=%d",
dev->sc_dev.dv_xname, err);
hpcdma_sglist_create(dsc, dev->sc_dmamap);
hpcdma_sglist_create(dsc, wsc->sc_dmamap);
wsc->sc_flags |= WDSC_DMA_MAPLOADED;
dsc->sc_dmacmd = HPC_DMACTL_ACTIVE; /* XXX - remove tests in MI */
if (flags & ACB_DATAIN) {
dsc->sc_flags |= HPC_DMA_READ;
} else {
dsc->sc_dmacmd |= HPC_DMACTL_DIR;
dsc->sc_flags &= ~HPC_DMA_READ;
}
splx(s);
}
return(count);
if (datain) {
dsc->sc_dmacmd = HPC_DMACTL_ACTIVE;
dsc->sc_flags |= HPCDMA_READ;
} else {
dsc->sc_dmacmd = HPC_DMACTL_ACTIVE | HPC_DMACTL_DIR;
dsc->sc_flags &= ~HPCDMA_READ;
}
}
return(count);
}
/*
@ -252,57 +222,64 @@ wdsc_dmasetup(dev, dmamap, flags)
*/
int
wdsc_dmago(dev)
struct sbic_softc *dev;
struct sbic_softc *dev;
{
struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma;
struct wdsc_softc *wsc = (void *)dev;
struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
if (dev->sc_tcnt == 0) {
return(0);
}
if (dsc->sc_dlen == 0)
return(0);
KASSERT((dsc->sc_flags & HPC_DMA_ACTIVE) == 0);
dsc->sc_flags |= HPC_DMA_ACTIVE;
KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0);
KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED));
bus_dmamap_sync(dev->sc_dmat, dev->sc_dmamap, 0, dev->sc_tcnt,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
wsc->sc_flags |= WDSC_DMA_ACTIVE;
hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */
bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, 0,
wsc->sc_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
return(dev->sc_dmamap->dm_mapsize);
hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */
return(wsc->sc_dmamap->dm_mapsize);
}
/*
* Stop DMA, and disable interrupts
* Stop DMA and unload active DMA maps
*/
void
wdsc_dmastop(dev)
struct sbic_softc *dev;
struct sbic_softc *dev;
{
struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma;
struct wdsc_softc *wsc = (void *)dev;
struct hpc_dma_softc *dsc = &wsc->sc_hpcdma;
if (dsc->sc_flags & HPC_DMA_ACTIVE) {
if (dsc->sc_flags & HPC_DMA_READ)
hpcdma_flush(dsc);
hpcdma_cntl(dsc, 0); /* Stop DMA */
bus_dmamap_sync(dev->sc_dmat, dev->sc_dmamap, 0,
dev->sc_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
dsc->sc_flags &= ~HPC_DMA_ACTIVE;
}
if (dev->sc_flags & SBICF_DMALOADED)
bus_dmamap_unload(dev->sc_dmat, dev->sc_dmamap);
if (wsc->sc_flags & WDSC_DMA_ACTIVE) {
if (dsc->sc_flags & HPCDMA_READ)
hpcdma_flush(dsc);
hpcdma_cntl(dsc, 0); /* Stop DMA */
bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, 0,
wsc->sc_dmamap->dm_mapsize,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
}
if (wsc->sc_flags & WDSC_DMA_MAPLOADED)
bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap);
wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED);
}
/*
* SCSI controller interrupt
* WD33c93 SCSI controller interrupt
*/
int
wdsc_scsiintr(arg)
void *arg;
void *arg;
{
struct sbic_softc *dev = arg;
int found;
struct sbic_softc *dev = arg;
struct wdsc_softc *wsc = arg;
int found;
found = sbicintr(dev);
return(found);
found = sbic_intr(dev);
if (found)
wsc->sc_intrcnt.ev_count++;
return(found);
}