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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <limits.h> 27 #include <sys/mdb_modapi.h> 28 #include <sys/sysinfo.h> 29 #include <sys/scsi/scsi.h> 30 #include <sys/scsi/adapters/pmcs/pmcs.h> 31 32 #define MDB_RD(a, b, c) mdb_vread(a, b, (uintptr_t)c) 33 #define NOREAD(a, b) mdb_warn("could not read " #a " at 0x%p", b) 34 35 static pmcs_hw_t ss; 36 static pmcs_xscsi_t **targets = NULL; 37 static int target_idx; 38 39 static uint32_t sas_phys, sata_phys, exp_phys, num_expanders, empty_phys; 40 41 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp); 42 43 static void 44 print_sas_address(pmcs_phy_t *phy) 45 { 46 int idx; 47 48 for (idx = 0; idx < 8; idx++) { 49 mdb_printf("%02x", phy->sas_address[idx]); 50 } 51 } 52 53 /*ARGSUSED*/ 54 static void 55 display_ic(struct pmcs_hw m, int verbose) 56 { 57 int msec_per_tick; 58 59 if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) { 60 mdb_warn("can't read msec_per_tick"); 61 msec_per_tick = 0; 62 } 63 64 mdb_printf("\n"); 65 mdb_printf("Interrupt coalescing timer info\n"); 66 mdb_printf("-------------------------------\n"); 67 if (msec_per_tick == 0) { 68 mdb_printf("Quantum : ?? ms\n"); 69 } else { 70 mdb_printf("Quantum : %d ms\n", 71 m.io_intr_coal.quantum * msec_per_tick); 72 } 73 mdb_printf("Timer enabled : "); 74 if (m.io_intr_coal.timer_on) { 75 mdb_printf("Yes\n"); 76 mdb_printf("Coalescing timer value : %d us\n", 77 m.io_intr_coal.intr_coal_timer); 78 } else { 79 mdb_printf("No\n"); 80 } 81 mdb_printf("Total nsecs between interrupts: %ld\n", 82 m.io_intr_coal.nsecs_between_intrs); 83 mdb_printf("Time of last I/O interrupt : %ld\n", 84 m.io_intr_coal.last_io_comp); 85 mdb_printf("Number of I/O interrupts : %d\n", 86 m.io_intr_coal.num_intrs); 87 mdb_printf("Number of I/O completions : %d\n", 88 m.io_intr_coal.num_io_completions); 89 mdb_printf("Max I/O completion interrupts : %d\n", 90 m.io_intr_coal.max_io_completions); 91 mdb_printf("Measured ECHO int latency : %d ns\n", 92 m.io_intr_coal.intr_latency); 93 mdb_printf("Interrupt threshold : %d\n", 94 m.io_intr_coal.intr_threshold); 95 } 96 97 /*ARGSUSED*/ 98 static int 99 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv) 100 { 101 struct pmcs_phy phy; 102 103 if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) != 104 sizeof (struct pmcs_phy)) { 105 return (DCMD_ERR); 106 } 107 108 mdb_printf("%16p %2d\n", addr, phy.phynum); 109 110 return (0); 111 } 112 113 /*ARGSUSED*/ 114 static int 115 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv) 116 { 117 struct pmcs_iport iport; 118 uintptr_t list_addr; 119 char *ua_state; 120 char portid[4]; 121 char unit_address[34]; 122 123 if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) != 124 sizeof (struct pmcs_iport)) { 125 return (DCMD_ERR); 126 } 127 128 if (mdb_readstr(unit_address, sizeof (unit_address), 129 (uintptr_t)(iport.ua)) == -1) { 130 strncpy(unit_address, "Unset", sizeof (unit_address)); 131 } 132 133 if (iport.portid == 0xffff) { 134 mdb_snprintf(portid, sizeof (portid), "%s", "-"); 135 } else { 136 mdb_snprintf(portid, sizeof (portid), "%d", iport.portid); 137 } 138 139 switch (iport.ua_state) { 140 case UA_INACTIVE: 141 ua_state = "Inactive"; 142 break; 143 case UA_PEND_ACTIVATE: 144 ua_state = "PendActivate"; 145 break; 146 case UA_ACTIVE: 147 ua_state = "Active"; 148 break; 149 case UA_PEND_DEACTIVATE: 150 ua_state = "PendDeactivate"; 151 break; 152 default: 153 ua_state = "Unknown"; 154 } 155 156 if (strlen(unit_address) < 3) { 157 /* Standard iport unit address */ 158 mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State", 159 "PortID", "NumPhys", "DIP\n"); 160 mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr, 161 ua_state, portid, iport.nphy, iport.dip); 162 } else { 163 /* Temporary iport unit address */ 164 mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport", 165 "UA State", "PortID", "NumPhys", "DIP\n"); 166 mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr, 167 ua_state, portid, iport.nphy, iport.dip); 168 } 169 170 if (iport.nphy > 0) { 171 mdb_inc_indent(4); 172 mdb_printf("%-18s %8s", "Phy", "PhyNum\n"); 173 mdb_inc_indent(2); 174 list_addr = 175 (uintptr_t)(addr + offsetof(struct pmcs_iport, phys)); 176 if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL, 177 list_addr) == -1) { 178 mdb_warn("pmcs iport walk failed"); 179 } 180 mdb_dec_indent(6); 181 mdb_printf("\n"); 182 } 183 184 return (0); 185 } 186 187 /*ARGSUSED*/ 188 static void 189 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose) 190 { 191 uintptr_t list_addr; 192 193 if (m.iports_attached) { 194 mdb_printf("Iport information:\n"); 195 mdb_printf("-----------------\n"); 196 } else { 197 mdb_printf("No Iports found.\n\n"); 198 return; 199 } 200 201 list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports)); 202 203 if (mdb_pwalk("list", pmcs_iport_walk_cb, NULL, list_addr) == -1) { 204 mdb_warn("pmcs iport walk failed"); 205 } 206 207 mdb_printf("\n"); 208 } 209 210 /*ARGSUSED*/ 211 static void 212 display_hwinfo(struct pmcs_hw m, int verbose) 213 { 214 struct pmcs_hw *mp = &m; 215 char *fwsupport; 216 217 switch (PMCS_FW_TYPE(mp)) { 218 case PMCS_FW_TYPE_RELEASED: 219 fwsupport = "Released"; 220 break; 221 case PMCS_FW_TYPE_DEVELOPMENT: 222 fwsupport = "Development"; 223 break; 224 case PMCS_FW_TYPE_ALPHA: 225 fwsupport = "Alpha"; 226 break; 227 case PMCS_FW_TYPE_BETA: 228 fwsupport = "Beta"; 229 break; 230 default: 231 fwsupport = "Special"; 232 break; 233 } 234 235 mdb_printf("\nHardware information:\n"); 236 mdb_printf("---------------------\n"); 237 238 mdb_printf("Chip revision: %c\n", 'A' + m.chiprev); 239 mdb_printf("SAS WWID: %"PRIx64"\n", m.sas_wwns[0]); 240 mdb_printf("Firmware version: %x.%x.%x (%s)\n", 241 PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp), 242 fwsupport); 243 244 mdb_printf("Number of PHYs: %d\n", m.nphy); 245 mdb_printf("Maximum commands: %d\n", m.max_cmd); 246 mdb_printf("Maximum devices: %d\n", m.max_dev); 247 mdb_printf("I/O queue depth: %d\n", m.ioq_depth); 248 if (m.fwlog == 0) { 249 mdb_printf("Firmware logging: Disabled\n"); 250 } else { 251 mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog); 252 } 253 } 254 255 static void 256 display_targets(struct pmcs_hw m, int verbose, int totals_only) 257 { 258 char *dtype; 259 pmcs_xscsi_t xs; 260 pmcs_phy_t phy; 261 uint16_t max_dev, idx; 262 uint32_t sas_targets = 0, smp_targets = 0, sata_targets = 0; 263 264 max_dev = m.max_dev; 265 266 if (targets == NULL) { 267 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 268 } 269 270 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 271 NOREAD(targets, m.targets); 272 return; 273 } 274 275 if (!totals_only) { 276 mdb_printf("\nTarget information:\n"); 277 mdb_printf("---------------------------------------\n"); 278 mdb_printf("VTGT %-16s %-16s %-5s %8s %s", "SAS Address", 279 "PHY Address", "DType", "Active", "DS"); 280 mdb_printf("\n"); 281 } 282 283 for (idx = 0; idx < max_dev; idx++) { 284 if (targets[idx] == NULL) { 285 continue; 286 } 287 288 if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) { 289 NOREAD(pmcs_xscsi_t, targets[idx]); 290 continue; 291 } 292 293 /* 294 * It has to be one of new, assigned or dying to be of interest. 295 */ 296 if (xs.new == 0 && xs.assigned == 0 && xs.dying == 0) { 297 continue; 298 } 299 300 switch (xs.dtype) { 301 case NOTHING: 302 dtype = "None"; 303 break; 304 case SATA: 305 dtype = "SATA"; 306 sata_targets++; 307 break; 308 case SAS: 309 dtype = "SAS"; 310 sas_targets++; 311 break; 312 case EXPANDER: 313 dtype = "SMP"; 314 smp_targets++; 315 break; 316 } 317 318 if (totals_only) { 319 continue; 320 } 321 322 if (xs.phy) { 323 if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) { 324 NOREAD(pmcs_phy_t, xs.phy); 325 continue; 326 } 327 mdb_printf("%4d ", idx); 328 print_sas_address(&phy); 329 mdb_printf(" %16p", xs.phy); 330 } else { 331 mdb_printf("%4d %16s", idx, "<no phy avail>"); 332 } 333 mdb_printf(" %5s", dtype); 334 mdb_printf(" %8d", xs.actv_cnt); 335 mdb_printf(" %2d", xs.dev_state); 336 337 if (verbose) { 338 if (xs.new) { 339 mdb_printf(" new"); 340 } else if (xs.dying) { 341 mdb_printf(" dying"); 342 } else if (xs.assigned) { 343 mdb_printf(" assigned"); 344 } 345 if (xs.draining) { 346 mdb_printf(" draining"); 347 } 348 if (xs.reset_wait) { 349 mdb_printf(" reset_wait"); 350 } 351 if (xs.resetting) { 352 mdb_printf(" resetting"); 353 } 354 if (xs.recover_wait) { 355 mdb_printf(" recover_wait"); 356 } 357 if (xs.recovering) { 358 mdb_printf(" recovering"); 359 } 360 if (xs.event_recovery) { 361 mdb_printf(" event recovery"); 362 } 363 if (xs.special_running) { 364 mdb_printf(" special_active"); 365 } 366 if (xs.ncq) { 367 mdb_printf(" ncq_tagmap=0x%x qdepth=%d", 368 xs.tagmap, xs.qdepth); 369 } else if (xs.pio) { 370 mdb_printf(" pio"); 371 } 372 } 373 374 mdb_printf("\n"); 375 } 376 377 if (!totals_only) { 378 mdb_printf("\n"); 379 } 380 381 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 382 "Configured targets:", (sas_targets + sata_targets + smp_targets), 383 sas_targets, sata_targets, smp_targets); 384 } 385 386 /*ARGSUSED1*/ 387 static void 388 display_work(struct pmcs_hw m, int verbose) 389 { 390 int idx; 391 int tgt; 392 int hdrp = 0; 393 pmcs_xscsi_t xs; 394 pmcs_phy_t phy; 395 char buf[16]; 396 pmcwork_t work, *wp = &work; 397 uintptr_t _wp; 398 char *state; 399 char *path; 400 401 mdb_printf("\nActive Work structure information:\n"); 402 mdb_printf("----------------------------------\n"); 403 404 _wp = (uintptr_t)m.work; 405 406 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 407 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 408 NOREAD(pmcwork_t, _wp); 409 continue; 410 } 411 if (wp->htag == PMCS_TAG_TYPE_FREE) { 412 continue; 413 } 414 if (hdrp++ == 0) { 415 mdb_printf("%8s %10s %20s %8s %8s O D\n", 416 "HTag", "State", "Phy Path", "Target", "Timer"); 417 } 418 switch (wp->state) { 419 case PMCS_WORK_STATE_NIL: 420 state = "N/A"; 421 break; 422 case PMCS_WORK_STATE_READY: 423 state = "Ready"; 424 break; 425 case PMCS_WORK_STATE_ONCHIP: 426 state = "On Chip"; 427 break; 428 case PMCS_WORK_STATE_INTR: 429 state = "In Intr"; 430 break; 431 case PMCS_WORK_STATE_IOCOMPQ: 432 state = "I/O Comp"; 433 break; 434 case PMCS_WORK_STATE_ABORTED: 435 state = "I/O Aborted"; 436 break; 437 case PMCS_WORK_STATE_TIMED_OUT: 438 state = "I/O Timed Out"; 439 break; 440 default: 441 mdb_snprintf(buf, sizeof (buf), "STATE=%d", wp->state); 442 state = buf; 443 break; 444 } 445 if (wp->ssp_event && wp->ssp_event != 0xffffffff) { 446 mdb_printf("SSP event 0x%x", wp->ssp_event); 447 } 448 tgt = -1; 449 if (wp->xp) { 450 if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) { 451 NOREAD(pmcs_xscsi_t, wp->xp); 452 } else { 453 tgt = xs.target_num; 454 } 455 } 456 if (wp->phy) { 457 if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) { 458 NOREAD(pmcs_phy_t, wp->phy); 459 continue; 460 } 461 path = phy.path; 462 } else { 463 path = "????"; 464 } 465 mdb_printf("%08x %10s %20s %8d %8u %1d %1d\n", 466 wp->htag, state, path, tgt, wp->timer, 467 wp->onwire, wp->dead); 468 } 469 } 470 471 static void 472 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int indent) 473 { 474 if (indent) 475 mdb_inc_indent(4); 476 if (printhdr) { 477 mdb_printf("%16s %16s %16s %8s %s\n", 478 "Command", "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 479 } 480 mdb_printf("%16p %16p %16p %08x %08x\n", 481 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag); 482 if (indent) 483 mdb_dec_indent(4); 484 } 485 486 /*ARGSUSED1*/ 487 static void 488 display_waitqs(struct pmcs_hw m, int verbose) 489 { 490 pmcs_cmd_t *sp, s; 491 pmcs_xscsi_t xs; 492 int first, i; 493 int max_dev = m.max_dev; 494 495 sp = m.dq.stqh_first; 496 first = 1; 497 while (sp) { 498 if (first) { 499 mdb_printf("\nDead Command Queue:\n"); 500 mdb_printf("---------------------------\n"); 501 } 502 if (MDB_RD(&s, sizeof (s), sp) == -1) { 503 NOREAD(pmcs_cmd_t, sp); 504 break; 505 } 506 print_spcmd(&s, sp, first, 0); 507 sp = s.cmd_next.stqe_next; 508 first = 0; 509 } 510 511 sp = m.cq.stqh_first; 512 first = 1; 513 while (sp) { 514 if (first) { 515 mdb_printf("\nCompletion Command Queue:\n"); 516 mdb_printf("---------------------------\n"); 517 } 518 if (MDB_RD(&s, sizeof (s), sp) == -1) { 519 NOREAD(pmcs_cmd_t, sp); 520 break; 521 } 522 print_spcmd(&s, sp, first, 0); 523 sp = s.cmd_next.stqe_next; 524 first = 0; 525 } 526 527 528 if (targets == NULL) { 529 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 530 } 531 532 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 533 NOREAD(targets, m.targets); 534 return; 535 } 536 537 for (i = 0; i < max_dev; i++) { 538 if (targets[i] == NULL) { 539 continue; 540 } 541 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) { 542 NOREAD(pmcs_xscsi_t, targets[i]); 543 continue; 544 } 545 sp = xs.wq.stqh_first; 546 first = 1; 547 while (sp) { 548 if (first) { 549 mdb_printf("\nTarget %u Wait Queue:\n", 550 xs.target_num); 551 mdb_printf("---------------------------\n"); 552 } 553 if (MDB_RD(&s, sizeof (s), sp) == -1) { 554 NOREAD(pmcs_cmd_t, sp); 555 break; 556 } 557 print_spcmd(&s, sp, first, 0); 558 sp = s.cmd_next.stqe_next; 559 first = 0; 560 } 561 sp = xs.aq.stqh_first; 562 first = 1; 563 while (sp) { 564 if (first) { 565 mdb_printf("\nTarget %u Active Queue:\n", 566 xs.target_num); 567 mdb_printf("---------------------------\n"); 568 } 569 if (MDB_RD(&s, sizeof (s), sp) == -1) { 570 NOREAD(pmcs_cmd_t, sp); 571 break; 572 } 573 print_spcmd(&s, sp, first, 0); 574 sp = s.cmd_next.stqe_next; 575 first = 0; 576 } 577 sp = xs.sq.stqh_first; 578 first = 1; 579 while (sp) { 580 if (first) { 581 mdb_printf("\nTarget %u Special Queue:\n", 582 xs.target_num); 583 mdb_printf("---------------------------\n"); 584 } 585 if (MDB_RD(&s, sizeof (s), sp) == -1) { 586 NOREAD(pmcs_cmd_t, sp); 587 break; 588 } 589 print_spcmd(&s, sp, first, 0); 590 sp = s.cmd_next.stqe_next; 591 first = 0; 592 } 593 } 594 } 595 596 static char * 597 ibq_type(int qnum) 598 { 599 if (qnum < 0 || qnum >= PMCS_NIQ) { 600 return ("UNKNOWN"); 601 } 602 603 if (qnum < PMCS_IQ_OTHER) { 604 return ("I/O"); 605 } 606 607 return ("Other"); 608 } 609 610 static char * 611 obq_type(int qnum) 612 { 613 switch (qnum) { 614 case PMCS_OQ_IODONE: 615 return ("I/O"); 616 break; 617 case PMCS_OQ_GENERAL: 618 return ("General"); 619 break; 620 case PMCS_OQ_EVENTS: 621 return ("Events"); 622 break; 623 default: 624 return ("UNKNOWN"); 625 } 626 } 627 628 static char * 629 iomb_cat(uint32_t cat) 630 { 631 switch (cat) { 632 case PMCS_IOMB_CAT_NET: 633 return ("NET"); 634 break; 635 case PMCS_IOMB_CAT_FC: 636 return ("FC"); 637 break; 638 case PMCS_IOMB_CAT_SAS: 639 return ("SAS"); 640 break; 641 case PMCS_IOMB_CAT_SCSI: 642 return ("SCSI"); 643 break; 644 default: 645 return ("???"); 646 } 647 } 648 649 static char * 650 inbound_iomb_opcode(uint32_t opcode) 651 { 652 switch (opcode) { 653 case PMCIN_ECHO: 654 return ("ECHO"); 655 break; 656 case PMCIN_GET_INFO: 657 return ("GET_INFO"); 658 break; 659 case PMCIN_GET_VPD: 660 return ("GET_VPD"); 661 break; 662 case PMCIN_PHY_START: 663 return ("PHY_START"); 664 break; 665 case PMCIN_PHY_STOP: 666 return ("PHY_STOP"); 667 break; 668 case PMCIN_SSP_INI_IO_START: 669 return ("INI_IO_START"); 670 break; 671 case PMCIN_SSP_INI_TM_START: 672 return ("INI_TM_START"); 673 break; 674 case PMCIN_SSP_INI_EXT_IO_START: 675 return ("INI_EXT_IO_START"); 676 break; 677 case PMCIN_DEVICE_HANDLE_ACCEPT: 678 return ("DEVICE_HANDLE_ACCEPT"); 679 break; 680 case PMCIN_SSP_TGT_IO_START: 681 return ("TGT_IO_START"); 682 break; 683 case PMCIN_SSP_TGT_RESPONSE_START: 684 return ("TGT_RESPONSE_START"); 685 break; 686 case PMCIN_SSP_INI_EDC_EXT_IO_START: 687 return ("INI_EDC_EXT_IO_START"); 688 break; 689 case PMCIN_SSP_INI_EDC_EXT_IO_START1: 690 return ("INI_EDC_EXT_IO_START1"); 691 break; 692 case PMCIN_SSP_TGT_EDC_IO_START: 693 return ("TGT_EDC_IO_START"); 694 break; 695 case PMCIN_SSP_ABORT: 696 return ("SSP_ABORT"); 697 break; 698 case PMCIN_DEREGISTER_DEVICE_HANDLE: 699 return ("DEREGISTER_DEVICE_HANDLE"); 700 break; 701 case PMCIN_GET_DEVICE_HANDLE: 702 return ("GET_DEVICE_HANDLE"); 703 break; 704 case PMCIN_SMP_REQUEST: 705 return ("SMP_REQUEST"); 706 break; 707 case PMCIN_SMP_RESPONSE: 708 return ("SMP_RESPONSE"); 709 break; 710 case PMCIN_SMP_ABORT: 711 return ("SMP_ABORT"); 712 break; 713 case PMCIN_ASSISTED_DISCOVERY: 714 return ("ASSISTED_DISCOVERY"); 715 break; 716 case PMCIN_REGISTER_DEVICE: 717 return ("REGISTER_DEVICE"); 718 break; 719 case PMCIN_SATA_HOST_IO_START: 720 return ("SATA_HOST_IO_START"); 721 break; 722 case PMCIN_SATA_ABORT: 723 return ("SATA_ABORT"); 724 break; 725 case PMCIN_LOCAL_PHY_CONTROL: 726 return ("LOCAL_PHY_CONTROL"); 727 break; 728 case PMCIN_GET_DEVICE_INFO: 729 return ("GET_DEVICE_INFO"); 730 break; 731 case PMCIN_TWI: 732 return ("TWI"); 733 break; 734 case PMCIN_FW_FLASH_UPDATE: 735 return ("FW_FLASH_UPDATE"); 736 break; 737 case PMCIN_SET_VPD: 738 return ("SET_VPD"); 739 break; 740 case PMCIN_GPIO: 741 return ("GPIO"); 742 break; 743 case PMCIN_SAS_DIAG_MODE_START_END: 744 return ("SAS_DIAG_MODE_START_END"); 745 break; 746 case PMCIN_SAS_DIAG_EXECUTE: 747 return ("SAS_DIAG_EXECUTE"); 748 break; 749 case PMCIN_SAW_HW_EVENT_ACK: 750 return ("SAS_HW_EVENT_ACK"); 751 break; 752 case PMCIN_GET_TIME_STAMP: 753 return ("GET_TIME_STAMP"); 754 break; 755 case PMCIN_PORT_CONTROL: 756 return ("PORT_CONTROL"); 757 break; 758 case PMCIN_GET_NVMD_DATA: 759 return ("GET_NVMD_DATA"); 760 break; 761 case PMCIN_SET_NVMD_DATA: 762 return ("SET_NVMD_DATA"); 763 break; 764 case PMCIN_SET_DEVICE_STATE: 765 return ("SET_DEVICE_STATE"); 766 break; 767 case PMCIN_GET_DEVICE_STATE: 768 return ("GET_DEVICE_STATE"); 769 break; 770 default: 771 return ("UNKNOWN"); 772 break; 773 } 774 } 775 776 static char * 777 outbound_iomb_opcode(uint32_t opcode) 778 { 779 switch (opcode) { 780 case PMCOUT_ECHO: 781 return ("ECHO"); 782 break; 783 case PMCOUT_GET_INFO: 784 return ("GET_INFO"); 785 break; 786 case PMCOUT_GET_VPD: 787 return ("GET_VPD"); 788 break; 789 case PMCOUT_SAS_HW_EVENT: 790 return ("SAS_HW_EVENT"); 791 break; 792 case PMCOUT_SSP_COMPLETION: 793 return ("SSP_COMPLETION"); 794 break; 795 case PMCOUT_SMP_COMPLETION: 796 return ("SMP_COMPLETION"); 797 break; 798 case PMCOUT_LOCAL_PHY_CONTROL: 799 return ("LOCAL_PHY_CONTROL"); 800 break; 801 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT: 802 return ("SAS_ASSISTED_DISCOVERY_SENT"); 803 break; 804 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT: 805 return ("SATA_ASSISTED_DISCOVERY_SENT"); 806 break; 807 case PMCOUT_DEVICE_REGISTRATION: 808 return ("DEVICE_REGISTRATION"); 809 break; 810 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 811 return ("DEREGISTER_DEVICE_HANDLE"); 812 break; 813 case PMCOUT_GET_DEVICE_HANDLE: 814 return ("GET_DEVICE_HANDLE"); 815 break; 816 case PMCOUT_SATA_COMPLETION: 817 return ("SATA_COMPLETION"); 818 break; 819 case PMCOUT_SATA_EVENT: 820 return ("SATA_EVENT"); 821 break; 822 case PMCOUT_SSP_EVENT: 823 return ("SSP_EVENT"); 824 break; 825 case PMCOUT_DEVICE_HANDLE_ARRIVED: 826 return ("DEVICE_HANDLE_ARRIVED"); 827 break; 828 case PMCOUT_SMP_REQUEST_RECEIVED: 829 return ("SMP_REQUEST_RECEIVED"); 830 break; 831 case PMCOUT_SSP_REQUEST_RECEIVED: 832 return ("SSP_REQUEST_RECEIVED"); 833 break; 834 case PMCOUT_DEVICE_INFO: 835 return ("DEVICE_INFO"); 836 break; 837 case PMCOUT_FW_FLASH_UPDATE: 838 return ("FW_FLASH_UPDATE"); 839 break; 840 case PMCOUT_SET_VPD: 841 return ("SET_VPD"); 842 break; 843 case PMCOUT_GPIO: 844 return ("GPIO"); 845 break; 846 case PMCOUT_GPIO_EVENT: 847 return ("GPIO_EVENT"); 848 break; 849 case PMCOUT_GENERAL_EVENT: 850 return ("GENERAL_EVENT"); 851 break; 852 case PMCOUT_TWI: 853 return ("TWI"); 854 break; 855 case PMCOUT_SSP_ABORT: 856 return ("SSP_ABORT"); 857 break; 858 case PMCOUT_SATA_ABORT: 859 return ("SATA_ABORT"); 860 break; 861 case PMCOUT_SAS_DIAG_MODE_START_END: 862 return ("SAS_DIAG_MODE_START_END"); 863 break; 864 case PMCOUT_SAS_DIAG_EXECUTE: 865 return ("SAS_DIAG_EXECUTE"); 866 break; 867 case PMCOUT_GET_TIME_STAMP: 868 return ("GET_TIME_STAMP"); 869 break; 870 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 871 return ("SAS_HW_EVENT_ACK_ACK"); 872 break; 873 case PMCOUT_PORT_CONTROL: 874 return ("PORT_CONTROL"); 875 break; 876 case PMCOUT_SKIP_ENTRIES: 877 return ("SKIP_ENTRIES"); 878 break; 879 case PMCOUT_SMP_ABORT: 880 return ("SMP_ABORT"); 881 break; 882 case PMCOUT_GET_NVMD_DATA: 883 return ("GET_NVMD_DATA"); 884 break; 885 case PMCOUT_SET_NVMD_DATA: 886 return ("SET_NVMD_DATA"); 887 break; 888 case PMCOUT_DEVICE_HANDLE_REMOVED: 889 return ("DEVICE_HANDLE_REMOVED"); 890 break; 891 case PMCOUT_SET_DEVICE_STATE: 892 return ("SET_DEVICE_STATE"); 893 break; 894 case PMCOUT_GET_DEVICE_STATE: 895 return ("GET_DEVICE_STATE"); 896 break; 897 case PMCOUT_SET_DEVICE_INFO: 898 return ("SET_DEVICE_INFO"); 899 break; 900 default: 901 return ("UNKNOWN"); 902 break; 903 } 904 } 905 906 static void 907 dump_one_qentry_outbound(uint32_t *qentryp, int idx) 908 { 909 int qeidx; 910 uint32_t word0 = LE_32(*qentryp); 911 912 mdb_printf("Entry #%02d\n", idx); 913 mdb_inc_indent(2); 914 915 mdb_printf("Header: 0x%08x (", word0); 916 if (word0 & PMCS_IOMB_VALID) { 917 mdb_printf("VALID, "); 918 } 919 if (word0 & PMCS_IOMB_HIPRI) { 920 mdb_printf("HIPRI, "); 921 } 922 mdb_printf("OBID=%d, ", 923 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 924 mdb_printf("CAT=%s, ", 925 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 926 mdb_printf("OPCODE=%s", 927 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 928 mdb_printf(")\n"); 929 930 mdb_printf("Remaining Payload:\n"); 931 932 mdb_inc_indent(2); 933 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 934 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 935 } 936 mdb_printf("\n"); 937 mdb_dec_indent(4); 938 } 939 940 static void 941 display_outbound_queues(struct pmcs_hw ss, uint_t verbose) 942 { 943 int idx, qidx; 944 uintptr_t obqp; 945 uint32_t *cip; 946 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 947 uint32_t last_consumed, oqpi; 948 949 mdb_printf("\n"); 950 mdb_printf("Outbound Queues\n"); 951 mdb_printf("---------------\n"); 952 953 mdb_inc_indent(2); 954 955 for (qidx = 0; qidx < PMCS_NOQ; qidx++) { 956 obqp = (uintptr_t)ss.oqp[qidx]; 957 958 if (obqp == NULL) { 959 mdb_printf("No outbound queue ptr for queue #%d\n", 960 qidx); 961 continue; 962 } 963 964 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx, 965 obq_type(qidx)); 966 /* 967 * Chip is the producer, so read the actual producer index 968 * and not the driver's version 969 */ 970 cip = (uint32_t *)((void *)ss.cip); 971 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET + 972 (qidx * 4)) == -1) { 973 mdb_warn("Couldn't read oqpi\n"); 974 break; 975 } 976 977 mdb_printf("Producer index: %d Consumer index: %d\n\n", 978 LE_32(oqpi), ss.oqci[qidx]); 979 mdb_inc_indent(2); 980 981 if (ss.oqci[qidx] == 0) { 982 last_consumed = ss.ioq_depth - 1; 983 } else { 984 last_consumed = ss.oqci[qidx] - 1; 985 } 986 987 988 if (!verbose) { 989 mdb_printf("Last processed entry:\n"); 990 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 991 (obqp + (PMCS_QENTRY_SIZE * last_consumed))) 992 == -1) { 993 mdb_warn("Couldn't read queue entry at 0x%p\n", 994 (obqp + (PMCS_QENTRY_SIZE * 995 last_consumed))); 996 break; 997 } 998 dump_one_qentry_outbound(qentryp, last_consumed); 999 mdb_printf("\n"); 1000 mdb_dec_indent(2); 1001 continue; 1002 } 1003 1004 for (idx = 0; idx < ss.ioq_depth; idx++) { 1005 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1006 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1007 mdb_warn("Couldn't read queue entry at 0x%p\n", 1008 (obqp + (PMCS_QENTRY_SIZE * idx))); 1009 break; 1010 } 1011 dump_one_qentry_outbound(qentryp, idx); 1012 } 1013 1014 mdb_printf("\n"); 1015 mdb_dec_indent(2); 1016 } 1017 1018 mdb_dec_indent(2); 1019 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1020 } 1021 1022 static void 1023 dump_one_qentry_inbound(uint32_t *qentryp, int idx) 1024 { 1025 int qeidx; 1026 uint32_t word0 = LE_32(*qentryp); 1027 1028 mdb_printf("Entry #%02d\n", idx); 1029 mdb_inc_indent(2); 1030 1031 mdb_printf("Header: 0x%08x (", word0); 1032 if (word0 & PMCS_IOMB_VALID) { 1033 mdb_printf("VALID, "); 1034 } 1035 if (word0 & PMCS_IOMB_HIPRI) { 1036 mdb_printf("HIPRI, "); 1037 } 1038 mdb_printf("OBID=%d, ", 1039 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1040 mdb_printf("CAT=%s, ", 1041 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1042 mdb_printf("OPCODE=%s", 1043 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1044 mdb_printf(")\n"); 1045 1046 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1))); 1047 mdb_printf("Remaining Payload:\n"); 1048 1049 mdb_inc_indent(2); 1050 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1051 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1052 } 1053 mdb_printf("\n"); 1054 mdb_dec_indent(4); 1055 } 1056 1057 static void 1058 display_inbound_queues(struct pmcs_hw ss, uint_t verbose) 1059 { 1060 int idx, qidx, iqci, last_consumed; 1061 uintptr_t ibqp; 1062 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1063 uint32_t *cip; 1064 1065 mdb_printf("\n"); 1066 mdb_printf("Inbound Queues\n"); 1067 mdb_printf("--------------\n"); 1068 1069 mdb_inc_indent(2); 1070 1071 for (qidx = 0; qidx < PMCS_NIQ; qidx++) { 1072 ibqp = (uintptr_t)ss.iqp[qidx]; 1073 1074 if (ibqp == NULL) { 1075 mdb_printf("No inbound queue ptr for queue #%d\n", 1076 qidx); 1077 continue; 1078 } 1079 1080 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx, 1081 ibq_type(qidx)); 1082 1083 cip = (uint32_t *)((void *)ss.cip); 1084 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) { 1085 mdb_warn("Couldn't read iqci\n"); 1086 break; 1087 } 1088 iqci = LE_32(iqci); 1089 1090 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1091 ss.shadow_iqpi[qidx], iqci); 1092 mdb_inc_indent(2); 1093 1094 if (iqci == 0) { 1095 last_consumed = ss.ioq_depth - 1; 1096 } else { 1097 last_consumed = iqci - 1; 1098 } 1099 1100 if (!verbose) { 1101 mdb_printf("Last processed entry:\n"); 1102 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1103 (ibqp + (PMCS_QENTRY_SIZE * last_consumed))) 1104 == -1) { 1105 mdb_warn("Couldn't read queue entry at 0x%p\n", 1106 (ibqp + (PMCS_QENTRY_SIZE * 1107 last_consumed))); 1108 break; 1109 } 1110 dump_one_qentry_inbound(qentryp, last_consumed); 1111 mdb_printf("\n"); 1112 mdb_dec_indent(2); 1113 continue; 1114 } 1115 1116 for (idx = 0; idx < ss.ioq_depth; idx++) { 1117 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1118 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1119 mdb_warn("Couldn't read queue entry at 0x%p\n", 1120 (ibqp + (PMCS_QENTRY_SIZE * idx))); 1121 break; 1122 } 1123 dump_one_qentry_inbound(qentryp, idx); 1124 } 1125 1126 mdb_printf("\n"); 1127 mdb_dec_indent(2); 1128 } 1129 1130 mdb_dec_indent(2); 1131 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1132 } 1133 1134 static void 1135 display_phy(struct pmcs_phy phy, int verbose, int totals_only) 1136 { 1137 char *dtype, *speed; 1138 char *yes = "Yes"; 1139 char *no = "No"; 1140 char *cfgd = no; 1141 char *apend = no; 1142 char *asent = no; 1143 char *dead = no; 1144 char *changed = no; 1145 1146 switch (phy.dtype) { 1147 case NOTHING: 1148 dtype = "None"; 1149 break; 1150 case SATA: 1151 dtype = "SATA"; 1152 if (phy.configured) { 1153 ++sata_phys; 1154 } 1155 break; 1156 case SAS: 1157 dtype = "SAS"; 1158 if (phy.configured) { 1159 ++sas_phys; 1160 } 1161 break; 1162 case EXPANDER: 1163 dtype = "EXP"; 1164 if (phy.configured) { 1165 ++exp_phys; 1166 } 1167 break; 1168 } 1169 1170 if (phy.dtype == NOTHING) { 1171 empty_phys++; 1172 } else if ((phy.dtype == EXPANDER) && phy.configured) { 1173 num_expanders++; 1174 } 1175 1176 if (totals_only) { 1177 return; 1178 } 1179 1180 switch (phy.link_rate) { 1181 case SAS_LINK_RATE_1_5GBIT: 1182 speed = "1.5Gb/s"; 1183 break; 1184 case SAS_LINK_RATE_3GBIT: 1185 speed = "3 Gb/s"; 1186 break; 1187 case SAS_LINK_RATE_6GBIT: 1188 speed = "6 Gb/s"; 1189 break; 1190 default: 1191 speed = "N/A"; 1192 break; 1193 } 1194 1195 if ((phy.dtype != NOTHING) || verbose) { 1196 print_sas_address(&phy); 1197 1198 if (phy.device_id != PMCS_INVALID_DEVICE_ID) { 1199 mdb_printf(" %3d %4d %6s %4s ", 1200 phy.device_id, phy.phynum, speed, dtype); 1201 } else { 1202 mdb_printf(" N/A %4d %6s %4s ", 1203 phy.phynum, speed, dtype); 1204 } 1205 1206 if (verbose) { 1207 if (phy.abort_sent) { 1208 asent = yes; 1209 } 1210 if (phy.abort_pending) { 1211 apend = yes; 1212 } 1213 if (phy.configured) { 1214 cfgd = yes; 1215 } 1216 if (phy.dead) { 1217 dead = yes; 1218 } 1219 if (phy.changed) { 1220 changed = yes; 1221 } 1222 1223 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d " 1224 "0x%p ", cfgd, apend, asent, 1225 changed, dead, phy.ref_count, phy.phy_lock); 1226 } 1227 1228 mdb_printf("Path: %s\n", phy.path); 1229 } 1230 } 1231 1232 static void 1233 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level, 1234 int totals_only) 1235 { 1236 pmcs_phy_t phy; 1237 pmcs_phy_t *pphy = parent; 1238 1239 mdb_inc_indent(3); 1240 1241 if (parent == NULL) { 1242 pphy = (pmcs_phy_t *)ss.root_phys; 1243 } else { 1244 pphy = (pmcs_phy_t *)parent; 1245 } 1246 1247 if (level == 0) { 1248 sas_phys = 0; 1249 sata_phys = 0; 1250 exp_phys = 0; 1251 num_expanders = 0; 1252 empty_phys = 0; 1253 } 1254 1255 if (!totals_only) { 1256 if (level == 0) { 1257 mdb_printf("PHY information\n"); 1258 } 1259 mdb_printf("--------\n"); 1260 mdb_printf("Level %2d\n", level); 1261 mdb_printf("--------\n"); 1262 mdb_printf("SAS Address Hdl Phy# Speed Type "); 1263 1264 if (verbose) { 1265 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref Lock\n"); 1266 } else { 1267 mdb_printf("\n"); 1268 } 1269 } 1270 1271 while (pphy) { 1272 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) { 1273 NOREAD(pmcs_phy_t, phy); 1274 break; 1275 } 1276 1277 display_phy(phy, verbose, totals_only); 1278 1279 if (phy.children) { 1280 display_phys(ss, verbose, phy.children, level + 1, 1281 totals_only); 1282 if (!totals_only) { 1283 mdb_printf("\n"); 1284 } 1285 } 1286 1287 pphy = phy.sibling; 1288 } 1289 1290 mdb_dec_indent(3); 1291 1292 if (level == 0) { 1293 if (verbose) { 1294 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) " 1295 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:", 1296 (sas_phys + sata_phys + num_expanders), 1297 sas_phys, sata_phys, num_expanders, 1298 (exp_phys - num_expanders), empty_phys); 1299 } else { 1300 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 1301 "Occupied PHYs:", 1302 (sas_phys + sata_phys + num_expanders), 1303 sas_phys, sata_phys, num_expanders); 1304 } 1305 } 1306 } 1307 1308 /* 1309 * MAX_INST_STRLEN is the largest string size from which we will attempt 1310 * to convert to an instance number. The string will be formed up as 1311 * "0t<inst>\0" so that mdb_strtoull can parse it properly. 1312 */ 1313 #define MAX_INST_STRLEN 8 1314 1315 static int 1316 pmcs_dump_tracelog(boolean_t filter, int instance) 1317 { 1318 pmcs_tbuf_t *tbuf_addr; 1319 uint_t tbuf_idx; 1320 pmcs_tbuf_t tbuf; 1321 boolean_t wrap, elem_filtered; 1322 uint_t start_idx, elems_to_print, idx, tbuf_num_elems; 1323 char *bufp; 1324 char elem_inst[MAX_INST_STRLEN], ei_idx; 1325 1326 /* Get the address of the first element */ 1327 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) { 1328 mdb_warn("can't read pmcs_tbuf"); 1329 return (DCMD_ERR); 1330 } 1331 1332 /* Get the total number */ 1333 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) { 1334 mdb_warn("can't read pmcs_tbuf_num_elems"); 1335 return (DCMD_ERR); 1336 } 1337 1338 /* Get the current index */ 1339 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) { 1340 mdb_warn("can't read pmcs_tbuf_idx"); 1341 return (DCMD_ERR); 1342 } 1343 1344 /* Indicator as to whether the buffer has wrapped */ 1345 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) { 1346 mdb_warn("can't read pmcs_tbuf_wrap"); 1347 return (DCMD_ERR); 1348 } 1349 1350 /* Figure out where we start and stop */ 1351 if (wrap) { 1352 start_idx = tbuf_idx; 1353 elems_to_print = tbuf_num_elems; 1354 } else { 1355 start_idx = 0; 1356 elems_to_print = tbuf_idx; 1357 } 1358 1359 idx = start_idx; 1360 1361 /* Dump the buffer contents */ 1362 while (elems_to_print != 0) { 1363 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx)) 1364 == -1) { 1365 NOREAD(tbuf, (tbuf_addr + idx)); 1366 return (DCMD_ERR); 1367 } 1368 1369 elem_filtered = B_FALSE; 1370 1371 if (filter) { 1372 bufp = tbuf.buf; 1373 /* Skip the driver name */ 1374 while (*bufp < '0' || *bufp > '9') { 1375 bufp++; 1376 } 1377 1378 ei_idx = 0; 1379 elem_inst[ei_idx++] = '0'; 1380 elem_inst[ei_idx++] = 't'; 1381 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) { 1382 elem_inst[ei_idx++] = *bufp; 1383 bufp++; 1384 } 1385 elem_inst[ei_idx] = 0; 1386 1387 /* Get the instance */ 1388 if ((int)mdb_strtoull(elem_inst) != instance) { 1389 elem_filtered = B_TRUE; 1390 } 1391 } 1392 1393 if (!elem_filtered) { 1394 mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf); 1395 } 1396 1397 --elems_to_print; 1398 if (++idx == tbuf_num_elems) { 1399 idx = 0; 1400 } 1401 } 1402 1403 return (DCMD_OK); 1404 } 1405 1406 /* 1407 * Walkers 1408 */ 1409 static int 1410 targets_walk_i(mdb_walk_state_t *wsp) 1411 { 1412 if (wsp->walk_addr == NULL) { 1413 mdb_warn("Can not perform global walk\n"); 1414 return (WALK_ERR); 1415 } 1416 1417 /* 1418 * Address provided belongs to HBA softstate. Get the targets pointer 1419 * to begin the walk. 1420 */ 1421 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1422 sizeof (pmcs_hw_t)) { 1423 mdb_warn("Unable to read HBA softstate\n"); 1424 return (WALK_ERR); 1425 } 1426 1427 if (targets == NULL) { 1428 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP); 1429 } 1430 1431 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) { 1432 NOREAD(targets, ss.targets); 1433 return (WALK_ERR); 1434 } 1435 1436 target_idx = 0; 1437 wsp->walk_addr = (uintptr_t)(targets[0]); 1438 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP); 1439 1440 return (WALK_NEXT); 1441 } 1442 1443 static int 1444 targets_walk_s(mdb_walk_state_t *wsp) 1445 { 1446 int status; 1447 1448 if (target_idx == ss.max_dev) { 1449 return (WALK_DONE); 1450 } 1451 1452 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t), 1453 wsp->walk_addr) == -1) { 1454 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr); 1455 return (WALK_DONE); 1456 } 1457 1458 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1459 wsp->walk_cbdata); 1460 1461 do { 1462 wsp->walk_addr = (uintptr_t)(targets[++target_idx]); 1463 } while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev)); 1464 1465 if (target_idx == ss.max_dev) { 1466 return (WALK_DONE); 1467 } 1468 1469 return (status); 1470 } 1471 1472 static void 1473 targets_walk_f(mdb_walk_state_t *wsp) 1474 { 1475 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t)); 1476 } 1477 1478 1479 static pmcs_phy_t * 1480 pmcs_next_sibling(pmcs_phy_t *phyp) 1481 { 1482 pmcs_phy_t parent; 1483 1484 /* 1485 * First, if this is a root PHY, there are no more siblings 1486 */ 1487 if (phyp->level == 0) { 1488 return (NULL); 1489 } 1490 1491 /* 1492 * Otherwise, next sibling is the parent's sibling 1493 */ 1494 while (phyp->level > 0) { 1495 if (mdb_vread(&parent, sizeof (pmcs_phy_t), 1496 (uintptr_t)phyp->parent) == -1) { 1497 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p", 1498 (void *)phyp->parent); 1499 return (NULL); 1500 } 1501 1502 if (parent.sibling != NULL) { 1503 break; 1504 } 1505 1506 phyp = phyp->parent; 1507 } 1508 1509 return (parent.sibling); 1510 } 1511 1512 static int 1513 phy_walk_i(mdb_walk_state_t *wsp) 1514 { 1515 if (wsp->walk_addr == NULL) { 1516 mdb_warn("Can not perform global walk\n"); 1517 return (WALK_ERR); 1518 } 1519 1520 /* 1521 * Address provided belongs to HBA softstate. Get the targets pointer 1522 * to begin the walk. 1523 */ 1524 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1525 sizeof (pmcs_hw_t)) { 1526 mdb_warn("Unable to read HBA softstate\n"); 1527 return (WALK_ERR); 1528 } 1529 1530 wsp->walk_addr = (uintptr_t)(ss.root_phys); 1531 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 1532 1533 return (WALK_NEXT); 1534 } 1535 1536 static int 1537 phy_walk_s(mdb_walk_state_t *wsp) 1538 { 1539 pmcs_phy_t *phyp, *nphyp; 1540 int status; 1541 1542 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 1543 wsp->walk_addr) == -1) { 1544 mdb_warn("phy_walk_s: Failed to read PHY at %p", 1545 (void *)wsp->walk_addr); 1546 return (WALK_DONE); 1547 } 1548 1549 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1550 wsp->walk_cbdata); 1551 1552 phyp = (pmcs_phy_t *)wsp->walk_data; 1553 if (phyp->children) { 1554 wsp->walk_addr = (uintptr_t)(phyp->children); 1555 } else { 1556 wsp->walk_addr = (uintptr_t)(phyp->sibling); 1557 } 1558 1559 if (wsp->walk_addr == NULL) { 1560 /* 1561 * We reached the end of this sibling list. Trudge back up 1562 * to the parent and find the next sibling after the expander 1563 * we just finished traversing, if there is one. 1564 */ 1565 nphyp = pmcs_next_sibling(phyp); 1566 1567 if (nphyp == NULL) { 1568 return (WALK_DONE); 1569 } 1570 1571 wsp->walk_addr = (uintptr_t)nphyp; 1572 } 1573 1574 return (status); 1575 } 1576 1577 static void 1578 phy_walk_f(mdb_walk_state_t *wsp) 1579 { 1580 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 1581 } 1582 1583 static int 1584 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1585 { 1586 struct pmcs_hw ss; 1587 uint_t verbose = FALSE; 1588 uint_t phy_info = FALSE; 1589 uint_t hw_info = FALSE; 1590 uint_t target_info = FALSE; 1591 uint_t work_info = FALSE; 1592 uint_t ic_info = FALSE; 1593 uint_t iport_info = FALSE; 1594 uint_t waitqs_info = FALSE; 1595 uint_t tracelog = FALSE; 1596 uint_t ibq = FALSE; 1597 uint_t obq = FALSE; 1598 uint_t tgt_phy_count = FALSE; 1599 int rv = DCMD_OK; 1600 void *pmcs_state; 1601 char *state_str; 1602 struct dev_info dip; 1603 1604 if (!(flags & DCMD_ADDRSPEC)) { 1605 pmcs_state = NULL; 1606 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 1607 mdb_warn("can't read pmcs_softc_state"); 1608 return (DCMD_ERR); 1609 } 1610 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 1611 (uintptr_t)pmcs_state) == -1) { 1612 mdb_warn("mdb_pwalk_dcmd failed"); 1613 return (DCMD_ERR); 1614 } 1615 return (DCMD_OK); 1616 } 1617 1618 if (mdb_getopts(argc, argv, 1619 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 1620 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 1621 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 1622 'l', MDB_OPT_SETBITS, TRUE, &tracelog, 1623 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 1624 'q', MDB_OPT_SETBITS, TRUE, &ibq, 1625 'Q', MDB_OPT_SETBITS, TRUE, &obq, 1626 't', MDB_OPT_SETBITS, TRUE, &target_info, 1627 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 1628 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1629 'w', MDB_OPT_SETBITS, TRUE, &work_info, 1630 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 1631 NULL) != argc) 1632 return (DCMD_USAGE); 1633 1634 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 1635 NOREAD(pmcs_hw_t, addr); 1636 return (DCMD_ERR); 1637 } 1638 1639 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 1640 NOREAD(pmcs_hw_t, addr); 1641 return (DCMD_ERR); 1642 } 1643 1644 /* 1645 * Dumping the trace log is special. It's global, not per-HBA. 1646 * Thus, a provided address is ignored. In addition, other options 1647 * cannot be specified at the same time. 1648 */ 1649 1650 if (tracelog) { 1651 if (hw_info || ic_info || iport_info || phy_info || work_info || 1652 target_info || waitqs_info || ibq || obq || tgt_phy_count) { 1653 return (DCMD_USAGE); 1654 } 1655 1656 if ((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) { 1657 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance)); 1658 } else if (flags & DCMD_LOOPFIRST) { 1659 return (pmcs_dump_tracelog(B_FALSE, 0)); 1660 } else { 1661 return (DCMD_OK); 1662 } 1663 } 1664 1665 /* processing completed */ 1666 1667 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 1668 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 1669 work_info || waitqs_info || ibq || obq || tgt_phy_count) { 1670 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 1671 mdb_printf("\n"); 1672 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 1673 "Address", "State", "Inst", "DIP"); 1674 mdb_printf("=================================" 1675 "============================================\n"); 1676 } 1677 1678 switch (ss.state) { 1679 case STATE_NIL: 1680 state_str = "Invalid"; 1681 break; 1682 case STATE_PROBING: 1683 state_str = "Probing"; 1684 break; 1685 case STATE_RUNNING: 1686 state_str = "Running"; 1687 break; 1688 case STATE_UNPROBING: 1689 state_str = "Unprobing"; 1690 break; 1691 case STATE_DEAD: 1692 state_str = "Dead"; 1693 break; 1694 } 1695 1696 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 1697 state_str, dip.devi_instance, ss.blocked, ss.configuring, 1698 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 1699 mdb_printf("\n"); 1700 1701 mdb_inc_indent(4); 1702 1703 if (waitqs_info) 1704 display_waitqs(ss, verbose); 1705 1706 if (hw_info) 1707 display_hwinfo(ss, verbose); 1708 1709 if (phy_info || tgt_phy_count) 1710 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 1711 1712 if (target_info || tgt_phy_count) 1713 display_targets(ss, verbose, tgt_phy_count); 1714 1715 if (work_info) 1716 display_work(ss, verbose); 1717 1718 if (ic_info) 1719 display_ic(ss, verbose); 1720 1721 if (ibq) 1722 display_inbound_queues(ss, verbose); 1723 1724 if (obq) 1725 display_outbound_queues(ss, verbose); 1726 1727 if (iport_info) 1728 display_iport(ss, addr, verbose); 1729 1730 mdb_dec_indent(4); 1731 1732 return (rv); 1733 } 1734 1735 void 1736 pmcs_help() 1737 { 1738 mdb_printf("Prints summary information about each pmcs instance.\n" 1739 " -h: Print more detailed hardware information\n" 1740 " -i: Print interrupt coalescing information\n" 1741 " -I: Print information about each iport\n" 1742 " -l: Dump the trace log (cannot be used with other options)\n" 1743 " -p: Print information about each attached PHY\n" 1744 " -q: Dump inbound queues\n" 1745 " -Q: Dump outbound queues\n" 1746 " -t: Print information about each known target\n" 1747 " -T: Print target and PHY count summary\n" 1748 " -w: Dump work structures\n" 1749 " -W: List pmcs cmds waiting on various queues\n" 1750 " -v: Add verbosity to the above options\n"); 1751 } 1752 1753 static const mdb_dcmd_t dcmds[] = { 1754 { "pmcs", "?[-hiIpQqtTwWv] | -l", "print pmcs information", 1755 pmcs_dcmd, pmcs_help 1756 }, 1757 { NULL } 1758 }; 1759 1760 static const mdb_walker_t walkers[] = { 1761 { "pmcs_targets", "walk target structures", 1762 targets_walk_i, targets_walk_s, targets_walk_f }, 1763 { "pmcs_phys", "walk PHY structures", 1764 phy_walk_i, phy_walk_s, phy_walk_f }, 1765 { NULL } 1766 }; 1767 1768 static const mdb_modinfo_t modinfo = { 1769 MDB_API_VERSION, dcmds, walkers 1770 }; 1771 1772 const mdb_modinfo_t * 1773 _mdb_init(void) 1774 { 1775 return (&modinfo); 1776 } 1777