1 /* $OpenBSD: dec_6600.c,v 1.14 2014/05/08 20:46:49 miod Exp $ */ 2 /* $NetBSD: dec_6600.c,v 1.7 2000/06/20 03:48:54 matt Exp $ */ 3 4 /* 5 * Copyright (c) 2009 Miodrag Vallat. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 /* 20 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University. 21 * All rights reserved. 22 * 23 * Author: Chris G. Demetriou 24 * 25 * Permission to use, copy, modify and distribute this software and 26 * its documentation is hereby granted, provided that both the copyright 27 * notice and this permission notice appear in all copies of the 28 * software, derivative works or modified versions, and any portions 29 * thereof, and that both notices appear in supporting documentation. 30 * 31 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 32 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 33 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 34 * 35 * Carnegie Mellon requests users of this software to return to 36 * 37 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 38 * School of Computer Science 39 * Carnegie Mellon University 40 * Pittsburgh PA 15213-3890 41 * 42 * any improvements or extensions that they make and grant Carnegie the 43 * rights to redistribute these changes. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/termios.h> 50 #include <dev/cons.h> 51 52 #include <machine/rpb.h> 53 #include <machine/autoconf.h> 54 #include <machine/cpuconf.h> 55 #include <machine/bus.h> 56 #include <machine/logout.h> 57 58 #include <dev/ic/comreg.h> 59 #include <dev/ic/comvar.h> 60 61 #include <dev/isa/isareg.h> 62 #include <dev/isa/isavar.h> 63 #include <dev/ic/i8042reg.h> 64 #include <dev/ic/pckbcvar.h> 65 #include <dev/pci/pcireg.h> 66 #include <dev/pci/pcivar.h> 67 68 #include <alpha/pci/tsreg.h> 69 #include <alpha/pci/tsvar.h> 70 71 #include <scsi/scsi_all.h> 72 #include <scsi/scsiconf.h> 73 #include <dev/ata/atavar.h> 74 75 #include "pckbd.h" 76 77 #ifndef CONSPEED 78 #define CONSPEED TTYDEF_SPEED 79 #endif 80 81 #define DR_VERBOSE(f) while (0) 82 83 static int comcnrate __attribute__((unused)) = CONSPEED; 84 85 void dec_6600_init(void); 86 static void dec_6600_cons_init(void); 87 static void dec_6600_device_register(struct device *, void *); 88 static void dec_6600_mcheck_handler(unsigned long, struct trapframe *, 89 unsigned long, unsigned long); 90 #ifndef SMALL_KERNEL 91 static void dec_6600_environmental_mcheck(unsigned long, struct trapframe *, 92 unsigned long, unsigned long); 93 static void dec_6600_mcheck(unsigned long, struct trapframe *, unsigned long, 94 unsigned long); 95 static void dec_6600_print_syndrome(int, unsigned long); 96 #endif 97 98 void 99 dec_6600_init() 100 { 101 102 platform.family = "6600"; 103 104 if ((platform.model = alpha_dsr_sysname()) == NULL) { 105 /* XXX Don't know the system variations, yet. */ 106 platform.model = alpha_unknown_sysname(); 107 } 108 109 platform.iobus = "tsc"; 110 platform.cons_init = dec_6600_cons_init; 111 platform.device_register = dec_6600_device_register; 112 platform.mcheck_handler = dec_6600_mcheck_handler; 113 STQP(TS_C_DIM0) = 0UL; 114 STQP(TS_C_DIM1) = 0UL; 115 } 116 117 static void 118 dec_6600_cons_init() 119 { 120 struct ctb *ctb; 121 u_int64_t ctbslot; 122 struct tsp_config *tsp; 123 124 ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off); 125 ctbslot = ctb->ctb_turboslot; 126 127 /* Console hose defaults to hose 0. */ 128 tsp_console_hose = 0; 129 130 tsp = tsp_init(0, tsp_console_hose); 131 132 switch (ctb->ctb_term_type) { 133 case CTB_PRINTERPORT: 134 /* serial console ... */ 135 /* XXX */ 136 { 137 /* 138 * Delay to allow PROM putchars to complete. 139 * FIFO depth * character time, 140 * character time = (1000000 / (defaultrate / 10)) 141 */ 142 DELAY(160000000 / comcnrate); 143 144 if(comcnattach(&tsp->pc_iot, 0x3f8, comcnrate, 145 COM_FREQ, 146 (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8)) 147 panic("can't init serial console"); 148 149 break; 150 } 151 152 case CTB_GRAPHICS: 153 #if NPCKBD > 0 154 /* display console ... */ 155 /* XXX */ 156 (void) pckbc_cnattach(&tsp->pc_iot, IO_KBD, KBCMDP, 0); 157 158 if (CTB_TURBOSLOT_TYPE(ctbslot) == 159 CTB_TURBOSLOT_TYPE_ISA) 160 isa_display_console(&tsp->pc_iot, &tsp->pc_memt); 161 else { 162 /* The display PCI might be different */ 163 tsp_console_hose = CTB_TURBOSLOT_HOSE(ctbslot); 164 tsp = tsp_init(0, tsp_console_hose); 165 pci_display_console(&tsp->pc_iot, &tsp->pc_memt, 166 &tsp->pc_pc, CTB_TURBOSLOT_BUS(ctbslot), 167 CTB_TURBOSLOT_SLOT(ctbslot), 0); 168 } 169 #else 170 panic("not configured to use display && keyboard console"); 171 #endif 172 break; 173 174 default: 175 printf("ctb_term_type = 0x%lx ctb_turboslot = 0x%lx" 176 " hose = %ld\n", 177 (unsigned long)ctb->ctb_term_type, 178 (unsigned long)ctbslot, 179 (unsigned long)CTB_TURBOSLOT_HOSE(ctbslot)); 180 181 panic("consinit: unknown console type %lu", 182 (unsigned long)ctb->ctb_term_type); 183 } 184 } 185 186 static void 187 dec_6600_device_register(dev, aux) 188 struct device *dev; 189 void *aux; 190 { 191 static int found, initted, diskboot, netboot; 192 static struct device *primarydev, *pcidev, *ctrlrdev; 193 struct bootdev_data *b = bootdev_data; 194 struct device *parent = dev->dv_parent; 195 struct cfdata *cf = dev->dv_cfdata; 196 struct cfdriver *cd = cf->cf_driver; 197 198 if (found) 199 return; 200 201 if (!initted) { 202 diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) || 203 (strncasecmp(b->protocol, "IDE", 3) == 0); 204 netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) || 205 (strncasecmp(b->protocol, "MOP", 3) == 0); 206 DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot, 207 netboot)); 208 initted = 1; 209 } 210 211 if (primarydev == NULL) { 212 if (strcmp(cd->cd_name, "tsp")) 213 return; 214 else { 215 struct tsp_attach_args *tsp = aux; 216 217 if (b->bus != tsp->tsp_slot) 218 return; 219 primarydev = dev; 220 DR_VERBOSE(printf("\nprimarydev = %s\n", 221 dev->dv_xname)); 222 return; 223 } 224 } 225 226 if (pcidev == NULL) { 227 if (strcmp(cd->cd_name, "pci")) 228 return; 229 /* 230 * Try to find primarydev anywhere in the ancestry. This is 231 * necessary if the PCI bus is hidden behind a bridge. 232 */ 233 while (parent) { 234 if (parent == primarydev) 235 break; 236 parent = parent->dv_parent; 237 } 238 if (!parent) 239 return; 240 else { 241 struct pcibus_attach_args *pba = aux; 242 243 if ((b->slot / 1000) != pba->pba_bus) 244 return; 245 246 pcidev = dev; 247 DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname)); 248 return; 249 } 250 } 251 252 if (ctrlrdev == NULL) { 253 if (parent != pcidev) 254 return; 255 else { 256 struct pci_attach_args *pa = aux; 257 int slot; 258 259 slot = pa->pa_bus * 1000 + pa->pa_function * 100 + 260 pa->pa_device; 261 if (b->slot != slot) 262 return; 263 264 if (netboot) { 265 booted_device = dev; 266 DR_VERBOSE(printf("\nbooted_device = %s\n", 267 dev->dv_xname)); 268 found = 1; 269 } else { 270 ctrlrdev = dev; 271 DR_VERBOSE(printf("\nctrlrdev = %s\n", 272 dev->dv_xname)); 273 } 274 return; 275 } 276 } 277 278 if (!diskboot) 279 return; 280 281 if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") || 282 !strcmp(cd->cd_name, "cd")) { 283 struct scsi_attach_args *sa = aux; 284 struct scsi_link *periph = sa->sa_sc_link; 285 int unit; 286 287 if (parent->dv_parent != ctrlrdev) 288 return; 289 290 unit = periph->target * 100 + periph->lun; 291 if (b->unit != unit) 292 return; 293 294 /* we've found it! */ 295 booted_device = dev; 296 DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname)); 297 found = 1; 298 } 299 300 /* 301 * Support to boot from IDE drives. 302 */ 303 if (!strcmp(cd->cd_name, "wd")) { 304 struct ata_atapi_attach *aa_link = aux; 305 306 if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0)) 307 return; 308 if (parent != ctrlrdev) 309 return; 310 311 DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n", 312 aa_link->aa_drv_data->drive, aa_link->aa_channel)); 313 DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n", 314 b->unit, b->channel)); 315 if (b->unit != aa_link->aa_drv_data->drive || 316 b->channel != aa_link->aa_channel) 317 return; 318 319 /* we've found it! */ 320 booted_device = dev; 321 DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname)); 322 found = 1; 323 } 324 } 325 326 #ifndef SMALL_KERNEL 327 static void 328 dec_6600_environmental_mcheck(unsigned long mces, struct trapframe *framep, 329 unsigned long vector, unsigned long logout) 330 { 331 mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout; 332 mc_env_ev6 *env = (mc_env_ev6 *)(logout + hdr->la_system_offset); 333 int silent = 0; 334 int itemno; 335 336 /* 337 * Note that we do not check for an expected machine check, 338 * since software is not supposed to trigger an environmental 339 * machine check, and there might be an environmental change 340 * just before our expected machine check occurs. 341 */ 342 343 /* 344 * Most environmental changes are handled at the RMC level, 345 * and we are either not notified (e.g. PCI door open) or 346 * drastic action is taken (e.g. the RMC will power down the 347 * system immediately if the CPU door is open). 348 * 349 * The only events we seem to be notified of are power supply 350 * failures. 351 */ 352 353 /* display CPU failures */ 354 for (itemno = 0; itemno < 4; itemno++) { 355 if ((env->cpuir & EV6_ENV_CPUIR_CPU_ENABLE(itemno)) != 0 && 356 (env->cpuir & EV6_ENV_CPUIR_CPU_FAIL(itemno)) != 0) { 357 printf("CPU%d FAILURE\n", itemno); 358 silent = 1; 359 } 360 } 361 362 /* display PSU failures */ 363 if (env->smir & EV6_ENV_SMIR_PSU_FAILURE) { 364 for (itemno = 0; itemno < 3; itemno++) { 365 if ((env->psir & EV6_ENV_PSIR_PSU_FAIL(itemno)) != 0) { 366 if ((env->psir & 367 EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0) 368 printf("PSU%d FAILURE\n", itemno); 369 else 370 printf("PSU%d DISABLED\n", itemno); 371 } else { 372 if ((env->psir & 373 EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0) 374 printf("PSU%d ENABLED\n", itemno); 375 } 376 } 377 silent = 1; 378 } 379 380 /* if we could not print a summary, display everything */ 381 if (silent == 0) { 382 printf(" Processor Environmental Machine Check, " 383 "Code 0x%x\n", hdr->mcheck_code); 384 385 printf("Flags\t%016lx\n", (unsigned long)env->flags); 386 printf("DIR\t%016lx\n", (unsigned long)env->c_dir); 387 printf("SMIR\t%016lx\n", (unsigned long)env->smir); 388 printf("CPUIR\t%016lx\n", (unsigned long)env->cpuir); 389 printf("PSIR\t%016lx\n", (unsigned long)env->psir); 390 printf("LM78_ISR\t%016lx\n", (unsigned long)env->lm78_isr); 391 printf("Doors\t%016lx\n", (unsigned long)env->doors); 392 printf("Temp Warning\t%016lx\n", 393 (unsigned long)env->temp_warning); 394 printf("Fan Control\t%016lx\n", 395 (unsigned long)env->fan_control); 396 printf("Fatal Power Down\t%016lx\n", 397 (unsigned long)env->fatal_power_down); 398 } 399 400 /* 401 * Apparently, these checks occur with MCES == 0, which 402 * is supposed to be an uncorrectable machine check. 403 * 404 * Until I know of a better way to tell recoverable and 405 * unrecoverable environmental checks apart, I'll use 406 * the fatal power down code to discriminate. 407 */ 408 if (mces == 0 && env->fatal_power_down == 0) 409 return; 410 else 411 machine_check(mces, framep, vector, logout); 412 } 413 414 /* 415 * Expected syndrome values per faulting bit 416 */ 417 static const uint8_t ev6_syndrome[64 + 8] = { 418 0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 419 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, 420 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 421 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4, 422 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 423 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5, 424 0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 425 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, 426 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 427 }; 428 429 static void 430 dec_6600_print_syndrome(int sno, unsigned long syndrome) 431 { 432 unsigned int bitno; 433 434 syndrome &= 0xff; 435 printf("Syndrome bits %d\t%02lx ", sno, syndrome); 436 for (bitno = 0; bitno < nitems(ev6_syndrome); bitno++) 437 if (syndrome == ev6_syndrome[bitno]) 438 break; 439 440 if (bitno < 64) 441 printf("(%d)\n", bitno); 442 else if (bitno < nitems(ev6_syndrome)) 443 printf("(CB%d)\n", bitno - 64); 444 else 445 printf("(unknown)\n"); 446 } 447 448 static void 449 dec_6600_mcheck(unsigned long mces, struct trapframe *framep, 450 unsigned long vector, unsigned long logout) 451 { 452 mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout; 453 struct mchkinfo *mcp; 454 455 /* 456 * If we expected a machine check, don't decode it. 457 */ 458 mcp = &curcpu()->ci_mcinfo; 459 if (mcp->mc_expected) { 460 machine_check(mces, framep, vector, logout); 461 return; 462 } 463 464 printf(" Processor Machine Check (%lx), Code 0x%x\n", 465 vector, hdr->mcheck_code); 466 467 if (vector == ALPHA_SYS_MCHECK) { 468 #ifdef notyet 469 mc_sys_ev6 *sys = (mc_sys_ev6 *)(logout + hdr->la_system_offset); 470 #endif 471 /* XXX Decode and report P-Chip errors */ 472 } else /* ALPHA_PROC_MCHECK */ { 473 mc_cpu_ev6 *cpu = (mc_cpu_ev6 *)(logout + hdr->la_cpu_offset); 474 size_t cpu_size = hdr->la_system_offset - hdr->la_cpu_offset; 475 476 printf("Dcache status\t0x%05lx\n", 477 (unsigned long)cpu->dc_stat & EV6_DC_STAT_MASK); 478 dec_6600_print_syndrome(0, cpu->c_syndrome_0); 479 dec_6600_print_syndrome(1, cpu->c_syndrome_1); 480 /* C_STAT */ 481 printf("C_STAT\t"); 482 switch (cpu->c_stat & EV6_C_STAT_MASK) { 483 case EV6_C_STAT_DBL_ISTREAM_BC_ECC_ERR: 484 printf("Bcache instruction stream double ECC error\n"); 485 break; 486 case EV6_C_STAT_DBL_ISTREAM_MEM_ECC_ERR: 487 printf("Memory instruction stream double ECC error\n"); 488 break; 489 case EV6_C_STAT_DBL_DSTREAM_BC_ECC_ERR: 490 printf("Bcache data stream double ECC error\n"); 491 break; 492 case EV6_C_STAT_DBL_DSTREAM_MEM_ECC_ERR: 493 printf("Memory data stream double ECC error\n"); 494 break; 495 case EV6_C_STAT_SNGL_ISTREAM_BC_ECC_ERR: 496 printf("Bcache instruction stream single ECC error\n"); 497 break; 498 case EV6_C_STAT_SNGL_ISTREAM_MEM_ECC_ERR: 499 printf("Memory instruction stream single ECC error\n"); 500 break; 501 case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR: 502 case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR2: 503 printf("Bcache probe hit error\n"); 504 break; 505 case EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR: 506 printf("Dcache data stream single ECC error\n"); 507 break; 508 case EV6_C_STAT_SNGL_DSTREAM_BC_ECC_ERR: 509 printf("Bcache data stream single ECC error\n"); 510 break; 511 case EV6_C_STAT_SNGL_DSTREAM_MEM_ECC_ERR: 512 printf("Memory data stream single ECC error\n"); 513 break; 514 case EV6_C_STAT_SNGL_DC_DUPLICATE_TAG_PERR: 515 printf("Dcache duplicate tag error\n"); 516 break; 517 case EV6_C_STAT_SNGL_BC_TAG_PERR: 518 printf("Bcache tag error\n"); 519 break; 520 case EV6_C_STAT_NO_ERROR: 521 if (cpu->dc_stat & EV6_DC_STAT_STORE_DATA_ECC_ERROR) { 522 printf("Bcache/Dcache victim read ECC error\n"); 523 break; 524 } 525 /* FALLTHROUGH */ 526 default: 527 printf("%02lx\n", (unsigned long)cpu->c_stat); 528 break; 529 } 530 /* C_ADDR */ 531 printf("Error address\t"); 532 if ((cpu->c_stat & EV6_C_STAT_MASK) == 533 EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR) 534 printf("0xXXXXXXXXXXX%05lx\n", 535 (unsigned long)cpu->c_addr & 0xfffc0); 536 else 537 printf("0x%016lx\n", 538 (unsigned long)cpu->c_addr & 0xffffffffffffffc0); 539 540 if (cpu_size > offsetof(mc_cpu_ev6, exc_addr)) { 541 printf("Exception address\t0x%016lx%s\n", 542 (unsigned long)cpu->exc_addr & 0xfffffffffffffffc, 543 cpu->exc_addr & 1 ? " in PAL mode" : ""); 544 /* other fields are not really informative */ 545 } 546 } 547 548 machine_check(mces, framep, vector, logout); 549 } 550 #endif 551 552 static void 553 dec_6600_mcheck_handler(unsigned long mces, struct trapframe *framep, 554 unsigned long vector, unsigned long param) 555 { 556 #ifdef SMALL_KERNEL 557 /* 558 * Even though we can not afford the machine check 559 * analysis code, we need to ignore environmental 560 * changes. 561 */ 562 if (vector == ALPHA_ENV_MCHECK) 563 return; 564 565 machine_check(mces, framep, vector, param); 566 #else 567 switch (vector) { 568 case ALPHA_ENV_MCHECK: 569 dec_6600_environmental_mcheck(mces, framep, vector, param); 570 break; 571 case ALPHA_PROC_MCHECK: 572 case ALPHA_SYS_MCHECK: 573 dec_6600_mcheck(mces, framep, vector, param); 574 break; 575 default: 576 machine_check(mces, framep, vector, param); 577 break; 578 } 579 #endif 580 } 581