1 /* $OpenBSD: dec_6600.c,v 1.13 2010/11/23 04:07:55 shadchin 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", ctb->ctb_term_type, ctbslot, 177 CTB_TURBOSLOT_HOSE(ctbslot)); 178 179 panic("consinit: unknown console type %ld", 180 ctb->ctb_term_type); 181 } 182 } 183 184 static void 185 dec_6600_device_register(dev, aux) 186 struct device *dev; 187 void *aux; 188 { 189 static int found, initted, diskboot, netboot; 190 static struct device *primarydev, *pcidev, *ctrlrdev; 191 struct bootdev_data *b = bootdev_data; 192 struct device *parent = dev->dv_parent; 193 struct cfdata *cf = dev->dv_cfdata; 194 struct cfdriver *cd = cf->cf_driver; 195 196 if (found) 197 return; 198 199 if (!initted) { 200 diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) || 201 (strncasecmp(b->protocol, "IDE", 3) == 0); 202 netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) || 203 (strncasecmp(b->protocol, "MOP", 3) == 0); 204 DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot, 205 netboot)); 206 initted = 1; 207 } 208 209 if (primarydev == NULL) { 210 if (strcmp(cd->cd_name, "tsp")) 211 return; 212 else { 213 struct tsp_attach_args *tsp = aux; 214 215 if (b->bus != tsp->tsp_slot) 216 return; 217 primarydev = dev; 218 DR_VERBOSE(printf("\nprimarydev = %s\n", 219 dev->dv_xname)); 220 return; 221 } 222 } 223 224 if (pcidev == NULL) { 225 if (strcmp(cd->cd_name, "pci")) 226 return; 227 /* 228 * Try to find primarydev anywhere in the ancestry. This is 229 * necessary if the PCI bus is hidden behind a bridge. 230 */ 231 while (parent) { 232 if (parent == primarydev) 233 break; 234 parent = parent->dv_parent; 235 } 236 if (!parent) 237 return; 238 else { 239 struct pcibus_attach_args *pba = aux; 240 241 if ((b->slot / 1000) != pba->pba_bus) 242 return; 243 244 pcidev = dev; 245 DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname)); 246 return; 247 } 248 } 249 250 if (ctrlrdev == NULL) { 251 if (parent != pcidev) 252 return; 253 else { 254 struct pci_attach_args *pa = aux; 255 int slot; 256 257 slot = pa->pa_bus * 1000 + pa->pa_function * 100 + 258 pa->pa_device; 259 if (b->slot != slot) 260 return; 261 262 if (netboot) { 263 booted_device = dev; 264 DR_VERBOSE(printf("\nbooted_device = %s\n", 265 dev->dv_xname)); 266 found = 1; 267 } else { 268 ctrlrdev = dev; 269 DR_VERBOSE(printf("\nctrlrdev = %s\n", 270 dev->dv_xname)); 271 } 272 return; 273 } 274 } 275 276 if (!diskboot) 277 return; 278 279 if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") || 280 !strcmp(cd->cd_name, "cd")) { 281 struct scsi_attach_args *sa = aux; 282 struct scsi_link *periph = sa->sa_sc_link; 283 int unit; 284 285 if (parent->dv_parent != ctrlrdev) 286 return; 287 288 unit = periph->target * 100 + periph->lun; 289 if (b->unit != unit) 290 return; 291 292 /* we've found it! */ 293 booted_device = dev; 294 DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname)); 295 found = 1; 296 } 297 298 /* 299 * Support to boot from IDE drives. 300 */ 301 if (!strcmp(cd->cd_name, "wd")) { 302 struct ata_atapi_attach *aa_link = aux; 303 304 if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0)) 305 return; 306 if (parent != ctrlrdev) 307 return; 308 309 DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n", 310 aa_link->aa_drv_data->drive, aa_link->aa_channel)); 311 DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n", 312 b->unit, b->channel)); 313 if (b->unit != aa_link->aa_drv_data->drive || 314 b->channel != aa_link->aa_channel) 315 return; 316 317 /* we've found it! */ 318 booted_device = dev; 319 DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname)); 320 found = 1; 321 } 322 } 323 324 #ifndef SMALL_KERNEL 325 static void 326 dec_6600_environmental_mcheck(unsigned long mces, struct trapframe *framep, 327 unsigned long vector, unsigned long logout) 328 { 329 mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout; 330 mc_env_ev6 *env = (mc_env_ev6 *)(logout + hdr->la_system_offset); 331 int silent = 0; 332 int itemno; 333 334 /* 335 * Note that we do not check for an expected machine check, 336 * since software is not supposed to trigger an environmental 337 * machine check, and there might be an environmental change 338 * just before our expected machine check occurs. 339 */ 340 341 /* 342 * Most environmental changes are handled at the RMC level, 343 * and we are either not notified (e.g. PCI door open) or 344 * drastic action is taken (e.g. the RMC will power down the 345 * system immediately if the CPU door is open). 346 * 347 * The only events we seem to be notified of are power supply 348 * failures. 349 */ 350 351 /* display CPU failures */ 352 for (itemno = 0; itemno < 4; itemno++) { 353 if ((env->cpuir & EV6_ENV_CPUIR_CPU_ENABLE(itemno)) != 0 && 354 (env->cpuir & EV6_ENV_CPUIR_CPU_FAIL(itemno)) != 0) { 355 printf("CPU%d FAILURE\n", itemno); 356 silent = 1; 357 } 358 } 359 360 /* display PSU failures */ 361 if (env->smir & EV6_ENV_SMIR_PSU_FAILURE) { 362 for (itemno = 0; itemno < 3; itemno++) { 363 if ((env->psir & EV6_ENV_PSIR_PSU_FAIL(itemno)) != 0) { 364 if ((env->psir & 365 EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0) 366 printf("PSU%d FAILURE\n", itemno); 367 else 368 printf("PSU%d DISABLED\n", itemno); 369 } else { 370 if ((env->psir & 371 EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0) 372 printf("PSU%d ENABLED\n", itemno); 373 } 374 } 375 silent = 1; 376 } 377 378 /* if we could not print a summary, display everything */ 379 if (silent == 0) { 380 printf(" Processor Environmental Machine Check, " 381 "Code 0x%x\n", hdr->mcheck_code); 382 383 printf("Flags\t%016x\n", env->flags); 384 printf("DIR\t%016x\n", env->c_dir); 385 printf("SMIR\t%016x\n", env->smir); 386 printf("CPUIR\t%016x\n", env->cpuir); 387 printf("PSIR\t%016x\n", env->psir); 388 printf("LM78_ISR\t%016x\n", env->lm78_isr); 389 printf("Doors\t%016x\n", env->doors); 390 printf("Temp Warning\t%016x\n", env->temp_warning); 391 printf("Fan Control\t%016x\n", env->fan_control); 392 printf("Fatal Power Down\t%016x\n", env->fatal_power_down); 393 } 394 395 /* 396 * Apparently, these checks occur with MCES == 0, which 397 * is supposed to be an uncorrectable machine check. 398 * 399 * Until I know of a better way to tell recoverable and 400 * unrecoverable environmental checks apart, I'll use 401 * the fatal power down code to discriminate. 402 */ 403 if (mces == 0 && env->fatal_power_down == 0) 404 return; 405 else 406 machine_check(mces, framep, vector, logout); 407 } 408 409 /* 410 * Expected syndrome values per faulting bit 411 */ 412 static const uint8_t ev6_syndrome[64 + 8] = { 413 0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 414 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, 415 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 416 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4, 417 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 418 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5, 419 0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 420 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, 421 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 422 }; 423 424 static void 425 dec_6600_print_syndrome(int sno, unsigned long syndrome) 426 { 427 unsigned int bitno; 428 429 syndrome &= 0xff; 430 printf("Syndrome bits %d\t%02x ", sno, syndrome); 431 for (bitno = 0; bitno < nitems(ev6_syndrome); bitno++) 432 if (syndrome == ev6_syndrome[bitno]) 433 break; 434 435 if (bitno < 64) 436 printf("(%d)\n", bitno); 437 else if (bitno < nitems(ev6_syndrome)) 438 printf("(CB%d)\n", bitno - 64); 439 else 440 printf("(unknown)\n"); 441 } 442 443 static void 444 dec_6600_mcheck(unsigned long mces, struct trapframe *framep, 445 unsigned long vector, unsigned long logout) 446 { 447 mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout; 448 struct mchkinfo *mcp; 449 450 /* 451 * If we expected a machine check, don't decode it. 452 */ 453 mcp = &curcpu()->ci_mcinfo; 454 if (mcp->mc_expected) { 455 machine_check(mces, framep, vector, logout); 456 return; 457 } 458 459 printf(" Processor Machine Check (%lx), Code 0x%x\n", 460 vector, hdr->mcheck_code); 461 462 if (vector == ALPHA_SYS_MCHECK) { 463 #ifdef notyet 464 mc_sys_ev6 *sys = (mc_sys_ev6 *)(logout + hdr->la_system_offset); 465 #endif 466 /* XXX Decode and report P-Chip errors */ 467 } else /* ALPHA_PROC_MCHECK */ { 468 mc_cpu_ev6 *cpu = (mc_cpu_ev6 *)(logout + hdr->la_cpu_offset); 469 size_t cpu_size = hdr->la_system_offset - hdr->la_cpu_offset; 470 471 printf("Dcache status\t0x%05x\n", 472 cpu->dc_stat & EV6_DC_STAT_MASK); 473 dec_6600_print_syndrome(0, cpu->c_syndrome_0); 474 dec_6600_print_syndrome(1, cpu->c_syndrome_1); 475 /* C_STAT */ 476 printf("C_STAT\t"); 477 switch (cpu->c_stat & EV6_C_STAT_MASK) { 478 case EV6_C_STAT_DBL_ISTREAM_BC_ECC_ERR: 479 printf("Bcache instruction stream double ECC error\n"); 480 break; 481 case EV6_C_STAT_DBL_ISTREAM_MEM_ECC_ERR: 482 printf("Memory instruction stream double ECC error\n"); 483 break; 484 case EV6_C_STAT_DBL_DSTREAM_BC_ECC_ERR: 485 printf("Bcache data stream double ECC error\n"); 486 break; 487 case EV6_C_STAT_DBL_DSTREAM_MEM_ECC_ERR: 488 printf("Memory data stream double ECC error\n"); 489 break; 490 case EV6_C_STAT_SNGL_ISTREAM_BC_ECC_ERR: 491 printf("Bcache instruction stream single ECC error\n"); 492 break; 493 case EV6_C_STAT_SNGL_ISTREAM_MEM_ECC_ERR: 494 printf("Memory instruction stream single ECC error\n"); 495 break; 496 case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR: 497 case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR2: 498 printf("Bcache probe hit error\n"); 499 break; 500 case EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR: 501 printf("Dcache data stream single ECC error\n"); 502 break; 503 case EV6_C_STAT_SNGL_DSTREAM_BC_ECC_ERR: 504 printf("Bcache data stream single ECC error\n"); 505 break; 506 case EV6_C_STAT_SNGL_DSTREAM_MEM_ECC_ERR: 507 printf("Memory data stream single ECC error\n"); 508 break; 509 case EV6_C_STAT_SNGL_DC_DUPLICATE_TAG_PERR: 510 printf("Dcache duplicate tag error\n"); 511 break; 512 case EV6_C_STAT_SNGL_BC_TAG_PERR: 513 printf("Bcache tag error\n"); 514 break; 515 case EV6_C_STAT_NO_ERROR: 516 if (cpu->dc_stat & EV6_DC_STAT_STORE_DATA_ECC_ERROR) { 517 printf("Bcache/Dcache victim read ECC error\n"); 518 break; 519 } 520 /* FALLTHROUGH */ 521 default: 522 printf("%02x\n", cpu->c_stat); 523 break; 524 } 525 /* C_ADDR */ 526 printf("Error address\t"); 527 if ((cpu->c_stat & EV6_C_STAT_MASK) == 528 EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR) 529 printf("0xXXXXXXXXXXX%05x\n", cpu->c_addr & 0xfffc0); 530 else 531 printf("0x%016x\n", cpu->c_addr & 0xffffffffffffffc0); 532 533 if (cpu_size > offsetof(mc_cpu_ev6, exc_addr)) { 534 printf("Exception address\t0x%016x%s\n", 535 cpu->exc_addr & 0xfffffffffffffffc, 536 cpu->exc_addr & 1 ? " in PAL mode" : ""); 537 /* other fields are not really informative */ 538 } 539 } 540 541 machine_check(mces, framep, vector, logout); 542 } 543 #endif 544 545 static void 546 dec_6600_mcheck_handler(unsigned long mces, struct trapframe *framep, 547 unsigned long vector, unsigned long param) 548 { 549 #ifdef SMALL_KERNEL 550 /* 551 * Even though we can not afford the machine check 552 * analysis code, we need to ignore environmental 553 * changes. 554 */ 555 if (vector == ALPHA_ENV_MCHECK) 556 return; 557 558 machine_check(mces, framep, vector, param); 559 #else 560 switch (vector) { 561 case ALPHA_ENV_MCHECK: 562 dec_6600_environmental_mcheck(mces, framep, vector, param); 563 break; 564 case ALPHA_PROC_MCHECK: 565 case ALPHA_SYS_MCHECK: 566 dec_6600_mcheck(mces, framep, vector, param); 567 break; 568 default: 569 machine_check(mces, framep, vector, param); 570 break; 571 } 572 #endif 573 } 574