1 /* $NetBSD: si.c,v 1.28 2026/04/26 12:49:38 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This file contains the machine-dependent parts of the Sony CXD1180 34 * controller. The machine-independent parts are in ncr5380sbc.c. 35 * Written by Izumi Tsutsui. 36 * 37 * This code is based on arch/vax/vsa/ncr.c and sun3/dev/si.c 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.28 2026/04/26 12:49:38 thorpej Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/buf.h> 47 48 #include <machine/cpu.h> 49 #include <m68k/cacheops.h> 50 51 #include <dev/scsipi/scsipi_all.h> 52 #include <dev/scsipi/scsiconf.h> 53 54 #include <dev/ic/ncr5380reg.h> 55 #include <dev/ic/ncr5380var.h> 56 57 #include <news68k/dev/hbvar.h> 58 #include <news68k/dev/dmac_0266.h> 59 60 #include "ioconf.h" 61 62 #define MIN_DMA_LEN 128 63 #define DMAC_BASE 0xe0e80000 /* XXX */ 64 #define SI_REGSIZE 8 65 66 struct si_softc { 67 struct ncr5380_softc ncr_sc; 68 int sc_options; 69 struct dma_regs *sc_regs; 70 int sc_xlen; 71 }; 72 73 static int si_match(device_t, cfdata_t, void *); 74 static void si_attach(device_t, device_t, void *); 75 static int si_test(bus_addr_t); 76 int si_intr(int); 77 78 static void si_dma_alloc(struct ncr5380_softc *); 79 static void si_dma_free(struct ncr5380_softc *); 80 static void si_dma_start(struct ncr5380_softc *); 81 static void si_dma_poll(struct ncr5380_softc *); 82 static void si_dma_eop(struct ncr5380_softc *); 83 static void si_dma_stop(struct ncr5380_softc *); 84 85 CFATTACH_DECL_NEW(si, sizeof(struct si_softc), 86 si_match, si_attach, NULL, NULL); 87 88 /* 89 * Options for disconnect/reselect, DMA, and interrupts. 90 * By default, allow disconnect/reselect on targets 4-6. 91 * Those are normally tapes that really need it enabled. 92 * The options are taken from the config file. 93 */ 94 #define SI_NO_DISCONNECT 0x000ff 95 #define SI_NO_PARITY_CHK 0x0ff00 96 #define SI_FORCE_POLLING 0x10000 97 #define SI_DISABLE_DMA 0x20000 98 99 int si_options = 0x00; 100 101 102 static int 103 si_match(device_t parent, cfdata_t cf, void *aux) 104 { 105 struct hb_attach_args *ha = aux; 106 int addr; 107 108 if (strcmp(ha->ha_name, "si")) 109 return 0; 110 111 addr = (ha->ha_address); 112 113 if (badbaddr((void *)addr)) 114 return 0; 115 116 if (si_test(addr) == 0) 117 return 0; 118 119 ha->ha_size = SI_REGSIZE; 120 121 return 1; 122 } 123 124 /* 125 * Explicitly probe CXD1180 for Nono emulator. 126 * Partially taken from nca_isa.c. 127 */ 128 static int 129 si_test(bus_addr_t addr) 130 { 131 volatile uint8_t *cxd = (uint8_t *)addr; 132 uint8_t bcsr; 133 134 #define SI_ODATA 0 135 #define SI_ICMD 1 136 #define SI_BUS_CSR 4 137 /* Reset the SCSI bus. */ 138 *(cxd + SI_ICMD) = SCI_ICMD_RST; 139 *(cxd + SI_ODATA) = 0; 140 141 /* Hold reset for at least 25 microsconds. */ 142 delay(500); 143 bcsr = *(cxd + SI_BUS_CSR); 144 *(cxd + SI_ICMD) = 0; 145 146 /* Check that status cleared. */ 147 if (bcsr != SCI_BUS_RST) { 148 /* Assume Nono, no si(4) here (yet). */ 149 return 0; 150 } 151 152 return 1; 153 } 154 155 /* 156 * Card attach function 157 */ 158 159 static void 160 si_attach(device_t parent, device_t self, void *aux) 161 { 162 struct si_softc *sc = device_private(self); 163 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 164 struct cfdata *cf = device_cfdata(self); 165 struct hb_attach_args *ha = aux; 166 167 ncr_sc->sc_dev = self; 168 ncr_sc->sc_regt = ha->ha_bust; 169 if (bus_space_map(ncr_sc->sc_regt, (bus_addr_t)ha->ha_address, 170 ha->ha_size, 0, &ncr_sc->sc_regh) != 0) { 171 aprint_error(": can't map device space\n"); 172 return; 173 } 174 175 /* Get options from config flags if specified. */ 176 if (cf->cf_flags) 177 sc->sc_options = cf->cf_flags; 178 else 179 sc->sc_options = si_options; 180 181 if (sc->sc_options != 0) 182 aprint_normal(": options=0x%x", sc->sc_options); 183 aprint_normal("\n"); 184 185 ncr_sc->sc_no_disconnect = (sc->sc_options & SI_NO_DISCONNECT); 186 ncr_sc->sc_parity_disable = (sc->sc_options & SI_NO_PARITY_CHK) >> 8; 187 if (sc->sc_options & SI_FORCE_POLLING) 188 ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; 189 190 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 191 ncr_sc->sc_dma_alloc = si_dma_alloc; 192 ncr_sc->sc_dma_free = si_dma_free; 193 ncr_sc->sc_dma_poll = si_dma_poll; 194 ncr_sc->sc_dma_start = si_dma_start; 195 ncr_sc->sc_dma_eop = si_dma_eop; 196 ncr_sc->sc_dma_stop = si_dma_stop; 197 198 if (sc->sc_options & SI_DISABLE_DMA) 199 /* Override this function pointer. */ 200 ncr_sc->sc_dma_alloc = NULL; 201 202 ncr_sc->sci_r0 = 0; 203 ncr_sc->sci_r1 = 1; 204 ncr_sc->sci_r2 = 2; 205 ncr_sc->sci_r3 = 3; 206 ncr_sc->sci_r4 = 4; 207 ncr_sc->sci_r5 = 5; 208 ncr_sc->sci_r6 = 6; 209 ncr_sc->sci_r7 = 7; 210 211 ncr_sc->sc_rev = NCR_VARIANT_CXD1180; 212 213 ncr_sc->sc_pio_in = ncr5380_pio_in; 214 ncr_sc->sc_pio_out = ncr5380_pio_out; 215 216 ncr_sc->sc_adapter.adapt_minphys = minphys; 217 ncr_sc->sc_channel.chan_id = 7; 218 219 /* soft reset DMAC */ 220 sc->sc_regs = (void *)(DMAC_BASE); 221 sc->sc_regs->ctl = DC_CTL_RST; 222 223 ncr5380_attach(ncr_sc); 224 } 225 226 int 227 si_intr(int unit) 228 { 229 struct si_softc *sc; 230 231 if (unit >= si_cd.cd_ndevs) 232 return 0; 233 234 sc = device_lookup_private(&si_cd, unit); /* XXX */ 235 (void)ncr5380_intr(&sc->ncr_sc); 236 237 return 0; 238 } 239 240 /* 241 * DMA routines for news1700 machines 242 */ 243 static void 244 si_dma_alloc(struct ncr5380_softc *ncr_sc) 245 { 246 struct sci_req *sr = ncr_sc->sc_current; 247 248 #ifdef DIAGNOSTIC 249 if (sr->sr_dma_hand != NULL) 250 panic("%s: DMA already in use", __func__); 251 #endif 252 253 /* 254 * On news68k, SCSI has its own DMAC so no need allocate it. 255 * Just mark that DMA is available. 256 */ 257 sr->sr_dma_hand = (void *)-1; 258 } 259 260 static void 261 si_dma_free(struct ncr5380_softc *ncr_sc) 262 { 263 struct sci_req *sr = ncr_sc->sc_current; 264 265 #ifdef DIAGNOSTIC 266 if (sr->sr_dma_hand == NULL) 267 panic("%s: DMA not in use", __func__); 268 #endif 269 270 sr->sr_dma_hand = NULL; 271 } 272 273 274 static void 275 si_dma_start(struct ncr5380_softc *ncr_sc) 276 { 277 struct si_softc *sc = (struct si_softc *)ncr_sc; 278 struct dma_regs *dmac = sc->sc_regs; 279 struct sci_req *sr = ncr_sc->sc_current; 280 u_int addr, offset, rest; 281 long len; 282 int i; 283 284 /* reset DMAC */ 285 dmac->ctl = DC_CTL_RST; 286 dmac->ctl = 0; 287 288 addr = (u_int)ncr_sc->sc_dataptr; 289 offset = addr & DMAC_SEG_OFFSET; 290 len = sc->sc_xlen = ncr_sc->sc_datalen; 291 292 /* set DMA transfer length */ 293 dmac->tcnt = (uint32_t)len; 294 295 /* set offset of first segment */ 296 dmac->offset = offset; 297 298 /* set first DMA segment address */ 299 dmac->tag = 0; 300 dmac->mapent = kvtop((void *)addr) >> DMAC_SEG_SHIFT; 301 rest = DMAC_SEG_SIZE - offset; 302 addr += rest; 303 len -= rest; 304 305 /* set all the rest segments */ 306 for (i = 1; len > 0; i++) { 307 dmac->tag = i; 308 dmac->mapent = kvtop((void *)addr) >> DMAC_SEG_SHIFT; 309 len -= DMAC_SEG_SIZE; 310 addr += DMAC_SEG_SIZE; 311 } 312 /* terminate TAG */ 313 dmac->tag = 0; 314 315 if (sr->sr_xs->xs_control & XS_CTL_DATA_OUT) { 316 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 317 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 318 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 319 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 320 321 /* set Dir */ 322 dmac->ctl = 0; 323 324 /* start DMA */ 325 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 326 dmac->ctl = DC_CTL_ENB; 327 } else { 328 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 329 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 330 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 331 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 332 333 /* set Dir */ 334 dmac->ctl = DC_CTL_MOD; 335 336 /* start DMA */ 337 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 338 dmac->ctl = DC_CTL_MOD | DC_CTL_ENB; 339 } 340 ncr_sc->sc_state |= NCR_DOINGDMA; 341 } 342 343 /* 344 * When? 345 */ 346 static void 347 si_dma_poll(struct ncr5380_softc *ncr_sc) 348 { 349 struct si_softc *sc = (struct si_softc *)ncr_sc; 350 struct dma_regs *dmac = sc->sc_regs; 351 int i; 352 353 #define POLL_TIMEOUT 100000 354 355 /* check DMAC interrupt status */ 356 for (i = 0; i < POLL_TIMEOUT; i++) { 357 if ((dmac->stat & DC_ST_INT) != 0) 358 break; 359 delay(10); 360 } 361 362 if (i == POLL_TIMEOUT) 363 printf("%s: DMA polling timeout\n", 364 device_xname(ncr_sc->sc_dev)); 365 } 366 367 /* 368 * news68k (probably) does not use the EOP signal. 369 */ 370 static void 371 si_dma_eop(struct ncr5380_softc *ncr_sc) 372 { 373 374 printf("si_dma_eop\n"); 375 } 376 377 static void 378 si_dma_stop(struct ncr5380_softc *ncr_sc) 379 { 380 struct si_softc *sc = (struct si_softc *)ncr_sc; 381 struct dma_regs *dmac = sc->sc_regs; 382 struct sci_req *sr = ncr_sc->sc_current; 383 int resid, ntrans; 384 385 /* check DMAC interrupt status */ 386 if ((dmac->stat & DC_ST_INT) == 0) { 387 #ifdef DEBUG 388 printf("%s: no DMA interrupt\n", __func__); 389 #endif 390 return; /* XXX */ 391 } 392 393 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 394 #ifdef DEBUG 395 printf("%s: dma not running\n", __func__); 396 #endif 397 return; 398 } 399 ncr_sc->sc_state &= ~NCR_DOINGDMA; 400 401 /* stop DMAC */ 402 resid = dmac->tcnt; 403 dmac->ctl &= ~DC_CTL_ENB; 404 405 /* OK, have either phase mis-match or end of DMA. */ 406 /* Set an impossible phase to prevent data movement? */ 407 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_INVALID); 408 409 /* Note that timeout may have set the error flag. */ 410 if (ncr_sc->sc_state & NCR_ABORTING) 411 goto out; 412 413 #ifdef DEBUG 414 if (resid) 415 printf("%s: datalen = 0x%x, resid = 0x%x\n", 416 __func__, sc->sc_xlen, resid); 417 #endif 418 419 ntrans = sc->sc_xlen - resid; 420 421 ncr_sc->sc_dataptr += ntrans; 422 ncr_sc->sc_datalen -= ntrans; 423 424 if (sr->sr_xs->xs_control & XS_CTL_DATA_IN) { 425 /* flush data cache */ 426 PCIA(); 427 } 428 429 out: 430 /* reset DMAC */ 431 dmac->ctl = DC_CTL_RST; 432 dmac->ctl = 0; 433 434 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 435 ~(SCI_MODE_DMA | SCI_MODE_DMA_IE)); 436 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 437 } 438