1 1.35 thorpej /* $NetBSD: wdsc.c,v 1.35 2021/08/07 16:19:00 thorpej Exp $ */ 2 1.1 chuck 3 1.1 chuck /* 4 1.1 chuck * Copyright (c) 1982, 1990 The Regents of the University of California. 5 1.1 chuck * All rights reserved. 6 1.1 chuck * 7 1.1 chuck * Redistribution and use in source and binary forms, with or without 8 1.1 chuck * modification, are permitted provided that the following conditions 9 1.1 chuck * are met: 10 1.1 chuck * 1. Redistributions of source code must retain the above copyright 11 1.1 chuck * notice, this list of conditions and the following disclaimer. 12 1.1 chuck * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 chuck * notice, this list of conditions and the following disclaimer in the 14 1.1 chuck * documentation and/or other materials provided with the distribution. 15 1.27 agc * 3. Neither the name of the University nor the names of its contributors 16 1.27 agc * may be used to endorse or promote products derived from this software 17 1.27 agc * without specific prior written permission. 18 1.27 agc * 19 1.27 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.27 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.27 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.27 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.27 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.27 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.27 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.27 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.27 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.27 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.27 agc * SUCH DAMAGE. 30 1.27 agc * 31 1.27 agc * @(#)wdsc.c 32 1.27 agc */ 33 1.27 agc 34 1.28 scw /*- 35 1.28 scw * Copyright (c) 1996-2004 The NetBSD Foundation, Inc. 36 1.28 scw * All rights reserved. 37 1.28 scw * 38 1.28 scw * This code is derived from software contributed to The NetBSD Foundation 39 1.28 scw * by Steve C. Woodford. 40 1.27 agc * 41 1.27 agc * Redistribution and use in source and binary forms, with or without 42 1.27 agc * modification, are permitted provided that the following conditions 43 1.27 agc * are met: 44 1.27 agc * 1. Redistributions of source code must retain the above copyright 45 1.27 agc * notice, this list of conditions and the following disclaimer. 46 1.27 agc * 2. Redistributions in binary form must reproduce the above copyright 47 1.27 agc * notice, this list of conditions and the following disclaimer in the 48 1.27 agc * documentation and/or other materials provided with the distribution. 49 1.1 chuck * 50 1.28 scw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 51 1.28 scw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 52 1.28 scw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 1.28 scw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 54 1.28 scw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 55 1.28 scw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 56 1.28 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 57 1.28 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 58 1.28 scw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59 1.28 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 1.28 scw * POSSIBILITY OF SUCH DAMAGE. 61 1.1 chuck */ 62 1.26 lukem 63 1.26 lukem #include <sys/cdefs.h> 64 1.35 thorpej __KERNEL_RCSID(0, "$NetBSD: wdsc.c,v 1.35 2021/08/07 16:19:00 thorpej Exp $"); 65 1.2 chuck 66 1.1 chuck #include <sys/param.h> 67 1.1 chuck #include <sys/systm.h> 68 1.1 chuck #include <sys/kernel.h> 69 1.1 chuck #include <sys/device.h> 70 1.2 chuck 71 1.10 bouyer #include <dev/scsipi/scsi_all.h> 72 1.10 bouyer #include <dev/scsipi/scsipi_all.h> 73 1.10 bouyer #include <dev/scsipi/scsiconf.h> 74 1.2 chuck 75 1.16 scw #include <machine/cpu.h> 76 1.17 scw #include <machine/bus.h> 77 1.3 chuck #include <machine/autoconf.h> 78 1.3 chuck 79 1.2 chuck #include <mvme68k/dev/dmavar.h> 80 1.1 chuck #include <mvme68k/dev/pccreg.h> 81 1.2 chuck #include <mvme68k/dev/pccvar.h> 82 1.1 chuck #include <mvme68k/dev/sbicreg.h> 83 1.1 chuck #include <mvme68k/dev/sbicvar.h> 84 1.1 chuck #include <mvme68k/dev/wdscreg.h> 85 1.1 chuck 86 1.30 tsutsui #include "ioconf.h" 87 1.30 tsutsui 88 1.32 chs void wdsc_pcc_attach(device_t, device_t, void *); 89 1.32 chs int wdsc_pcc_match(device_t, cfdata_t, void *); 90 1.1 chuck 91 1.32 chs CFATTACH_DECL_NEW(wdsc_pcc, sizeof(struct sbic_softc), 92 1.23 thorpej wdsc_pcc_match, wdsc_pcc_attach, NULL, NULL); 93 1.17 scw 94 1.30 tsutsui void wdsc_enintr(struct sbic_softc *); 95 1.30 tsutsui int wdsc_dmago(struct sbic_softc *, char *, int, int); 96 1.30 tsutsui int wdsc_dmanext(struct sbic_softc *); 97 1.30 tsutsui void wdsc_dmastop(struct sbic_softc *); 98 1.30 tsutsui int wdsc_dmaintr(void *); 99 1.30 tsutsui int wdsc_scsiintr(void *); 100 1.1 chuck 101 1.1 chuck /* 102 1.1 chuck * Match for SCSI devices on the onboard WD33C93 chip 103 1.1 chuck */ 104 1.1 chuck int 105 1.32 chs wdsc_pcc_match(device_t parent, cfdata_t cf, void *aux) 106 1.1 chuck { 107 1.32 chs struct pcc_attach_args *pa = aux; 108 1.2 chuck 109 1.30 tsutsui if (strcmp(pa->pa_name, wdsc_cd.cd_name)) 110 1.30 tsutsui return 0; 111 1.2 chuck 112 1.30 tsutsui pa->pa_ipl = cf->pcccf_ipl; 113 1.30 tsutsui return 1; 114 1.1 chuck } 115 1.1 chuck 116 1.1 chuck /* 117 1.1 chuck * Attach the wdsc driver 118 1.1 chuck */ 119 1.1 chuck void 120 1.32 chs wdsc_pcc_attach(device_t parent, device_t self, void *aux) 121 1.1 chuck { 122 1.30 tsutsui struct sbic_softc *sc; 123 1.30 tsutsui struct pcc_attach_args *pa; 124 1.30 tsutsui bus_space_handle_t bush; 125 1.30 tsutsui static struct evcnt evcnt; /* XXXSCW: Temporary hack */ 126 1.30 tsutsui 127 1.32 chs sc = device_private(self); 128 1.33 msaitoh sc->sc_dev = self; 129 1.32 chs pa = aux; 130 1.30 tsutsui 131 1.30 tsutsui bus_space_map(pa->pa_bust, pa->pa_offset, 0x20, 0, &bush); 132 1.30 tsutsui 133 1.30 tsutsui /* 134 1.30 tsutsui * XXXSCW: We *need* an MI, bus_spaced WD33C93 driver... 135 1.30 tsutsui */ 136 1.30 tsutsui sc->sc_sbicp = (sbic_regmap_p) bush; 137 1.30 tsutsui 138 1.30 tsutsui sc->sc_driver = (void *) &evcnt; 139 1.30 tsutsui sc->sc_enintr = wdsc_enintr; 140 1.30 tsutsui sc->sc_dmago = wdsc_dmago; 141 1.30 tsutsui sc->sc_dmanext = wdsc_dmanext; 142 1.30 tsutsui sc->sc_dmastop = wdsc_dmastop; 143 1.30 tsutsui sc->sc_dmacmd = 0; 144 1.30 tsutsui 145 1.32 chs sc->sc_adapter.adapt_dev = self; 146 1.30 tsutsui sc->sc_adapter.adapt_nchannels = 1; 147 1.30 tsutsui sc->sc_adapter.adapt_openings = 7; 148 1.30 tsutsui sc->sc_adapter.adapt_max_periph = 1; 149 1.30 tsutsui sc->sc_adapter.adapt_ioctl = NULL; 150 1.30 tsutsui sc->sc_adapter.adapt_minphys = sbic_minphys; 151 1.30 tsutsui sc->sc_adapter.adapt_request = sbic_scsi_request; 152 1.30 tsutsui 153 1.30 tsutsui sc->sc_channel.chan_adapter = &sc->sc_adapter; 154 1.30 tsutsui sc->sc_channel.chan_bustype = &scsi_bustype; 155 1.30 tsutsui sc->sc_channel.chan_channel = 0; 156 1.30 tsutsui sc->sc_channel.chan_ntargets = 8; 157 1.30 tsutsui sc->sc_channel.chan_nluns = 8; 158 1.30 tsutsui sc->sc_channel.chan_id = 7; 159 1.30 tsutsui 160 1.30 tsutsui printf(": WD33C93 SCSI, target %d\n", sc->sc_channel.chan_id); 161 1.30 tsutsui 162 1.30 tsutsui /* 163 1.30 tsutsui * Everything is a valid DMA address. 164 1.30 tsutsui */ 165 1.30 tsutsui sc->sc_dmamask = 0; 166 1.30 tsutsui 167 1.30 tsutsui /* 168 1.30 tsutsui * The onboard WD33C93 of the '147 is usually clocked at 10MHz... 169 1.30 tsutsui * (We use 10 times this for accuracy in later calculations) 170 1.30 tsutsui */ 171 1.30 tsutsui sc->sc_clkfreq = 100; 172 1.30 tsutsui 173 1.30 tsutsui /* 174 1.30 tsutsui * Initialise the hardware 175 1.30 tsutsui */ 176 1.30 tsutsui sbicinit(sc); 177 1.30 tsutsui 178 1.30 tsutsui /* 179 1.30 tsutsui * Fix up the interrupts 180 1.30 tsutsui */ 181 1.30 tsutsui sc->sc_ipl = pa->pa_ipl & PCC_IMASK; 182 1.30 tsutsui 183 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL, PCC_ICLEAR); 184 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, PCC_ICLEAR); 185 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0); 186 1.30 tsutsui 187 1.30 tsutsui evcnt_attach_dynamic(&evcnt, EVCNT_TYPE_INTR, pccintr_evcnt(sc->sc_ipl), 188 1.32 chs "disk", device_xname(self)); 189 1.30 tsutsui pccintr_establish(PCCV_DMA, wdsc_dmaintr, sc->sc_ipl, sc, &evcnt); 190 1.30 tsutsui pccintr_establish(PCCV_SCSI, wdsc_scsiintr, sc->sc_ipl, sc, &evcnt); 191 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL, 192 1.30 tsutsui sc->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 193 1.1 chuck 194 1.35 thorpej (void)config_found(self, &sc->sc_channel, scsiprint, CFARGS_NONE); 195 1.1 chuck } 196 1.1 chuck 197 1.1 chuck /* 198 1.1 chuck * Enable DMA interrupts 199 1.1 chuck */ 200 1.1 chuck void 201 1.30 tsutsui wdsc_enintr(struct sbic_softc *dev) 202 1.1 chuck { 203 1.1 chuck 204 1.30 tsutsui dev->sc_flags |= SBICF_INTR; 205 1.30 tsutsui 206 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, 207 1.30 tsutsui dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 208 1.1 chuck } 209 1.1 chuck 210 1.1 chuck /* 211 1.1 chuck * Prime the hardware for a DMA transfer 212 1.1 chuck */ 213 1.1 chuck int 214 1.30 tsutsui wdsc_dmago(struct sbic_softc *dev, char *addr, int count, int flags) 215 1.1 chuck { 216 1.1 chuck 217 1.30 tsutsui /* 218 1.30 tsutsui * Set up the command word based on flags 219 1.30 tsutsui */ 220 1.30 tsutsui if ((flags & DMAGO_READ) == 0) 221 1.30 tsutsui dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE; 222 1.30 tsutsui else 223 1.30 tsutsui dev->sc_dmacmd = DMAC_CSR_ENABLE; 224 1.30 tsutsui 225 1.30 tsutsui dev->sc_flags |= SBICF_INTR; 226 1.30 tsutsui dev->sc_tcnt = dev->sc_cur->dc_count << 1; 227 1.30 tsutsui 228 1.30 tsutsui /* 229 1.30 tsutsui * Prime the hardware. 230 1.30 tsutsui * Note, it's probably not necessary to do this here, since dmanext 231 1.30 tsutsui * is called just prior to the actual transfer. 232 1.30 tsutsui */ 233 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0); 234 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, 235 1.30 tsutsui dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 236 1.30 tsutsui pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR, 237 1.30 tsutsui (uint32_t) dev->sc_cur->dc_addr); 238 1.30 tsutsui pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT, 239 1.30 tsutsui (uint32_t) dev->sc_tcnt | (1 << 24)); 240 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd); 241 1.30 tsutsui 242 1.30 tsutsui return dev->sc_tcnt; 243 1.1 chuck } 244 1.1 chuck 245 1.1 chuck /* 246 1.1 chuck * Prime the hardware for the next DMA transfer 247 1.1 chuck */ 248 1.1 chuck int 249 1.30 tsutsui wdsc_dmanext(struct sbic_softc *dev) 250 1.1 chuck { 251 1.1 chuck 252 1.30 tsutsui if (dev->sc_cur > dev->sc_last) { 253 1.30 tsutsui /* 254 1.30 tsutsui * Shouldn't happen !! 255 1.30 tsutsui */ 256 1.30 tsutsui printf("wdsc_dmanext at end !!!\n"); 257 1.30 tsutsui wdsc_dmastop(dev); 258 1.30 tsutsui return 0; 259 1.30 tsutsui } 260 1.30 tsutsui 261 1.30 tsutsui dev->sc_tcnt = dev->sc_cur->dc_count << 1; 262 1.30 tsutsui 263 1.30 tsutsui /* 264 1.30 tsutsui * Load the next DMA address 265 1.30 tsutsui */ 266 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0); 267 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, 268 1.30 tsutsui dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 269 1.30 tsutsui pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR, 270 1.30 tsutsui (uint32_t) dev->sc_cur->dc_addr); 271 1.30 tsutsui pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT, 272 1.30 tsutsui (uint32_t) dev->sc_tcnt | (1 << 24)); 273 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd); 274 1.30 tsutsui 275 1.30 tsutsui return dev->sc_tcnt; 276 1.1 chuck } 277 1.1 chuck 278 1.1 chuck /* 279 1.1 chuck * Stop DMA, and disable interrupts 280 1.1 chuck */ 281 1.1 chuck void 282 1.30 tsutsui wdsc_dmastop(struct sbic_softc *dev) 283 1.1 chuck { 284 1.30 tsutsui int s; 285 1.1 chuck 286 1.30 tsutsui s = splbio(); 287 1.1 chuck 288 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0); 289 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, dev->sc_ipl | PCC_ICLEAR); 290 1.1 chuck 291 1.30 tsutsui splx(s); 292 1.1 chuck } 293 1.1 chuck 294 1.1 chuck /* 295 1.1 chuck * Come here following a DMA interrupt 296 1.1 chuck */ 297 1.1 chuck int 298 1.30 tsutsui wdsc_dmaintr(void *arg) 299 1.1 chuck { 300 1.30 tsutsui struct sbic_softc *dev = arg; 301 1.30 tsutsui int found = 0; 302 1.1 chuck 303 1.30 tsutsui /* 304 1.30 tsutsui * Really a DMA interrupt? 305 1.30 tsutsui */ 306 1.30 tsutsui if ((pcc_reg_read(sys_pcc, PCCREG_DMA_INTR_CTRL) & 0x80) == 0) 307 1.30 tsutsui return 0; 308 1.30 tsutsui 309 1.30 tsutsui /* 310 1.30 tsutsui * Was it a completion interrupt? 311 1.30 tsutsui * XXXSCW Note: Support for other DMA interrupts is required, 312 1.30 tsutsui * eg. buserr 313 1.30 tsutsui */ 314 1.30 tsutsui if (pcc_reg_read(sys_pcc, PCCREG_DMA_CONTROL) & DMAC_CSR_DONE) { 315 1.30 tsutsui ++found; 316 1.30 tsutsui 317 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, 318 1.30 tsutsui dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 319 1.30 tsutsui } 320 1.1 chuck 321 1.30 tsutsui return found; 322 1.1 chuck } 323 1.1 chuck 324 1.1 chuck /* 325 1.1 chuck * Come here for SCSI interrupts 326 1.1 chuck */ 327 1.1 chuck int 328 1.30 tsutsui wdsc_scsiintr(void *arg) 329 1.1 chuck { 330 1.30 tsutsui struct sbic_softc *dev = arg; 331 1.30 tsutsui int found; 332 1.1 chuck 333 1.30 tsutsui /* 334 1.30 tsutsui * Really a SCSI interrupt? 335 1.30 tsutsui */ 336 1.30 tsutsui if ((pcc_reg_read(sys_pcc, PCCREG_SCSI_INTR_CTRL) & 0x80) == 0) 337 1.30 tsutsui return 0; 338 1.30 tsutsui 339 1.30 tsutsui /* 340 1.30 tsutsui * Go handle it 341 1.30 tsutsui */ 342 1.30 tsutsui found = sbicintr(dev); 343 1.30 tsutsui 344 1.30 tsutsui /* 345 1.30 tsutsui * Acknowledge and clear the interrupt 346 1.30 tsutsui */ 347 1.30 tsutsui pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL, 348 1.17 scw dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR); 349 1.1 chuck 350 1.30 tsutsui return found; 351 1.1 chuck } 352