1/* $NetBSD: spc.c,v 1.9 2024/01/16 05:48:28 thorpej 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#include "opt_useleds.h" 29 30#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 31 32__KERNEL_RCSID(0, "$NetBSD: spc.c,v 1.9 2024/01/16 05:48:28 thorpej Exp $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/device.h> 37 38#include <machine/autoconf.h> 39#include <machine/bus.h> 40#include <machine/cpu.h> 41#include <machine/intr.h> 42 43#include <hp300/dev/dioreg.h> 44#include <hp300/dev/diovar.h> 45#include <hp300/dev/diodevs.h> 46 47#include <dev/scsipi/scsi_all.h> 48#include <dev/scsipi/scsipi_all.h> 49#include <dev/scsipi/scsi_message.h> 50#include <dev/scsipi/scsiconf.h> 51 52#include <dev/ic/mb89352reg.h> 53#include <dev/ic/mb89352var.h> 54 55#include <hp300/dev/hp98265reg.h> 56#include <hp300/dev/dmareg.h> 57#include <hp300/dev/dmavar.h> 58 59#ifdef USELEDS 60#include <hp300/hp300/leds.h> 61#endif 62 63static int spc_dio_match(device_t, cfdata_t, void *); 64static void spc_dio_attach(device_t, device_t, void *); 65static void spc_dio_dmastart(struct spc_softc *, void *, size_t, int); 66static void spc_dio_dmadone(struct spc_softc *); 67static void spc_dio_dmago(void *); 68static void spc_dio_dmastop(void *); 69 70struct spc_dio_softc { 71 struct spc_softc sc_spc; /* MI spc softc */ 72 73 /* DIO specific goo. */ 74 struct bus_space_tag sc_tag; /* bus space tag with oddbyte func */ 75 bus_space_handle_t sc_iohsc; /* bus space handle for HPSCSI */ 76 struct dmaqueue sc_dq; /* DMA job queue */ 77 u_int sc_dflags; /* DMA flags */ 78#define SCSI_DMA32 0x01 /* 32-bit DMA should be used */ 79#define SCSI_HAVEDMA 0x02 /* controller has DMA channel */ 80#define SCSI_DATAIN 0x04 /* DMA direction */ 81}; 82 83CFATTACH_DECL_NEW(spc, sizeof(struct spc_dio_softc), 84 spc_dio_match, spc_dio_attach, NULL, NULL); 85 86static int 87spc_dio_match(device_t parent, cfdata_t cf, void *aux) 88{ 89 struct dio_attach_args *da = aux; 90 91 switch (da->da_id) { 92 case DIO_DEVICE_ID_SCSI0: 93 case DIO_DEVICE_ID_SCSI1: 94 case DIO_DEVICE_ID_SCSI2: 95 case DIO_DEVICE_ID_SCSI3: 96 return 1; 97 } 98 99 return 0; 100} 101 102static void 103spc_dio_attach(device_t parent, device_t self, void *aux) 104{ 105 struct spc_dio_softc *dsc = device_private(self); 106 struct spc_softc *sc = &dsc->sc_spc; 107 struct dio_attach_args *da = aux; 108 bus_space_tag_t iot = &dsc->sc_tag; 109 bus_space_handle_t iohsc, iohspc; 110 uint8_t id; 111 112 sc->sc_dev = self; 113 memcpy(iot, da->da_bst, sizeof(struct bus_space_tag)); 114 dio_set_bus_space_oddbyte(iot); 115 116 if (bus_space_map(iot, da->da_addr, da->da_size, 0, &iohsc)) { 117 aprint_error(": can't map SCSI registers\n"); 118 return; 119 } 120 121 if (bus_space_subregion(iot, iohsc, SPC_OFFSET, SPC_SIZE, &iohspc)) { 122 aprint_error(": can't map SPC registers\n"); 123 return; 124 } 125 126 aprint_normal(": 98265A SCSI"); 127 128 bus_space_write_1(iot, iohsc, HPSCSI_ID, 0xff); 129 DELAY(100); 130 id = bus_space_read_1(iot, iohsc, HPSCSI_ID); 131 if ((id & ID_WORD_DMA) == 0) { 132 aprint_normal(", 32-bit DMA"); 133 dsc->sc_dflags |= SCSI_DMA32; 134 } 135 id &= ID_MASK; 136 aprint_normal(", SCSI ID %d\n", id); 137 138 sc->sc_iot = iot; 139 sc->sc_ioh = iohspc; 140 sc->sc_initiator = id; 141 142 sc->sc_dma_start = spc_dio_dmastart; 143 sc->sc_dma_done = spc_dio_dmadone; 144 145 dsc->sc_iohsc = iohsc; 146 dsc->sc_dq.dq_softc = dsc; 147 dsc->sc_dq.dq_start = spc_dio_dmago; 148 dsc->sc_dq.dq_done = spc_dio_dmastop; 149 150 bus_space_write_1(iot, iohsc, HPSCSI_CSR, 0x00); 151 bus_space_write_1(iot, iohsc, HPSCSI_HCONF, 0x00); 152 153 dio_intr_establish(spc_intr, (void *)sc, da->da_ipl, ISRPRI_BIO); 154 155 spc_attach(sc); 156 157 /* Enable SPC interrupts. */ 158 bus_space_write_1(iot, iohsc, HPSCSI_CSR, CSR_IE); 159} 160 161static void 162spc_dio_dmastart(struct spc_softc *sc, void *addr, size_t size, int datain) 163{ 164 struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; 165 166 dsc->sc_dq.dq_chan = DMA0 | DMA1; 167 dsc->sc_dflags |= SCSI_HAVEDMA; 168 if (datain) 169 dsc->sc_dflags |= SCSI_DATAIN; 170 else 171 dsc->sc_dflags &= ~SCSI_DATAIN; 172 173 if (dmareq(&dsc->sc_dq) != 0) 174 /* DMA channel is available, so start DMA immediately */ 175 spc_dio_dmago(dsc); 176 /* else dma start function will be called later from dmafree(). */ 177} 178 179static void 180spc_dio_dmago(void *arg) 181{ 182 struct spc_dio_softc *dsc = arg; 183 struct spc_softc *sc = &dsc->sc_spc; 184 bus_space_tag_t iot; 185 bus_space_handle_t iohsc, iohspc; 186 int len, chan; 187 uint32_t dmaflags; 188 uint8_t cmd; 189 190 iot = sc->sc_iot; 191 iohspc = sc->sc_ioh; 192 iohsc = dsc->sc_iohsc; 193 194 bus_space_write_1(iot, iohsc, HPSCSI_HCONF, 0); 195 196 cmd = CSR_IE; 197 dmaflags = DMAGO_NOINT; 198 chan = dsc->sc_dq.dq_chan; 199 if ((dsc->sc_dflags & SCSI_DATAIN) != 0) { 200 cmd |= CSR_DMAIN; 201 dmaflags |= DMAGO_READ; 202 } 203 if ((dsc->sc_dflags & SCSI_DMA32) != 0 && 204 ((u_int)sc->sc_dp & 3) == 0 && 205 (sc->sc_dleft & 3) == 0) { 206 cmd |= CSR_DMA32; 207 dmaflags |= DMAGO_LWORD; 208 } else 209 dmaflags |= DMAGO_WORD; 210 211 dmago(chan, sc->sc_dp, sc->sc_dleft, dmaflags); 212 213 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 214 cmd |= (chan == 0) ? CSR_DE0 : CSR_DE1; 215 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 216 217 cmd = SCMD_XFR; 218 len = sc->sc_dleft; 219 220 if ((len & (DEV_BSIZE - 1)) != 0) /* XXX ??? */ { 221 cmd |= SCMD_PAD; 222#if 0 223 if ((dsc->sc_dflags & SCSI_DATAIN) != 0) 224 len += 2; /* XXX ??? */ 225#endif 226 } 227 228 bus_space_write_1(iot, iohspc, TCH, len >> 16); 229 bus_space_write_1(iot, iohspc, TCM, len >> 8); 230 bus_space_write_1(iot, iohspc, TCL, len); 231 bus_space_write_1(iot, iohspc, PCTL, sc->sc_phase | PCTL_BFINT_ENAB); 232 bus_space_write_1(iot, iohspc, SCMD, cmd); 233 234 sc->sc_flags |= SPC_DOINGDMA; 235#ifdef USELEDS 236 ledcontrol(LED_DISK, 0, 0); 237#endif 238} 239 240static void 241spc_dio_dmadone(struct spc_softc *sc) 242{ 243 struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc; 244 bus_space_tag_t iot; 245 bus_space_handle_t ioh, iohsc; 246 int resid, trans; 247 uint8_t cmd; 248 249 iot = sc->sc_iot; 250 ioh = sc->sc_ioh; 251 iohsc = dsc->sc_iohsc; 252 253 /* wait DMA complete */ 254 if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0) { 255 int timeout = 1000; /* XXX how long? */ 256 while ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0) { 257 if (--timeout < 0) 258 printf("%s: DMA complete timeout\n", 259 device_xname(sc->sc_dev)); 260 DELAY(1); 261 } 262 } 263 264 if ((dsc->sc_dflags & SCSI_HAVEDMA) != 0) { 265 dmafree(&dsc->sc_dq); 266 dsc->sc_dflags &= ~SCSI_HAVEDMA; 267 } 268 269 cmd = bus_space_read_1(iot, iohsc, HPSCSI_CSR); 270 cmd &= ~(CSR_DE1|CSR_DE0); 271 bus_space_write_1(iot, iohsc, HPSCSI_CSR, cmd); 272 273 resid = bus_space_read_1(iot, ioh, TCH) << 16 | 274 bus_space_read_1(iot, ioh, TCM) << 8 | 275 bus_space_read_1(iot, ioh, TCL); 276 trans = sc->sc_dleft - resid; 277 sc->sc_dp += trans; 278 sc->sc_dleft -= trans; 279 280 sc->sc_flags &= ~SPC_DOINGDMA; 281#ifdef USELEDS 282 ledcontrol(0, LED_DISK, 0); 283#endif 284} 285 286static void 287spc_dio_dmastop(void *arg) 288{ 289 struct spc_dio_softc *dsc = arg; 290 struct spc_softc *sc = &dsc->sc_spc; 291 uint8_t cmd; 292 293 /* XXX When is this function called? */ 294 cmd = bus_space_read_1(sc->sc_iot, dsc->sc_iohsc, HPSCSI_CSR); 295 cmd &= ~(CSR_DE1|CSR_DE0); 296 bus_space_write_1(sc->sc_iot, dsc->sc_iohsc, HPSCSI_CSR, cmd); 297 298 dsc->sc_dflags &= ~SCSI_HAVEDMA; 299 sc->sc_flags &= ~SPC_DOINGDMA; 300#ifdef USELEDS 301 ledcontrol(0, LED_DISK, 0); 302#endif 303} 304