1 /* $NetBSD: spc.c,v 1.2 2003/11/17 14:37:59 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Izumi Tsutsui. 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. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "opt_ddb.h" 31 32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 __KERNEL_RCSID(0, "$NetBSD: spc.c,v 1.2 2003/11/17 14:37:59 tsutsui Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 40 #include <machine/autoconf.h> 41 #include <machine/bus.h> 42 #include <machine/cpu.h> 43 #include <machine/intr.h> 44 45 #include <hp300/dev/dioreg.h> 46 #include <hp300/dev/diovar.h> 47 #include <hp300/dev/diodevs.h> 48 49 #include <dev/scsipi/scsi_all.h> 50 #include <dev/scsipi/scsipi_all.h> 51 #include <dev/scsipi/scsi_message.h> 52 #include <dev/scsipi/scsiconf.h> 53 54 #include <dev/ic/mb89352reg.h> 55 #include <dev/ic/mb89352var.h> 56 57 #include <hp300/dev/hp98265reg.h> 58 #include <hp300/dev/dmareg.h> 59 #include <hp300/dev/dmavar.h> 60 61 static int spc_dio_match __P((struct device *, struct cfdata *, void *)); 62 static void spc_dio_attach __P((struct device *, struct device *, void *)); 63 static void spc_dio_dmastart __P((struct spc_softc *, void *, size_t, int)); 64 static void spc_dio_dmadone __P((struct spc_softc *)); 65 static void spc_dio_dmago __P((void *)); 66 static void spc_dio_dmastop __P((void *)); 67 68 struct spc_dio_softc { 69 struct spc_softc sc_spc; /* MI spc softc */ 70 71 /* DIO specific goo. */ 72 struct bus_space_tag sc_tag; /* bus space tag with oddbyte func */ 73 bus_space_handle_t sc_iohsc; /* bus space handle for HPSCSI */ 74 struct dmaqueue sc_dq; /* DMA job queue */ 75 u_int sc_dflags; /* DMA flags */ 76 #define SCSI_DMA32 0x01 /* 32-bit DMA should be used */ 77 #define SCSI_HAVEDMA 0x02 /* controller has DMA channel */ 78 #define SCSI_DATAIN 0x04 /* DMA direction */ 79 }; 80 81 CFATTACH_DECL(spc, sizeof(struct spc_dio_softc), 82 spc_dio_match, spc_dio_attach, NULL, NULL); 83 84 static int 85 spc_dio_match(parent, cf, aux) 86 struct device *parent; 87 struct cfdata *cf; 88 void *aux; 89 { 90 struct dio_attach_args *da = aux; 91 92 switch (da->da_id) { 93 case DIO_DEVICE_ID_SCSI0: 94 case DIO_DEVICE_ID_SCSI1: 95 case DIO_DEVICE_ID_SCSI2: 96 case DIO_DEVICE_ID_SCSI3: 97 return 1; 98 } 99 100 return 0; 101 } 102 103 static void 104 spc_dio_attach(parent, self, aux) 105 struct device *parent, *self; 106 void *aux; 107 { 108 struct spc_dio_softc *dsc = (struct spc_dio_softc *)self; 109 struct spc_softc *sc = &dsc->sc_spc; 110 struct dio_attach_args *da = aux; 111 bus_space_tag_t iot = &dsc->sc_tag; 112 bus_space_handle_t iohsc, iohspc; 113 u_int8_t id; 114 115 memcpy(iot, da->da_bst, sizeof(struct bus_space_tag)); 116 dio_set_bus_space_oddbyte(iot); 117 118 if (bus_space_map(iot, da->da_addr, da->da_size, 0, &iohsc)) { 119 printf(": can't map SCSI registers\n"); 120 return; 121 } 122 123 if (bus_space_subregion(iot, iohsc, SPC_OFFSET, SPC_SIZE, &iohspc)) { 124 printf(": can't map SPC registers\n"); 125 return; 126 } 127 128 printf(": 98265A SCSI"); 129 130 bus_space_write_1(iot, iohsc, HPSCSI_ID, 0xff); 131 DELAY(100); 132 id = bus_space_read_1(iot, iohsc, HPSCSI_ID); 133 if ((id & ID_WORD_DMA) == 0) { 134 printf(", 32-bit DMA"); 135 dsc->sc_dflags |= SCSI_DMA32; 136 } 137 id &= ID_MASK; 138 printf(", SCSI ID %d\n", id); 139 140 sc->sc_iot = iot; 141 sc->sc_ioh = iohspc; 142 sc->sc_initiator = id; 143 144 sc->sc_dma_start = spc_dio_dmastart; 145 sc->sc_dma_done = spc_dio_dmadone; 146 147 dsc->sc_iohsc = iohsc; 148 dsc->sc_dq.dq_softc = dsc; 149 dsc->sc_dq.dq_start = spc_dio_dmago; 150 dsc->sc_dq.dq_done = spc_dio_dmastop; 151 152 bus_space_write_1(iot, iohsc, HPSCSI_CSR, 0x00); 153 bus_space_write_1(iot, iohsc, HPSCSI_HCONF, 0x00); 154 155 dio_intr_establish(spc_intr, (void *)sc, da->da_ipl, IPL_BIO); 156 157 spc_attach(sc); 158 159 /* Enable SPC interrupts. */ 160 bus_space_write_1(iot, iohsc, HPSCSI_CSR, CSR_IE); 161 } 162 163 static 164 void spc_dio_dmastart(sc, addr, size, datain) 165 struct spc_softc *sc; 166 void *addr; 167 size_t size; 168 int datain; 169 { 170 struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; 171 172 dsc->sc_dq.dq_chan = DMA0 | DMA1; 173 dsc->sc_dflags |= SCSI_HAVEDMA; 174 if (datain) 175 dsc->sc_dflags |= SCSI_DATAIN; 176 else 177 dsc->sc_dflags &= ~SCSI_DATAIN; 178 179 if (dmareq(&dsc->sc_dq) != 0) 180 /* DMA channel is available, so start DMA immediately */ 181 spc_dio_dmago((void *)dsc); 182 /* else dma start function will be called later from dmafree(). */ 183 } 184 185 static 186 void spc_dio_dmago(arg) 187 void *arg; 188 { 189 struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg; 190 struct spc_softc *sc = &dsc->sc_spc; 191 bus_space_tag_t iot; 192 bus_space_handle_t iohsc, iohspc; 193 int len, chan; 194 u_int32_t dmaflags; 195 u_int8_t cmd; 196 197 iot = sc->sc_iot; 198 iohspc = sc->sc_ioh; 199 iohsc = dsc->sc_iohsc; 200 201 bus_space_write_1(iot, iohsc, HPSCSI_HCONF, 0); 202 203 cmd = CSR_IE; 204 dmaflags = DMAGO_NOINT; 205 chan = dsc->sc_dq.dq_chan; 206 if ((dsc->sc_dflags & SCSI_DATAIN) != 0) { 207 cmd |= CSR_DMAIN; 208 dmaflags |= DMAGO_READ; 209 } 210 if ((dsc->sc_dflags & SCSI_DMA32) != 0 && 211 ((u_int)sc->sc_dp & 3) == 0 && 212 (sc->sc_dleft & 3) == 0) { 213 cmd |= CSR_DMA32; 214 dmaflags |= DMAGO_LWORD; 215 } else 216 dmaflags |= DMAGO_WORD; 217 218 dmago(chan, sc->sc_dp, sc->sc_dleft, dmaflags); 219 220 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 221 cmd |= (chan == 0) ? CSR_DE0 : CSR_DE1; 222 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 223 224 cmd = SCMD_XFR; 225 len = sc->sc_dleft; 226 227 if ((len & (DEV_BSIZE - 1)) != 0) /* XXX ??? */ { 228 cmd |= SCMD_PAD; 229 #if 0 230 if ((dsc->sc_dflags & SCSI_DATAIN) != 0) 231 len += 2; /* XXX ??? */ 232 #endif 233 } 234 235 bus_space_write_1(iot, iohspc, TCH, len >> 16); 236 bus_space_write_1(iot, iohspc, TCM, len >> 8); 237 bus_space_write_1(iot, iohspc, TCL, len); 238 bus_space_write_1(iot, iohspc, PCTL, sc->sc_phase | PCTL_BFINT_ENAB); 239 bus_space_write_1(iot, iohspc, SCMD, cmd); 240 241 sc->sc_flags |= SPC_DOINGDMA; 242 } 243 244 static 245 void spc_dio_dmadone(sc) 246 struct spc_softc *sc; 247 { 248 struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; 249 bus_space_tag_t iot; 250 bus_space_handle_t ioh, iohsc; 251 int resid, trans; 252 u_int8_t cmd; 253 254 iot = sc->sc_iot; 255 ioh = sc->sc_ioh; 256 iohsc = dsc->sc_iohsc; 257 258 /* wait DMA complete */ 259 if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0) { 260 int timeout = 1000; /* XXX how long? */ 261 while ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0) { 262 if (--timeout < 0) 263 printf("%s: DMA complete timeout\n", 264 sc->sc_dev.dv_xname); 265 DELAY(1); 266 } 267 } 268 269 if ((dsc->sc_dflags & SCSI_HAVEDMA) != 0) { 270 dmafree(&dsc->sc_dq); 271 dsc->sc_dflags &= ~SCSI_HAVEDMA; 272 } 273 274 cmd = bus_space_read_1(iot, iohsc, HPSCSI_CSR); 275 cmd &= ~(CSR_DE1|CSR_DE0); 276 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 277 278 resid = bus_space_read_1(iot, ioh, TCH) << 16 | 279 bus_space_read_1(iot, ioh, TCM) << 8 | 280 bus_space_read_1(iot, ioh, TCL); 281 trans = sc->sc_dleft - resid; 282 sc->sc_dp += trans; 283 sc->sc_dleft -= trans; 284 285 sc->sc_flags &= ~SPC_DOINGDMA; 286 } 287 288 static 289 void spc_dio_dmastop(arg) 290 void *arg; 291 { 292 struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg; 293 struct spc_softc *sc = &dsc->sc_spc; 294 u_int8_t cmd; 295 296 /* XXX When is this function called? */ 297 cmd = bus_space_read_1(sc->sc_iot, dsc->sc_iohsc, HPSCSI_CSR); 298 cmd &= ~(CSR_DE1|CSR_DE0); 299 bus_space_write_1(sc->sc_iot, dsc->sc_iohsc, HPSCSI_CSR, cmd); 300 301 dsc->sc_dflags &= ~SCSI_HAVEDMA; 302 sc->sc_flags &= ~SPC_DOINGDMA; 303 } 304