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