1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <limits.h> 26 #include <sys/mdb_modapi.h> 27 #include <mdb/mdb_ctf.h> 28 #include <sys/sysinfo.h> 29 #include <sys/byteorder.h> 30 #include <sys/nvpair.h> 31 #include <sys/damap.h> 32 #include <sys/scsi/scsi.h> 33 #include <sys/scsi/adapters/pmcs/pmcs.h> 34 #ifndef _KMDB 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <unistd.h> 39 #endif /* _KMDB */ 40 41 /* 42 * We need use this to pass the settings when display_iport 43 */ 44 typedef struct per_iport_setting { 45 uint_t pis_damap_info; /* -m: DAM/damap */ 46 uint_t pis_dtc_info; /* -d: device tree children: dev_info/path_info */ 47 } per_iport_setting_t; 48 49 /* 50 * This structure is used for sorting work structures by the wserno 51 */ 52 typedef struct wserno_list { 53 int serno; 54 int idx; 55 struct wserno_list *next; 56 struct wserno_list *prev; 57 } wserno_list_t; 58 59 #define MDB_RD(a, b, c) mdb_vread(a, b, (uintptr_t)c) 60 #define NOREAD(a, b) mdb_warn("could not read " #a " at 0x%p", b) 61 62 static pmcs_hw_t ss; 63 static pmcs_xscsi_t **targets = NULL; 64 static int target_idx; 65 66 static uint32_t sas_phys, sata_phys, exp_phys, num_expanders, empty_phys; 67 68 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp); 69 static void display_one_work(pmcwork_t *wp, int verbose, int idx); 70 71 static void 72 print_sas_address(pmcs_phy_t *phy) 73 { 74 int idx; 75 76 for (idx = 0; idx < 8; idx++) { 77 mdb_printf("%02x", phy->sas_address[idx]); 78 } 79 } 80 81 static void 82 pmcs_fwtime_to_systime(struct pmcs_hw ss, uint32_t fw_hi, uint32_t fw_lo, 83 struct timespec *stime) 84 { 85 uint64_t fwtime; 86 time_t secs; 87 long nsecs; 88 boolean_t backward_time = B_FALSE; 89 90 fwtime = ((uint64_t)fw_hi << 32) | fw_lo; 91 92 /* 93 * If fwtime < ss.fw_timestamp, then we need to adjust the clock 94 * time backwards from ss.sys_timestamp. Otherwise, the adjustment 95 * goes forward in time 96 */ 97 if (fwtime >= ss.fw_timestamp) { 98 fwtime -= ss.fw_timestamp; 99 } else { 100 fwtime = ss.fw_timestamp - fwtime; 101 backward_time = B_TRUE; 102 } 103 104 secs = ((time_t)fwtime / NSECS_PER_SEC); 105 nsecs = ((long)fwtime % NSECS_PER_SEC); 106 107 stime->tv_sec = ss.sys_timestamp.tv_sec; 108 stime->tv_nsec = ss.sys_timestamp.tv_nsec; 109 110 if (backward_time) { 111 if (stime->tv_nsec < nsecs) { 112 stime->tv_sec--; 113 stime->tv_nsec = stime->tv_nsec + NSECS_PER_SEC - nsecs; 114 } else { 115 stime->tv_nsec -= nsecs; 116 } 117 stime->tv_sec -= secs; 118 } else { 119 if (stime->tv_nsec + nsecs > NSECS_PER_SEC) { 120 stime->tv_sec++; 121 } 122 stime->tv_nsec = (stime->tv_nsec + nsecs) % NSECS_PER_SEC; 123 stime->tv_sec += secs; 124 } 125 } 126 127 /*ARGSUSED*/ 128 static void 129 display_ic(struct pmcs_hw m, int verbose) 130 { 131 int msec_per_tick; 132 133 if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) { 134 mdb_warn("can't read msec_per_tick"); 135 msec_per_tick = 0; 136 } 137 138 mdb_printf("\n"); 139 mdb_printf("Interrupt coalescing timer info\n"); 140 mdb_printf("-------------------------------\n"); 141 if (msec_per_tick == 0) { 142 mdb_printf("Quantum : ?? ms\n"); 143 } else { 144 mdb_printf("Quantum : %d ms\n", 145 m.io_intr_coal.quantum * msec_per_tick); 146 } 147 mdb_printf("Timer enabled : "); 148 if (m.io_intr_coal.timer_on) { 149 mdb_printf("Yes\n"); 150 mdb_printf("Coalescing timer value : %d us\n", 151 m.io_intr_coal.intr_coal_timer); 152 } else { 153 mdb_printf("No\n"); 154 } 155 mdb_printf("Total nsecs between interrupts: %ld\n", 156 m.io_intr_coal.nsecs_between_intrs); 157 mdb_printf("Time of last I/O interrupt : %ld\n", 158 m.io_intr_coal.last_io_comp); 159 mdb_printf("Number of I/O interrupts : %d\n", 160 m.io_intr_coal.num_intrs); 161 mdb_printf("Number of I/O completions : %d\n", 162 m.io_intr_coal.num_io_completions); 163 mdb_printf("Max I/O completion interrupts : %d\n", 164 m.io_intr_coal.max_io_completions); 165 mdb_printf("Measured ECHO int latency : %d ns\n", 166 m.io_intr_coal.intr_latency); 167 mdb_printf("Interrupt threshold : %d\n", 168 m.io_intr_coal.intr_threshold); 169 } 170 171 /*ARGSUSED*/ 172 static int 173 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv) 174 { 175 struct pmcs_phy phy; 176 177 if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) != 178 sizeof (struct pmcs_phy)) { 179 return (DCMD_ERR); 180 } 181 182 mdb_printf("%16p %2d\n", addr, phy.phynum); 183 184 return (0); 185 } 186 187 static int 188 display_iport_damap(dev_info_t *pdip) 189 { 190 int rval = DCMD_ERR; 191 struct dev_info dip; 192 scsi_hba_tran_t sht; 193 mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */ 194 ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */ 195 uintptr_t dam0; 196 uintptr_t dam1; 197 198 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) != 199 sizeof (struct dev_info)) { 200 return (rval); 201 } 202 203 if (dip.devi_driver_data == NULL) { 204 return (rval); 205 } 206 207 if (mdb_vread(&sht, sizeof (scsi_hba_tran_t), 208 (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) { 209 return (rval); 210 } 211 212 if (sht.tran_tgtmap == NULL) { 213 return (rval); 214 } 215 216 if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) { 217 return (rval); 218 } 219 220 if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) { 221 return (rval); 222 } 223 224 tmd_offset /= NBBY; 225 mdb_vread(&dam0, sizeof (dam0), 226 (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap)); 227 mdb_vread(&dam1, sizeof (dam1), 228 (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap)); 229 230 if (dam0 != NULL) { 231 rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL); 232 mdb_printf("\n"); 233 if (rval != DCMD_OK) { 234 return (rval); 235 } 236 } 237 238 if (dam1 != NULL) { 239 rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL); 240 mdb_printf("\n"); 241 } 242 243 return (rval); 244 } 245 246 /* ARGSUSED */ 247 static int 248 display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv) 249 { 250 uint_t *idx = (uint_t *)priv; 251 struct dev_info dip; 252 char devi_name[MAXNAMELEN]; 253 char devi_addr[MAXNAMELEN]; 254 255 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) != 256 sizeof (struct dev_info)) { 257 return (DCMD_ERR); 258 } 259 260 if (mdb_readstr(devi_name, sizeof (devi_name), 261 (uintptr_t)dip.devi_node_name) == -1) { 262 devi_name[0] = '?'; 263 devi_name[1] = '\0'; 264 } 265 266 if (mdb_readstr(devi_addr, sizeof (devi_addr), 267 (uintptr_t)dip.devi_addr) == -1) { 268 devi_addr[0] = '?'; 269 devi_addr[1] = '\0'; 270 } 271 272 mdb_printf(" %3d: @%-21s%10s@\t%p::devinfo -s\n", 273 (*idx)++, devi_addr, devi_name, addr); 274 return (DCMD_OK); 275 } 276 277 /* ARGSUSED */ 278 static int 279 display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv) 280 { 281 uint_t *idx = (uint_t *)priv; 282 struct mdi_pathinfo mpi; 283 char pi_addr[MAXNAMELEN]; 284 285 if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) != 286 sizeof (struct mdi_pathinfo)) { 287 return (DCMD_ERR); 288 } 289 290 if (mdb_readstr(pi_addr, sizeof (pi_addr), 291 (uintptr_t)mpi.pi_addr) == -1) { 292 pi_addr[0] = '?'; 293 pi_addr[1] = '\0'; 294 } 295 296 mdb_printf(" %3d: @%-21s %p::print struct mdi_pathinfo\n", 297 (*idx)++, pi_addr, addr); 298 return (DCMD_OK); 299 } 300 301 static int 302 display_iport_dtc(dev_info_t *pdip) 303 { 304 int rval = DCMD_ERR; 305 struct dev_info dip; 306 struct mdi_phci phci; 307 uint_t didx = 1; 308 uint_t pidx = 1; 309 310 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) != 311 sizeof (struct dev_info)) { 312 return (rval); 313 } 314 315 mdb_printf("Device tree children - dev_info:\n"); 316 if (dip.devi_child == NULL) { 317 mdb_printf("\tdevi_child is NULL, no dev_info\n\n"); 318 goto skip_di; 319 } 320 321 /* 322 * First, we dump the iport's children dev_info node information. 323 * use existing walker: devinfo_siblings 324 */ 325 mdb_printf("\t#: @unit-address name@\tdrill-down\n"); 326 rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb, 327 (void *)&didx, (uintptr_t)dip.devi_child); 328 mdb_printf("\n"); 329 330 skip_di: 331 /* 332 * Then we try to dump the iport's path_info node information. 333 * use existing walker: mdipi_phci_list 334 */ 335 mdb_printf("Device tree children - path_info:\n"); 336 if (mdb_vread(&phci, sizeof (struct mdi_phci), 337 (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) { 338 mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n"); 339 return (rval); 340 } 341 342 if (phci.ph_path_head == NULL) { 343 mdb_printf("\tph_path_head is NULL, no path_info\n\n"); 344 return (rval); 345 } 346 347 mdb_printf("\t#: @unit-address drill-down\n"); 348 rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb, 349 (void *)&pidx, (uintptr_t)phci.ph_path_head); 350 mdb_printf("\n"); 351 return (rval); 352 } 353 354 static void 355 display_iport_more(dev_info_t *dip, per_iport_setting_t *pis) 356 { 357 if (pis->pis_damap_info) { 358 (void) display_iport_damap(dip); 359 } 360 361 if (pis->pis_dtc_info) { 362 (void) display_iport_dtc(dip); 363 } 364 } 365 366 /*ARGSUSED*/ 367 static int 368 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv) 369 { 370 struct pmcs_iport iport; 371 uintptr_t list_addr; 372 char *ua_state; 373 char portid[4]; 374 char unit_address[34]; 375 per_iport_setting_t *pis = (per_iport_setting_t *)priv; 376 377 if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) != 378 sizeof (struct pmcs_iport)) { 379 return (DCMD_ERR); 380 } 381 382 if (mdb_readstr(unit_address, sizeof (unit_address), 383 (uintptr_t)(iport.ua)) == -1) { 384 strncpy(unit_address, "Unset", sizeof (unit_address)); 385 } 386 387 if (iport.portid == 0xffff) { 388 mdb_snprintf(portid, sizeof (portid), "%s", "-"); 389 } else if (iport.portid == PMCS_IPORT_INVALID_PORT_ID) { 390 mdb_snprintf(portid, sizeof (portid), "%s", "N/A"); 391 } else { 392 mdb_snprintf(portid, sizeof (portid), "%d", iport.portid); 393 } 394 395 switch (iport.ua_state) { 396 case UA_INACTIVE: 397 ua_state = "Inactive"; 398 break; 399 case UA_PEND_ACTIVATE: 400 ua_state = "PendActivate"; 401 break; 402 case UA_ACTIVE: 403 ua_state = "Active"; 404 break; 405 case UA_PEND_DEACTIVATE: 406 ua_state = "PendDeactivate"; 407 break; 408 default: 409 ua_state = "Unknown"; 410 } 411 412 if (strlen(unit_address) < 3) { 413 /* Standard iport unit address */ 414 mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State", 415 "PortID", "NumPhys", "DIP\n"); 416 mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr, 417 ua_state, portid, iport.nphy, iport.dip); 418 } else { 419 /* Temporary iport unit address */ 420 mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport", 421 "UA State", "PortID", "NumPhys", "DIP\n"); 422 mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr, 423 ua_state, portid, iport.nphy, iport.dip); 424 } 425 426 if (iport.nphy > 0) { 427 mdb_inc_indent(4); 428 mdb_printf("%-18s %8s", "Phy", "PhyNum\n"); 429 mdb_inc_indent(2); 430 list_addr = 431 (uintptr_t)(addr + offsetof(struct pmcs_iport, phys)); 432 if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL, 433 list_addr) == -1) { 434 mdb_warn("pmcs iport walk failed"); 435 } 436 mdb_dec_indent(6); 437 mdb_printf("\n"); 438 } 439 440 /* 441 * See if we need to show more information based on 'd' or 'm' options 442 */ 443 display_iport_more(iport.dip, pis); 444 445 return (0); 446 } 447 448 /*ARGSUSED*/ 449 static void 450 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose, 451 per_iport_setting_t *pis) 452 { 453 uintptr_t list_addr; 454 455 if (m.iports_attached) { 456 mdb_printf("Iport information:\n"); 457 mdb_printf("-----------------\n"); 458 } else { 459 mdb_printf("No Iports found.\n\n"); 460 return; 461 } 462 463 list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports)); 464 465 if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) { 466 mdb_warn("pmcs iport walk failed"); 467 } 468 469 mdb_printf("\n"); 470 } 471 472 /* ARGSUSED */ 473 static int 474 pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv) 475 { 476 pmcs_phy_t phy; 477 478 if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) { 479 mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p", 480 (void *)addr); 481 return (DCMD_ERR); 482 } 483 484 if (phy.configured && (phy.target == NULL)) { 485 mdb_printf("SAS address: "); 486 print_sas_address(&phy); 487 mdb_printf(" DType: "); 488 switch (phy.dtype) { 489 case SAS: 490 mdb_printf("%4s", "SAS"); 491 break; 492 case SATA: 493 mdb_printf("%4s", "SATA"); 494 break; 495 case EXPANDER: 496 mdb_printf("%4s", "SMP"); 497 break; 498 default: 499 mdb_printf("%4s", "N/A"); 500 break; 501 } 502 mdb_printf(" Path: %s\n", phy.path); 503 } 504 505 return (0); 506 } 507 508 static void 509 display_unconfigured_targets(uintptr_t addr) 510 { 511 mdb_printf("Unconfigured target SAS address:\n\n"); 512 513 if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) { 514 mdb_warn("pmcs phys walk failed"); 515 } 516 } 517 518 static void 519 display_completion_queue(struct pmcs_hw ss) 520 { 521 pmcs_iocomp_cb_t ccb, *ccbp; 522 pmcwork_t work; 523 524 if (ss.iocomp_cb_head == NULL) { 525 mdb_printf("Completion queue is empty.\n"); 526 return; 527 } 528 529 ccbp = ss.iocomp_cb_head; 530 mdb_printf("%8s %10s %20s %8s %8s O D\n", 531 "HTag", "State", "Phy Path", "Target", "Timer"); 532 533 while (ccbp) { 534 if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t), 535 (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) { 536 mdb_warn("Unable to read completion queue entry\n"); 537 return; 538 } 539 540 if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk) 541 != sizeof (pmcwork_t)) { 542 mdb_warn("Unable to read work structure\n"); 543 return; 544 } 545 546 /* 547 * Only print the work structure if it's still active. If 548 * it's not, it's been completed since we started looking at 549 * it. 550 */ 551 if (work.state != PMCS_WORK_STATE_NIL) { 552 display_one_work(&work, 0, 0); 553 } 554 ccbp = ccb.next; 555 } 556 } 557 558 static void 559 display_event_log(struct pmcs_hw ss) 560 { 561 pmcs_fw_event_hdr_t fwhdr; 562 char *header_id, *entry, *fwlogp; 563 uint32_t total_size = PMCS_FWLOG_SIZE, log_size, index, *swapp, sidx; 564 pmcs_fw_event_entry_t *fw_entryp; 565 struct timespec systime; 566 567 if (ss.fwlogp == NULL) { 568 mdb_printf("There is no firmware event log.\n"); 569 return; 570 } 571 572 fwlogp = (char *)ss.fwlogp; 573 574 while (total_size != 0) { 575 if (mdb_vread(&fwhdr, sizeof (pmcs_fw_event_hdr_t), 576 (uintptr_t)fwlogp) != sizeof (pmcs_fw_event_hdr_t)) { 577 mdb_warn("Unable to read firmware event log header\n"); 578 return; 579 } 580 581 /* 582 * Firmware event log is little-endian 583 */ 584 swapp = (uint32_t *)&fwhdr; 585 for (sidx = 0; sidx < (sizeof (pmcs_fw_event_hdr_t) / 586 sizeof (uint32_t)); sidx++) { 587 *swapp = LE_32(*swapp); 588 swapp++; 589 } 590 591 if (fwhdr.fw_el_signature == PMCS_FWLOG_AAP1_SIG) { 592 header_id = "AAP1"; 593 } else if (fwhdr.fw_el_signature == PMCS_FWLOG_IOP_SIG) { 594 header_id = "IOP"; 595 } else { 596 mdb_warn("Invalid firmware event log signature\n"); 597 return; 598 } 599 600 mdb_printf("Event Log: %s\n", header_id); 601 mdb_printf("Oldest entry: %d\n", fwhdr.fw_el_oldest_idx); 602 mdb_printf("Latest entry: %d\n", fwhdr.fw_el_latest_idx); 603 604 entry = mdb_alloc(fwhdr.fw_el_entry_size, UM_SLEEP); 605 fw_entryp = (pmcs_fw_event_entry_t *)((void *)entry); 606 total_size -= sizeof (pmcs_fw_event_hdr_t); 607 log_size = fwhdr.fw_el_buf_size; 608 fwlogp += fwhdr.fw_el_entry_start_offset; 609 swapp = (uint32_t *)((void *)entry); 610 index = 0; 611 612 mdb_printf("%8s %16s %32s %8s %3s %8s %8s %8s %8s", 613 "Index", "Timestamp", "Time", "Seq Num", "Sev", "Word 0", 614 "Word 1", "Word 2", "Word 3"); 615 mdb_printf("\n"); 616 617 while (log_size != 0) { 618 if (mdb_vread(entry, fwhdr.fw_el_entry_size, 619 (uintptr_t)fwlogp) != fwhdr.fw_el_entry_size) { 620 mdb_warn("Unable to read event log entry\n"); 621 goto bail_out; 622 } 623 624 for (sidx = 0; sidx < (fwhdr.fw_el_entry_size / 625 sizeof (uint32_t)); sidx++) { 626 *(swapp + sidx) = LE_32(*(swapp + sidx)); 627 } 628 629 if (fw_entryp->ts_upper || fw_entryp->ts_lower) { 630 pmcs_fwtime_to_systime(ss, fw_entryp->ts_upper, 631 fw_entryp->ts_lower, &systime); 632 mdb_printf("%8d %08x%08x [%Y.%09ld] %8d %3d " 633 "%08x %08x %08x %08x\n", index, 634 fw_entryp->ts_upper, fw_entryp->ts_lower, 635 systime, fw_entryp->seq_num, 636 fw_entryp->severity, fw_entryp->logw0, 637 fw_entryp->logw1, fw_entryp->logw2, 638 fw_entryp->logw3); 639 } 640 641 fwlogp += fwhdr.fw_el_entry_size; 642 total_size -= fwhdr.fw_el_entry_size; 643 log_size -= fwhdr.fw_el_entry_size; 644 index++; 645 } 646 647 mdb_printf("\n"); 648 } 649 650 bail_out: 651 mdb_free(entry, fwhdr.fw_el_entry_size); 652 } 653 654 /*ARGSUSED*/ 655 static void 656 display_hwinfo(struct pmcs_hw m, int verbose) 657 { 658 struct pmcs_hw *mp = &m; 659 char *fwsupport; 660 661 switch (PMCS_FW_TYPE(mp)) { 662 case PMCS_FW_TYPE_RELEASED: 663 fwsupport = "Released"; 664 break; 665 case PMCS_FW_TYPE_DEVELOPMENT: 666 fwsupport = "Development"; 667 break; 668 case PMCS_FW_TYPE_ALPHA: 669 fwsupport = "Alpha"; 670 break; 671 case PMCS_FW_TYPE_BETA: 672 fwsupport = "Beta"; 673 break; 674 default: 675 fwsupport = "Special"; 676 break; 677 } 678 679 mdb_printf("\nHardware information:\n"); 680 mdb_printf("---------------------\n"); 681 682 mdb_printf("Chip revision: %c\n", 'A' + m.chiprev); 683 mdb_printf("SAS WWID: %"PRIx64"\n", m.sas_wwns[0]); 684 mdb_printf("Firmware version: %x.%x.%x (%s)\n", 685 PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp), 686 fwsupport); 687 mdb_printf("ILA version: %08x\n", m.ila_ver); 688 mdb_printf("Active f/w img: %c\n", (m.fw_active_img) ? 'A' : 'B'); 689 690 mdb_printf("Number of PHYs: %d\n", m.nphy); 691 mdb_printf("Maximum commands: %d\n", m.max_cmd); 692 mdb_printf("Maximum devices: %d\n", m.max_dev); 693 mdb_printf("I/O queue depth: %d\n", m.ioq_depth); 694 mdb_printf("Open retry intvl: %d usecs\n", m.open_retry_interval); 695 if (m.fwlog == 0) { 696 mdb_printf("Firmware logging: Disabled\n"); 697 } else { 698 mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog); 699 } 700 if (m.fwlog_file == 0) { 701 mdb_printf("Firmware logfile: Not configured\n"); 702 } else { 703 mdb_printf("Firmware logfile: Configured\n"); 704 mdb_inc_indent(2); 705 mdb_printf("AAP1 log file: %s\n", m.fwlogfile_aap1); 706 mdb_printf("IOP logfile: %s\n", m.fwlogfile_iop); 707 mdb_dec_indent(2); 708 } 709 } 710 711 static void 712 display_targets(struct pmcs_hw m, int verbose, int totals_only) 713 { 714 char *dtype; 715 pmcs_xscsi_t xs; 716 pmcs_phy_t phy; 717 uint16_t max_dev, idx; 718 uint32_t sas_targets = 0, smp_targets = 0, sata_targets = 0; 719 720 max_dev = m.max_dev; 721 722 if (targets == NULL) { 723 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 724 } 725 726 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 727 NOREAD(targets, m.targets); 728 return; 729 } 730 731 if (!totals_only) { 732 mdb_printf("\nTarget information:\n"); 733 mdb_printf("---------------------------------------\n"); 734 mdb_printf("VTGT %-16s %-16s %-5s %4s %6s %s", "SAS Address", 735 "PHY Address", "DType", "Actv", "OnChip", "DS"); 736 mdb_printf("\n"); 737 } 738 739 for (idx = 0; idx < max_dev; idx++) { 740 if (targets[idx] == NULL) { 741 continue; 742 } 743 744 if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) { 745 NOREAD(pmcs_xscsi_t, targets[idx]); 746 continue; 747 } 748 749 /* 750 * It has to be new or assigned to be of interest. 751 */ 752 if (xs.new == 0 && xs.assigned == 0) { 753 continue; 754 } 755 756 switch (xs.dtype) { 757 case NOTHING: 758 dtype = "None"; 759 break; 760 case SATA: 761 dtype = "SATA"; 762 sata_targets++; 763 break; 764 case SAS: 765 dtype = "SAS"; 766 sas_targets++; 767 break; 768 case EXPANDER: 769 dtype = "SMP"; 770 smp_targets++; 771 break; 772 } 773 774 if (totals_only) { 775 continue; 776 } 777 778 if (xs.phy) { 779 if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) { 780 NOREAD(pmcs_phy_t, xs.phy); 781 continue; 782 } 783 mdb_printf("%4d ", idx); 784 print_sas_address(&phy); 785 mdb_printf(" %16p", xs.phy); 786 } else { 787 mdb_printf("%4d %16s", idx, "<no phy avail>"); 788 } 789 mdb_printf(" %5s", dtype); 790 mdb_printf(" %4d", xs.actv_pkts); 791 mdb_printf(" %6d", xs.actv_cnt); 792 mdb_printf(" %2d", xs.dev_state); 793 794 if (verbose) { 795 if (xs.new) { 796 mdb_printf(" new"); 797 } 798 if (xs.assigned) { 799 mdb_printf(" assigned"); 800 } 801 if (xs.draining) { 802 mdb_printf(" draining"); 803 } 804 if (xs.reset_wait) { 805 mdb_printf(" reset_wait"); 806 } 807 if (xs.resetting) { 808 mdb_printf(" resetting"); 809 } 810 if (xs.recover_wait) { 811 mdb_printf(" recover_wait"); 812 } 813 if (xs.recovering) { 814 mdb_printf(" recovering"); 815 } 816 if (xs.event_recovery) { 817 mdb_printf(" event recovery"); 818 } 819 if (xs.special_running) { 820 mdb_printf(" special_active"); 821 } 822 if (xs.ncq) { 823 mdb_printf(" ncq_tagmap=0x%x qdepth=%d", 824 xs.tagmap, xs.qdepth); 825 } else if (xs.pio) { 826 mdb_printf(" pio"); 827 } 828 } 829 830 mdb_printf("\n"); 831 } 832 833 if (!totals_only) { 834 mdb_printf("\n"); 835 } 836 837 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 838 "Configured targets:", (sas_targets + sata_targets + smp_targets), 839 sas_targets, sata_targets, smp_targets); 840 } 841 842 static char * 843 work_state_to_string(uint32_t state) 844 { 845 char *state_string; 846 847 switch (state) { 848 case PMCS_WORK_STATE_NIL: 849 state_string = "Free"; 850 break; 851 case PMCS_WORK_STATE_READY: 852 state_string = "Ready"; 853 break; 854 case PMCS_WORK_STATE_ONCHIP: 855 state_string = "On Chip"; 856 break; 857 case PMCS_WORK_STATE_INTR: 858 state_string = "In Intr"; 859 break; 860 case PMCS_WORK_STATE_IOCOMPQ: 861 state_string = "I/O Comp"; 862 break; 863 case PMCS_WORK_STATE_ABORTED: 864 state_string = "I/O Aborted"; 865 break; 866 case PMCS_WORK_STATE_TIMED_OUT: 867 state_string = "I/O Timed Out"; 868 break; 869 default: 870 state_string = "INVALID"; 871 break; 872 } 873 874 return (state_string); 875 } 876 877 static void 878 display_one_work(pmcwork_t *wp, int verbose, int idx) 879 { 880 char *state, *last_state; 881 char *path; 882 pmcs_xscsi_t xs; 883 pmcs_phy_t phy; 884 int tgt; 885 886 state = work_state_to_string(wp->state); 887 last_state = work_state_to_string(wp->last_state); 888 889 if (wp->ssp_event && wp->ssp_event != 0xffffffff) { 890 mdb_printf("SSP event 0x%x", wp->ssp_event); 891 } 892 893 tgt = -1; 894 if (wp->xp) { 895 if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) { 896 NOREAD(pmcs_xscsi_t, wp->xp); 897 } else { 898 tgt = xs.target_num; 899 } 900 } 901 if (wp->phy) { 902 if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) { 903 NOREAD(pmcs_phy_t, wp->phy); 904 } 905 path = phy.path; 906 } else { 907 path = "N/A"; 908 } 909 910 if (verbose) { 911 mdb_printf("%4d ", idx); 912 } 913 if (tgt == -1) { 914 mdb_printf("%08x %10s %20s N/A %8u %1d %1d ", 915 wp->htag, state, path, wp->timer, 916 wp->onwire, wp->dead); 917 } else { 918 mdb_printf("%08x %10s %20s %8d %8u %1d %1d ", 919 wp->htag, state, path, tgt, wp->timer, 920 wp->onwire, wp->dead); 921 } 922 if (verbose) { 923 mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n", 924 wp->last_htag, last_state, wp->last_phy, wp->last_xp, 925 wp->last_arg); 926 } else { 927 mdb_printf("\n"); 928 } 929 } 930 931 static void 932 display_work(struct pmcs_hw m, int verbose, int wserno) 933 { 934 int idx; 935 boolean_t header_printed = B_FALSE; 936 pmcwork_t *wp; 937 wserno_list_t *sernop, *sp, *newsp, *sphead = NULL; 938 uintptr_t _wp; 939 int serno; 940 941 wp = mdb_alloc(sizeof (pmcwork_t) * m.max_cmd, UM_SLEEP); 942 _wp = (uintptr_t)m.work; 943 sernop = mdb_alloc(sizeof (wserno_list_t) * m.max_cmd, UM_SLEEP); 944 bzero(sernop, sizeof (wserno_list_t) * m.max_cmd); 945 946 mdb_printf("\nActive Work structure information:\n"); 947 mdb_printf("----------------------------------\n"); 948 949 /* 950 * Read in all the work structures 951 */ 952 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 953 if (MDB_RD(wp + idx, sizeof (pmcwork_t), _wp) == -1) { 954 NOREAD(pmcwork_t, _wp); 955 continue; 956 } 957 } 958 959 /* 960 * Sort by serial number? 961 */ 962 if (wserno) { 963 for (idx = 0; idx < m.max_cmd; idx++) { 964 if ((wp + idx)->htag == 0) { 965 serno = PMCS_TAG_SERNO((wp + idx)->last_htag); 966 } else { 967 serno = PMCS_TAG_SERNO((wp + idx)->htag); 968 } 969 970 /* Start at the beginning of the list */ 971 sp = sphead; 972 newsp = sernop + idx; 973 /* If this is the first entry, just add it */ 974 if (sphead == NULL) { 975 sphead = sernop; 976 sphead->serno = serno; 977 sphead->idx = idx; 978 sphead->next = NULL; 979 sphead->prev = NULL; 980 continue; 981 } 982 983 newsp->serno = serno; 984 newsp->idx = idx; 985 986 /* Find out where in the list this goes */ 987 while (sp) { 988 /* This item goes before sp */ 989 if (serno < sp->serno) { 990 newsp->next = sp; 991 newsp->prev = sp->prev; 992 if (newsp->prev == NULL) { 993 sphead = newsp; 994 } else { 995 newsp->prev->next = newsp; 996 } 997 sp->prev = newsp; 998 break; 999 } 1000 1001 /* 1002 * If sp->next is NULL, this entry goes at the 1003 * end of the list 1004 */ 1005 if (sp->next == NULL) { 1006 sp->next = newsp; 1007 newsp->next = NULL; 1008 newsp->prev = sp; 1009 break; 1010 } 1011 1012 sp = sp->next; 1013 } 1014 } 1015 1016 /* 1017 * Now print the sorted list 1018 */ 1019 mdb_printf(" Idx %8s %10s %20s %8s %8s O D ", 1020 "HTag", "State", "Phy Path", "Target", "Timer"); 1021 mdb_printf("%8s %10s %18s %18s %18s\n", "LastHTAG", 1022 "LastState", "LastPHY", "LastTgt", "LastArg"); 1023 1024 sp = sphead; 1025 while (sp) { 1026 display_one_work(wp + sp->idx, 1, sp->idx); 1027 sp = sp->next; 1028 } 1029 1030 goto out; 1031 } 1032 1033 /* 1034 * Now print the list, sorted by index 1035 */ 1036 for (idx = 0; idx < m.max_cmd; idx++) { 1037 if (!verbose && ((wp + idx)->htag == PMCS_TAG_TYPE_FREE)) { 1038 continue; 1039 } 1040 1041 if (header_printed == B_FALSE) { 1042 if (verbose) { 1043 mdb_printf("%4s ", "Idx"); 1044 } 1045 mdb_printf("%8s %10s %20s %8s %8s O D ", 1046 "HTag", "State", "Phy Path", "Target", "Timer"); 1047 if (verbose) { 1048 mdb_printf("%8s %10s %18s %18s %18s\n", 1049 "LastHTAG", "LastState", "LastPHY", 1050 "LastTgt", "LastArg"); 1051 } else { 1052 mdb_printf("\n"); 1053 } 1054 header_printed = B_TRUE; 1055 } 1056 1057 display_one_work(wp + idx, verbose, idx); 1058 } 1059 1060 out: 1061 mdb_free(wp, sizeof (pmcwork_t) * m.max_cmd); 1062 mdb_free(sernop, sizeof (wserno_list_t) * m.max_cmd); 1063 } 1064 1065 static void 1066 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose) 1067 { 1068 int cdb_size, idx; 1069 struct scsi_pkt pkt; 1070 uchar_t cdb[256]; 1071 1072 if (printhdr) { 1073 if (verbose) { 1074 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command", 1075 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 1076 } else { 1077 mdb_printf("%16s %16s %16s %8s %s\n", "Command", 1078 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 1079 } 1080 } 1081 1082 mdb_printf("%16p %16p %16p %08x %08x ", 1083 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag); 1084 1085 /* 1086 * If we're printing verbose, dump the CDB as well. 1087 */ 1088 if (verbose) { 1089 if (sp->cmd_pkt) { 1090 if (mdb_vread(&pkt, sizeof (struct scsi_pkt), 1091 (uintptr_t)sp->cmd_pkt) != 1092 sizeof (struct scsi_pkt)) { 1093 mdb_warn("Unable to read SCSI pkt\n"); 1094 return; 1095 } 1096 cdb_size = pkt.pkt_cdblen; 1097 if (mdb_vread(&cdb[0], cdb_size, 1098 (uintptr_t)pkt.pkt_cdbp) != cdb_size) { 1099 mdb_warn("Unable to read CDB\n"); 1100 return; 1101 } 1102 1103 for (idx = 0; idx < cdb_size; idx++) { 1104 mdb_printf("%02x ", cdb[idx]); 1105 } 1106 } else { 1107 mdb_printf("N/A"); 1108 } 1109 1110 mdb_printf("\n"); 1111 } else { 1112 mdb_printf("\n"); 1113 } 1114 } 1115 1116 /*ARGSUSED1*/ 1117 static void 1118 display_waitqs(struct pmcs_hw m, int verbose) 1119 { 1120 pmcs_cmd_t *sp, s; 1121 pmcs_xscsi_t xs; 1122 int first, i; 1123 int max_dev = m.max_dev; 1124 1125 sp = m.dq.stqh_first; 1126 first = 1; 1127 while (sp) { 1128 if (first) { 1129 mdb_printf("\nDead Command Queue:\n"); 1130 mdb_printf("---------------------------\n"); 1131 } 1132 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1133 NOREAD(pmcs_cmd_t, sp); 1134 break; 1135 } 1136 print_spcmd(&s, sp, first, verbose); 1137 sp = s.cmd_next.stqe_next; 1138 first = 0; 1139 } 1140 1141 sp = m.cq.stqh_first; 1142 first = 1; 1143 while (sp) { 1144 if (first) { 1145 mdb_printf("\nCompletion Command Queue:\n"); 1146 mdb_printf("---------------------------\n"); 1147 } 1148 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1149 NOREAD(pmcs_cmd_t, sp); 1150 break; 1151 } 1152 print_spcmd(&s, sp, first, verbose); 1153 sp = s.cmd_next.stqe_next; 1154 first = 0; 1155 } 1156 1157 1158 if (targets == NULL) { 1159 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 1160 } 1161 1162 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 1163 NOREAD(targets, m.targets); 1164 return; 1165 } 1166 1167 for (i = 0; i < max_dev; i++) { 1168 if (targets[i] == NULL) { 1169 continue; 1170 } 1171 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) { 1172 NOREAD(pmcs_xscsi_t, targets[i]); 1173 continue; 1174 } 1175 sp = xs.wq.stqh_first; 1176 first = 1; 1177 while (sp) { 1178 if (first) { 1179 mdb_printf("\nTarget %u Wait Queue:\n", 1180 xs.target_num); 1181 mdb_printf("---------------------------\n"); 1182 } 1183 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1184 NOREAD(pmcs_cmd_t, sp); 1185 break; 1186 } 1187 print_spcmd(&s, sp, first, verbose); 1188 sp = s.cmd_next.stqe_next; 1189 first = 0; 1190 } 1191 sp = xs.aq.stqh_first; 1192 first = 1; 1193 while (sp) { 1194 if (first) { 1195 mdb_printf("\nTarget %u Active Queue:\n", 1196 xs.target_num); 1197 mdb_printf("---------------------------\n"); 1198 } 1199 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1200 NOREAD(pmcs_cmd_t, sp); 1201 break; 1202 } 1203 print_spcmd(&s, sp, first, verbose); 1204 sp = s.cmd_next.stqe_next; 1205 first = 0; 1206 } 1207 sp = xs.sq.stqh_first; 1208 first = 1; 1209 while (sp) { 1210 if (first) { 1211 mdb_printf("\nTarget %u Special Queue:\n", 1212 xs.target_num); 1213 mdb_printf("---------------------------\n"); 1214 } 1215 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1216 NOREAD(pmcs_cmd_t, sp); 1217 break; 1218 } 1219 print_spcmd(&s, sp, first, verbose); 1220 sp = s.cmd_next.stqe_next; 1221 first = 0; 1222 } 1223 } 1224 } 1225 1226 static char * 1227 ibq_type(int qnum) 1228 { 1229 if (qnum < 0 || qnum >= PMCS_NIQ) { 1230 return ("UNKNOWN"); 1231 } 1232 1233 if (qnum < PMCS_IQ_OTHER) { 1234 return ("I/O"); 1235 } 1236 1237 return ("Other"); 1238 } 1239 1240 static char * 1241 obq_type(int qnum) 1242 { 1243 switch (qnum) { 1244 case PMCS_OQ_IODONE: 1245 return ("I/O"); 1246 break; 1247 case PMCS_OQ_GENERAL: 1248 return ("General"); 1249 break; 1250 case PMCS_OQ_EVENTS: 1251 return ("Events"); 1252 break; 1253 default: 1254 return ("UNKNOWN"); 1255 } 1256 } 1257 1258 static char * 1259 iomb_cat(uint32_t cat) 1260 { 1261 switch (cat) { 1262 case PMCS_IOMB_CAT_NET: 1263 return ("NET"); 1264 break; 1265 case PMCS_IOMB_CAT_FC: 1266 return ("FC"); 1267 break; 1268 case PMCS_IOMB_CAT_SAS: 1269 return ("SAS"); 1270 break; 1271 case PMCS_IOMB_CAT_SCSI: 1272 return ("SCSI"); 1273 break; 1274 default: 1275 return ("???"); 1276 } 1277 } 1278 1279 static char * 1280 iomb_event(uint8_t event) 1281 { 1282 switch (event) { 1283 case IOP_EVENT_PHY_STOP_STATUS: 1284 return ("PHY STOP"); 1285 break; 1286 case IOP_EVENT_SAS_PHY_UP: 1287 return ("PHY UP"); 1288 break; 1289 case IOP_EVENT_SATA_PHY_UP: 1290 return ("SATA PHY UP"); 1291 break; 1292 case IOP_EVENT_SATA_SPINUP_HOLD: 1293 return ("SATA SPINUP HOLD"); 1294 break; 1295 case IOP_EVENT_PHY_DOWN: 1296 return ("PHY DOWN"); 1297 break; 1298 case IOP_EVENT_BROADCAST_CHANGE: 1299 return ("BROADCAST CHANGE"); 1300 break; 1301 case IOP_EVENT_BROADCAST_SES: 1302 return ("BROADCAST SES"); 1303 break; 1304 case IOP_EVENT_PHY_ERR_INBOUND_CRC: 1305 return ("INBOUND CRC ERROR"); 1306 break; 1307 case IOP_EVENT_HARD_RESET_RECEIVED: 1308 return ("HARD RESET"); 1309 break; 1310 case IOP_EVENT_EVENT_ID_FRAME_TIMO: 1311 return ("IDENTIFY FRAME TIMEOUT"); 1312 break; 1313 case IOP_EVENT_BROADCAST_EXP: 1314 return ("BROADCAST EXPANDER"); 1315 break; 1316 case IOP_EVENT_PHY_START_STATUS: 1317 return ("PHY START"); 1318 break; 1319 case IOP_EVENT_PHY_ERR_INVALID_DWORD: 1320 return ("INVALID DWORD"); 1321 break; 1322 case IOP_EVENT_PHY_ERR_DISPARITY_ERROR: 1323 return ("DISPARITY ERROR"); 1324 break; 1325 case IOP_EVENT_PHY_ERR_CODE_VIOLATION: 1326 return ("CODE VIOLATION"); 1327 break; 1328 case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN: 1329 return ("LOSS OF DWORD SYNC"); 1330 break; 1331 case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD: 1332 return ("PHY RESET FAILED"); 1333 break; 1334 case IOP_EVENT_PORT_RECOVERY_TIMER_TMO: 1335 return ("PORT RECOVERY TIMEOUT"); 1336 break; 1337 case IOP_EVENT_PORT_RECOVER: 1338 return ("PORT RECOVERY"); 1339 break; 1340 case IOP_EVENT_PORT_RESET_TIMER_TMO: 1341 return ("PORT RESET TIMEOUT"); 1342 break; 1343 case IOP_EVENT_PORT_RESET_COMPLETE: 1344 return ("PORT RESET COMPLETE"); 1345 break; 1346 case IOP_EVENT_BROADCAST_ASYNC_EVENT: 1347 return ("BROADCAST ASYNC"); 1348 break; 1349 case IOP_EVENT_IT_NEXUS_LOSS: 1350 return ("I/T NEXUS LOSS"); 1351 break; 1352 default: 1353 return ("Unknown Event"); 1354 } 1355 } 1356 1357 static char * 1358 inbound_iomb_opcode(uint32_t opcode) 1359 { 1360 switch (opcode) { 1361 case PMCIN_ECHO: 1362 return ("ECHO"); 1363 break; 1364 case PMCIN_GET_INFO: 1365 return ("GET_INFO"); 1366 break; 1367 case PMCIN_GET_VPD: 1368 return ("GET_VPD"); 1369 break; 1370 case PMCIN_PHY_START: 1371 return ("PHY_START"); 1372 break; 1373 case PMCIN_PHY_STOP: 1374 return ("PHY_STOP"); 1375 break; 1376 case PMCIN_SSP_INI_IO_START: 1377 return ("INI_IO_START"); 1378 break; 1379 case PMCIN_SSP_INI_TM_START: 1380 return ("INI_TM_START"); 1381 break; 1382 case PMCIN_SSP_INI_EXT_IO_START: 1383 return ("INI_EXT_IO_START"); 1384 break; 1385 case PMCIN_DEVICE_HANDLE_ACCEPT: 1386 return ("DEVICE_HANDLE_ACCEPT"); 1387 break; 1388 case PMCIN_SSP_TGT_IO_START: 1389 return ("TGT_IO_START"); 1390 break; 1391 case PMCIN_SSP_TGT_RESPONSE_START: 1392 return ("TGT_RESPONSE_START"); 1393 break; 1394 case PMCIN_SSP_INI_EDC_EXT_IO_START: 1395 return ("INI_EDC_EXT_IO_START"); 1396 break; 1397 case PMCIN_SSP_INI_EDC_EXT_IO_START1: 1398 return ("INI_EDC_EXT_IO_START1"); 1399 break; 1400 case PMCIN_SSP_TGT_EDC_IO_START: 1401 return ("TGT_EDC_IO_START"); 1402 break; 1403 case PMCIN_SSP_ABORT: 1404 return ("SSP_ABORT"); 1405 break; 1406 case PMCIN_DEREGISTER_DEVICE_HANDLE: 1407 return ("DEREGISTER_DEVICE_HANDLE"); 1408 break; 1409 case PMCIN_GET_DEVICE_HANDLE: 1410 return ("GET_DEVICE_HANDLE"); 1411 break; 1412 case PMCIN_SMP_REQUEST: 1413 return ("SMP_REQUEST"); 1414 break; 1415 case PMCIN_SMP_RESPONSE: 1416 return ("SMP_RESPONSE"); 1417 break; 1418 case PMCIN_SMP_ABORT: 1419 return ("SMP_ABORT"); 1420 break; 1421 case PMCIN_ASSISTED_DISCOVERY: 1422 return ("ASSISTED_DISCOVERY"); 1423 break; 1424 case PMCIN_REGISTER_DEVICE: 1425 return ("REGISTER_DEVICE"); 1426 break; 1427 case PMCIN_SATA_HOST_IO_START: 1428 return ("SATA_HOST_IO_START"); 1429 break; 1430 case PMCIN_SATA_ABORT: 1431 return ("SATA_ABORT"); 1432 break; 1433 case PMCIN_LOCAL_PHY_CONTROL: 1434 return ("LOCAL_PHY_CONTROL"); 1435 break; 1436 case PMCIN_GET_DEVICE_INFO: 1437 return ("GET_DEVICE_INFO"); 1438 break; 1439 case PMCIN_TWI: 1440 return ("TWI"); 1441 break; 1442 case PMCIN_FW_FLASH_UPDATE: 1443 return ("FW_FLASH_UPDATE"); 1444 break; 1445 case PMCIN_SET_VPD: 1446 return ("SET_VPD"); 1447 break; 1448 case PMCIN_GPIO: 1449 return ("GPIO"); 1450 break; 1451 case PMCIN_SAS_DIAG_MODE_START_END: 1452 return ("SAS_DIAG_MODE_START_END"); 1453 break; 1454 case PMCIN_SAS_DIAG_EXECUTE: 1455 return ("SAS_DIAG_EXECUTE"); 1456 break; 1457 case PMCIN_SAW_HW_EVENT_ACK: 1458 return ("SAS_HW_EVENT_ACK"); 1459 break; 1460 case PMCIN_GET_TIME_STAMP: 1461 return ("GET_TIME_STAMP"); 1462 break; 1463 case PMCIN_PORT_CONTROL: 1464 return ("PORT_CONTROL"); 1465 break; 1466 case PMCIN_GET_NVMD_DATA: 1467 return ("GET_NVMD_DATA"); 1468 break; 1469 case PMCIN_SET_NVMD_DATA: 1470 return ("SET_NVMD_DATA"); 1471 break; 1472 case PMCIN_SET_DEVICE_STATE: 1473 return ("SET_DEVICE_STATE"); 1474 break; 1475 case PMCIN_GET_DEVICE_STATE: 1476 return ("GET_DEVICE_STATE"); 1477 break; 1478 default: 1479 return ("UNKNOWN"); 1480 break; 1481 } 1482 } 1483 1484 static char * 1485 outbound_iomb_opcode(uint32_t opcode) 1486 { 1487 switch (opcode) { 1488 case PMCOUT_ECHO: 1489 return ("ECHO"); 1490 break; 1491 case PMCOUT_GET_INFO: 1492 return ("GET_INFO"); 1493 break; 1494 case PMCOUT_GET_VPD: 1495 return ("GET_VPD"); 1496 break; 1497 case PMCOUT_SAS_HW_EVENT: 1498 return ("SAS_HW_EVENT"); 1499 break; 1500 case PMCOUT_SSP_COMPLETION: 1501 return ("SSP_COMPLETION"); 1502 break; 1503 case PMCOUT_SMP_COMPLETION: 1504 return ("SMP_COMPLETION"); 1505 break; 1506 case PMCOUT_LOCAL_PHY_CONTROL: 1507 return ("LOCAL_PHY_CONTROL"); 1508 break; 1509 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT: 1510 return ("SAS_ASSISTED_DISCOVERY_SENT"); 1511 break; 1512 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT: 1513 return ("SATA_ASSISTED_DISCOVERY_SENT"); 1514 break; 1515 case PMCOUT_DEVICE_REGISTRATION: 1516 return ("DEVICE_REGISTRATION"); 1517 break; 1518 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1519 return ("DEREGISTER_DEVICE_HANDLE"); 1520 break; 1521 case PMCOUT_GET_DEVICE_HANDLE: 1522 return ("GET_DEVICE_HANDLE"); 1523 break; 1524 case PMCOUT_SATA_COMPLETION: 1525 return ("SATA_COMPLETION"); 1526 break; 1527 case PMCOUT_SATA_EVENT: 1528 return ("SATA_EVENT"); 1529 break; 1530 case PMCOUT_SSP_EVENT: 1531 return ("SSP_EVENT"); 1532 break; 1533 case PMCOUT_DEVICE_HANDLE_ARRIVED: 1534 return ("DEVICE_HANDLE_ARRIVED"); 1535 break; 1536 case PMCOUT_SMP_REQUEST_RECEIVED: 1537 return ("SMP_REQUEST_RECEIVED"); 1538 break; 1539 case PMCOUT_SSP_REQUEST_RECEIVED: 1540 return ("SSP_REQUEST_RECEIVED"); 1541 break; 1542 case PMCOUT_DEVICE_INFO: 1543 return ("DEVICE_INFO"); 1544 break; 1545 case PMCOUT_FW_FLASH_UPDATE: 1546 return ("FW_FLASH_UPDATE"); 1547 break; 1548 case PMCOUT_SET_VPD: 1549 return ("SET_VPD"); 1550 break; 1551 case PMCOUT_GPIO: 1552 return ("GPIO"); 1553 break; 1554 case PMCOUT_GPIO_EVENT: 1555 return ("GPIO_EVENT"); 1556 break; 1557 case PMCOUT_GENERAL_EVENT: 1558 return ("GENERAL_EVENT"); 1559 break; 1560 case PMCOUT_TWI: 1561 return ("TWI"); 1562 break; 1563 case PMCOUT_SSP_ABORT: 1564 return ("SSP_ABORT"); 1565 break; 1566 case PMCOUT_SATA_ABORT: 1567 return ("SATA_ABORT"); 1568 break; 1569 case PMCOUT_SAS_DIAG_MODE_START_END: 1570 return ("SAS_DIAG_MODE_START_END"); 1571 break; 1572 case PMCOUT_SAS_DIAG_EXECUTE: 1573 return ("SAS_DIAG_EXECUTE"); 1574 break; 1575 case PMCOUT_GET_TIME_STAMP: 1576 return ("GET_TIME_STAMP"); 1577 break; 1578 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1579 return ("SAS_HW_EVENT_ACK_ACK"); 1580 break; 1581 case PMCOUT_PORT_CONTROL: 1582 return ("PORT_CONTROL"); 1583 break; 1584 case PMCOUT_SKIP_ENTRIES: 1585 return ("SKIP_ENTRIES"); 1586 break; 1587 case PMCOUT_SMP_ABORT: 1588 return ("SMP_ABORT"); 1589 break; 1590 case PMCOUT_GET_NVMD_DATA: 1591 return ("GET_NVMD_DATA"); 1592 break; 1593 case PMCOUT_SET_NVMD_DATA: 1594 return ("SET_NVMD_DATA"); 1595 break; 1596 case PMCOUT_DEVICE_HANDLE_REMOVED: 1597 return ("DEVICE_HANDLE_REMOVED"); 1598 break; 1599 case PMCOUT_SET_DEVICE_STATE: 1600 return ("SET_DEVICE_STATE"); 1601 break; 1602 case PMCOUT_GET_DEVICE_STATE: 1603 return ("GET_DEVICE_STATE"); 1604 break; 1605 case PMCOUT_SET_DEVICE_INFO: 1606 return ("SET_DEVICE_INFO"); 1607 break; 1608 default: 1609 return ("UNKNOWN"); 1610 break; 1611 } 1612 } 1613 1614 static void 1615 dump_one_qentry_outbound(uint32_t *qentryp, int idx) 1616 { 1617 int qeidx; 1618 uint32_t word0 = LE_32(*qentryp); 1619 uint32_t word1 = LE_32(*(qentryp + 1)); 1620 uint8_t iop_event; 1621 1622 mdb_printf("Entry #%02d\n", idx); 1623 mdb_inc_indent(2); 1624 1625 mdb_printf("Header: 0x%08x (", word0); 1626 if (word0 & PMCS_IOMB_VALID) { 1627 mdb_printf("VALID, "); 1628 } 1629 if (word0 & PMCS_IOMB_HIPRI) { 1630 mdb_printf("HIPRI, "); 1631 } 1632 mdb_printf("OBID=%d, ", 1633 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1634 mdb_printf("CAT=%s, ", 1635 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1636 mdb_printf("OPCODE=%s", 1637 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1638 if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) { 1639 iop_event = IOP_EVENT_EVENT(word1); 1640 mdb_printf(" <%s>", iomb_event(iop_event)); 1641 } 1642 mdb_printf(")\n"); 1643 1644 mdb_printf("Remaining Payload:\n"); 1645 1646 mdb_inc_indent(2); 1647 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1648 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1649 } 1650 mdb_printf("\n"); 1651 mdb_dec_indent(4); 1652 } 1653 1654 static void 1655 display_outbound_queues(struct pmcs_hw ss, uint_t verbose) 1656 { 1657 int idx, qidx; 1658 uintptr_t obqp; 1659 uint32_t *cip; 1660 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1661 uint32_t last_consumed, oqpi; 1662 1663 mdb_printf("\n"); 1664 mdb_printf("Outbound Queues\n"); 1665 mdb_printf("---------------\n"); 1666 1667 mdb_inc_indent(2); 1668 1669 for (qidx = 0; qidx < PMCS_NOQ; qidx++) { 1670 obqp = (uintptr_t)ss.oqp[qidx]; 1671 1672 if (obqp == NULL) { 1673 mdb_printf("No outbound queue ptr for queue #%d\n", 1674 qidx); 1675 continue; 1676 } 1677 1678 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx, 1679 obq_type(qidx)); 1680 /* 1681 * Chip is the producer, so read the actual producer index 1682 * and not the driver's version 1683 */ 1684 cip = (uint32_t *)((void *)ss.cip); 1685 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET + 1686 (qidx * 4)) == -1) { 1687 mdb_warn("Couldn't read oqpi\n"); 1688 break; 1689 } 1690 1691 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1692 LE_32(oqpi), ss.oqci[qidx]); 1693 mdb_inc_indent(2); 1694 1695 if (ss.oqci[qidx] == 0) { 1696 last_consumed = ss.ioq_depth - 1; 1697 } else { 1698 last_consumed = ss.oqci[qidx] - 1; 1699 } 1700 1701 1702 if (!verbose) { 1703 mdb_printf("Last processed entry:\n"); 1704 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1705 (obqp + (PMCS_QENTRY_SIZE * last_consumed))) 1706 == -1) { 1707 mdb_warn("Couldn't read queue entry at 0x%p\n", 1708 (obqp + (PMCS_QENTRY_SIZE * 1709 last_consumed))); 1710 break; 1711 } 1712 dump_one_qentry_outbound(qentryp, last_consumed); 1713 mdb_printf("\n"); 1714 mdb_dec_indent(2); 1715 continue; 1716 } 1717 1718 for (idx = 0; idx < ss.ioq_depth; idx++) { 1719 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1720 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1721 mdb_warn("Couldn't read queue entry at 0x%p\n", 1722 (obqp + (PMCS_QENTRY_SIZE * idx))); 1723 break; 1724 } 1725 dump_one_qentry_outbound(qentryp, idx); 1726 } 1727 1728 mdb_printf("\n"); 1729 mdb_dec_indent(2); 1730 } 1731 1732 mdb_dec_indent(2); 1733 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1734 } 1735 1736 static void 1737 dump_one_qentry_inbound(uint32_t *qentryp, int idx) 1738 { 1739 int qeidx; 1740 uint32_t word0 = LE_32(*qentryp); 1741 1742 mdb_printf("Entry #%02d\n", idx); 1743 mdb_inc_indent(2); 1744 1745 mdb_printf("Header: 0x%08x (", word0); 1746 if (word0 & PMCS_IOMB_VALID) { 1747 mdb_printf("VALID, "); 1748 } 1749 if (word0 & PMCS_IOMB_HIPRI) { 1750 mdb_printf("HIPRI, "); 1751 } 1752 mdb_printf("OBID=%d, ", 1753 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1754 mdb_printf("CAT=%s, ", 1755 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1756 mdb_printf("OPCODE=%s", 1757 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1758 mdb_printf(")\n"); 1759 1760 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1))); 1761 mdb_printf("Remaining Payload:\n"); 1762 1763 mdb_inc_indent(2); 1764 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1765 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1766 } 1767 mdb_printf("\n"); 1768 mdb_dec_indent(4); 1769 } 1770 1771 static void 1772 display_inbound_queues(struct pmcs_hw ss, uint_t verbose) 1773 { 1774 int idx, qidx, iqci, last_consumed; 1775 uintptr_t ibqp; 1776 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1777 uint32_t *cip; 1778 1779 mdb_printf("\n"); 1780 mdb_printf("Inbound Queues\n"); 1781 mdb_printf("--------------\n"); 1782 1783 mdb_inc_indent(2); 1784 1785 for (qidx = 0; qidx < PMCS_NIQ; qidx++) { 1786 ibqp = (uintptr_t)ss.iqp[qidx]; 1787 1788 if (ibqp == NULL) { 1789 mdb_printf("No inbound queue ptr for queue #%d\n", 1790 qidx); 1791 continue; 1792 } 1793 1794 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx, 1795 ibq_type(qidx)); 1796 1797 cip = (uint32_t *)((void *)ss.cip); 1798 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) { 1799 mdb_warn("Couldn't read iqci\n"); 1800 break; 1801 } 1802 iqci = LE_32(iqci); 1803 1804 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1805 ss.shadow_iqpi[qidx], iqci); 1806 mdb_inc_indent(2); 1807 1808 if (iqci == 0) { 1809 last_consumed = ss.ioq_depth - 1; 1810 } else { 1811 last_consumed = iqci - 1; 1812 } 1813 1814 if (!verbose) { 1815 mdb_printf("Last processed entry:\n"); 1816 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1817 (ibqp + (PMCS_QENTRY_SIZE * last_consumed))) 1818 == -1) { 1819 mdb_warn("Couldn't read queue entry at 0x%p\n", 1820 (ibqp + (PMCS_QENTRY_SIZE * 1821 last_consumed))); 1822 break; 1823 } 1824 dump_one_qentry_inbound(qentryp, last_consumed); 1825 mdb_printf("\n"); 1826 mdb_dec_indent(2); 1827 continue; 1828 } 1829 1830 for (idx = 0; idx < ss.ioq_depth; idx++) { 1831 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1832 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1833 mdb_warn("Couldn't read queue entry at 0x%p\n", 1834 (ibqp + (PMCS_QENTRY_SIZE * idx))); 1835 break; 1836 } 1837 dump_one_qentry_inbound(qentryp, idx); 1838 } 1839 1840 mdb_printf("\n"); 1841 mdb_dec_indent(2); 1842 } 1843 1844 mdb_dec_indent(2); 1845 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1846 } 1847 1848 /* 1849 * phy is our copy of the PHY structure. phyp is the pointer to the actual 1850 * kernel PHY data structure 1851 */ 1852 static void 1853 display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose, 1854 int totals_only) 1855 { 1856 char *dtype, *speed; 1857 char *yes = "Yes"; 1858 char *no = "No"; 1859 char *cfgd = no; 1860 char *apend = no; 1861 char *asent = no; 1862 char *dead = no; 1863 char *changed = no; 1864 char route_attr, route_method; 1865 1866 switch (phy.dtype) { 1867 case NOTHING: 1868 dtype = "None"; 1869 break; 1870 case SATA: 1871 dtype = "SATA"; 1872 if (phy.configured) { 1873 ++sata_phys; 1874 } 1875 break; 1876 case SAS: 1877 dtype = "SAS"; 1878 if (phy.configured) { 1879 ++sas_phys; 1880 } 1881 break; 1882 case EXPANDER: 1883 dtype = "EXP"; 1884 if (phy.configured) { 1885 ++exp_phys; 1886 } 1887 break; 1888 } 1889 1890 if (phy.dtype == NOTHING) { 1891 empty_phys++; 1892 } else if ((phy.dtype == EXPANDER) && phy.configured) { 1893 num_expanders++; 1894 } 1895 1896 if (totals_only) { 1897 return; 1898 } 1899 1900 switch (phy.link_rate) { 1901 case SAS_LINK_RATE_1_5GBIT: 1902 speed = "1.5Gb/s"; 1903 break; 1904 case SAS_LINK_RATE_3GBIT: 1905 speed = "3 Gb/s"; 1906 break; 1907 case SAS_LINK_RATE_6GBIT: 1908 speed = "6 Gb/s"; 1909 break; 1910 default: 1911 speed = "N/A"; 1912 break; 1913 } 1914 1915 if ((phy.dtype != NOTHING) || verbose) { 1916 print_sas_address(&phy); 1917 1918 if (phy.device_id != PMCS_INVALID_DEVICE_ID) { 1919 mdb_printf(" %3d %4d %6s %4s ", 1920 phy.device_id, phy.phynum, speed, dtype); 1921 } else { 1922 mdb_printf(" N/A %4d %6s %4s ", 1923 phy.phynum, speed, dtype); 1924 } 1925 1926 if (verbose) { 1927 if (phy.abort_sent) { 1928 asent = yes; 1929 } 1930 if (phy.abort_pending) { 1931 apend = yes; 1932 } 1933 if (phy.configured) { 1934 cfgd = yes; 1935 } 1936 if (phy.dead) { 1937 dead = yes; 1938 } 1939 if (phy.changed) { 1940 changed = yes; 1941 } 1942 1943 switch (phy.routing_attr) { 1944 case SMP_ROUTING_DIRECT: 1945 route_attr = 'D'; 1946 break; 1947 case SMP_ROUTING_SUBTRACTIVE: 1948 route_attr = 'S'; 1949 break; 1950 case SMP_ROUTING_TABLE: 1951 route_attr = 'T'; 1952 break; 1953 default: 1954 route_attr = '?'; 1955 break; 1956 } 1957 1958 switch (phy.routing_method) { 1959 case SMP_ROUTING_DIRECT: 1960 route_method = 'D'; 1961 break; 1962 case SMP_ROUTING_SUBTRACTIVE: 1963 route_method = 'S'; 1964 break; 1965 case SMP_ROUTING_TABLE: 1966 route_method = 'T'; 1967 break; 1968 default: 1969 route_attr = '?'; 1970 break; 1971 } 1972 1973 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d " 1974 "%1d 0x%p ", cfgd, apend, asent, changed, dead, 1975 phy.ref_count, route_attr, route_method, 1976 phy.enum_attempts, phy.reenumerate, phy.phy_lock); 1977 } 1978 1979 mdb_printf("Path: %s\n", phy.path); 1980 1981 /* 1982 * In verbose mode, on the next line print the drill down 1983 * info to see either the DISCOVER response or the REPORT 1984 * GENERAL response depending on the PHY's dtype 1985 */ 1986 if (verbose) { 1987 uintptr_t tphyp = (uintptr_t)phyp; 1988 1989 mdb_inc_indent(4); 1990 switch (phy.dtype) { 1991 case EXPANDER: 1992 if (!phy.configured) { 1993 break; 1994 } 1995 mdb_printf("REPORT GENERAL response: %p::" 1996 "print smp_report_general_resp_t\n", 1997 (tphyp + offsetof(struct pmcs_phy, 1998 rg_resp))); 1999 break; 2000 case SAS: 2001 case SATA: 2002 mdb_printf("DISCOVER response: %p::" 2003 "print smp_discover_resp_t\n", 2004 (tphyp + offsetof(struct pmcs_phy, 2005 disc_resp))); 2006 break; 2007 default: 2008 break; 2009 } 2010 mdb_dec_indent(4); 2011 } 2012 } 2013 } 2014 2015 static void 2016 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level, 2017 int totals_only) 2018 { 2019 pmcs_phy_t phy; 2020 pmcs_phy_t *pphy = parent; 2021 2022 mdb_inc_indent(3); 2023 2024 if (parent == NULL) { 2025 pphy = (pmcs_phy_t *)ss.root_phys; 2026 } else { 2027 pphy = (pmcs_phy_t *)parent; 2028 } 2029 2030 if (level == 0) { 2031 sas_phys = 0; 2032 sata_phys = 0; 2033 exp_phys = 0; 2034 num_expanders = 0; 2035 empty_phys = 0; 2036 } 2037 2038 if (!totals_only) { 2039 if (level == 0) { 2040 mdb_printf("PHY information\n"); 2041 } 2042 mdb_printf("--------\n"); 2043 mdb_printf("Level %2d\n", level); 2044 mdb_printf("--------\n"); 2045 mdb_printf("SAS Address Hdl Phy# Speed Type "); 2046 2047 if (verbose) { 2048 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R " 2049 "Lock\n"); 2050 } else { 2051 mdb_printf("\n"); 2052 } 2053 } 2054 2055 while (pphy) { 2056 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) { 2057 NOREAD(pmcs_phy_t, phy); 2058 break; 2059 } 2060 2061 display_phy(phy, pphy, verbose, totals_only); 2062 2063 if (phy.children) { 2064 display_phys(ss, verbose, phy.children, level + 1, 2065 totals_only); 2066 if (!totals_only) { 2067 mdb_printf("\n"); 2068 } 2069 } 2070 2071 pphy = phy.sibling; 2072 } 2073 2074 mdb_dec_indent(3); 2075 2076 if (level == 0) { 2077 if (verbose) { 2078 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) " 2079 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:", 2080 (sas_phys + sata_phys + num_expanders), 2081 sas_phys, sata_phys, num_expanders, 2082 (exp_phys - num_expanders), empty_phys); 2083 } else { 2084 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 2085 "Occupied PHYs:", 2086 (sas_phys + sata_phys + num_expanders), 2087 sas_phys, sata_phys, num_expanders); 2088 } 2089 } 2090 } 2091 2092 /* 2093 * filter is used to indicate whether we are filtering log messages based 2094 * on "instance". The other filtering (based on options) depends on the 2095 * values that are passed in for "sas_addr" and "phy_path". 2096 * 2097 * MAX_INST_STRLEN is the largest string size from which we will attempt 2098 * to convert to an instance number. The string will be formed up as 2099 * "0t<inst>\0" so that mdb_strtoull can parse it properly. 2100 */ 2101 #define MAX_INST_STRLEN 8 2102 2103 static int 2104 pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines, 2105 const char *phy_path, uint64_t sas_address, uint64_t verbose) 2106 { 2107 pmcs_tbuf_t *tbuf_addr; 2108 uint_t tbuf_idx; 2109 pmcs_tbuf_t tbuf; 2110 boolean_t wrap, elem_filtered; 2111 uint_t start_idx, elems_to_print, idx, tbuf_num_elems; 2112 char *bufp; 2113 char elem_inst[MAX_INST_STRLEN], ei_idx; 2114 uint64_t sas_addr; 2115 uint8_t *sas_addressp; 2116 2117 /* Get the address of the first element */ 2118 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) { 2119 mdb_warn("can't read pmcs_tbuf"); 2120 return (DCMD_ERR); 2121 } 2122 2123 /* Get the total number */ 2124 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) { 2125 mdb_warn("can't read pmcs_tbuf_num_elems"); 2126 return (DCMD_ERR); 2127 } 2128 2129 /* Get the current index */ 2130 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) { 2131 mdb_warn("can't read pmcs_tbuf_idx"); 2132 return (DCMD_ERR); 2133 } 2134 2135 /* Indicator as to whether the buffer has wrapped */ 2136 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) { 2137 mdb_warn("can't read pmcs_tbuf_wrap"); 2138 return (DCMD_ERR); 2139 } 2140 2141 /* 2142 * On little-endian systems, the SAS address passed in will be 2143 * byte swapped. Take care of that here. 2144 */ 2145 #if defined(_LITTLE_ENDIAN) 2146 sas_addr = ((sas_address << 56) | 2147 ((sas_address << 40) & 0xff000000000000ULL) | 2148 ((sas_address << 24) & 0xff0000000000ULL) | 2149 ((sas_address << 8) & 0xff00000000ULL) | 2150 ((sas_address >> 8) & 0xff000000ULL) | 2151 ((sas_address >> 24) & 0xff0000ULL) | 2152 ((sas_address >> 40) & 0xff00ULL) | 2153 (sas_address >> 56)); 2154 #else 2155 sas_addr = sas_address; 2156 #endif 2157 sas_addressp = (uint8_t *)&sas_addr; 2158 2159 /* Ensure the tail number isn't greater than the size of the log */ 2160 if (tail_lines > tbuf_num_elems) { 2161 tail_lines = tbuf_num_elems; 2162 } 2163 2164 /* Figure out where we start and stop */ 2165 if (wrap) { 2166 if (tail_lines) { 2167 /* Do we need to wrap backwards? */ 2168 if (tail_lines > tbuf_idx) { 2169 start_idx = tbuf_num_elems - (tail_lines - 2170 tbuf_idx); 2171 } else { 2172 start_idx = tbuf_idx - tail_lines; 2173 } 2174 elems_to_print = tail_lines; 2175 } else { 2176 start_idx = tbuf_idx; 2177 elems_to_print = tbuf_num_elems; 2178 } 2179 } else { 2180 if (tail_lines > tbuf_idx) { 2181 tail_lines = tbuf_idx; 2182 } 2183 if (tail_lines) { 2184 start_idx = tbuf_idx - tail_lines; 2185 elems_to_print = tail_lines; 2186 } else { 2187 start_idx = 0; 2188 elems_to_print = tbuf_idx; 2189 } 2190 } 2191 2192 idx = start_idx; 2193 2194 /* Dump the buffer contents */ 2195 while (elems_to_print != 0) { 2196 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx)) 2197 == -1) { 2198 NOREAD(tbuf, (tbuf_addr + idx)); 2199 return (DCMD_ERR); 2200 } 2201 2202 /* 2203 * Check for filtering on HBA instance 2204 */ 2205 elem_filtered = B_FALSE; 2206 2207 if (filter) { 2208 bufp = tbuf.buf; 2209 /* Skip the driver name */ 2210 while (*bufp < '0' || *bufp > '9') { 2211 bufp++; 2212 } 2213 2214 ei_idx = 0; 2215 elem_inst[ei_idx++] = '0'; 2216 elem_inst[ei_idx++] = 't'; 2217 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) { 2218 elem_inst[ei_idx++] = *bufp; 2219 bufp++; 2220 } 2221 elem_inst[ei_idx] = 0; 2222 2223 /* Get the instance */ 2224 if ((int)mdb_strtoull(elem_inst) != instance) { 2225 elem_filtered = B_TRUE; 2226 } 2227 } 2228 2229 if (!elem_filtered && (phy_path || sas_address)) { 2230 /* 2231 * This message is not being filtered by HBA instance. 2232 * Now check to see if we're filtering based on 2233 * PHY path or SAS address. 2234 * Filtering is an "OR" operation. So, if any of the 2235 * criteria matches, this message will be printed. 2236 */ 2237 elem_filtered = B_TRUE; 2238 2239 if (phy_path != NULL) { 2240 if (strncmp(phy_path, tbuf.phy_path, 2241 PMCS_TBUF_UA_MAX_SIZE) == 0) { 2242 elem_filtered = B_FALSE; 2243 } 2244 } 2245 if (sas_address != 0) { 2246 if (memcmp(sas_addressp, tbuf.phy_sas_address, 2247 8) == 0) { 2248 elem_filtered = B_FALSE; 2249 } 2250 } 2251 } 2252 2253 if (!elem_filtered) { 2254 /* 2255 * If the -v flag was given, print the firmware 2256 * timestamp along with the clock time 2257 */ 2258 mdb_printf("%Y.%09ld ", tbuf.timestamp); 2259 if (verbose) { 2260 mdb_printf("(0x%" PRIx64 ") ", 2261 tbuf.fw_timestamp); 2262 } 2263 mdb_printf("%s\n", tbuf.buf); 2264 } 2265 2266 --elems_to_print; 2267 if (++idx == tbuf_num_elems) { 2268 idx = 0; 2269 } 2270 } 2271 2272 return (DCMD_OK); 2273 } 2274 2275 /* 2276 * Walkers 2277 */ 2278 static int 2279 targets_walk_i(mdb_walk_state_t *wsp) 2280 { 2281 if (wsp->walk_addr == NULL) { 2282 mdb_warn("Can not perform global walk\n"); 2283 return (WALK_ERR); 2284 } 2285 2286 /* 2287 * Address provided belongs to HBA softstate. Get the targets pointer 2288 * to begin the walk. 2289 */ 2290 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 2291 sizeof (pmcs_hw_t)) { 2292 mdb_warn("Unable to read HBA softstate\n"); 2293 return (WALK_ERR); 2294 } 2295 2296 if (targets == NULL) { 2297 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP); 2298 } 2299 2300 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) { 2301 NOREAD(targets, ss.targets); 2302 return (WALK_ERR); 2303 } 2304 2305 target_idx = 0; 2306 wsp->walk_addr = (uintptr_t)(targets[0]); 2307 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP); 2308 2309 return (WALK_NEXT); 2310 } 2311 2312 static int 2313 targets_walk_s(mdb_walk_state_t *wsp) 2314 { 2315 int status; 2316 2317 if (target_idx == ss.max_dev) { 2318 return (WALK_DONE); 2319 } 2320 2321 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t), 2322 wsp->walk_addr) == -1) { 2323 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr); 2324 return (WALK_DONE); 2325 } 2326 2327 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 2328 wsp->walk_cbdata); 2329 2330 do { 2331 wsp->walk_addr = (uintptr_t)(targets[++target_idx]); 2332 } while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev)); 2333 2334 if (target_idx == ss.max_dev) { 2335 return (WALK_DONE); 2336 } 2337 2338 return (status); 2339 } 2340 2341 static void 2342 targets_walk_f(mdb_walk_state_t *wsp) 2343 { 2344 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t)); 2345 } 2346 2347 2348 static pmcs_phy_t * 2349 pmcs_next_sibling(pmcs_phy_t *phyp) 2350 { 2351 pmcs_phy_t parent; 2352 2353 /* 2354 * First, if this is a root PHY, there are no more siblings 2355 */ 2356 if (phyp->level == 0) { 2357 return (NULL); 2358 } 2359 2360 /* 2361 * Otherwise, next sibling is the parent's sibling 2362 */ 2363 while (phyp->level > 0) { 2364 if (mdb_vread(&parent, sizeof (pmcs_phy_t), 2365 (uintptr_t)phyp->parent) == -1) { 2366 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p", 2367 (void *)phyp->parent); 2368 return (NULL); 2369 } 2370 2371 if (parent.sibling != NULL) { 2372 break; 2373 } 2374 2375 /* 2376 * If this PHY's sibling is NULL and it's a root phy, 2377 * we're done. 2378 */ 2379 if (parent.level == 0) { 2380 return (NULL); 2381 } 2382 2383 phyp = phyp->parent; 2384 } 2385 2386 return (parent.sibling); 2387 } 2388 2389 static int 2390 phy_walk_i(mdb_walk_state_t *wsp) 2391 { 2392 if (wsp->walk_addr == NULL) { 2393 mdb_warn("Can not perform global walk\n"); 2394 return (WALK_ERR); 2395 } 2396 2397 /* 2398 * Address provided belongs to HBA softstate. Get the targets pointer 2399 * to begin the walk. 2400 */ 2401 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 2402 sizeof (pmcs_hw_t)) { 2403 mdb_warn("Unable to read HBA softstate\n"); 2404 return (WALK_ERR); 2405 } 2406 2407 wsp->walk_addr = (uintptr_t)(ss.root_phys); 2408 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 2409 2410 return (WALK_NEXT); 2411 } 2412 2413 static int 2414 phy_walk_s(mdb_walk_state_t *wsp) 2415 { 2416 pmcs_phy_t *phyp, *nphyp; 2417 int status; 2418 2419 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 2420 wsp->walk_addr) == -1) { 2421 mdb_warn("phy_walk_s: Failed to read PHY at %p", 2422 (void *)wsp->walk_addr); 2423 return (WALK_DONE); 2424 } 2425 2426 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 2427 wsp->walk_cbdata); 2428 2429 phyp = (pmcs_phy_t *)wsp->walk_data; 2430 if (phyp->children) { 2431 wsp->walk_addr = (uintptr_t)(phyp->children); 2432 } else { 2433 wsp->walk_addr = (uintptr_t)(phyp->sibling); 2434 } 2435 2436 if (wsp->walk_addr == NULL) { 2437 /* 2438 * We reached the end of this sibling list. Trudge back up 2439 * to the parent and find the next sibling after the expander 2440 * we just finished traversing, if there is one. 2441 */ 2442 nphyp = pmcs_next_sibling(phyp); 2443 2444 if (nphyp == NULL) { 2445 return (WALK_DONE); 2446 } 2447 2448 wsp->walk_addr = (uintptr_t)nphyp; 2449 } 2450 2451 return (status); 2452 } 2453 2454 static void 2455 phy_walk_f(mdb_walk_state_t *wsp) 2456 { 2457 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 2458 } 2459 2460 static void 2461 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum, 2462 uintmax_t tag_type) 2463 { 2464 int idx; 2465 pmcwork_t work, *wp = &work; 2466 uintptr_t _wp; 2467 boolean_t printed_header = B_FALSE; 2468 uint32_t mask, mask_val, match_val; 2469 char *match_type; 2470 2471 if (index != UINT_MAX) { 2472 match_type = "index"; 2473 mask = PMCS_TAG_INDEX_MASK; 2474 mask_val = index << PMCS_TAG_INDEX_SHIFT; 2475 match_val = index; 2476 } else if (snum != UINT_MAX) { 2477 match_type = "serial number"; 2478 mask = PMCS_TAG_SERNO_MASK; 2479 mask_val = snum << PMCS_TAG_SERNO_SHIFT; 2480 match_val = snum; 2481 } else { 2482 switch (tag_type) { 2483 case PMCS_TAG_TYPE_NONE: 2484 match_type = "tag type NONE"; 2485 break; 2486 case PMCS_TAG_TYPE_CBACK: 2487 match_type = "tag type CBACK"; 2488 break; 2489 case PMCS_TAG_TYPE_WAIT: 2490 match_type = "tag type WAIT"; 2491 break; 2492 } 2493 mask = PMCS_TAG_TYPE_MASK; 2494 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT; 2495 match_val = tag_type; 2496 } 2497 2498 _wp = (uintptr_t)ss.work; 2499 2500 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 2501 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 2502 NOREAD(pmcwork_t, _wp); 2503 continue; 2504 } 2505 2506 if ((work.htag & mask) != mask_val) { 2507 continue; 2508 } 2509 2510 if (printed_header == B_FALSE) { 2511 if (tag_type) { 2512 mdb_printf("\nWork structures matching %s\n\n", 2513 match_type, match_val); 2514 } else { 2515 mdb_printf("\nWork structures matching %s of " 2516 "0x%x\n\n", match_type, match_val); 2517 } 2518 mdb_printf("%8s %10s %20s %8s %8s O D\n", 2519 "HTag", "State", "Phy Path", "Target", "Timer"); 2520 printed_header = B_TRUE; 2521 } 2522 2523 display_one_work(wp, 0, 0); 2524 } 2525 2526 if (!printed_header) { 2527 mdb_printf("No work structure matches found\n"); 2528 } 2529 } 2530 2531 static int 2532 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2533 { 2534 struct pmcs_hw ss; 2535 uintmax_t tag_type = UINT_MAX; 2536 uintmax_t snum = UINT_MAX; 2537 uintmax_t index = UINT_MAX; 2538 int args = 0; 2539 void *pmcs_state; 2540 char *state_str; 2541 struct dev_info dip; 2542 2543 if (!(flags & DCMD_ADDRSPEC)) { 2544 pmcs_state = NULL; 2545 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2546 mdb_warn("can't read pmcs_softc_state"); 2547 return (DCMD_ERR); 2548 } 2549 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc, 2550 argv, (uintptr_t)pmcs_state) == -1) { 2551 mdb_warn("mdb_pwalk_dcmd failed"); 2552 return (DCMD_ERR); 2553 } 2554 return (DCMD_OK); 2555 } 2556 2557 if (mdb_getopts(argc, argv, 2558 'i', MDB_OPT_UINT64, &index, 2559 's', MDB_OPT_UINT64, &snum, 2560 't', MDB_OPT_UINT64, &tag_type) != argc) 2561 return (DCMD_USAGE); 2562 2563 /* 2564 * Count the number of supplied options and make sure they are 2565 * within appropriate ranges. If they're set to UINT_MAX, that means 2566 * they were not supplied, in which case reset them to 0. 2567 */ 2568 if (index != UINT_MAX) { 2569 args++; 2570 if (index > PMCS_TAG_INDEX_MASK) { 2571 mdb_warn("Index is out of range\n"); 2572 return (DCMD_USAGE); 2573 } 2574 } 2575 2576 if (tag_type != UINT_MAX) { 2577 args++; 2578 switch (tag_type) { 2579 case PMCS_TAG_TYPE_NONE: 2580 case PMCS_TAG_TYPE_CBACK: 2581 case PMCS_TAG_TYPE_WAIT: 2582 break; 2583 default: 2584 mdb_warn("Invalid tag type\n"); 2585 return (DCMD_USAGE); 2586 } 2587 } 2588 2589 if (snum != UINT_MAX) { 2590 args++; 2591 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) { 2592 mdb_warn("Serial number is out of range\n"); 2593 return (DCMD_USAGE); 2594 } 2595 } 2596 2597 /* 2598 * Make sure 1 and only 1 option is specified 2599 */ 2600 if ((args == 0) || (args > 1)) { 2601 mdb_warn("Exactly one of -i, -s and -t must be specified\n"); 2602 return (DCMD_USAGE); 2603 } 2604 2605 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2606 NOREAD(pmcs_hw_t, addr); 2607 return (DCMD_ERR); 2608 } 2609 2610 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2611 NOREAD(pmcs_hw_t, addr); 2612 return (DCMD_ERR); 2613 } 2614 2615 /* processing completed */ 2616 2617 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2618 (flags & DCMD_LOOPFIRST)) { 2619 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2620 mdb_printf("\n"); 2621 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2622 "Address", "State", "Inst", "DIP"); 2623 mdb_printf("=================================" 2624 "============================================\n"); 2625 } 2626 2627 switch (ss.state) { 2628 case STATE_NIL: 2629 state_str = "Invalid"; 2630 break; 2631 case STATE_PROBING: 2632 state_str = "Probing"; 2633 break; 2634 case STATE_RUNNING: 2635 state_str = "Running"; 2636 break; 2637 case STATE_UNPROBING: 2638 state_str = "Unprobing"; 2639 break; 2640 case STATE_DEAD: 2641 state_str = "Dead"; 2642 break; 2643 case STATE_IN_RESET: 2644 state_str = "In Reset"; 2645 break; 2646 } 2647 2648 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2649 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2650 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2651 mdb_printf("\n"); 2652 2653 mdb_inc_indent(4); 2654 display_matching_work(ss, index, snum, tag_type); 2655 mdb_dec_indent(4); 2656 mdb_printf("\n"); 2657 2658 return (DCMD_OK); 2659 } 2660 2661 #ifndef _KMDB 2662 static int 2663 pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile) 2664 { 2665 uint8_t *fwlogp; 2666 int ofilefd = -1; 2667 char ofilename[MAXPATHLEN]; 2668 int rval = DCMD_OK; 2669 2670 if (ss->fwlogp == NULL) { 2671 mdb_warn("Firmware event log disabled for instance %d", 2672 instance); 2673 return (DCMD_OK); 2674 } 2675 2676 if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) > 2677 MAXPATHLEN) { 2678 mdb_warn("Output filename is too long for instance %d", 2679 instance); 2680 return (DCMD_ERR); 2681 } 2682 2683 fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP); 2684 2685 if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) { 2686 NOREAD(fwlogp, ss->fwlogp); 2687 rval = DCMD_ERR; 2688 goto cleanup; 2689 } 2690 2691 ofilefd = open(ofilename, O_WRONLY | O_CREAT, 2692 S_IRUSR | S_IRGRP | S_IROTH); 2693 if (ofilefd < 0) { 2694 mdb_warn("Unable to open '%s' to dump instance %d event log", 2695 ofilename, instance); 2696 rval = DCMD_ERR; 2697 goto cleanup; 2698 } 2699 2700 if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) { 2701 mdb_warn("Failed to write %d bytes to output file: instance %d", 2702 PMCS_FWLOG_SIZE, instance); 2703 rval = DCMD_ERR; 2704 goto cleanup; 2705 } 2706 2707 mdb_printf("Event log for instance %d written to %s\n", instance, 2708 ofilename); 2709 2710 cleanup: 2711 if (ofilefd >= 0) { 2712 close(ofilefd); 2713 } 2714 mdb_free(fwlogp, PMCS_FWLOG_SIZE); 2715 return (rval); 2716 } 2717 2718 static int 2719 pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2720 { 2721 void *pmcs_state; 2722 const char *ofile = NULL; 2723 struct pmcs_hw ss; 2724 struct dev_info dip; 2725 2726 if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) { 2727 return (DCMD_USAGE); 2728 } 2729 2730 if (ofile == NULL) { 2731 mdb_printf("No output file specified\n"); 2732 return (DCMD_USAGE); 2733 } 2734 2735 if (!(flags & DCMD_ADDRSPEC)) { 2736 pmcs_state = NULL; 2737 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2738 mdb_warn("can't read pmcs_softc_state"); 2739 return (DCMD_ERR); 2740 } 2741 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc, 2742 argv, (uintptr_t)pmcs_state) == -1) { 2743 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2744 return (DCMD_ERR); 2745 } 2746 return (DCMD_OK); 2747 } 2748 2749 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2750 NOREAD(pmcs_hw_t, addr); 2751 return (DCMD_ERR); 2752 } 2753 2754 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2755 NOREAD(pmcs_hw_t, addr); 2756 return (DCMD_ERR); 2757 } 2758 2759 return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile)); 2760 } 2761 #endif /* _KMDB */ 2762 2763 static int 2764 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2765 { 2766 void *pmcs_state; 2767 struct pmcs_hw ss; 2768 struct dev_info dip; 2769 const char *match_phy_path = NULL; 2770 uint64_t match_sas_address = 0, tail_lines = 0; 2771 uint_t verbose = 0; 2772 2773 if (!(flags & DCMD_ADDRSPEC)) { 2774 pmcs_state = NULL; 2775 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2776 mdb_warn("can't read pmcs_softc_state"); 2777 return (DCMD_ERR); 2778 } 2779 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc, 2780 argv, (uintptr_t)pmcs_state) == -1) { 2781 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2782 return (DCMD_ERR); 2783 } 2784 return (DCMD_OK); 2785 } 2786 2787 if (mdb_getopts(argc, argv, 2788 'l', MDB_OPT_UINT64, &tail_lines, 2789 'p', MDB_OPT_STR, &match_phy_path, 2790 's', MDB_OPT_UINT64, &match_sas_address, 2791 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2792 NULL) != argc) { 2793 return (DCMD_USAGE); 2794 } 2795 2796 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2797 NOREAD(pmcs_hw_t, addr); 2798 return (DCMD_ERR); 2799 } 2800 2801 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2802 NOREAD(pmcs_hw_t, addr); 2803 return (DCMD_ERR); 2804 } 2805 2806 if (!(flags & DCMD_LOOP)) { 2807 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance, 2808 tail_lines, match_phy_path, match_sas_address, verbose)); 2809 } else if (flags & DCMD_LOOPFIRST) { 2810 return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines, 2811 match_phy_path, match_sas_address, verbose)); 2812 } else { 2813 return (DCMD_OK); 2814 } 2815 } 2816 2817 static int 2818 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2819 { 2820 struct pmcs_hw ss; 2821 uint_t verbose = FALSE; 2822 uint_t phy_info = FALSE; 2823 uint_t hw_info = FALSE; 2824 uint_t target_info = FALSE; 2825 uint_t work_info = FALSE; 2826 uint_t ic_info = FALSE; 2827 uint_t iport_info = FALSE; 2828 uint_t waitqs_info = FALSE; 2829 uint_t ibq = FALSE; 2830 uint_t obq = FALSE; 2831 uint_t tgt_phy_count = FALSE; 2832 uint_t compq = FALSE; 2833 uint_t unconfigured = FALSE; 2834 uint_t damap_info = FALSE; 2835 uint_t dtc_info = FALSE; 2836 uint_t wserno = FALSE; 2837 uint_t fwlog = FALSE; 2838 int rv = DCMD_OK; 2839 void *pmcs_state; 2840 char *state_str; 2841 struct dev_info dip; 2842 per_iport_setting_t pis; 2843 2844 if (!(flags & DCMD_ADDRSPEC)) { 2845 pmcs_state = NULL; 2846 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2847 mdb_warn("can't read pmcs_softc_state"); 2848 return (DCMD_ERR); 2849 } 2850 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 2851 (uintptr_t)pmcs_state) == -1) { 2852 mdb_warn("mdb_pwalk_dcmd failed"); 2853 return (DCMD_ERR); 2854 } 2855 return (DCMD_OK); 2856 } 2857 2858 if (mdb_getopts(argc, argv, 2859 'c', MDB_OPT_SETBITS, TRUE, &compq, 2860 'd', MDB_OPT_SETBITS, TRUE, &dtc_info, 2861 'e', MDB_OPT_SETBITS, TRUE, &fwlog, 2862 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 2863 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 2864 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 2865 'm', MDB_OPT_SETBITS, TRUE, &damap_info, 2866 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 2867 'q', MDB_OPT_SETBITS, TRUE, &ibq, 2868 'Q', MDB_OPT_SETBITS, TRUE, &obq, 2869 's', MDB_OPT_SETBITS, TRUE, &wserno, 2870 't', MDB_OPT_SETBITS, TRUE, &target_info, 2871 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 2872 'u', MDB_OPT_SETBITS, TRUE, &unconfigured, 2873 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2874 'w', MDB_OPT_SETBITS, TRUE, &work_info, 2875 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 2876 NULL) != argc) 2877 return (DCMD_USAGE); 2878 2879 /* 2880 * The 'd' and 'm' options implicitly enable the 'I' option 2881 */ 2882 pis.pis_damap_info = damap_info; 2883 pis.pis_dtc_info = dtc_info; 2884 if (damap_info || dtc_info) { 2885 iport_info = TRUE; 2886 } 2887 2888 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2889 NOREAD(pmcs_hw_t, addr); 2890 return (DCMD_ERR); 2891 } 2892 2893 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2894 NOREAD(pmcs_hw_t, addr); 2895 return (DCMD_ERR); 2896 } 2897 2898 /* processing completed */ 2899 2900 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2901 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 2902 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq || 2903 unconfigured || fwlog) { 2904 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2905 mdb_printf("\n"); 2906 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2907 "Address", "State", "Inst", "DIP"); 2908 mdb_printf("=================================" 2909 "============================================\n"); 2910 } 2911 2912 switch (ss.state) { 2913 case STATE_NIL: 2914 state_str = "Invalid"; 2915 break; 2916 case STATE_PROBING: 2917 state_str = "Probing"; 2918 break; 2919 case STATE_RUNNING: 2920 state_str = "Running"; 2921 break; 2922 case STATE_UNPROBING: 2923 state_str = "Unprobing"; 2924 break; 2925 case STATE_DEAD: 2926 state_str = "Dead"; 2927 break; 2928 case STATE_IN_RESET: 2929 state_str = "In Reset"; 2930 break; 2931 } 2932 2933 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2934 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2935 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2936 mdb_printf("\n"); 2937 2938 mdb_inc_indent(4); 2939 2940 if (waitqs_info) 2941 display_waitqs(ss, verbose); 2942 2943 if (hw_info) 2944 display_hwinfo(ss, verbose); 2945 2946 if (phy_info || tgt_phy_count) 2947 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 2948 2949 if (target_info || tgt_phy_count) 2950 display_targets(ss, verbose, tgt_phy_count); 2951 2952 if (work_info || wserno) 2953 display_work(ss, verbose, wserno); 2954 2955 if (ic_info) 2956 display_ic(ss, verbose); 2957 2958 if (ibq) 2959 display_inbound_queues(ss, verbose); 2960 2961 if (obq) 2962 display_outbound_queues(ss, verbose); 2963 2964 if (iport_info) 2965 display_iport(ss, addr, verbose, &pis); 2966 2967 if (compq) 2968 display_completion_queue(ss); 2969 2970 if (unconfigured) 2971 display_unconfigured_targets(addr); 2972 2973 if (fwlog) 2974 display_event_log(ss); 2975 2976 mdb_dec_indent(4); 2977 2978 return (rv); 2979 } 2980 2981 void 2982 pmcs_help() 2983 { 2984 mdb_printf("Prints summary information about each pmcs instance.\n" 2985 " -c: Dump the completion queue\n" 2986 " -d: Print per-iport information about device tree children\n" 2987 " -e: Display the in-memory firmware event log\n" 2988 " -h: Print more detailed hardware information\n" 2989 " -i: Print interrupt coalescing information\n" 2990 " -I: Print information about each iport\n" 2991 " -m: Print per-iport information about DAM/damap state\n" 2992 " -p: Print information about each attached PHY\n" 2993 " -q: Dump inbound queues\n" 2994 " -Q: Dump outbound queues\n" 2995 " -s: Dump all work structures sorted by serial number\n" 2996 " -t: Print information about each configured target\n" 2997 " -T: Print target and PHY count summary\n" 2998 " -u: Show SAS address of all unconfigured targets\n" 2999 " -w: Dump work structures\n" 3000 " -W: List pmcs cmds waiting on various queues\n" 3001 " -v: Add verbosity to the above options\n"); 3002 } 3003 3004 void 3005 pmcs_log_help() 3006 { 3007 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n" 3008 " -l TAIL_LINES: Dump the last TAIL_LINES messages\n" 3009 " -p PHY_PATH: Dump messages matching PHY_PATH\n" 3010 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n" 3011 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n" 3012 " SAS_ADDRESS can be found with ::pmcs -t " 3013 "(e.g. 5000c5000358c221)\n"); 3014 } 3015 void 3016 pmcs_tag_help() 3017 { 3018 mdb_printf("Print all work structures by matching the tag.\n" 3019 " -i index: Match tag index (0x000 - 0xfff)\n" 3020 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n" 3021 " -t tagtype: Match tag type [NONE(1), CBACK(2), " 3022 "WAIT(3)]\n"); 3023 } 3024 3025 static const mdb_dcmd_t dcmds[] = { 3026 { "pmcs", "?[-cdehiImpQqtTuwWv]", "print pmcs information", 3027 pmcs_dcmd, pmcs_help 3028 }, 3029 { "pmcs_log", 3030 "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]", 3031 "dump pmcs log file", pmcs_log, pmcs_log_help 3032 }, 3033 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]", 3034 "Find work structures by tag type, serial number or index", 3035 pmcs_tag, pmcs_tag_help 3036 }, 3037 #ifndef _KMDB 3038 { "pmcs_fwlog", 3039 "?-o output_file", 3040 "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL 3041 }, 3042 #endif /* _KMDB */ 3043 { NULL } 3044 }; 3045 3046 static const mdb_walker_t walkers[] = { 3047 { "pmcs_targets", "walk target structures", 3048 targets_walk_i, targets_walk_s, targets_walk_f }, 3049 { "pmcs_phys", "walk PHY structures", 3050 phy_walk_i, phy_walk_s, phy_walk_f }, 3051 { NULL } 3052 }; 3053 3054 static const mdb_modinfo_t modinfo = { 3055 MDB_API_VERSION, dcmds, walkers 3056 }; 3057 3058 const mdb_modinfo_t * 3059 _mdb_init(void) 3060 { 3061 return (&modinfo); 3062 } 3063