1 /* $NetBSD: si_obio.c,v 1.39 2024/12/20 23:52:00 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, and Gordon W. Ross. 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 only the machine-dependent parts of the 34 * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) 35 * The machine-independent parts are in ncr5380sbc.c 36 * 37 * Supported hardware includes: 38 * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) 39 * Sun SCSI-3 on VME (Sun3/160,Sun3/260) 40 * 41 * Could be made to support the Sun3/E if someone wanted to. 42 * 43 * Note: Both supported variants of the Sun SCSI-3 adapter have 44 * some really unusual "features" for this driver to deal with, 45 * generally related to the DMA engine. The OBIO variant will 46 * ignore any attempt to write the FIFO count register while the 47 * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with 48 * by setting the FIFO count early in COMMAND or MSG_IN phase. 49 * 50 * The VME variant has a bit to enable or disable the DMA engine, 51 * but that bit also gates the interrupt line from the NCR5380! 52 * Therefore, in order to get any interrupt from the 5380, (i.e. 53 * for reselect) one must clear the DMA engine transfer count and 54 * then enable DMA. This has the further complication that you 55 * CAN NOT touch the NCR5380 while the DMA enable bit is set, so 56 * we have to turn DMA back off before we even look at the 5380. 57 * 58 * What wonderfully whacky hardware this is! 59 * 60 * Credits, history: 61 * 62 * David Jones wrote the initial version of this module, which 63 * included support for the VME adapter only. (no reselection). 64 * 65 * Gordon Ross added support for the OBIO adapter, and re-worked 66 * both the VME and OBIO code to support disconnect/reselect. 67 * (Required figuring out the hardware "features" noted above.) 68 * 69 * The autoconfiguration boilerplate came from Adam Glass. 70 */ 71 72 /***************************************************************** 73 * OBIO functions for DMA 74 ****************************************************************/ 75 76 #include <sys/cdefs.h> 77 __KERNEL_RCSID(0, "$NetBSD: si_obio.c,v 1.39 2024/12/20 23:52:00 tsutsui Exp $"); 78 79 #include <sys/param.h> 80 #include <sys/systm.h> 81 #include <sys/errno.h> 82 #include <sys/kernel.h> 83 #include <sys/device.h> 84 #include <sys/buf.h> 85 #include <sys/proc.h> 86 87 #include <dev/scsipi/scsi_all.h> 88 #include <dev/scsipi/scsipi_all.h> 89 #include <dev/scsipi/scsipi_debug.h> 90 #include <dev/scsipi/scsiconf.h> 91 92 #include <machine/autoconf.h> 93 #include <machine/dvma.h> 94 95 /* #define DEBUG XXX */ 96 97 #include <dev/ic/ncr5380reg.h> 98 #include <dev/ic/ncr5380var.h> 99 100 #include "sireg.h" 101 #include "sivar.h" 102 #include "am9516.h" 103 104 /* 105 * How many uS. to delay after touching the am9516 UDC. 106 */ 107 #define UDC_WAIT_USEC 5 108 109 void si_obio_dma_setup(struct ncr5380_softc *); 110 void si_obio_dma_start(struct ncr5380_softc *); 111 void si_obio_dma_eop(struct ncr5380_softc *); 112 void si_obio_dma_stop(struct ncr5380_softc *); 113 114 static void si_obio_reset(struct ncr5380_softc *); 115 116 static inline void si_obio_udc_write(volatile struct si_regs *, int, int); 117 static inline int si_obio_udc_read(volatile struct si_regs *, int); 118 119 120 /* 121 * New-style autoconfig attachment 122 */ 123 124 static int si_obio_match(device_t, cfdata_t, void *); 125 static void si_obio_attach(device_t, device_t, void *); 126 127 CFATTACH_DECL_NEW(si_obio, sizeof(struct si_softc), 128 si_obio_match, si_obio_attach, NULL, NULL); 129 130 /* 131 * Options for disconnect/reselect, DMA, and interrupts. 132 * By default, allow disconnect/reselect on targets 4-6. 133 * Those are normally tapes that really need it enabled. 134 */ 135 int si_obio_options = 0x0f; 136 137 138 static int 139 si_obio_match(device_t parent, cfdata_t cf, void *aux) 140 { 141 struct confargs *ca = aux; 142 143 /* Make sure something is there... */ 144 if (bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1) == -1) 145 return 0; 146 147 /* Default interrupt priority. */ 148 if (ca->ca_intpri == -1) 149 ca->ca_intpri = 2; 150 151 return 1; 152 } 153 154 static void 155 si_obio_attach(device_t parent, device_t self, void *args) 156 { 157 struct si_softc *sc = device_private(self); 158 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 159 struct cfdata *cf = device_cfdata(self); 160 struct confargs *ca = args; 161 162 ncr_sc->sc_dev = self; 163 sc->sc_bst = ca->ca_bustag; 164 sc->sc_dmat = ca->ca_dmatag; 165 166 if (bus_space_map(sc->sc_bst, ca->ca_paddr, sizeof(struct si_regs), 0, 167 &sc->sc_bsh) != 0) { 168 aprint_error(": can't map register\n"); 169 return; 170 } 171 sc->sc_regs = bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 172 173 if (bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0, 174 BUS_DMA_NOWAIT, &sc->sc_dmap) != 0) { 175 aprint_error(": can't create DMA map\n"); 176 return; 177 } 178 179 /* Get options from config flags if specified. */ 180 if (cf->cf_flags) 181 sc->sc_options = cf->cf_flags; 182 else 183 sc->sc_options = si_obio_options; 184 185 aprint_normal(": options=0x%x\n", sc->sc_options); 186 187 sc->sc_adapter_type = ca->ca_bustype; 188 189 /* 190 * MD function pointers used by the MI code. 191 */ 192 ncr_sc->sc_pio_out = ncr5380_pio_out; 193 ncr_sc->sc_pio_in = ncr5380_pio_in; 194 ncr_sc->sc_dma_alloc = si_dma_alloc; 195 ncr_sc->sc_dma_free = si_dma_free; 196 ncr_sc->sc_dma_setup = si_obio_dma_setup; 197 ncr_sc->sc_dma_start = si_obio_dma_start; 198 ncr_sc->sc_dma_poll = si_dma_poll; 199 ncr_sc->sc_dma_eop = si_obio_dma_eop; 200 ncr_sc->sc_dma_stop = si_obio_dma_stop; 201 ncr_sc->sc_intr_on = NULL; 202 ncr_sc->sc_intr_off = NULL; 203 204 /* Need DVMA-capable memory for the UDC command block. */ 205 sc->sc_dmacmd = dvma_malloc(sizeof(struct udc_table)); 206 207 /* Attach interrupt handler. */ 208 isr_add_autovect(si_intr, (void *)sc, ca->ca_intpri); 209 210 /* Reset the hardware. */ 211 si_obio_reset(ncr_sc); 212 213 /* Do the common attach stuff. */ 214 si_attach(sc); 215 } 216 217 static void 218 si_obio_reset(struct ncr5380_softc *ncr_sc) 219 { 220 struct si_softc *sc = (struct si_softc *)ncr_sc; 221 volatile struct si_regs *si = sc->sc_regs; 222 223 #ifdef DEBUG 224 if (si_debug) { 225 printf("%s\n", __func__); 226 } 227 #endif 228 229 /* 230 * The SCSI3 controller has an 8K FIFO to buffer data between the 231 * 5380 and the DMA. Make sure it starts out empty. 232 * 233 * The reset bits in the CSR are active low. 234 */ 235 si->si_csr = 0; 236 delay(10); 237 si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES | SI_CSR_INTR_EN; 238 delay(10); 239 si->fifo_count = 0; 240 } 241 242 static inline void 243 si_obio_udc_write(volatile struct si_regs *si, int regnum, int value) 244 { 245 246 si->udc_addr = regnum; 247 delay(UDC_WAIT_USEC); 248 si->udc_data = value; 249 delay(UDC_WAIT_USEC); 250 } 251 252 static inline int 253 si_obio_udc_read(volatile struct si_regs *si, int regnum) 254 { 255 int value; 256 257 si->udc_addr = regnum; 258 delay(UDC_WAIT_USEC); 259 value = si->udc_data; 260 delay(UDC_WAIT_USEC); 261 262 return value; 263 } 264 265 266 /* 267 * This function is called during the COMMAND or MSG_IN phase 268 * that precedes a DATA_IN or DATA_OUT phase, in case we need 269 * to setup the DMA engine before the bus enters a DATA phase. 270 * 271 * The OBIO "si" IGNORES any attempt to set the FIFO count 272 * register after the SCSI bus goes into any DATA phase, so 273 * this function has to setup the evil FIFO logic. 274 */ 275 void 276 si_obio_dma_setup(struct ncr5380_softc *ncr_sc) 277 { 278 struct si_softc *sc = (struct si_softc *)ncr_sc; 279 struct sci_req *sr = ncr_sc->sc_current; 280 struct si_dma_handle *dh = sr->sr_dma_hand; 281 volatile struct si_regs *si = sc->sc_regs; 282 struct udc_table *cmd; 283 long data_pa, cmd_pa; 284 int xlen; 285 286 /* 287 * Get the DVMA mapping for this segment. 288 * XXX - Should separate allocation and mapin. 289 */ 290 data_pa = dh->dh_dmaaddr; 291 if (data_pa & 1) 292 panic("%s: bad pa=0x%lx", __func__, data_pa); 293 xlen = dh->dh_dmalen; 294 sc->sc_reqlen = xlen; /* XXX: or less? */ 295 296 #ifdef DEBUG 297 if (si_debug & 2) { 298 printf("%s: dh=%p, pa=0x%lx, xlen=0x%x\n", 299 __func__, dh, data_pa, xlen); 300 } 301 #endif 302 303 /* Reset the UDC. (In case not already reset?) */ 304 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); 305 306 /* Reset the FIFO */ 307 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ 308 si->si_csr |= SI_CSR_FIFO_RES; 309 310 /* Set direction (send/recv) */ 311 if (dh->dh_flags & SIDH_OUT) { 312 si->si_csr |= SI_CSR_SEND; 313 } else { 314 si->si_csr &= ~SI_CSR_SEND; 315 } 316 317 /* Set the FIFO counter. */ 318 si->fifo_count = xlen; 319 320 /* Reset the UDC. */ 321 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); 322 323 /* 324 * XXX: Reset the FIFO again! Comment from Sprite: 325 * Go through reset again because of the bug on the 3/50 326 * where bytes occasionally linger in the DMA fifo. 327 */ 328 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ 329 si->si_csr |= SI_CSR_FIFO_RES; 330 331 #ifdef DEBUG 332 /* Make sure the extra FIFO reset did not hit the count. */ 333 if (si->fifo_count != xlen) { 334 printf("%s: fifo_count=0x%x, xlen=0x%x\n", 335 __func__, si->fifo_count, xlen); 336 Debugger(); 337 } 338 #endif 339 340 /* 341 * Set up the DMA controller. The DMA controller on 342 * OBIO needs a command block in DVMA space. 343 */ 344 cmd = sc->sc_dmacmd; 345 cmd->addrh = ((data_pa & 0xFF0000) >> 8) | UDC_ADDR_INFO; 346 cmd->addrl = data_pa & 0xFFFF; 347 cmd->count = xlen / 2; /* bytes -> words */ 348 cmd->cmrh = UDC_CMR_HIGH; 349 if (dh->dh_flags & SIDH_OUT) { 350 if (xlen & 1) 351 cmd->count++; 352 cmd->cmrl = UDC_CMR_LSEND; 353 cmd->rsel = UDC_RSEL_SEND; 354 } else { 355 cmd->cmrl = UDC_CMR_LRECV; 356 cmd->rsel = UDC_RSEL_RECV; 357 } 358 359 /* Tell the DMA chip where the control block is. */ 360 cmd_pa = dvma_kvtopa(cmd, BUS_OBIO); 361 si_obio_udc_write(si, UDC_ADR_CAR_HIGH, (cmd_pa & 0xff0000) >> 8); 362 si_obio_udc_write(si, UDC_ADR_CAR_LOW, (cmd_pa & 0xffff)); 363 364 /* Tell the chip to be a DMA master. */ 365 si_obio_udc_write(si, UDC_ADR_MODE, UDC_MODE); 366 367 /* Tell the chip to interrupt on error. */ 368 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_CIE); 369 370 /* Will do "start chain" command in _dma_start. */ 371 } 372 373 374 void 375 si_obio_dma_start(struct ncr5380_softc *ncr_sc) 376 { 377 struct si_softc *sc = (struct si_softc *)ncr_sc; 378 struct sci_req *sr = ncr_sc->sc_current; 379 struct si_dma_handle *dh = sr->sr_dma_hand; 380 volatile struct si_regs *si = sc->sc_regs; 381 int s; 382 383 #ifdef DEBUG 384 if (si_debug & 2) { 385 printf("%s: sr=%p\n", __func__, sr); 386 } 387 #endif 388 389 /* This MAY be time critical (not sure). */ 390 s = splhigh(); 391 392 /* Finally, give the UDC a "start chain" command. */ 393 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_STRT_CHN); 394 395 /* 396 * Acknowledge the phase change. (After DMA setup!) 397 * Put the SBIC into DMA mode, and start the transfer. 398 */ 399 if (dh->dh_flags & SIDH_OUT) { 400 *ncr_sc->sci_tcmd = PHASE_DATA_OUT; 401 SCI_CLR_INTR(ncr_sc); 402 *ncr_sc->sci_icmd = SCI_ICMD_DATA; 403 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); 404 *ncr_sc->sci_dma_send = 0; /* start it */ 405 } else { 406 *ncr_sc->sci_tcmd = PHASE_DATA_IN; 407 SCI_CLR_INTR(ncr_sc); 408 *ncr_sc->sci_icmd = 0; 409 *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); 410 *ncr_sc->sci_irecv = 0; /* start it */ 411 } 412 413 splx(s); 414 ncr_sc->sc_state |= NCR_DOINGDMA; 415 416 #ifdef DEBUG 417 if (si_debug & 2) { 418 printf("%s: started, flags=0x%x\n", 419 __func__, ncr_sc->sc_state); 420 } 421 #endif 422 } 423 424 425 void 426 si_obio_dma_eop(struct ncr5380_softc *ncr_sc) 427 { 428 429 /* Not needed - DMA was stopped prior to examining sci_csr */ 430 } 431 432 433 void 434 si_obio_dma_stop(struct ncr5380_softc *ncr_sc) 435 { 436 struct si_softc *sc = (struct si_softc *)ncr_sc; 437 struct sci_req *sr = ncr_sc->sc_current; 438 struct si_dma_handle *dh = sr->sr_dma_hand; 439 volatile struct si_regs *si = sc->sc_regs; 440 int resid, ntrans, tmo, udc_cnt; 441 442 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 443 #ifdef DEBUG 444 printf("%s: DMA not running\n", __func__); 445 #endif 446 return; 447 } 448 ncr_sc->sc_state &= ~NCR_DOINGDMA; 449 450 NCR_TRACE("si_dma_stop: top, csr=0x%x\n", si->si_csr); 451 452 /* OK, have either phase mis-match or end of DMA. */ 453 /* Set an impossible phase to prevent data movement? */ 454 *ncr_sc->sci_tcmd = PHASE_INVALID; 455 456 /* Check for DMA errors. */ 457 if (si->si_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { 458 printf("si: DMA error, csr=0x%x, reset\n", si->si_csr); 459 sr->sr_xs->error = XS_DRIVER_STUFFUP; 460 ncr_sc->sc_state |= NCR_ABORTING; 461 si_obio_reset(ncr_sc); 462 goto out; 463 } 464 465 /* Note that timeout may have set the error flag. */ 466 if (ncr_sc->sc_state & NCR_ABORTING) 467 goto out; 468 469 /* 470 * After a read, wait for the FIFO to empty. 471 * Note: this only works on the OBIO version. 472 */ 473 if ((dh->dh_flags & SIDH_OUT) == 0) { 474 tmo = 200000; /* X10 = 2 sec. */ 475 for (;;) { 476 if (si->si_csr & SI_CSR_FIFO_EMPTY) 477 break; 478 if (--tmo <= 0) { 479 printf("si: DMA FIFO did not empty, reset\n"); 480 ncr_sc->sc_state |= NCR_ABORTING; 481 /* si_obio_reset(ncr_sc); */ 482 goto out; 483 } 484 delay(10); 485 } 486 } 487 488 /* 489 * Now try to figure out how much actually transferred. 490 * The fifo_count might not reflect how many bytes were 491 * actually transferred. 492 */ 493 resid = si->fifo_count & 0xFFFF; 494 ntrans = sc->sc_reqlen - resid; 495 496 #ifdef DEBUG 497 if (si_debug & 2) { 498 printf("%s: resid=0x%x ntrans=0x%x\n", 499 __func__, resid, ntrans); 500 } 501 #endif 502 503 /* XXX: Treat (ntrans==0) as a special, non-error case? */ 504 if (ntrans < MIN_DMA_LEN) { 505 printf("si: fifo count: 0x%x\n", resid); 506 ncr_sc->sc_state |= NCR_ABORTING; 507 goto out; 508 } 509 if (ntrans > ncr_sc->sc_datalen) 510 panic("%s: excess transfer", __func__); 511 512 /* Adjust data pointer */ 513 ncr_sc->sc_dataptr += ntrans; 514 ncr_sc->sc_datalen -= ntrans; 515 516 /* 517 * After a read, we may need to clean-up 518 * "Left-over bytes" (yuck!) 519 */ 520 if ((dh->dh_flags & SIDH_OUT) == 0) { 521 /* If odd transfer count, grab last byte by hand. */ 522 if (ntrans & 1) { 523 NCR_TRACE("si_dma_stop: leftover 1 at 0x%x\n", 524 (int) ncr_sc->sc_dataptr - 1); 525 ncr_sc->sc_dataptr[-1] = 526 (si->fifo_data & 0xff00) >> 8; 527 goto out; 528 } 529 /* UDC might not have transferred the last word. */ 530 udc_cnt = si_obio_udc_read(si, UDC_ADR_COUNT); 531 if (((udc_cnt * 2) - resid) == 2) { 532 NCR_TRACE("si_dma_stop: leftover 2 at 0x%x\n", 533 (int) ncr_sc->sc_dataptr - 2); 534 ncr_sc->sc_dataptr[-2] = 535 (si->fifo_data & 0xff00) >> 8; 536 ncr_sc->sc_dataptr[-1] = 537 (si->fifo_data & 0x00ff); 538 } 539 } 540 541 out: 542 /* Reset the UDC. */ 543 si_obio_udc_write(si, UDC_ADR_COMMAND, UDC_CMD_RESET); 544 si->fifo_count = 0; 545 si->si_csr &= ~SI_CSR_SEND; 546 547 /* Reset the FIFO */ 548 si->si_csr &= ~SI_CSR_FIFO_RES; /* active low */ 549 si->si_csr |= SI_CSR_FIFO_RES; 550 551 /* Put SBIC back in PIO mode. */ 552 /* XXX: set tcmd to PHASE_INVALID? */ 553 *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); 554 *ncr_sc->sci_icmd = 0; 555 } 556 557