1 /* $NetBSD: ncr.c,v 1.52 2024/02/17 17:41:43 tsutsui 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 NCR-5380 34 * controller. The machine-independent parts are in ncr5380sbc.c. 35 * 36 * Jens A. Nilsson. 37 * 38 * Credits: 39 * 40 * This code is based on arch/sun3/dev/si* 41 * Written by David Jones, Gordon Ross, and Adam Glass. 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: ncr.c,v 1.52 2024/02/17 17:41:43 tsutsui Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/buf.h> 50 #include <sys/bus.h> 51 #include <sys/cpu.h> 52 #include <sys/device.h> 53 #include <sys/errno.h> 54 #include <sys/kernel.h> 55 #include <sys/proc.h> 56 57 #include <dev/scsipi/scsi_all.h> 58 #include <dev/scsipi/scsipi_all.h> 59 #include <dev/scsipi/scsipi_debug.h> 60 #include <dev/scsipi/scsiconf.h> 61 62 #include <dev/ic/ncr5380reg.h> 63 #include <dev/ic/ncr5380var.h> 64 65 #include <machine/vsbus.h> 66 #include <machine/sid.h> 67 #include <machine/scb.h> 68 #include <machine/clock.h> 69 #include <machine/ka420.h> 70 71 #include "ioconf.h" 72 73 #define MIN_DMA_LEN 128 74 75 struct si_dma_handle { 76 int dh_flags; 77 #define SIDH_BUSY 1 78 #define SIDH_OUT 2 79 void *dh_addr; 80 int dh_len; 81 struct proc *dh_proc; 82 }; 83 84 struct si_softc { 85 struct ncr5380_softc ncr_sc; 86 struct evcnt ncr_intrcnt; 87 void *ncr_addr; 88 int ncr_off; 89 int ncr_dmaaddr; 90 int ncr_dmacount; 91 int ncr_dmadir; 92 struct si_dma_handle ncr_dma[SCI_OPENINGS]; 93 struct vsbus_dma sc_vd; 94 int onlyscsi; /* This machine needs no queueing */ 95 }; 96 97 static int ncr_dmasize; 98 99 static int si_vsbus_match(device_t, cfdata_t, void *); 100 static void si_vsbus_attach(device_t, device_t, void *); 101 static void si_minphys(struct buf *); 102 103 static void si_dma_alloc(struct ncr5380_softc *); 104 static void si_dma_free(struct ncr5380_softc *); 105 static void si_dma_setup(struct ncr5380_softc *); 106 static void si_dma_start(struct ncr5380_softc *); 107 static void si_dma_poll(struct ncr5380_softc *); 108 static void si_dma_eop(struct ncr5380_softc *); 109 static void si_dma_stop(struct ncr5380_softc *); 110 static void si_dma_go(void *); 111 112 CFATTACH_DECL_NEW(si_vsbus, sizeof(struct si_softc), 113 si_vsbus_match, si_vsbus_attach, NULL, NULL); 114 115 static int 116 si_vsbus_match(device_t parent, cfdata_t cf, void *aux) 117 { 118 struct vsbus_attach_args * const va = aux; 119 volatile char *si_csr = (char *) va->va_addr; 120 121 if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_46 122 || vax_boardtype == VAX_BTYP_48 || vax_boardtype == VAX_BTYP_53) 123 return 0; 124 /* This is the way Linux autoprobes the interrupt MK-990321 */ 125 si_csr[12] = 0; 126 si_csr[16] = 0x80; 127 si_csr[0] = 0x80; 128 si_csr[4] = 5; /* 0xcf */ 129 DELAY(100000); 130 return 1; 131 } 132 133 static void 134 si_vsbus_attach(device_t parent, device_t self, void *aux) 135 { 136 struct vsbus_attach_args * const va = aux; 137 struct si_softc * const sc = device_private(self); 138 struct ncr5380_softc * const ncr_sc = &sc->ncr_sc; 139 int tweak, target; 140 141 ncr_sc->sc_dev = self; 142 143 scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr5380_intr, sc, 144 SCB_ISTACK, &sc->ncr_intrcnt); 145 evcnt_attach_dynamic(&sc->ncr_intrcnt, EVCNT_TYPE_INTR, NULL, 146 device_xname(self), "intr"); 147 148 /* 149 * DMA area mapin. 150 * On VS3100, split the 128K block between the two devices. 151 * On VS2000, don't care for now. 152 */ 153 #define DMASIZE (64*1024) 154 if (va->va_paddr & 0x100) { /* Secondary SCSI controller */ 155 sc->ncr_off = DMASIZE; 156 sc->onlyscsi = 1; 157 } 158 sc->ncr_addr = (void *)va->va_dmaaddr; 159 ncr_dmasize = uimin(va->va_dmasize, MAXPHYS); 160 161 /* 162 * MD function pointers used by the MI code. 163 */ 164 ncr_sc->sc_dma_alloc = si_dma_alloc; 165 ncr_sc->sc_dma_free = si_dma_free; 166 ncr_sc->sc_dma_setup = si_dma_setup; 167 ncr_sc->sc_dma_start = si_dma_start; 168 ncr_sc->sc_dma_poll = si_dma_poll; 169 ncr_sc->sc_dma_eop = si_dma_eop; 170 ncr_sc->sc_dma_stop = si_dma_stop; 171 172 /* DMA control register offsets */ 173 sc->ncr_dmaaddr = 32; /* DMA address in buffer, longword */ 174 sc->ncr_dmacount = 64; /* DMA count register */ 175 sc->ncr_dmadir = 68; /* Direction of DMA transfer */ 176 177 ncr_sc->sc_pio_out = ncr5380_pio_out; 178 ncr_sc->sc_pio_in = ncr5380_pio_in; 179 180 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 181 182 /* 183 * Initialize fields used by the MI code. 184 */ 185 /* ncr_sc->sc_regt = Unused on VAX */ 186 ncr_sc->sc_regh = vax_map_physmem(va->va_paddr, 1); 187 188 /* Register offsets */ 189 ncr_sc->sci_r0 = 0; 190 ncr_sc->sci_r1 = 4; 191 ncr_sc->sci_r2 = 8; 192 ncr_sc->sci_r3 = 12; 193 ncr_sc->sci_r4 = 16; 194 ncr_sc->sci_r5 = 20; 195 ncr_sc->sci_r6 = 24; 196 ncr_sc->sci_r7 = 28; 197 198 ncr_sc->sc_rev = NCR_VARIANT_NCR5380; 199 200 ncr_sc->sc_no_disconnect = 0xff; 201 202 /* 203 * Get the SCSI chip target address out of NVRAM. 204 * This do not apply to the VS2000. 205 */ 206 tweak = clk_tweak + (va->va_paddr & 0x100 ? 3 : 0); 207 if (vax_boardtype == VAX_BTYP_410) 208 target = 7; 209 else 210 target = (clk_page[0xbc/2] >> tweak) & 7; 211 212 /* 213 * Explicitly enable upto 128KB "Big DMA" on KA420. 214 * (It looks KA420 firmware doesn't enable it on network boot) 215 */ 216 #define STC_MODE_OFF (KA420_STC_MODE - KA420_SCS_BASE) 217 if (vax_boardtype == VAX_BTYP_420) { 218 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 219 STC_MODE_OFF, 1); 220 } 221 222 aprint_normal("\n"); 223 aprint_normal_dev(self, "NCR5380, SCSI ID %d\n", target); 224 225 ncr_sc->sc_adapter.adapt_minphys = si_minphys; 226 ncr_sc->sc_channel.chan_id = target; 227 228 /* 229 * Init the vsbus DMA resource queue struct */ 230 sc->sc_vd.vd_go = si_dma_go; 231 sc->sc_vd.vd_arg = sc; 232 233 /* 234 * Initialize si board itself. 235 */ 236 ncr5380_attach(ncr_sc); 237 } 238 239 /* 240 * Adjust the max transfer size. The DMA buffer is only 16k on VS2000. 241 */ 242 static void 243 si_minphys(struct buf *bp) 244 { 245 if (bp->b_bcount > ncr_dmasize) 246 bp->b_bcount = ncr_dmasize; 247 } 248 249 void 250 si_dma_alloc(struct ncr5380_softc *ncr_sc) 251 { 252 struct si_softc *sc = (struct si_softc *)ncr_sc; 253 struct sci_req *sr = ncr_sc->sc_current; 254 struct scsipi_xfer *xs = sr->sr_xs; 255 struct si_dma_handle *dh; 256 int xlen, i; 257 258 #ifdef DIAGNOSTIC 259 if (sr->sr_dma_hand != NULL) 260 panic("si_dma_alloc: already have DMA handle"); 261 #endif 262 263 /* Polled transfers shouldn't allocate a DMA handle. */ 264 if (sr->sr_flags & SR_IMMED) 265 return; 266 267 xlen = ncr_sc->sc_datalen; 268 269 /* Make sure our caller checked sc_min_dma_len. */ 270 if (xlen < MIN_DMA_LEN) 271 panic("si_dma_alloc: len=0x%x", xlen); 272 273 /* 274 * Find free PDMA handle. Guaranteed to find one since we 275 * have as many PDMA handles as the driver has processes. 276 * (instances?) 277 */ 278 for (i = 0; i < SCI_OPENINGS; i++) { 279 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 280 goto found; 281 } 282 panic("sbc: no free PDMA handles"); 283 found: 284 dh = &sc->ncr_dma[i]; 285 dh->dh_flags = SIDH_BUSY; 286 dh->dh_addr = ncr_sc->sc_dataptr; 287 dh->dh_len = xlen; 288 if (((vaddr_t)ncr_sc->sc_dataptr & KERNBASE) == 0) { 289 if (xs->bp == NULL) 290 panic("si_dma_alloc"); 291 dh->dh_proc = xs->bp->b_proc; 292 } 293 294 /* Remember dest buffer parameters */ 295 if (xs->xs_control & XS_CTL_DATA_OUT) 296 dh->dh_flags |= SIDH_OUT; 297 298 sr->sr_dma_hand = dh; 299 } 300 301 void 302 si_dma_free(struct ncr5380_softc *ncr_sc) 303 { 304 struct sci_req *sr = ncr_sc->sc_current; 305 struct si_dma_handle *dh = sr->sr_dma_hand; 306 307 if (dh->dh_flags & SIDH_BUSY) 308 dh->dh_flags = 0; 309 else 310 printf("si_dma_free: free'ing unused buffer\n"); 311 312 sr->sr_dma_hand = NULL; 313 } 314 315 void 316 si_dma_setup(struct ncr5380_softc *ncr_sc) 317 { 318 /* Do nothing here */ 319 } 320 321 void 322 si_dma_start(struct ncr5380_softc *ncr_sc) 323 { 324 struct si_softc *sc = (struct si_softc *)ncr_sc; 325 326 /* Just put on queue; will call go() from below */ 327 if (sc->onlyscsi) 328 si_dma_go(ncr_sc); 329 else 330 vsbus_dma_start(&sc->sc_vd); 331 } 332 333 /* 334 * go() routine called when another transfer somewhere is finished. 335 */ 336 void 337 si_dma_go(void *arg) 338 { 339 struct ncr5380_softc *ncr_sc = arg; 340 struct si_softc *sc = (struct si_softc *)ncr_sc; 341 struct sci_req *sr = ncr_sc->sc_current; 342 struct si_dma_handle *dh = sr->sr_dma_hand; 343 344 /* 345 * Set the VAX-DMA-specific registers, and copy the data if 346 * it is directed "outbound". 347 */ 348 if (dh->dh_flags & SIDH_OUT) { 349 vsbus_copyfromproc(dh->dh_proc, dh->dh_addr, 350 (char *)sc->ncr_addr + sc->ncr_off, dh->dh_len); 351 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 352 sc->ncr_dmadir, 0); 353 } else { 354 bus_space_write_1(ncr_sc->sc_regt, ncr_sc->sc_regh, 355 sc->ncr_dmadir, 1); 356 } 357 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 358 sc->ncr_dmacount, -dh->dh_len); 359 bus_space_write_4(ncr_sc->sc_regt, ncr_sc->sc_regh, 360 sc->ncr_dmaaddr, sc->ncr_off); 361 /* 362 * Now from the 5380-internal DMA registers. 363 */ 364 if (dh->dh_flags & SIDH_OUT) { 365 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 366 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 367 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 368 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 369 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 370 } else { 371 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 372 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 373 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 374 | SCI_MODE_DMA | SCI_MODE_DMA_IE); 375 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 376 } 377 ncr_sc->sc_state |= NCR_DOINGDMA; 378 } 379 380 /* 381 * When? 382 */ 383 void 384 si_dma_poll(struct ncr5380_softc *ncr_sc) 385 { 386 printf("si_dma_poll\n"); 387 } 388 389 /* 390 * When? 391 */ 392 void 393 si_dma_eop(struct ncr5380_softc *ncr_sc) 394 { 395 printf("si_dma_eop\n"); 396 } 397 398 void 399 si_dma_stop(struct ncr5380_softc *ncr_sc) 400 { 401 struct si_softc *sc = (struct si_softc *)ncr_sc; 402 struct sci_req *sr = ncr_sc->sc_current; 403 struct si_dma_handle *dh = sr->sr_dma_hand; 404 int count, i; 405 406 if (ncr_sc->sc_state & NCR_DOINGDMA) 407 ncr_sc->sc_state &= ~NCR_DOINGDMA; 408 409 /* 410 * Sometimes the FIFO buffer isn't drained when the 411 * interrupt is posted. Just loop here and hope that 412 * it will drain soon. 413 */ 414 for (i = 0; i < 20000; i++) { 415 count = bus_space_read_4(ncr_sc->sc_regt, 416 ncr_sc->sc_regh, sc->ncr_dmacount); 417 if (count == 0) 418 break; 419 DELAY(100); 420 } 421 if (count == 0) { 422 if (((dh->dh_flags & SIDH_OUT) == 0)) { 423 vsbus_copytoproc(dh->dh_proc, 424 (char *)sc->ncr_addr + sc->ncr_off, 425 dh->dh_addr, dh->dh_len); 426 } 427 ncr_sc->sc_dataptr += dh->dh_len; 428 ncr_sc->sc_datalen -= dh->dh_len; 429 } 430 431 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 432 ~(SCI_MODE_DMA | SCI_MODE_DMA_IE)); 433 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 434 if (sc->onlyscsi == 0) 435 vsbus_dma_intr(); /* Try to start more transfers */ 436 } 437