1 1.35 tsutsui /* $NetBSD: wdsc.c,v 1.35 2018/09/02 16:18:50 tsutsui Exp $ */ 2 1.1 wdk 3 1.1 wdk /* 4 1.1 wdk * Copyright (c) 2001 Wayne Knowles 5 1.1 wdk * All rights reserved. 6 1.1 wdk * 7 1.1 wdk * This code is derived from software contributed to The NetBSD Foundation 8 1.1 wdk * by Wayne Knowles 9 1.1 wdk * 10 1.1 wdk * Redistribution and use in source and binary forms, with or without 11 1.1 wdk * modification, are permitted provided that the following conditions 12 1.1 wdk * are met: 13 1.1 wdk * 1. Redistributions of source code must retain the above copyright 14 1.1 wdk * notice, this list of conditions and the following disclaimer. 15 1.1 wdk * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 wdk * notice, this list of conditions and the following disclaimer in the 17 1.1 wdk * documentation and/or other materials provided with the distribution. 18 1.25 martin * 3. All advertising materials mentioning features or use of this software 19 1.25 martin * must display the following acknowledgement: 20 1.25 martin * This product includes software developed by the NetBSD 21 1.25 martin * Foundation, Inc. and its contributors. 22 1.25 martin * 4. Neither the name of The NetBSD Foundation nor the names of its 23 1.25 martin * contributors may be used to endorse or promote products derived 24 1.25 martin * from this software without specific prior written permission. 25 1.1 wdk * 26 1.1 wdk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 1.1 wdk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 1.1 wdk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 1.1 wdk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 1.1 wdk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 1.1 wdk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 1.1 wdk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 1.1 wdk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 1.1 wdk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 1.1 wdk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 1.1 wdk * POSSIBILITY OF SUCH DAMAGE. 37 1.1 wdk */ 38 1.11 lukem 39 1.11 lukem #include <sys/cdefs.h> 40 1.35 tsutsui __KERNEL_RCSID(0, "$NetBSD: wdsc.c,v 1.35 2018/09/02 16:18:50 tsutsui Exp $"); 41 1.1 wdk 42 1.1 wdk #include <sys/param.h> 43 1.1 wdk #include <sys/systm.h> 44 1.1 wdk #include <sys/kernel.h> 45 1.1 wdk #include <sys/device.h> 46 1.1 wdk #include <sys/buf.h> 47 1.1 wdk 48 1.1 wdk #include <dev/scsipi/scsi_all.h> 49 1.1 wdk #include <dev/scsipi/scsipi_all.h> 50 1.1 wdk #include <dev/scsipi/scsiconf.h> 51 1.1 wdk 52 1.1 wdk #include <machine/cpu.h> 53 1.32 dyoung #include <sys/bus.h> 54 1.1 wdk #include <machine/autoconf.h> 55 1.18 rumble #include <machine/machtype.h> 56 1.19 rumble #include <machine/sysconf.h> 57 1.1 wdk 58 1.1 wdk #include <sgimips/hpc/hpcvar.h> 59 1.1 wdk #include <sgimips/hpc/hpcreg.h> 60 1.1 wdk #include <sgimips/hpc/hpcdma.h> 61 1.1 wdk 62 1.16 bjh21 #include <dev/ic/wd33c93reg.h> 63 1.16 bjh21 #include <dev/ic/wd33c93var.h> 64 1.1 wdk 65 1.2 wdk #include <opt_kgdb.h> 66 1.2 wdk #include <sys/kgdb.h> 67 1.2 wdk 68 1.1 wdk struct wdsc_softc { 69 1.6 thorpej struct wd33c93_softc sc_wd33c93; /* Must be first */ 70 1.7 simonb struct evcnt sc_intrcnt; /* Interrupt counter */ 71 1.2 wdk bus_dma_tag_t sc_dmat; 72 1.2 wdk bus_dmamap_t sc_dmamap; 73 1.2 wdk int sc_flags; 74 1.2 wdk #define WDSC_DMA_ACTIVE 0x1 75 1.7 simonb #define WDSC_DMA_MAPLOADED 0x2 76 1.1 wdk struct hpc_dma_softc sc_hpcdma; 77 1.1 wdk }; 78 1.1 wdk 79 1.1 wdk 80 1.31 tsutsui int wdsc_match(device_t, cfdata_t, void *); 81 1.31 tsutsui void wdsc_attach(device_t, device_t, void *); 82 1.1 wdk 83 1.26 bjh21 CFATTACH_DECL_NEW(wdsc, sizeof(struct wdsc_softc), 84 1.10 thorpej wdsc_match, wdsc_attach, NULL, NULL); 85 1.1 wdk 86 1.31 tsutsui int wdsc_dmasetup(struct wd33c93_softc *, void ** ,size_t *, int, size_t *); 87 1.31 tsutsui int wdsc_dmago(struct wd33c93_softc *); 88 1.31 tsutsui void wdsc_dmastop(struct wd33c93_softc *); 89 1.31 tsutsui void wdsc_reset(struct wd33c93_softc *); 90 1.31 tsutsui int wdsc_dmaintr(void *); 91 1.31 tsutsui int wdsc_scsiintr(void *); 92 1.1 wdk 93 1.1 wdk /* 94 1.19 rumble * Match for SCSI devices on the onboard and GIO32 adapter WD33C93 chips 95 1.1 wdk */ 96 1.1 wdk int 97 1.33 chs wdsc_match(device_t parent, cfdata_t cf, void *aux) 98 1.1 wdk { 99 1.33 chs struct hpc_attach_args *haa = aux; 100 1.1 wdk 101 1.19 rumble if (strcmp(haa->ha_name, cf->cf_name) == 0) { 102 1.29 matt vaddr_t reset, asr, reg; 103 1.19 rumble 104 1.19 rumble reset = MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_dmaoff + 105 1.19 rumble haa->hpc_regs->scsi0_ctl); 106 1.19 rumble asr = MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_devoff); 107 1.19 rumble 108 1.35 tsutsui /* XXX: hpc1 offset due to SGIMIPS_BUS_SPACE_HPC brain damage */ 109 1.35 tsutsui asr = (asr + 3) & ~0x3; 110 1.35 tsutsui 111 1.19 rumble if (platform.badaddr((void *)reset, sizeof(reset))) 112 1.31 tsutsui return 0; 113 1.19 rumble 114 1.19 rumble *(volatile uint32_t *)reset = haa->hpc_regs->scsi_dmactl_reset; 115 1.19 rumble delay(1000); 116 1.19 rumble *(volatile uint32_t *)reset = 0x0; 117 1.19 rumble 118 1.19 rumble if (platform.badaddr((void *)asr, sizeof(asr))) 119 1.31 tsutsui return 0; 120 1.19 rumble 121 1.19 rumble reg = *(volatile uint32_t *)asr; 122 1.19 rumble if (haa->hpc_regs->revision == 3) { 123 1.19 rumble if ((reg & 0xff) == SBIC_ASR_INT) 124 1.31 tsutsui return 1; 125 1.19 rumble } else { 126 1.19 rumble if (((reg >> 8) & 0xff) == SBIC_ASR_INT) 127 1.31 tsutsui return 1; 128 1.19 rumble } 129 1.19 rumble } 130 1.4 thorpej 131 1.31 tsutsui return 0; 132 1.1 wdk } 133 1.1 wdk 134 1.1 wdk /* 135 1.1 wdk * Attach the wdsc driver 136 1.1 wdk */ 137 1.1 wdk void 138 1.27 tsutsui wdsc_attach(device_t parent, device_t self, void *aux) 139 1.1 wdk { 140 1.27 tsutsui struct wdsc_softc *wsc = device_private(self); 141 1.26 bjh21 struct wd33c93_softc *sc = &wsc->sc_wd33c93; 142 1.27 tsutsui struct hpc_attach_args *haa = aux; 143 1.2 wdk int err; 144 1.1 wdk 145 1.27 tsutsui sc->sc_dev = self; 146 1.4 thorpej sc->sc_regt = haa->ha_st; 147 1.2 wdk wsc->sc_dmat = haa->ha_dmat; 148 1.1 wdk 149 1.12 sekiya wsc->sc_hpcdma.hpc = haa->hpc_regs; 150 1.12 sekiya 151 1.4 thorpej if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, 152 1.34 macallan haa->ha_devoff + 0 + 3, 1, &sc->sc_asr_regh)) != 0) { 153 1.28 rumble printf(": unable to map asr reg, err=%d\n", err); 154 1.28 rumble return; 155 1.28 rumble } 156 1.28 rumble 157 1.28 rumble if ((err = bus_space_subregion(haa->ha_st, haa->ha_sh, 158 1.34 macallan haa->ha_devoff + 4 + 3, 1, &sc->sc_data_regh)) != 0) { 159 1.34 macallan printf(": unable to map data reg, err=%d\n", err); 160 1.2 wdk return; 161 1.2 wdk } 162 1.1 wdk 163 1.31 tsutsui if (bus_dmamap_create(wsc->sc_dmat, MAXPHYS, 164 1.31 tsutsui wsc->sc_hpcdma.hpc->scsi_dma_segs, 165 1.31 tsutsui wsc->sc_hpcdma.hpc->scsi_dma_segs_size, 166 1.31 tsutsui wsc->sc_hpcdma.hpc->scsi_dma_segs_size, 167 1.31 tsutsui BUS_DMA_WAITOK, &wsc->sc_dmamap) != 0) { 168 1.1 wdk printf(": failed to create dmamap\n"); 169 1.2 wdk return; 170 1.2 wdk } 171 1.1 wdk 172 1.2 wdk sc->sc_dmasetup = wdsc_dmasetup; 173 1.2 wdk sc->sc_dmago = wdsc_dmago; 174 1.2 wdk sc->sc_dmastop = wdsc_dmastop; 175 1.3 thorpej sc->sc_reset = wdsc_reset; 176 1.1 wdk 177 1.6 thorpej sc->sc_adapter.adapt_request = wd33c93_scsi_request; 178 1.2 wdk sc->sc_adapter.adapt_minphys = minphys; 179 1.1 wdk 180 1.12 sekiya sc->sc_id = 0; /* Host ID = 0 */ 181 1.21 rumble sc->sc_clkfreq = 200; /* 20MHz */ 182 1.22 rumble sc->sc_dmamode = SBIC_CTL_BURST_DMA; 183 1.1 wdk 184 1.2 wdk evcnt_attach_dynamic(&wsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 185 1.26 bjh21 device_xname(sc->sc_dev), "intr"); 186 1.1 wdk 187 1.4 thorpej if ((cpu_intr_establish(haa->ha_irq, IPL_BIO, 188 1.27 tsutsui wdsc_scsiintr, wsc)) == NULL) { 189 1.2 wdk printf(": unable to establish interrupt!\n"); 190 1.2 wdk return; 191 1.2 wdk } 192 1.1 wdk 193 1.13 sekiya hpcdma_init(haa, &wsc->sc_hpcdma, wsc->sc_hpcdma.hpc->scsi_dma_segs); 194 1.6 thorpej wd33c93_attach(sc); 195 1.1 wdk } 196 1.1 wdk 197 1.1 wdk /* 198 1.1 wdk * Prime the hardware for a DMA transfer 199 1.2 wdk * 200 1.2 wdk * Requires splbio() interrupts to be disabled by the caller 201 1.1 wdk */ 202 1.1 wdk int 203 1.31 tsutsui wdsc_dmasetup(struct wd33c93_softc *sc, void **addr, size_t *len, int datain, 204 1.31 tsutsui size_t *dmasize) 205 1.1 wdk { 206 1.27 tsutsui struct wdsc_softc *wsc = (struct wdsc_softc *)sc; 207 1.2 wdk struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; 208 1.7 simonb int count, err; 209 1.7 simonb void *vaddr; 210 1.2 wdk 211 1.2 wdk KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0); 212 1.2 wdk 213 1.2 wdk vaddr = *addr; 214 1.2 wdk count = dsc->sc_dlen = *len; 215 1.2 wdk if (count) { 216 1.2 wdk KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED) == 0); 217 1.1 wdk 218 1.2 wdk /* Build list of physical addresses for this transfer */ 219 1.31 tsutsui if ((err = bus_dmamap_load(wsc->sc_dmat, wsc->sc_dmamap, 220 1.31 tsutsui vaddr, count, NULL /* kernel address */, 221 1.31 tsutsui BUS_DMA_NOWAIT)) != 0) 222 1.2 wdk panic("%s: bus_dmamap_load err=%d", 223 1.27 tsutsui device_xname(sc->sc_dev), err); 224 1.2 wdk 225 1.2 wdk hpcdma_sglist_create(dsc, wsc->sc_dmamap); 226 1.2 wdk wsc->sc_flags |= WDSC_DMA_MAPLOADED; 227 1.2 wdk 228 1.2 wdk if (datain) { 229 1.18 rumble dsc->sc_dmacmd = 230 1.18 rumble wsc->sc_hpcdma.hpc->scsi_dma_datain_cmd; 231 1.2 wdk dsc->sc_flags |= HPCDMA_READ; 232 1.2 wdk } else { 233 1.18 rumble dsc->sc_dmacmd = 234 1.18 rumble wsc->sc_hpcdma.hpc->scsi_dma_dataout_cmd; 235 1.2 wdk dsc->sc_flags &= ~HPCDMA_READ; 236 1.2 wdk } 237 1.2 wdk } 238 1.31 tsutsui return count; 239 1.1 wdk } 240 1.1 wdk 241 1.1 wdk /* 242 1.1 wdk * Prime the hardware for the next DMA transfer 243 1.1 wdk */ 244 1.1 wdk int 245 1.27 tsutsui wdsc_dmago(struct wd33c93_softc *sc) 246 1.1 wdk { 247 1.27 tsutsui struct wdsc_softc *wsc = (struct wdsc_softc *)sc; 248 1.2 wdk struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; 249 1.1 wdk 250 1.2 wdk if (dsc->sc_dlen == 0) 251 1.31 tsutsui return 0; 252 1.1 wdk 253 1.2 wdk KASSERT((wsc->sc_flags & WDSC_DMA_ACTIVE) == 0); 254 1.2 wdk KASSERT((wsc->sc_flags & WDSC_DMA_MAPLOADED)); 255 1.1 wdk 256 1.2 wdk wsc->sc_flags |= WDSC_DMA_ACTIVE; 257 1.1 wdk 258 1.31 tsutsui bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, 259 1.31 tsutsui 0, wsc->sc_dmamap->dm_mapsize, 260 1.31 tsutsui (dsc->sc_flags & HPCDMA_READ) ? 261 1.31 tsutsui BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 262 1.1 wdk 263 1.2 wdk hpcdma_cntl(dsc, dsc->sc_dmacmd); /* Thunderbirds are go! */ 264 1.2 wdk 265 1.31 tsutsui return wsc->sc_dmamap->dm_mapsize; 266 1.1 wdk } 267 1.1 wdk 268 1.1 wdk /* 269 1.2 wdk * Stop DMA and unload active DMA maps 270 1.1 wdk */ 271 1.1 wdk void 272 1.27 tsutsui wdsc_dmastop(struct wd33c93_softc *sc) 273 1.1 wdk { 274 1.27 tsutsui struct wdsc_softc *wsc = (struct wdsc_softc *)sc; 275 1.2 wdk struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; 276 1.1 wdk 277 1.2 wdk if (wsc->sc_flags & WDSC_DMA_ACTIVE) { 278 1.2 wdk if (dsc->sc_flags & HPCDMA_READ) 279 1.2 wdk hpcdma_flush(dsc); 280 1.2 wdk hpcdma_cntl(dsc, 0); /* Stop DMA */ 281 1.31 tsutsui bus_dmamap_sync(wsc->sc_dmat, wsc->sc_dmamap, 282 1.31 tsutsui 0, wsc->sc_dmamap->dm_mapsize, 283 1.30 tsutsui (dsc->sc_flags & HPCDMA_READ) ? 284 1.30 tsutsui BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 285 1.2 wdk } 286 1.2 wdk if (wsc->sc_flags & WDSC_DMA_MAPLOADED) 287 1.2 wdk bus_dmamap_unload(wsc->sc_dmat, wsc->sc_dmamap); 288 1.2 wdk wsc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED); 289 1.3 thorpej } 290 1.3 thorpej 291 1.3 thorpej /* 292 1.3 thorpej * Reset the controller. 293 1.3 thorpej */ 294 1.3 thorpej void 295 1.27 tsutsui wdsc_reset(struct wd33c93_softc *sc) 296 1.3 thorpej { 297 1.27 tsutsui struct wdsc_softc *wsc = (struct wdsc_softc *)sc; 298 1.3 thorpej struct hpc_dma_softc *dsc = &wsc->sc_hpcdma; 299 1.3 thorpej 300 1.3 thorpej hpcdma_reset(dsc); 301 1.1 wdk } 302 1.1 wdk 303 1.1 wdk /* 304 1.2 wdk * WD33c93 SCSI controller interrupt 305 1.1 wdk */ 306 1.1 wdk int 307 1.14 sekiya wdsc_scsiintr(void *arg) 308 1.1 wdk { 309 1.2 wdk struct wdsc_softc *wsc = arg; 310 1.27 tsutsui struct wd33c93_softc *sc = &wsc->sc_wd33c93; 311 1.2 wdk int found; 312 1.2 wdk 313 1.27 tsutsui found = wd33c93_intr(sc); 314 1.2 wdk if (found) 315 1.2 wdk wsc->sc_intrcnt.ev_count++; 316 1.31 tsutsui return found; 317 1.1 wdk } 318