spc.c revision 1.2
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 61static int spc_dio_match __P((struct device *, struct cfdata *, void *)); 62static void spc_dio_attach __P((struct device *, struct device *, void *)); 63static void spc_dio_dmastart __P((struct spc_softc *, void *, size_t, int)); 64static void spc_dio_dmadone __P((struct spc_softc *)); 65static void spc_dio_dmago __P((void *)); 66static void spc_dio_dmastop __P((void *)); 67 68struct 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 81CFATTACH_DECL(spc, sizeof(struct spc_dio_softc), 82 spc_dio_match, spc_dio_attach, NULL, NULL); 83 84static int 85spc_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 103static void 104spc_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 163static 164void 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 185static 186void 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 244static 245void 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 288static 289void 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