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