1 /* $OpenBSD: tcds.c,v 1.2 2002/10/12 01:09:44 krw Exp $ */ 2 /* $NetBSD: tcds.c,v 1.3 2001/11/13 06:26:10 lukem Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 43 * All rights reserved. 44 * 45 * Author: Keith Bostic, Chris G. Demetriou 46 * 47 * Permission to use, copy, modify and distribute this software and 48 * its documentation is hereby granted, provided that both the copyright 49 * notice and this permission notice appear in all copies of the 50 * software, derivative works or modified versions, and any portions 51 * thereof, and that both notices appear in supporting documentation. 52 * 53 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 54 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 55 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 56 * 57 * Carnegie Mellon requests users of this software to return to 58 * 59 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 60 * School of Computer Science 61 * Carnegie Mellon University 62 * Pittsburgh PA 15213-3890 63 * 64 * any improvements or extensions that they make and grant Carnegie the 65 * rights to redistribute these changes. 66 */ 67 68 #include <sys/param.h> 69 #include <sys/kernel.h> 70 #include <sys/systm.h> 71 #include <sys/device.h> 72 #include <sys/malloc.h> 73 74 #ifdef __alpha__ 75 #include <machine/rpb.h> 76 #endif /* __alpha__ */ 77 78 #include <scsi/scsi_all.h> 79 #include <scsi/scsiconf.h> 80 81 #include <dev/ic/ncr53c9xvar.h> 82 83 #include <machine/bus.h> 84 85 #ifndef EVCNT_COUNTERS 86 #include <machine/intrcnt.h> 87 #endif 88 89 #include <dev/tc/tcvar.h> 90 #include <dev/tc/tcdsreg.h> 91 #include <dev/tc/tcdsvar.h> 92 93 struct tcds_softc { 94 struct device sc_dv; 95 bus_space_tag_t sc_bst; 96 bus_space_handle_t sc_bsh; 97 bus_dma_tag_t sc_dmat; 98 void *sc_cookie; 99 int sc_flags; 100 struct tcds_slotconfig sc_slots[2]; 101 }; 102 103 /* sc_flags */ 104 #define TCDSF_BASEBOARD 0x01 /* baseboard on DEC 3000 */ 105 #define TCDSF_FASTSCSI 0x02 /* supports Fast SCSI */ 106 107 /* Definition of the driver for autoconfig. */ 108 int tcdsmatch(struct device *, void *, void *); 109 void tcdsattach(struct device *, struct device *, void *); 110 int tcdsprint(void *, const char *); 111 int tcdssubmatch(struct device *, void *, void *); 112 113 struct cfattach tcds_ca = { 114 sizeof(struct tcds_softc), tcdsmatch, tcdsattach, 115 }; 116 117 struct cfdriver tcds_cd = { 118 NULL, "tcds", DV_DULL, 119 }; 120 121 /*static*/ int tcds_intr(void *); 122 /*static*/ int tcds_intrnull(void *); 123 124 struct tcds_device { 125 const char *td_name; 126 int td_flags; 127 } tcds_devices[] = { 128 #ifdef __alpha__ 129 { "PMAZ-DS ", TCDSF_BASEBOARD }, 130 { "PMAZ-FS ", TCDSF_BASEBOARD|TCDSF_FASTSCSI }, 131 #endif /* __alpha__ */ 132 { "PMAZB-AA", 0 }, 133 { "PMAZC-AA", TCDSF_FASTSCSI }, 134 { NULL, 0 }, 135 }; 136 137 struct tcds_device *tcds_lookup(const char *); 138 void tcds_params(struct tcds_softc *, int, int *, int *); 139 140 struct tcds_device * 141 tcds_lookup(modname) 142 const char *modname; 143 { 144 struct tcds_device *td; 145 146 for (td = tcds_devices; td->td_name != NULL; td++) 147 if (strncmp(td->td_name, modname, TC_ROM_LLEN) == 0) 148 return (td); 149 150 return (NULL); 151 } 152 153 int 154 tcdsmatch(parent, cfdata, aux) 155 struct device *parent; 156 void *cfdata, *aux; 157 { 158 struct tc_attach_args *ta = aux; 159 160 return (tcds_lookup(ta->ta_modname) != NULL); 161 } 162 163 void 164 tcdsattach(parent, self, aux) 165 struct device *parent, *self; 166 void *aux; 167 { 168 struct tcds_softc *sc = (struct tcds_softc *)self; 169 struct tc_attach_args *ta = aux; 170 struct tcdsdev_attach_args tcdsdev; 171 struct tcds_slotconfig *slotc; 172 struct tcds_device *td; 173 bus_space_handle_t sbsh[2]; 174 int i, gpi2; 175 const struct evcnt *pevcnt; 176 177 td = tcds_lookup(ta->ta_modname); 178 if (td == NULL) 179 panic("tcdsattach: impossible"); 180 181 printf(": TurboChannel Dual SCSI"); 182 if (td->td_flags & TCDSF_BASEBOARD) 183 printf(" (baseboard)"); 184 printf("\n"); 185 186 sc->sc_flags = td->td_flags; 187 188 sc->sc_bst = ta->ta_memt; 189 sc->sc_dmat = ta->ta_dmat; 190 191 /* 192 * Map the device. 193 */ 194 if (bus_space_map(sc->sc_bst, ta->ta_addr, 195 (TCDS_SCSI1_OFFSET + 0x100), 0, &sc->sc_bsh)) { 196 printf("%s: unable to map device\n", sc->sc_dv.dv_xname); 197 return; 198 } 199 200 /* 201 * Now, slice off two subregions for the individual NCR SCSI chips. 202 */ 203 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, TCDS_SCSI0_OFFSET, 204 0x100, &sbsh[0]) || 205 bus_space_subregion(sc->sc_bst, sc->sc_bsh, TCDS_SCSI1_OFFSET, 206 0x100, &sbsh[1])) { 207 printf("%s: unable to subregion SCSI chip space\n", 208 sc->sc_dv.dv_xname); 209 return; 210 } 211 212 sc->sc_cookie = ta->ta_cookie; 213 214 pevcnt = tc_intr_evcnt(parent, sc->sc_cookie); 215 tc_intr_establish(parent, sc->sc_cookie, TC_IPL_BIO, tcds_intr, sc); 216 217 /* 218 * XXX 219 * IMER apparently has some random (or, not so random, but still 220 * not useful) bits set in it when the system boots. Clear it. 221 */ 222 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_IMER, 0); 223 224 /* XXX Initial contents of CIR? */ 225 226 /* 227 * Remember if GPI2 is set in the CIR; we'll need it later. 228 */ 229 gpi2 = (bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR) & 230 TCDS_CIR_GPI_2) != 0; 231 232 /* 233 * Set up the per-slot defintions for later use. 234 */ 235 236 /* fill in common information first */ 237 for (i = 0; i < 2; i++) { 238 char *cp; 239 240 slotc = &sc->sc_slots[i]; 241 bzero(slotc, sizeof *slotc); /* clear everything */ 242 243 cp = slotc->sc_name; 244 snprintf(cp, sizeof(slotc->sc_name), "chip %d", i); 245 #ifdef EVCNT_COUNTERS 246 evcnt_attach_dynamic(&slotc->sc_evcnt, EVCNT_TYPE_INTR, 247 pevcnt, sc->sc_dv.dv_xname, cp); 248 #endif 249 250 slotc->sc_slot = i; 251 slotc->sc_bst = sc->sc_bst; 252 slotc->sc_bsh = sc->sc_bsh; 253 slotc->sc_intrhand = tcds_intrnull; 254 slotc->sc_intrarg = (void *)(long)i; 255 } 256 257 /* information for slot 0 */ 258 slotc = &sc->sc_slots[0]; 259 slotc->sc_resetbits = TCDS_CIR_SCSI0_RESET; 260 slotc->sc_intrmaskbits = 261 TCDS_IMER_SCSI0_MASK | TCDS_IMER_SCSI0_ENB; 262 slotc->sc_intrbits = TCDS_CIR_SCSI0_INT; 263 slotc->sc_dmabits = TCDS_CIR_SCSI0_DMAENA; 264 slotc->sc_errorbits = 0; /* XXX */ 265 slotc->sc_sda = TCDS_SCSI0_DMA_ADDR; 266 slotc->sc_dic = TCDS_SCSI0_DMA_INTR; 267 slotc->sc_dud0 = TCDS_SCSI0_DMA_DUD0; 268 slotc->sc_dud1 = TCDS_SCSI0_DMA_DUD1; 269 270 /* information for slot 1 */ 271 slotc = &sc->sc_slots[1]; 272 slotc->sc_resetbits = TCDS_CIR_SCSI1_RESET; 273 slotc->sc_intrmaskbits = 274 TCDS_IMER_SCSI1_MASK | TCDS_IMER_SCSI1_ENB; 275 slotc->sc_intrbits = TCDS_CIR_SCSI1_INT; 276 slotc->sc_dmabits = TCDS_CIR_SCSI1_DMAENA; 277 slotc->sc_errorbits = 0; /* XXX */ 278 slotc->sc_sda = TCDS_SCSI1_DMA_ADDR; 279 slotc->sc_dic = TCDS_SCSI1_DMA_INTR; 280 slotc->sc_dud0 = TCDS_SCSI1_DMA_DUD0; 281 slotc->sc_dud1 = TCDS_SCSI1_DMA_DUD1; 282 283 /* find the hardware attached to the TCDS ASIC */ 284 for (i = 0; i < 2; i++) { 285 tcds_params(sc, i, &tcdsdev.tcdsda_id, 286 &tcdsdev.tcdsda_fast); 287 288 tcdsdev.tcdsda_bst = sc->sc_bst; 289 tcdsdev.tcdsda_bsh = sbsh[i]; 290 tcdsdev.tcdsda_dmat = sc->sc_dmat; 291 tcdsdev.tcdsda_chip = i; 292 tcdsdev.tcdsda_sc = &sc->sc_slots[i]; 293 /* 294 * Determine the chip frequency. TCDSF_FASTSCSI will be set 295 * for TC option cards. For baseboard chips, GPI2 is set, for a 296 * 25MHz clock, else a 40MHz clock. 297 */ 298 if ((sc->sc_flags & TCDSF_BASEBOARD && gpi2 == 0) || 299 sc->sc_flags & TCDSF_FASTSCSI) { 300 tcdsdev.tcdsda_freq = 40000000; 301 tcdsdev.tcdsda_period = tcdsdev.tcdsda_fast ? 4 : 8; 302 } else { 303 tcdsdev.tcdsda_freq = 25000000; 304 tcdsdev.tcdsda_period = 5; 305 } 306 if (sc->sc_flags & TCDSF_BASEBOARD) 307 tcdsdev.tcdsda_variant = NCR_VARIANT_NCR53C94; 308 else 309 tcdsdev.tcdsda_variant = NCR_VARIANT_NCR53C96; 310 311 tcds_scsi_reset(tcdsdev.tcdsda_sc); 312 313 config_found_sm(self, &tcdsdev, tcdsprint, tcdssubmatch); 314 #ifdef __alpha__ 315 /* 316 * The second SCSI chip isn't present on the baseboard TCDS 317 * on the DEC Alpha 3000/300 series. 318 */ 319 if (sc->sc_flags & TCDSF_BASEBOARD && 320 cputype == ST_DEC_3000_300) 321 break; 322 #endif /* __alpha__ */ 323 } 324 } 325 326 int 327 tcdssubmatch(parent, vcf, aux) 328 struct device *parent; 329 void *vcf, *aux; 330 { 331 struct tcdsdev_attach_args *tcdsdev = aux; 332 struct cfdata *cf = vcf; 333 334 if (cf->cf_loc[0] != -1 && 335 cf->cf_loc[0] != tcdsdev->tcdsda_chip) 336 return (0); 337 338 return ((*cf->cf_attach->ca_match)(parent, vcf, aux)); 339 } 340 341 int 342 tcdsprint(aux, pnp) 343 void *aux; 344 const char *pnp; 345 { 346 struct tcdsdev_attach_args *tcdsdev = aux; 347 348 /* Only ASCs can attach to TCDSs; easy. */ 349 if (pnp) 350 printf("asc at %s", pnp); 351 352 printf(" chip %d", tcdsdev->tcdsda_chip); 353 354 return (UNCONF); 355 } 356 357 void 358 tcds_intr_establish(tcds, slot, func, arg) 359 struct device *tcds; 360 int slot; 361 int (*func)(void *); 362 void *arg; 363 { 364 struct tcds_softc *sc = (struct tcds_softc *)tcds; 365 366 if (sc->sc_slots[slot].sc_intrhand != tcds_intrnull) 367 panic("tcds_intr_establish: chip %d twice", slot); 368 369 sc->sc_slots[slot].sc_intrhand = func; 370 sc->sc_slots[slot].sc_intrarg = arg; 371 tcds_scsi_reset(&sc->sc_slots[slot]); 372 } 373 374 void 375 tcds_intr_disestablish(tcds, slot) 376 struct device *tcds; 377 int slot; 378 { 379 struct tcds_softc *sc = (struct tcds_softc *)tcds; 380 381 if (sc->sc_slots[slot].sc_intrhand == tcds_intrnull) 382 panic("tcds_intr_disestablish: chip %d missing intr", 383 slot); 384 385 sc->sc_slots[slot].sc_intrhand = tcds_intrnull; 386 sc->sc_slots[slot].sc_intrarg = (void *)(u_long)slot; 387 388 tcds_dma_enable(&sc->sc_slots[slot], 0); 389 tcds_scsi_enable(&sc->sc_slots[slot], 0); 390 } 391 392 int 393 tcds_intrnull(val) 394 void *val; 395 { 396 397 panic("tcds_intrnull: uncaught TCDS intr for chip %lu", 398 (u_long)val); 399 } 400 401 void 402 tcds_scsi_reset(sc) 403 struct tcds_slotconfig *sc; 404 { 405 u_int32_t cir; 406 407 tcds_dma_enable(sc, 0); 408 tcds_scsi_enable(sc, 0); 409 410 cir = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 411 TCDS_CIR_CLR(cir, sc->sc_resetbits); 412 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR, cir); 413 414 DELAY(1); 415 416 cir = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 417 TCDS_CIR_SET(cir, sc->sc_resetbits); 418 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR, cir); 419 420 tcds_scsi_enable(sc, 1); 421 tcds_dma_enable(sc, 1); 422 } 423 424 void 425 tcds_scsi_enable(sc, on) 426 struct tcds_slotconfig *sc; 427 int on; 428 { 429 u_int32_t imer; 430 431 imer = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_IMER); 432 433 if (on) 434 imer |= sc->sc_intrmaskbits; 435 else 436 imer &= ~sc->sc_intrmaskbits; 437 438 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_IMER, imer); 439 } 440 441 void 442 tcds_dma_enable(sc, on) 443 struct tcds_slotconfig *sc; 444 int on; 445 { 446 u_int32_t cir; 447 448 cir = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 449 450 /* XXX Clear/set IOSLOT/PBS bits. */ 451 if (on) 452 TCDS_CIR_SET(cir, sc->sc_dmabits); 453 else 454 TCDS_CIR_CLR(cir, sc->sc_dmabits); 455 456 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR, cir); 457 } 458 459 int 460 tcds_scsi_isintr(sc, clear) 461 struct tcds_slotconfig *sc; 462 int clear; 463 { 464 u_int32_t cir; 465 466 cir = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 467 468 if ((cir & sc->sc_intrbits) != 0) { 469 if (clear) { 470 TCDS_CIR_CLR(cir, sc->sc_intrbits); 471 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR, 472 cir); 473 } 474 return (1); 475 } else 476 return (0); 477 } 478 479 int 480 tcds_scsi_iserr(sc) 481 struct tcds_slotconfig *sc; 482 { 483 u_int32_t cir; 484 485 cir = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 486 return ((cir & sc->sc_errorbits) != 0); 487 } 488 489 int 490 tcds_intr(arg) 491 void *arg; 492 { 493 struct tcds_softc *sc = arg; 494 u_int32_t ir, ir0; 495 496 /* 497 * XXX 498 * Copy and clear (gag!) the interrupts. 499 */ 500 ir = ir0 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR); 501 TCDS_CIR_CLR(ir0, TCDS_CIR_ALLINTR); 502 bus_space_write_4(sc->sc_bst, sc->sc_bsh, TCDS_CIR, ir0); 503 tc_syncbus(); 504 505 #ifdef EVCNT_COUNTERS 506 #define INCRINTRCNT(slot) sc->sc_slots[slot].sc_evcnt.ev_count++ 507 #else 508 #define INCRINTRCNT(slot) intrcnt[INTRCNT_TCDS + slot]++ 509 #endif 510 511 #define CHECKINTR(slot) \ 512 if (ir & sc->sc_slots[slot].sc_intrbits) { \ 513 INCRINTRCNT(slot); \ 514 (void)(*sc->sc_slots[slot].sc_intrhand) \ 515 (sc->sc_slots[slot].sc_intrarg); \ 516 } 517 CHECKINTR(0); 518 CHECKINTR(1); 519 #undef CHECKINTR 520 521 #ifdef DIAGNOSTIC 522 /* 523 * Interrupts not currently handled, but would like to know if they 524 * occur. 525 * 526 * XXX 527 * Don't know if we have to set the interrupt mask and enable bits 528 * in the IMER to allow some of them to happen? 529 */ 530 #define PRINTINTR(msg, bits) \ 531 if (ir & bits) \ 532 printf("%s: %s", sc->sc_dv.dv_xname, msg); 533 PRINTINTR("SCSI0 DREQ interrupt.\n", TCDS_CIR_SCSI0_DREQ); 534 PRINTINTR("SCSI1 DREQ interrupt.\n", TCDS_CIR_SCSI1_DREQ); 535 PRINTINTR("SCSI0 prefetch interrupt.\n", TCDS_CIR_SCSI0_PREFETCH); 536 PRINTINTR("SCSI1 prefetch interrupt.\n", TCDS_CIR_SCSI1_PREFETCH); 537 PRINTINTR("SCSI0 DMA error.\n", TCDS_CIR_SCSI0_DMA); 538 PRINTINTR("SCSI1 DMA error.\n", TCDS_CIR_SCSI1_DMA); 539 PRINTINTR("SCSI0 DB parity error.\n", TCDS_CIR_SCSI0_DB); 540 PRINTINTR("SCSI1 DB parity error.\n", TCDS_CIR_SCSI1_DB); 541 PRINTINTR("SCSI0 DMA buffer parity error.\n", TCDS_CIR_SCSI0_DMAB_PAR); 542 PRINTINTR("SCSI1 DMA buffer parity error.\n", TCDS_CIR_SCSI1_DMAB_PAR); 543 PRINTINTR("SCSI0 DMA read parity error.\n", TCDS_CIR_SCSI0_DMAR_PAR); 544 PRINTINTR("SCSI1 DMA read parity error.\n", TCDS_CIR_SCSI1_DMAR_PAR); 545 PRINTINTR("TC write parity error.\n", TCDS_CIR_TCIOW_PAR); 546 PRINTINTR("TC I/O address parity error.\n", TCDS_CIR_TCIOA_PAR); 547 #undef PRINTINTR 548 #endif 549 550 /* 551 * XXX 552 * The MACH source had this, with the comment: 553 * This is wrong, but machine keeps dying. 554 */ 555 DELAY(1); 556 557 return (1); 558 } 559 560 void 561 tcds_params(sc, chip, idp, fastp) 562 struct tcds_softc *sc; 563 int chip, *idp, *fastp; 564 { 565 int id, fast; 566 u_int32_t ids; 567 568 #ifdef __alpha__ 569 if (sc->sc_flags & TCDSF_BASEBOARD) { 570 extern u_int8_t dec_3000_scsiid[], dec_3000_scsifast[]; 571 572 id = dec_3000_scsiid[chip]; 573 fast = dec_3000_scsifast[chip]; 574 } else 575 #endif /* __alpha__ */ 576 { 577 /* 578 * SCSI IDs are stored in the EEPROM, along with whether or 579 * not the device is "fast". Chip 0 is the high nibble, 580 * chip 1 the low nibble. 581 */ 582 ids = bus_space_read_4(sc->sc_bst, sc->sc_bsh, TCDS_EEPROM_IDS); 583 if (chip == 0) 584 ids >>= 4; 585 586 id = ids & 0x7; 587 fast = ids & 0x8; 588 } 589 590 if (id < 0 || id > 7) { 591 printf("%s: WARNING: bad SCSI ID %d for chip %d, using 7\n", 592 sc->sc_dv.dv_xname, id, chip); 593 id = 7; 594 } 595 596 if (fast) 597 printf("%s: fast mode set for chip %d\n", 598 sc->sc_dv.dv_xname, chip); 599 600 *idp = id; 601 *fastp = fast; 602 } 603