1 /* $NetBSD: wdsc.c,v 1.1 2001/08/19 03:16:22 wdk Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Wayne Knowles 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wayne Knowles 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * TODO: 41 * 42 * Support for 2nd SCSI controller 43 * evcnt(9) hooks 44 * remove struct dma_chain 45 * dma{setup,stop,go} API similar to NCR93c9x MI driver 46 * improve hpcdma functions 47 * cleanup softc stuff 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/kernel.h> 53 #include <sys/device.h> 54 #include <sys/buf.h> 55 56 #include <dev/scsipi/scsi_all.h> 57 #include <dev/scsipi/scsipi_all.h> 58 #include <dev/scsipi/scsiconf.h> 59 60 #include <machine/cpu.h> 61 #include <machine/bus.h> 62 #include <machine/autoconf.h> 63 64 #include <sgimips/hpc/hpcvar.h> 65 #include <sgimips/hpc/hpcreg.h> 66 #include <sgimips/hpc/hpcdma.h> 67 68 #include <sgimips/hpc/sbicreg.h> 69 #include <sgimips/hpc/sbicvar.h> 70 71 struct wdsc_softc { 72 struct sbic_softc sc_sbic; /* Must be first */ 73 74 struct hpc_dma_softc sc_hpcdma; 75 }; 76 77 78 void wdsc_attach __P((struct device *, struct device *, void *)); 79 int wdsc_match __P((struct device *, struct cfdata *, void *)); 80 81 struct cfattach wdsc_ca = { 82 sizeof(struct wdsc_softc), wdsc_match, wdsc_attach 83 }; 84 85 extern struct cfdriver wdsc_cd; 86 87 void wdsc_enintr __P((struct sbic_softc *)); 88 int wdsc_dmasetup __P((struct sbic_softc *, bus_dmamap_t, int)); 89 int wdsc_dmago __P((struct sbic_softc *)); 90 void wdsc_dmastop __P((struct sbic_softc *)); 91 int wdsc_dmaintr __P((void *)); 92 int wdsc_scsiintr __P((void *)); 93 94 #define MAX_SCSI_XFER (512*1024) 95 #define MAX_SEG_SZ 8192 96 #define MAX_DMA_SZ MAX_SCSI_XFER 97 #define DMA_SEGS (MAX_DMA_SZ/MAX_SEG_SZ) 98 99 /* 100 * Match for SCSI devices on the onboard WD33C93 chip 101 */ 102 int 103 wdsc_match(pdp, cf, auxp) 104 struct device *pdp; 105 struct cfdata *cf; 106 void *auxp; 107 { 108 struct hpc_attach_args *haa = auxp; 109 110 if (strcmp(haa->ha_name, wdsc_cd.cd_name)) 111 return (0); 112 return (1); 113 } 114 115 /* 116 * Attach the wdsc driver 117 */ 118 void 119 wdsc_attach(pdp, dp, auxp) 120 struct device *pdp, *dp; 121 void *auxp; 122 { 123 struct sbic_softc *sc = (void *)dp; 124 struct wdsc_softc *wdsc = (void *)dp; 125 struct hpc_attach_args *haa = auxp; 126 int err; 127 128 sc->sc_regt = haa->ha_iot; 129 sc->sc_dmat = haa->ha_dmat; 130 131 if ((err = bus_space_subregion(haa->ha_iot, haa->ha_ioh, 132 HPC_SCSI0_DEVREGS, 133 HPC_SCSI0_DEVREGS_SIZE, 134 &sc->sc_regh)) != 0) { 135 printf(": unable to map WD33C93 regs, err=%d\n", err); 136 goto fail; 137 } 138 139 if (bus_dmamap_create(sc->sc_dmat, MAX_DMA_SZ, 140 DMA_SEGS, MAX_SEG_SZ, MAX_SEG_SZ, 141 BUS_DMA_WAITOK, 142 &sc->sc_dmamap) != 0) { 143 printf(": failed to create dmamap\n"); 144 goto fail; 145 } 146 147 hpcdma_init(haa, &wdsc->sc_hpcdma, DMA_SEGS); 148 149 sc->sc_enintr = wdsc_enintr; 150 sc->sc_dmasetup = wdsc_dmasetup; 151 sc->sc_dmago = wdsc_dmago; 152 sc->sc_dmastop = wdsc_dmastop; 153 154 sc->sc_adapter.adapt_dev = &sc->sc_dev; 155 sc->sc_adapter.adapt_nchannels = 1; 156 sc->sc_adapter.adapt_openings = 7; 157 sc->sc_adapter.adapt_max_periph = 1; 158 sc->sc_adapter.adapt_ioctl = NULL; 159 sc->sc_adapter.adapt_minphys = minphys; 160 sc->sc_adapter.adapt_request = sbic_scsi_request; 161 sc->sc_channel.chan_adapter = &sc->sc_adapter; 162 sc->sc_channel.chan_bustype = &scsi_bustype; 163 sc->sc_channel.chan_channel = 0; 164 sc->sc_channel.chan_ntargets = 8; 165 sc->sc_channel.chan_nluns = 8; 166 sc->sc_channel.chan_id = 7; 167 168 printf(": WD33C93 SCSI, target %d\n", sc->sc_channel.chan_id); 169 170 /* 171 * Controller clock frequency * 10 172 */ 173 sc->sc_clkfreq = 200; 174 175 /* 176 * Initialise the hardware 177 */ 178 sbicinit(sc); 179 180 /* XXX: 1 = IRQ_LOCAL0 + 1 */ 181 if ((cpu_intr_establish(1, IPL_BIO, wdsc_scsiintr, sc)) == NULL) { 182 printf(": unable to establish interrupt!\n"); 183 goto fail; 184 } 185 186 (void)config_found(dp, &sc->sc_channel, scsiprint); 187 188 fail: 189 return; 190 } 191 192 /* 193 * Enable DMA interrupts 194 */ 195 void 196 wdsc_enintr(dev) 197 struct sbic_softc *dev; 198 { 199 dev->sc_flags |= SBICF_INTR; 200 } 201 202 /* 203 * Prime the hardware for a DMA transfer 204 */ 205 int 206 wdsc_dmasetup(dev, dmamap, flags) 207 struct sbic_softc *dev; 208 bus_dmamap_t dmamap; 209 int flags; 210 { 211 struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma; 212 struct sbic_acb *acb = dev->sc_nexus; 213 int s; 214 int count, err; 215 void *vaddr; 216 217 KASSERT((dsc->sc_flags & HPC_DMA_ACTIVE) == 0); 218 219 vaddr = acb->sc_kv.dc_addr; 220 count = acb->sc_kv.dc_count; 221 222 if (count) { 223 s = splbio(); 224 225 /* have dmamap for the transfering addresses */ 226 if ((err=bus_dmamap_load(dev->sc_dmat, dev->sc_dmamap, 227 vaddr, count, 228 NULL /* kernel address */, 229 BUS_DMA_NOWAIT)) != 0) 230 panic("%s: bus_dmamap_load err=%d", 231 dev->sc_dev.dv_xname, err); 232 233 dev->sc_flags |= SBICF_DMALOADED; /* XXX - Move to MD */ 234 dev->sc_flags |= SBICF_INTR; 235 236 hpcdma_sglist_create(dsc, dev->sc_dmamap); 237 238 dsc->sc_dmacmd = HPC_DMACTL_ACTIVE; /* XXX - remove tests in MI */ 239 if (flags & ACB_DATAIN) { 240 dsc->sc_flags |= HPC_DMA_READ; 241 } else { 242 dsc->sc_dmacmd |= HPC_DMACTL_DIR; 243 dsc->sc_flags &= ~HPC_DMA_READ; 244 } 245 splx(s); 246 } 247 return(count); 248 } 249 250 /* 251 * Prime the hardware for the next DMA transfer 252 */ 253 int 254 wdsc_dmago(dev) 255 struct sbic_softc *dev; 256 { 257 struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma; 258 259 if (dev->sc_tcnt == 0) { 260 return(0); 261 } 262 263 KASSERT((dsc->sc_flags & HPC_DMA_ACTIVE) == 0); 264 dsc->sc_flags |= HPC_DMA_ACTIVE; 265 266 bus_dmamap_sync(dev->sc_dmat, dev->sc_dmamap, 0, dev->sc_tcnt, 267 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 268 269 hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */ 270 271 return(dev->sc_dmamap->dm_mapsize); 272 } 273 274 /* 275 * Stop DMA, and disable interrupts 276 */ 277 void 278 wdsc_dmastop(dev) 279 struct sbic_softc *dev; 280 { 281 struct hpc_dma_softc *dsc = &((struct wdsc_softc *)dev)->sc_hpcdma; 282 283 if (dsc->sc_flags & HPC_DMA_ACTIVE) { 284 if (dsc->sc_flags & HPC_DMA_READ) 285 hpcdma_flush(dsc); 286 hpcdma_cntl(dsc, 0); /* Stop DMA */ 287 bus_dmamap_sync(dev->sc_dmat, dev->sc_dmamap, 0, 288 dev->sc_dmamap->dm_mapsize, 289 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 290 dsc->sc_flags &= ~HPC_DMA_ACTIVE; 291 } 292 if (dev->sc_flags & SBICF_DMALOADED) 293 bus_dmamap_unload(dev->sc_dmat, dev->sc_dmamap); 294 } 295 296 /* 297 * SCSI controller interrupt 298 */ 299 int 300 wdsc_scsiintr(arg) 301 void *arg; 302 { 303 struct sbic_softc *dev = arg; 304 int found; 305 306 found = sbicintr(dev); 307 return(found); 308 } 309