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/byteorder.h> 30 #include <sys/scsi/scsi.h> 31 #include <sys/scsi/adapters/pmcs/pmcs.h> 32 33 #define MDB_RD(a, b, c) mdb_vread(a, b, (uintptr_t)c) 34 #define NOREAD(a, b) mdb_warn("could not read " #a " at 0x%p", b) 35 36 static pmcs_hw_t ss; 37 static pmcs_xscsi_t **targets = NULL; 38 static int target_idx; 39 40 static uint32_t sas_phys, sata_phys, exp_phys, num_expanders, empty_phys; 41 42 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp); 43 static void display_one_work(pmcwork_t *wp, int verbose, int idx); 44 45 static void 46 print_sas_address(pmcs_phy_t *phy) 47 { 48 int idx; 49 50 for (idx = 0; idx < 8; idx++) { 51 mdb_printf("%02x", phy->sas_address[idx]); 52 } 53 } 54 55 /*ARGSUSED*/ 56 static void 57 display_ic(struct pmcs_hw m, int verbose) 58 { 59 int msec_per_tick; 60 61 if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) { 62 mdb_warn("can't read msec_per_tick"); 63 msec_per_tick = 0; 64 } 65 66 mdb_printf("\n"); 67 mdb_printf("Interrupt coalescing timer info\n"); 68 mdb_printf("-------------------------------\n"); 69 if (msec_per_tick == 0) { 70 mdb_printf("Quantum : ?? ms\n"); 71 } else { 72 mdb_printf("Quantum : %d ms\n", 73 m.io_intr_coal.quantum * msec_per_tick); 74 } 75 mdb_printf("Timer enabled : "); 76 if (m.io_intr_coal.timer_on) { 77 mdb_printf("Yes\n"); 78 mdb_printf("Coalescing timer value : %d us\n", 79 m.io_intr_coal.intr_coal_timer); 80 } else { 81 mdb_printf("No\n"); 82 } 83 mdb_printf("Total nsecs between interrupts: %ld\n", 84 m.io_intr_coal.nsecs_between_intrs); 85 mdb_printf("Time of last I/O interrupt : %ld\n", 86 m.io_intr_coal.last_io_comp); 87 mdb_printf("Number of I/O interrupts : %d\n", 88 m.io_intr_coal.num_intrs); 89 mdb_printf("Number of I/O completions : %d\n", 90 m.io_intr_coal.num_io_completions); 91 mdb_printf("Max I/O completion interrupts : %d\n", 92 m.io_intr_coal.max_io_completions); 93 mdb_printf("Measured ECHO int latency : %d ns\n", 94 m.io_intr_coal.intr_latency); 95 mdb_printf("Interrupt threshold : %d\n", 96 m.io_intr_coal.intr_threshold); 97 } 98 99 /*ARGSUSED*/ 100 static int 101 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv) 102 { 103 struct pmcs_phy phy; 104 105 if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) != 106 sizeof (struct pmcs_phy)) { 107 return (DCMD_ERR); 108 } 109 110 mdb_printf("%16p %2d\n", addr, phy.phynum); 111 112 return (0); 113 } 114 115 /*ARGSUSED*/ 116 static int 117 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv) 118 { 119 struct pmcs_iport iport; 120 uintptr_t list_addr; 121 char *ua_state; 122 char portid[4]; 123 char unit_address[34]; 124 125 if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) != 126 sizeof (struct pmcs_iport)) { 127 return (DCMD_ERR); 128 } 129 130 if (mdb_readstr(unit_address, sizeof (unit_address), 131 (uintptr_t)(iport.ua)) == -1) { 132 strncpy(unit_address, "Unset", sizeof (unit_address)); 133 } 134 135 if (iport.portid == 0xffff) { 136 mdb_snprintf(portid, sizeof (portid), "%s", "-"); 137 } else { 138 mdb_snprintf(portid, sizeof (portid), "%d", iport.portid); 139 } 140 141 switch (iport.ua_state) { 142 case UA_INACTIVE: 143 ua_state = "Inactive"; 144 break; 145 case UA_PEND_ACTIVATE: 146 ua_state = "PendActivate"; 147 break; 148 case UA_ACTIVE: 149 ua_state = "Active"; 150 break; 151 case UA_PEND_DEACTIVATE: 152 ua_state = "PendDeactivate"; 153 break; 154 default: 155 ua_state = "Unknown"; 156 } 157 158 if (strlen(unit_address) < 3) { 159 /* Standard iport unit address */ 160 mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State", 161 "PortID", "NumPhys", "DIP\n"); 162 mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr, 163 ua_state, portid, iport.nphy, iport.dip); 164 } else { 165 /* Temporary iport unit address */ 166 mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport", 167 "UA State", "PortID", "NumPhys", "DIP\n"); 168 mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr, 169 ua_state, portid, iport.nphy, iport.dip); 170 } 171 172 if (iport.nphy > 0) { 173 mdb_inc_indent(4); 174 mdb_printf("%-18s %8s", "Phy", "PhyNum\n"); 175 mdb_inc_indent(2); 176 list_addr = 177 (uintptr_t)(addr + offsetof(struct pmcs_iport, phys)); 178 if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL, 179 list_addr) == -1) { 180 mdb_warn("pmcs iport walk failed"); 181 } 182 mdb_dec_indent(6); 183 mdb_printf("\n"); 184 } 185 186 return (0); 187 } 188 189 /*ARGSUSED*/ 190 static void 191 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose) 192 { 193 uintptr_t list_addr; 194 195 if (m.iports_attached) { 196 mdb_printf("Iport information:\n"); 197 mdb_printf("-----------------\n"); 198 } else { 199 mdb_printf("No Iports found.\n\n"); 200 return; 201 } 202 203 list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports)); 204 205 if (mdb_pwalk("list", pmcs_iport_walk_cb, NULL, list_addr) == -1) { 206 mdb_warn("pmcs iport walk failed"); 207 } 208 209 mdb_printf("\n"); 210 } 211 212 /* ARGSUSED */ 213 static int 214 pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv) 215 { 216 pmcs_phy_t phy; 217 218 if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) { 219 mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p", 220 (void *)addr); 221 return (DCMD_ERR); 222 } 223 224 if (phy.configured && (phy.target == NULL)) { 225 mdb_printf("SAS address: "); 226 print_sas_address(&phy); 227 mdb_printf(" DType: "); 228 switch (phy.dtype) { 229 case SAS: 230 mdb_printf("%4s", "SAS"); 231 break; 232 case SATA: 233 mdb_printf("%4s", "SATA"); 234 break; 235 case EXPANDER: 236 mdb_printf("%4s", "SMP"); 237 break; 238 default: 239 mdb_printf("%4s", "N/A"); 240 break; 241 } 242 mdb_printf(" Path: %s\n", phy.path); 243 } 244 245 return (0); 246 } 247 248 static void 249 display_unconfigured_targets(uintptr_t addr) 250 { 251 mdb_printf("Unconfigured target SAS address:\n\n"); 252 253 if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) { 254 mdb_warn("pmcs phys walk failed"); 255 } 256 } 257 258 static void 259 display_completion_queue(struct pmcs_hw ss) 260 { 261 pmcs_iocomp_cb_t ccb, *ccbp; 262 pmcwork_t work; 263 264 if (ss.iocomp_cb_head == NULL) { 265 mdb_printf("Completion queue is empty.\n"); 266 return; 267 } 268 269 ccbp = ss.iocomp_cb_head; 270 mdb_printf("%8s %10s %20s %8s %8s O D\n", 271 "HTag", "State", "Phy Path", "Target", "Timer"); 272 273 while (ccbp) { 274 if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t), 275 (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) { 276 mdb_warn("Unable to read completion queue entry\n"); 277 return; 278 } 279 280 if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk) 281 != sizeof (pmcwork_t)) { 282 mdb_warn("Unable to read work structure\n"); 283 return; 284 } 285 286 /* 287 * Only print the work structure if it's still active. If 288 * it's not, it's been completed since we started looking at 289 * it. 290 */ 291 if (work.state != PMCS_WORK_STATE_NIL) { 292 display_one_work(&work, 0, 0); 293 } 294 ccbp = ccb.next; 295 } 296 } 297 298 /*ARGSUSED*/ 299 static void 300 display_hwinfo(struct pmcs_hw m, int verbose) 301 { 302 struct pmcs_hw *mp = &m; 303 char *fwsupport; 304 305 switch (PMCS_FW_TYPE(mp)) { 306 case PMCS_FW_TYPE_RELEASED: 307 fwsupport = "Released"; 308 break; 309 case PMCS_FW_TYPE_DEVELOPMENT: 310 fwsupport = "Development"; 311 break; 312 case PMCS_FW_TYPE_ALPHA: 313 fwsupport = "Alpha"; 314 break; 315 case PMCS_FW_TYPE_BETA: 316 fwsupport = "Beta"; 317 break; 318 default: 319 fwsupport = "Special"; 320 break; 321 } 322 323 mdb_printf("\nHardware information:\n"); 324 mdb_printf("---------------------\n"); 325 326 mdb_printf("Chip revision: %c\n", 'A' + m.chiprev); 327 mdb_printf("SAS WWID: %"PRIx64"\n", m.sas_wwns[0]); 328 mdb_printf("Firmware version: %x.%x.%x (%s)\n", 329 PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp), 330 fwsupport); 331 332 mdb_printf("Number of PHYs: %d\n", m.nphy); 333 mdb_printf("Maximum commands: %d\n", m.max_cmd); 334 mdb_printf("Maximum devices: %d\n", m.max_dev); 335 mdb_printf("I/O queue depth: %d\n", m.ioq_depth); 336 if (m.fwlog == 0) { 337 mdb_printf("Firmware logging: Disabled\n"); 338 } else { 339 mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog); 340 } 341 } 342 343 static void 344 display_targets(struct pmcs_hw m, int verbose, int totals_only) 345 { 346 char *dtype; 347 pmcs_xscsi_t xs; 348 pmcs_phy_t phy; 349 uint16_t max_dev, idx; 350 uint32_t sas_targets = 0, smp_targets = 0, sata_targets = 0; 351 352 max_dev = m.max_dev; 353 354 if (targets == NULL) { 355 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 356 } 357 358 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 359 NOREAD(targets, m.targets); 360 return; 361 } 362 363 if (!totals_only) { 364 mdb_printf("\nTarget information:\n"); 365 mdb_printf("---------------------------------------\n"); 366 mdb_printf("VTGT %-16s %-16s %-5s %8s %s", "SAS Address", 367 "PHY Address", "DType", "Active", "DS"); 368 mdb_printf("\n"); 369 } 370 371 for (idx = 0; idx < max_dev; idx++) { 372 if (targets[idx] == NULL) { 373 continue; 374 } 375 376 if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) { 377 NOREAD(pmcs_xscsi_t, targets[idx]); 378 continue; 379 } 380 381 /* 382 * It has to be new or assigned to be of interest. 383 */ 384 if (xs.new == 0 && xs.assigned == 0) { 385 continue; 386 } 387 388 switch (xs.dtype) { 389 case NOTHING: 390 dtype = "None"; 391 break; 392 case SATA: 393 dtype = "SATA"; 394 sata_targets++; 395 break; 396 case SAS: 397 dtype = "SAS"; 398 sas_targets++; 399 break; 400 case EXPANDER: 401 dtype = "SMP"; 402 smp_targets++; 403 break; 404 } 405 406 if (totals_only) { 407 continue; 408 } 409 410 if (xs.phy) { 411 if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) { 412 NOREAD(pmcs_phy_t, xs.phy); 413 continue; 414 } 415 mdb_printf("%4d ", idx); 416 print_sas_address(&phy); 417 mdb_printf(" %16p", xs.phy); 418 } else { 419 mdb_printf("%4d %16s", idx, "<no phy avail>"); 420 } 421 mdb_printf(" %5s", dtype); 422 mdb_printf(" %8d", xs.actv_cnt); 423 mdb_printf(" %2d", xs.dev_state); 424 425 if (verbose) { 426 if (xs.new) { 427 mdb_printf(" new"); 428 } 429 if (xs.assigned) { 430 mdb_printf(" assigned"); 431 } 432 if (xs.draining) { 433 mdb_printf(" draining"); 434 } 435 if (xs.reset_wait) { 436 mdb_printf(" reset_wait"); 437 } 438 if (xs.resetting) { 439 mdb_printf(" resetting"); 440 } 441 if (xs.recover_wait) { 442 mdb_printf(" recover_wait"); 443 } 444 if (xs.recovering) { 445 mdb_printf(" recovering"); 446 } 447 if (xs.event_recovery) { 448 mdb_printf(" event recovery"); 449 } 450 if (xs.special_running) { 451 mdb_printf(" special_active"); 452 } 453 if (xs.ncq) { 454 mdb_printf(" ncq_tagmap=0x%x qdepth=%d", 455 xs.tagmap, xs.qdepth); 456 } else if (xs.pio) { 457 mdb_printf(" pio"); 458 } 459 } 460 461 mdb_printf("\n"); 462 } 463 464 if (!totals_only) { 465 mdb_printf("\n"); 466 } 467 468 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 469 "Configured targets:", (sas_targets + sata_targets + smp_targets), 470 sas_targets, sata_targets, smp_targets); 471 } 472 473 static char * 474 work_state_to_string(uint32_t state) 475 { 476 char *state_string; 477 478 switch (state) { 479 case PMCS_WORK_STATE_NIL: 480 state_string = "Free"; 481 break; 482 case PMCS_WORK_STATE_READY: 483 state_string = "Ready"; 484 break; 485 case PMCS_WORK_STATE_ONCHIP: 486 state_string = "On Chip"; 487 break; 488 case PMCS_WORK_STATE_INTR: 489 state_string = "In Intr"; 490 break; 491 case PMCS_WORK_STATE_IOCOMPQ: 492 state_string = "I/O Comp"; 493 break; 494 case PMCS_WORK_STATE_ABORTED: 495 state_string = "I/O Aborted"; 496 break; 497 case PMCS_WORK_STATE_TIMED_OUT: 498 state_string = "I/O Timed Out"; 499 break; 500 default: 501 state_string = "INVALID"; 502 break; 503 } 504 505 return (state_string); 506 } 507 508 static void 509 display_one_work(pmcwork_t *wp, int verbose, int idx) 510 { 511 char *state, *last_state; 512 char *path; 513 pmcs_xscsi_t xs; 514 pmcs_phy_t phy; 515 int tgt; 516 517 state = work_state_to_string(wp->state); 518 last_state = work_state_to_string(wp->last_state); 519 520 if (wp->ssp_event && wp->ssp_event != 0xffffffff) { 521 mdb_printf("SSP event 0x%x", wp->ssp_event); 522 } 523 524 tgt = -1; 525 if (wp->xp) { 526 if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) { 527 NOREAD(pmcs_xscsi_t, wp->xp); 528 } else { 529 tgt = xs.target_num; 530 } 531 } 532 if (wp->phy) { 533 if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) { 534 NOREAD(pmcs_phy_t, wp->phy); 535 } 536 path = phy.path; 537 } else { 538 path = "N/A"; 539 } 540 541 if (verbose) { 542 mdb_printf("%4d ", idx); 543 } 544 if (tgt == -1) { 545 mdb_printf("%08x %10s %20s N/A %8u %1d %1d ", 546 wp->htag, state, path, wp->timer, 547 wp->onwire, wp->dead); 548 } else { 549 mdb_printf("%08x %10s %20s %8d %8u %1d %1d ", 550 wp->htag, state, path, tgt, wp->timer, 551 wp->onwire, wp->dead); 552 } 553 if (verbose) { 554 mdb_printf("%08x %10s 0x%016p 0x%016p\n", 555 wp->last_htag, last_state, wp->last_phy, wp->last_xp); 556 } else { 557 mdb_printf("\n"); 558 } 559 } 560 561 static void 562 display_work(struct pmcs_hw m, int verbose) 563 { 564 int idx; 565 boolean_t header_printed = B_FALSE; 566 pmcwork_t work, *wp = &work; 567 uintptr_t _wp; 568 569 mdb_printf("\nActive Work structure information:\n"); 570 mdb_printf("----------------------------------\n"); 571 572 _wp = (uintptr_t)m.work; 573 574 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 575 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 576 NOREAD(pmcwork_t, _wp); 577 continue; 578 } 579 580 if (!verbose && (wp->htag == PMCS_TAG_TYPE_FREE)) { 581 continue; 582 } 583 584 if (header_printed == B_FALSE) { 585 if (verbose) { 586 mdb_printf("%4s ", "Idx"); 587 } 588 mdb_printf("%8s %10s %20s %8s %8s O D ", 589 "HTag", "State", "Phy Path", "Target", "Timer"); 590 if (verbose) { 591 mdb_printf("%8s %10s %18s %18s\n", "LastHTAG", 592 "LastState", "LastPHY", "LastTgt"); 593 } else { 594 mdb_printf("\n"); 595 } 596 header_printed = B_TRUE; 597 } 598 599 display_one_work(wp, verbose, idx); 600 } 601 } 602 603 static void 604 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose) 605 { 606 int cdb_size, idx; 607 struct scsi_pkt pkt; 608 uchar_t cdb[256]; 609 610 if (printhdr) { 611 if (verbose) { 612 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command", 613 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 614 } else { 615 mdb_printf("%16s %16s %16s %8s %s\n", "Command", 616 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 617 } 618 } 619 620 mdb_printf("%16p %16p %16p %08x %08x ", 621 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag); 622 623 /* 624 * If we're printing verbose, dump the CDB as well. 625 */ 626 if (verbose) { 627 if (sp->cmd_pkt) { 628 if (mdb_vread(&pkt, sizeof (struct scsi_pkt), 629 (uintptr_t)sp->cmd_pkt) != 630 sizeof (struct scsi_pkt)) { 631 mdb_warn("Unable to read SCSI pkt\n"); 632 return; 633 } 634 cdb_size = pkt.pkt_cdblen; 635 if (mdb_vread(&cdb[0], cdb_size, 636 (uintptr_t)pkt.pkt_cdbp) != cdb_size) { 637 mdb_warn("Unable to read CDB\n"); 638 return; 639 } 640 641 for (idx = 0; idx < cdb_size; idx++) { 642 mdb_printf("%02x ", cdb[idx]); 643 } 644 } else { 645 mdb_printf("N/A"); 646 } 647 648 mdb_printf("\n"); 649 } else { 650 mdb_printf("\n"); 651 } 652 } 653 654 /*ARGSUSED1*/ 655 static void 656 display_waitqs(struct pmcs_hw m, int verbose) 657 { 658 pmcs_cmd_t *sp, s; 659 pmcs_xscsi_t xs; 660 int first, i; 661 int max_dev = m.max_dev; 662 663 sp = m.dq.stqh_first; 664 first = 1; 665 while (sp) { 666 if (first) { 667 mdb_printf("\nDead Command Queue:\n"); 668 mdb_printf("---------------------------\n"); 669 } 670 if (MDB_RD(&s, sizeof (s), sp) == -1) { 671 NOREAD(pmcs_cmd_t, sp); 672 break; 673 } 674 print_spcmd(&s, sp, first, verbose); 675 sp = s.cmd_next.stqe_next; 676 first = 0; 677 } 678 679 sp = m.cq.stqh_first; 680 first = 1; 681 while (sp) { 682 if (first) { 683 mdb_printf("\nCompletion Command Queue:\n"); 684 mdb_printf("---------------------------\n"); 685 } 686 if (MDB_RD(&s, sizeof (s), sp) == -1) { 687 NOREAD(pmcs_cmd_t, sp); 688 break; 689 } 690 print_spcmd(&s, sp, first, verbose); 691 sp = s.cmd_next.stqe_next; 692 first = 0; 693 } 694 695 696 if (targets == NULL) { 697 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 698 } 699 700 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 701 NOREAD(targets, m.targets); 702 return; 703 } 704 705 for (i = 0; i < max_dev; i++) { 706 if (targets[i] == NULL) { 707 continue; 708 } 709 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) { 710 NOREAD(pmcs_xscsi_t, targets[i]); 711 continue; 712 } 713 sp = xs.wq.stqh_first; 714 first = 1; 715 while (sp) { 716 if (first) { 717 mdb_printf("\nTarget %u Wait Queue:\n", 718 xs.target_num); 719 mdb_printf("---------------------------\n"); 720 } 721 if (MDB_RD(&s, sizeof (s), sp) == -1) { 722 NOREAD(pmcs_cmd_t, sp); 723 break; 724 } 725 print_spcmd(&s, sp, first, verbose); 726 sp = s.cmd_next.stqe_next; 727 first = 0; 728 } 729 sp = xs.aq.stqh_first; 730 first = 1; 731 while (sp) { 732 if (first) { 733 mdb_printf("\nTarget %u Active Queue:\n", 734 xs.target_num); 735 mdb_printf("---------------------------\n"); 736 } 737 if (MDB_RD(&s, sizeof (s), sp) == -1) { 738 NOREAD(pmcs_cmd_t, sp); 739 break; 740 } 741 print_spcmd(&s, sp, first, verbose); 742 sp = s.cmd_next.stqe_next; 743 first = 0; 744 } 745 sp = xs.sq.stqh_first; 746 first = 1; 747 while (sp) { 748 if (first) { 749 mdb_printf("\nTarget %u Special Queue:\n", 750 xs.target_num); 751 mdb_printf("---------------------------\n"); 752 } 753 if (MDB_RD(&s, sizeof (s), sp) == -1) { 754 NOREAD(pmcs_cmd_t, sp); 755 break; 756 } 757 print_spcmd(&s, sp, first, verbose); 758 sp = s.cmd_next.stqe_next; 759 first = 0; 760 } 761 } 762 } 763 764 static char * 765 ibq_type(int qnum) 766 { 767 if (qnum < 0 || qnum >= PMCS_NIQ) { 768 return ("UNKNOWN"); 769 } 770 771 if (qnum < PMCS_IQ_OTHER) { 772 return ("I/O"); 773 } 774 775 return ("Other"); 776 } 777 778 static char * 779 obq_type(int qnum) 780 { 781 switch (qnum) { 782 case PMCS_OQ_IODONE: 783 return ("I/O"); 784 break; 785 case PMCS_OQ_GENERAL: 786 return ("General"); 787 break; 788 case PMCS_OQ_EVENTS: 789 return ("Events"); 790 break; 791 default: 792 return ("UNKNOWN"); 793 } 794 } 795 796 static char * 797 iomb_cat(uint32_t cat) 798 { 799 switch (cat) { 800 case PMCS_IOMB_CAT_NET: 801 return ("NET"); 802 break; 803 case PMCS_IOMB_CAT_FC: 804 return ("FC"); 805 break; 806 case PMCS_IOMB_CAT_SAS: 807 return ("SAS"); 808 break; 809 case PMCS_IOMB_CAT_SCSI: 810 return ("SCSI"); 811 break; 812 default: 813 return ("???"); 814 } 815 } 816 817 static char * 818 inbound_iomb_opcode(uint32_t opcode) 819 { 820 switch (opcode) { 821 case PMCIN_ECHO: 822 return ("ECHO"); 823 break; 824 case PMCIN_GET_INFO: 825 return ("GET_INFO"); 826 break; 827 case PMCIN_GET_VPD: 828 return ("GET_VPD"); 829 break; 830 case PMCIN_PHY_START: 831 return ("PHY_START"); 832 break; 833 case PMCIN_PHY_STOP: 834 return ("PHY_STOP"); 835 break; 836 case PMCIN_SSP_INI_IO_START: 837 return ("INI_IO_START"); 838 break; 839 case PMCIN_SSP_INI_TM_START: 840 return ("INI_TM_START"); 841 break; 842 case PMCIN_SSP_INI_EXT_IO_START: 843 return ("INI_EXT_IO_START"); 844 break; 845 case PMCIN_DEVICE_HANDLE_ACCEPT: 846 return ("DEVICE_HANDLE_ACCEPT"); 847 break; 848 case PMCIN_SSP_TGT_IO_START: 849 return ("TGT_IO_START"); 850 break; 851 case PMCIN_SSP_TGT_RESPONSE_START: 852 return ("TGT_RESPONSE_START"); 853 break; 854 case PMCIN_SSP_INI_EDC_EXT_IO_START: 855 return ("INI_EDC_EXT_IO_START"); 856 break; 857 case PMCIN_SSP_INI_EDC_EXT_IO_START1: 858 return ("INI_EDC_EXT_IO_START1"); 859 break; 860 case PMCIN_SSP_TGT_EDC_IO_START: 861 return ("TGT_EDC_IO_START"); 862 break; 863 case PMCIN_SSP_ABORT: 864 return ("SSP_ABORT"); 865 break; 866 case PMCIN_DEREGISTER_DEVICE_HANDLE: 867 return ("DEREGISTER_DEVICE_HANDLE"); 868 break; 869 case PMCIN_GET_DEVICE_HANDLE: 870 return ("GET_DEVICE_HANDLE"); 871 break; 872 case PMCIN_SMP_REQUEST: 873 return ("SMP_REQUEST"); 874 break; 875 case PMCIN_SMP_RESPONSE: 876 return ("SMP_RESPONSE"); 877 break; 878 case PMCIN_SMP_ABORT: 879 return ("SMP_ABORT"); 880 break; 881 case PMCIN_ASSISTED_DISCOVERY: 882 return ("ASSISTED_DISCOVERY"); 883 break; 884 case PMCIN_REGISTER_DEVICE: 885 return ("REGISTER_DEVICE"); 886 break; 887 case PMCIN_SATA_HOST_IO_START: 888 return ("SATA_HOST_IO_START"); 889 break; 890 case PMCIN_SATA_ABORT: 891 return ("SATA_ABORT"); 892 break; 893 case PMCIN_LOCAL_PHY_CONTROL: 894 return ("LOCAL_PHY_CONTROL"); 895 break; 896 case PMCIN_GET_DEVICE_INFO: 897 return ("GET_DEVICE_INFO"); 898 break; 899 case PMCIN_TWI: 900 return ("TWI"); 901 break; 902 case PMCIN_FW_FLASH_UPDATE: 903 return ("FW_FLASH_UPDATE"); 904 break; 905 case PMCIN_SET_VPD: 906 return ("SET_VPD"); 907 break; 908 case PMCIN_GPIO: 909 return ("GPIO"); 910 break; 911 case PMCIN_SAS_DIAG_MODE_START_END: 912 return ("SAS_DIAG_MODE_START_END"); 913 break; 914 case PMCIN_SAS_DIAG_EXECUTE: 915 return ("SAS_DIAG_EXECUTE"); 916 break; 917 case PMCIN_SAW_HW_EVENT_ACK: 918 return ("SAS_HW_EVENT_ACK"); 919 break; 920 case PMCIN_GET_TIME_STAMP: 921 return ("GET_TIME_STAMP"); 922 break; 923 case PMCIN_PORT_CONTROL: 924 return ("PORT_CONTROL"); 925 break; 926 case PMCIN_GET_NVMD_DATA: 927 return ("GET_NVMD_DATA"); 928 break; 929 case PMCIN_SET_NVMD_DATA: 930 return ("SET_NVMD_DATA"); 931 break; 932 case PMCIN_SET_DEVICE_STATE: 933 return ("SET_DEVICE_STATE"); 934 break; 935 case PMCIN_GET_DEVICE_STATE: 936 return ("GET_DEVICE_STATE"); 937 break; 938 default: 939 return ("UNKNOWN"); 940 break; 941 } 942 } 943 944 static char * 945 outbound_iomb_opcode(uint32_t opcode) 946 { 947 switch (opcode) { 948 case PMCOUT_ECHO: 949 return ("ECHO"); 950 break; 951 case PMCOUT_GET_INFO: 952 return ("GET_INFO"); 953 break; 954 case PMCOUT_GET_VPD: 955 return ("GET_VPD"); 956 break; 957 case PMCOUT_SAS_HW_EVENT: 958 return ("SAS_HW_EVENT"); 959 break; 960 case PMCOUT_SSP_COMPLETION: 961 return ("SSP_COMPLETION"); 962 break; 963 case PMCOUT_SMP_COMPLETION: 964 return ("SMP_COMPLETION"); 965 break; 966 case PMCOUT_LOCAL_PHY_CONTROL: 967 return ("LOCAL_PHY_CONTROL"); 968 break; 969 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT: 970 return ("SAS_ASSISTED_DISCOVERY_SENT"); 971 break; 972 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT: 973 return ("SATA_ASSISTED_DISCOVERY_SENT"); 974 break; 975 case PMCOUT_DEVICE_REGISTRATION: 976 return ("DEVICE_REGISTRATION"); 977 break; 978 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 979 return ("DEREGISTER_DEVICE_HANDLE"); 980 break; 981 case PMCOUT_GET_DEVICE_HANDLE: 982 return ("GET_DEVICE_HANDLE"); 983 break; 984 case PMCOUT_SATA_COMPLETION: 985 return ("SATA_COMPLETION"); 986 break; 987 case PMCOUT_SATA_EVENT: 988 return ("SATA_EVENT"); 989 break; 990 case PMCOUT_SSP_EVENT: 991 return ("SSP_EVENT"); 992 break; 993 case PMCOUT_DEVICE_HANDLE_ARRIVED: 994 return ("DEVICE_HANDLE_ARRIVED"); 995 break; 996 case PMCOUT_SMP_REQUEST_RECEIVED: 997 return ("SMP_REQUEST_RECEIVED"); 998 break; 999 case PMCOUT_SSP_REQUEST_RECEIVED: 1000 return ("SSP_REQUEST_RECEIVED"); 1001 break; 1002 case PMCOUT_DEVICE_INFO: 1003 return ("DEVICE_INFO"); 1004 break; 1005 case PMCOUT_FW_FLASH_UPDATE: 1006 return ("FW_FLASH_UPDATE"); 1007 break; 1008 case PMCOUT_SET_VPD: 1009 return ("SET_VPD"); 1010 break; 1011 case PMCOUT_GPIO: 1012 return ("GPIO"); 1013 break; 1014 case PMCOUT_GPIO_EVENT: 1015 return ("GPIO_EVENT"); 1016 break; 1017 case PMCOUT_GENERAL_EVENT: 1018 return ("GENERAL_EVENT"); 1019 break; 1020 case PMCOUT_TWI: 1021 return ("TWI"); 1022 break; 1023 case PMCOUT_SSP_ABORT: 1024 return ("SSP_ABORT"); 1025 break; 1026 case PMCOUT_SATA_ABORT: 1027 return ("SATA_ABORT"); 1028 break; 1029 case PMCOUT_SAS_DIAG_MODE_START_END: 1030 return ("SAS_DIAG_MODE_START_END"); 1031 break; 1032 case PMCOUT_SAS_DIAG_EXECUTE: 1033 return ("SAS_DIAG_EXECUTE"); 1034 break; 1035 case PMCOUT_GET_TIME_STAMP: 1036 return ("GET_TIME_STAMP"); 1037 break; 1038 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1039 return ("SAS_HW_EVENT_ACK_ACK"); 1040 break; 1041 case PMCOUT_PORT_CONTROL: 1042 return ("PORT_CONTROL"); 1043 break; 1044 case PMCOUT_SKIP_ENTRIES: 1045 return ("SKIP_ENTRIES"); 1046 break; 1047 case PMCOUT_SMP_ABORT: 1048 return ("SMP_ABORT"); 1049 break; 1050 case PMCOUT_GET_NVMD_DATA: 1051 return ("GET_NVMD_DATA"); 1052 break; 1053 case PMCOUT_SET_NVMD_DATA: 1054 return ("SET_NVMD_DATA"); 1055 break; 1056 case PMCOUT_DEVICE_HANDLE_REMOVED: 1057 return ("DEVICE_HANDLE_REMOVED"); 1058 break; 1059 case PMCOUT_SET_DEVICE_STATE: 1060 return ("SET_DEVICE_STATE"); 1061 break; 1062 case PMCOUT_GET_DEVICE_STATE: 1063 return ("GET_DEVICE_STATE"); 1064 break; 1065 case PMCOUT_SET_DEVICE_INFO: 1066 return ("SET_DEVICE_INFO"); 1067 break; 1068 default: 1069 return ("UNKNOWN"); 1070 break; 1071 } 1072 } 1073 1074 static void 1075 dump_one_qentry_outbound(uint32_t *qentryp, int idx) 1076 { 1077 int qeidx; 1078 uint32_t word0 = LE_32(*qentryp); 1079 1080 mdb_printf("Entry #%02d\n", idx); 1081 mdb_inc_indent(2); 1082 1083 mdb_printf("Header: 0x%08x (", word0); 1084 if (word0 & PMCS_IOMB_VALID) { 1085 mdb_printf("VALID, "); 1086 } 1087 if (word0 & PMCS_IOMB_HIPRI) { 1088 mdb_printf("HIPRI, "); 1089 } 1090 mdb_printf("OBID=%d, ", 1091 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1092 mdb_printf("CAT=%s, ", 1093 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1094 mdb_printf("OPCODE=%s", 1095 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1096 mdb_printf(")\n"); 1097 1098 mdb_printf("Remaining Payload:\n"); 1099 1100 mdb_inc_indent(2); 1101 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1102 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1103 } 1104 mdb_printf("\n"); 1105 mdb_dec_indent(4); 1106 } 1107 1108 static void 1109 display_outbound_queues(struct pmcs_hw ss, uint_t verbose) 1110 { 1111 int idx, qidx; 1112 uintptr_t obqp; 1113 uint32_t *cip; 1114 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1115 uint32_t last_consumed, oqpi; 1116 1117 mdb_printf("\n"); 1118 mdb_printf("Outbound Queues\n"); 1119 mdb_printf("---------------\n"); 1120 1121 mdb_inc_indent(2); 1122 1123 for (qidx = 0; qidx < PMCS_NOQ; qidx++) { 1124 obqp = (uintptr_t)ss.oqp[qidx]; 1125 1126 if (obqp == NULL) { 1127 mdb_printf("No outbound queue ptr for queue #%d\n", 1128 qidx); 1129 continue; 1130 } 1131 1132 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx, 1133 obq_type(qidx)); 1134 /* 1135 * Chip is the producer, so read the actual producer index 1136 * and not the driver's version 1137 */ 1138 cip = (uint32_t *)((void *)ss.cip); 1139 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET + 1140 (qidx * 4)) == -1) { 1141 mdb_warn("Couldn't read oqpi\n"); 1142 break; 1143 } 1144 1145 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1146 LE_32(oqpi), ss.oqci[qidx]); 1147 mdb_inc_indent(2); 1148 1149 if (ss.oqci[qidx] == 0) { 1150 last_consumed = ss.ioq_depth - 1; 1151 } else { 1152 last_consumed = ss.oqci[qidx] - 1; 1153 } 1154 1155 1156 if (!verbose) { 1157 mdb_printf("Last processed entry:\n"); 1158 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1159 (obqp + (PMCS_QENTRY_SIZE * last_consumed))) 1160 == -1) { 1161 mdb_warn("Couldn't read queue entry at 0x%p\n", 1162 (obqp + (PMCS_QENTRY_SIZE * 1163 last_consumed))); 1164 break; 1165 } 1166 dump_one_qentry_outbound(qentryp, last_consumed); 1167 mdb_printf("\n"); 1168 mdb_dec_indent(2); 1169 continue; 1170 } 1171 1172 for (idx = 0; idx < ss.ioq_depth; idx++) { 1173 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1174 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1175 mdb_warn("Couldn't read queue entry at 0x%p\n", 1176 (obqp + (PMCS_QENTRY_SIZE * idx))); 1177 break; 1178 } 1179 dump_one_qentry_outbound(qentryp, idx); 1180 } 1181 1182 mdb_printf("\n"); 1183 mdb_dec_indent(2); 1184 } 1185 1186 mdb_dec_indent(2); 1187 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1188 } 1189 1190 static void 1191 dump_one_qentry_inbound(uint32_t *qentryp, int idx) 1192 { 1193 int qeidx; 1194 uint32_t word0 = LE_32(*qentryp); 1195 1196 mdb_printf("Entry #%02d\n", idx); 1197 mdb_inc_indent(2); 1198 1199 mdb_printf("Header: 0x%08x (", word0); 1200 if (word0 & PMCS_IOMB_VALID) { 1201 mdb_printf("VALID, "); 1202 } 1203 if (word0 & PMCS_IOMB_HIPRI) { 1204 mdb_printf("HIPRI, "); 1205 } 1206 mdb_printf("OBID=%d, ", 1207 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1208 mdb_printf("CAT=%s, ", 1209 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1210 mdb_printf("OPCODE=%s", 1211 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1212 mdb_printf(")\n"); 1213 1214 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1))); 1215 mdb_printf("Remaining Payload:\n"); 1216 1217 mdb_inc_indent(2); 1218 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1219 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1220 } 1221 mdb_printf("\n"); 1222 mdb_dec_indent(4); 1223 } 1224 1225 static void 1226 display_inbound_queues(struct pmcs_hw ss, uint_t verbose) 1227 { 1228 int idx, qidx, iqci, last_consumed; 1229 uintptr_t ibqp; 1230 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1231 uint32_t *cip; 1232 1233 mdb_printf("\n"); 1234 mdb_printf("Inbound Queues\n"); 1235 mdb_printf("--------------\n"); 1236 1237 mdb_inc_indent(2); 1238 1239 for (qidx = 0; qidx < PMCS_NIQ; qidx++) { 1240 ibqp = (uintptr_t)ss.iqp[qidx]; 1241 1242 if (ibqp == NULL) { 1243 mdb_printf("No inbound queue ptr for queue #%d\n", 1244 qidx); 1245 continue; 1246 } 1247 1248 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx, 1249 ibq_type(qidx)); 1250 1251 cip = (uint32_t *)((void *)ss.cip); 1252 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) { 1253 mdb_warn("Couldn't read iqci\n"); 1254 break; 1255 } 1256 iqci = LE_32(iqci); 1257 1258 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1259 ss.shadow_iqpi[qidx], iqci); 1260 mdb_inc_indent(2); 1261 1262 if (iqci == 0) { 1263 last_consumed = ss.ioq_depth - 1; 1264 } else { 1265 last_consumed = iqci - 1; 1266 } 1267 1268 if (!verbose) { 1269 mdb_printf("Last processed entry:\n"); 1270 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1271 (ibqp + (PMCS_QENTRY_SIZE * last_consumed))) 1272 == -1) { 1273 mdb_warn("Couldn't read queue entry at 0x%p\n", 1274 (ibqp + (PMCS_QENTRY_SIZE * 1275 last_consumed))); 1276 break; 1277 } 1278 dump_one_qentry_inbound(qentryp, last_consumed); 1279 mdb_printf("\n"); 1280 mdb_dec_indent(2); 1281 continue; 1282 } 1283 1284 for (idx = 0; idx < ss.ioq_depth; idx++) { 1285 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1286 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1287 mdb_warn("Couldn't read queue entry at 0x%p\n", 1288 (ibqp + (PMCS_QENTRY_SIZE * idx))); 1289 break; 1290 } 1291 dump_one_qentry_inbound(qentryp, idx); 1292 } 1293 1294 mdb_printf("\n"); 1295 mdb_dec_indent(2); 1296 } 1297 1298 mdb_dec_indent(2); 1299 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1300 } 1301 1302 static void 1303 display_phy(struct pmcs_phy phy, int verbose, int totals_only) 1304 { 1305 char *dtype, *speed; 1306 char *yes = "Yes"; 1307 char *no = "No"; 1308 char *cfgd = no; 1309 char *apend = no; 1310 char *asent = no; 1311 char *dead = no; 1312 char *changed = no; 1313 1314 switch (phy.dtype) { 1315 case NOTHING: 1316 dtype = "None"; 1317 break; 1318 case SATA: 1319 dtype = "SATA"; 1320 if (phy.configured) { 1321 ++sata_phys; 1322 } 1323 break; 1324 case SAS: 1325 dtype = "SAS"; 1326 if (phy.configured) { 1327 ++sas_phys; 1328 } 1329 break; 1330 case EXPANDER: 1331 dtype = "EXP"; 1332 if (phy.configured) { 1333 ++exp_phys; 1334 } 1335 break; 1336 } 1337 1338 if (phy.dtype == NOTHING) { 1339 empty_phys++; 1340 } else if ((phy.dtype == EXPANDER) && phy.configured) { 1341 num_expanders++; 1342 } 1343 1344 if (totals_only) { 1345 return; 1346 } 1347 1348 switch (phy.link_rate) { 1349 case SAS_LINK_RATE_1_5GBIT: 1350 speed = "1.5Gb/s"; 1351 break; 1352 case SAS_LINK_RATE_3GBIT: 1353 speed = "3 Gb/s"; 1354 break; 1355 case SAS_LINK_RATE_6GBIT: 1356 speed = "6 Gb/s"; 1357 break; 1358 default: 1359 speed = "N/A"; 1360 break; 1361 } 1362 1363 if ((phy.dtype != NOTHING) || verbose) { 1364 print_sas_address(&phy); 1365 1366 if (phy.device_id != PMCS_INVALID_DEVICE_ID) { 1367 mdb_printf(" %3d %4d %6s %4s ", 1368 phy.device_id, phy.phynum, speed, dtype); 1369 } else { 1370 mdb_printf(" N/A %4d %6s %4s ", 1371 phy.phynum, speed, dtype); 1372 } 1373 1374 if (verbose) { 1375 if (phy.abort_sent) { 1376 asent = yes; 1377 } 1378 if (phy.abort_pending) { 1379 apend = yes; 1380 } 1381 if (phy.configured) { 1382 cfgd = yes; 1383 } 1384 if (phy.dead) { 1385 dead = yes; 1386 } 1387 if (phy.changed) { 1388 changed = yes; 1389 } 1390 1391 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d " 1392 "0x%p ", cfgd, apend, asent, 1393 changed, dead, phy.ref_count, phy.phy_lock); 1394 } 1395 1396 mdb_printf("Path: %s\n", phy.path); 1397 } 1398 } 1399 1400 static void 1401 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level, 1402 int totals_only) 1403 { 1404 pmcs_phy_t phy; 1405 pmcs_phy_t *pphy = parent; 1406 1407 mdb_inc_indent(3); 1408 1409 if (parent == NULL) { 1410 pphy = (pmcs_phy_t *)ss.root_phys; 1411 } else { 1412 pphy = (pmcs_phy_t *)parent; 1413 } 1414 1415 if (level == 0) { 1416 sas_phys = 0; 1417 sata_phys = 0; 1418 exp_phys = 0; 1419 num_expanders = 0; 1420 empty_phys = 0; 1421 } 1422 1423 if (!totals_only) { 1424 if (level == 0) { 1425 mdb_printf("PHY information\n"); 1426 } 1427 mdb_printf("--------\n"); 1428 mdb_printf("Level %2d\n", level); 1429 mdb_printf("--------\n"); 1430 mdb_printf("SAS Address Hdl Phy# Speed Type "); 1431 1432 if (verbose) { 1433 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref Lock\n"); 1434 } else { 1435 mdb_printf("\n"); 1436 } 1437 } 1438 1439 while (pphy) { 1440 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) { 1441 NOREAD(pmcs_phy_t, phy); 1442 break; 1443 } 1444 1445 display_phy(phy, verbose, totals_only); 1446 1447 if (phy.children) { 1448 display_phys(ss, verbose, phy.children, level + 1, 1449 totals_only); 1450 if (!totals_only) { 1451 mdb_printf("\n"); 1452 } 1453 } 1454 1455 pphy = phy.sibling; 1456 } 1457 1458 mdb_dec_indent(3); 1459 1460 if (level == 0) { 1461 if (verbose) { 1462 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) " 1463 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:", 1464 (sas_phys + sata_phys + num_expanders), 1465 sas_phys, sata_phys, num_expanders, 1466 (exp_phys - num_expanders), empty_phys); 1467 } else { 1468 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 1469 "Occupied PHYs:", 1470 (sas_phys + sata_phys + num_expanders), 1471 sas_phys, sata_phys, num_expanders); 1472 } 1473 } 1474 } 1475 1476 /* 1477 * filter is used to indicate whether we are filtering log messages based 1478 * on "instance". The other filtering (based on options) depends on the 1479 * values that are passed in for "sas_addr" and "phy_path". 1480 * 1481 * MAX_INST_STRLEN is the largest string size from which we will attempt 1482 * to convert to an instance number. The string will be formed up as 1483 * "0t<inst>\0" so that mdb_strtoull can parse it properly. 1484 */ 1485 #define MAX_INST_STRLEN 8 1486 1487 static int 1488 pmcs_dump_tracelog(boolean_t filter, int instance, const char *phy_path, 1489 uint64_t sas_address) 1490 { 1491 pmcs_tbuf_t *tbuf_addr; 1492 uint_t tbuf_idx; 1493 pmcs_tbuf_t tbuf; 1494 boolean_t wrap, elem_filtered; 1495 uint_t start_idx, elems_to_print, idx, tbuf_num_elems; 1496 char *bufp; 1497 char elem_inst[MAX_INST_STRLEN], ei_idx; 1498 uint64_t sas_addr; 1499 uint8_t *sas_addressp; 1500 1501 /* Get the address of the first element */ 1502 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) { 1503 mdb_warn("can't read pmcs_tbuf"); 1504 return (DCMD_ERR); 1505 } 1506 1507 /* Get the total number */ 1508 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) { 1509 mdb_warn("can't read pmcs_tbuf_num_elems"); 1510 return (DCMD_ERR); 1511 } 1512 1513 /* Get the current index */ 1514 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) { 1515 mdb_warn("can't read pmcs_tbuf_idx"); 1516 return (DCMD_ERR); 1517 } 1518 1519 /* Indicator as to whether the buffer has wrapped */ 1520 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) { 1521 mdb_warn("can't read pmcs_tbuf_wrap"); 1522 return (DCMD_ERR); 1523 } 1524 1525 /* 1526 * On little-endian systems, the SAS address passed in will be 1527 * byte swapped. Take care of that here. 1528 */ 1529 #if defined(_LITTLE_ENDIAN) 1530 sas_addr = ((sas_address << 56) | 1531 ((sas_address << 40) & 0xff000000000000ULL) | 1532 ((sas_address << 24) & 0xff0000000000ULL) | 1533 ((sas_address << 8) & 0xff00000000ULL) | 1534 ((sas_address >> 8) & 0xff000000ULL) | 1535 ((sas_address >> 24) & 0xff0000ULL) | 1536 ((sas_address >> 40) & 0xff00ULL) | 1537 (sas_address >> 56)); 1538 #else 1539 sas_addr = sas_address; 1540 #endif 1541 sas_addressp = (uint8_t *)&sas_addr; 1542 1543 /* Figure out where we start and stop */ 1544 if (wrap) { 1545 start_idx = tbuf_idx; 1546 elems_to_print = tbuf_num_elems; 1547 } else { 1548 start_idx = 0; 1549 elems_to_print = tbuf_idx; 1550 } 1551 1552 idx = start_idx; 1553 1554 /* Dump the buffer contents */ 1555 while (elems_to_print != 0) { 1556 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx)) 1557 == -1) { 1558 NOREAD(tbuf, (tbuf_addr + idx)); 1559 return (DCMD_ERR); 1560 } 1561 1562 /* 1563 * Check for filtering on HBA instance 1564 */ 1565 elem_filtered = B_FALSE; 1566 1567 if (filter) { 1568 bufp = tbuf.buf; 1569 /* Skip the driver name */ 1570 while (*bufp < '0' || *bufp > '9') { 1571 bufp++; 1572 } 1573 1574 ei_idx = 0; 1575 elem_inst[ei_idx++] = '0'; 1576 elem_inst[ei_idx++] = 't'; 1577 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) { 1578 elem_inst[ei_idx++] = *bufp; 1579 bufp++; 1580 } 1581 elem_inst[ei_idx] = 0; 1582 1583 /* Get the instance */ 1584 if ((int)mdb_strtoull(elem_inst) != instance) { 1585 elem_filtered = B_TRUE; 1586 } 1587 } 1588 1589 if (!elem_filtered && (phy_path || sas_address)) { 1590 /* 1591 * This message is not being filtered by HBA instance. 1592 * Now check to see if we're filtering based on 1593 * PHY path or SAS address. 1594 * Filtering is an "OR" operation. So, if any of the 1595 * criteria matches, this message will be printed. 1596 */ 1597 elem_filtered = B_TRUE; 1598 1599 if (phy_path != NULL) { 1600 if (strncmp(phy_path, tbuf.phy_path, 1601 PMCS_TBUF_UA_MAX_SIZE) == 0) { 1602 elem_filtered = B_FALSE; 1603 } 1604 } 1605 if (sas_address != 0) { 1606 if (memcmp(sas_addressp, tbuf.phy_sas_address, 1607 8) == 0) { 1608 elem_filtered = B_FALSE; 1609 } 1610 } 1611 } 1612 1613 if (!elem_filtered) { 1614 mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf); 1615 } 1616 1617 --elems_to_print; 1618 if (++idx == tbuf_num_elems) { 1619 idx = 0; 1620 } 1621 } 1622 1623 return (DCMD_OK); 1624 } 1625 1626 /* 1627 * Walkers 1628 */ 1629 static int 1630 targets_walk_i(mdb_walk_state_t *wsp) 1631 { 1632 if (wsp->walk_addr == NULL) { 1633 mdb_warn("Can not perform global walk\n"); 1634 return (WALK_ERR); 1635 } 1636 1637 /* 1638 * Address provided belongs to HBA softstate. Get the targets pointer 1639 * to begin the walk. 1640 */ 1641 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1642 sizeof (pmcs_hw_t)) { 1643 mdb_warn("Unable to read HBA softstate\n"); 1644 return (WALK_ERR); 1645 } 1646 1647 if (targets == NULL) { 1648 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP); 1649 } 1650 1651 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) { 1652 NOREAD(targets, ss.targets); 1653 return (WALK_ERR); 1654 } 1655 1656 target_idx = 0; 1657 wsp->walk_addr = (uintptr_t)(targets[0]); 1658 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP); 1659 1660 return (WALK_NEXT); 1661 } 1662 1663 static int 1664 targets_walk_s(mdb_walk_state_t *wsp) 1665 { 1666 int status; 1667 1668 if (target_idx == ss.max_dev) { 1669 return (WALK_DONE); 1670 } 1671 1672 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t), 1673 wsp->walk_addr) == -1) { 1674 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr); 1675 return (WALK_DONE); 1676 } 1677 1678 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1679 wsp->walk_cbdata); 1680 1681 do { 1682 wsp->walk_addr = (uintptr_t)(targets[++target_idx]); 1683 } while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev)); 1684 1685 if (target_idx == ss.max_dev) { 1686 return (WALK_DONE); 1687 } 1688 1689 return (status); 1690 } 1691 1692 static void 1693 targets_walk_f(mdb_walk_state_t *wsp) 1694 { 1695 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t)); 1696 } 1697 1698 1699 static pmcs_phy_t * 1700 pmcs_next_sibling(pmcs_phy_t *phyp) 1701 { 1702 pmcs_phy_t parent; 1703 1704 /* 1705 * First, if this is a root PHY, there are no more siblings 1706 */ 1707 if (phyp->level == 0) { 1708 return (NULL); 1709 } 1710 1711 /* 1712 * Otherwise, next sibling is the parent's sibling 1713 */ 1714 while (phyp->level > 0) { 1715 if (mdb_vread(&parent, sizeof (pmcs_phy_t), 1716 (uintptr_t)phyp->parent) == -1) { 1717 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p", 1718 (void *)phyp->parent); 1719 return (NULL); 1720 } 1721 1722 if (parent.sibling != NULL) { 1723 break; 1724 } 1725 1726 phyp = phyp->parent; 1727 } 1728 1729 return (parent.sibling); 1730 } 1731 1732 static int 1733 phy_walk_i(mdb_walk_state_t *wsp) 1734 { 1735 if (wsp->walk_addr == NULL) { 1736 mdb_warn("Can not perform global walk\n"); 1737 return (WALK_ERR); 1738 } 1739 1740 /* 1741 * Address provided belongs to HBA softstate. Get the targets pointer 1742 * to begin the walk. 1743 */ 1744 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1745 sizeof (pmcs_hw_t)) { 1746 mdb_warn("Unable to read HBA softstate\n"); 1747 return (WALK_ERR); 1748 } 1749 1750 wsp->walk_addr = (uintptr_t)(ss.root_phys); 1751 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 1752 1753 return (WALK_NEXT); 1754 } 1755 1756 static int 1757 phy_walk_s(mdb_walk_state_t *wsp) 1758 { 1759 pmcs_phy_t *phyp, *nphyp; 1760 int status; 1761 1762 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 1763 wsp->walk_addr) == -1) { 1764 mdb_warn("phy_walk_s: Failed to read PHY at %p", 1765 (void *)wsp->walk_addr); 1766 return (WALK_DONE); 1767 } 1768 1769 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1770 wsp->walk_cbdata); 1771 1772 phyp = (pmcs_phy_t *)wsp->walk_data; 1773 if (phyp->children) { 1774 wsp->walk_addr = (uintptr_t)(phyp->children); 1775 } else { 1776 wsp->walk_addr = (uintptr_t)(phyp->sibling); 1777 } 1778 1779 if (wsp->walk_addr == NULL) { 1780 /* 1781 * We reached the end of this sibling list. Trudge back up 1782 * to the parent and find the next sibling after the expander 1783 * we just finished traversing, if there is one. 1784 */ 1785 nphyp = pmcs_next_sibling(phyp); 1786 1787 if (nphyp == NULL) { 1788 return (WALK_DONE); 1789 } 1790 1791 wsp->walk_addr = (uintptr_t)nphyp; 1792 } 1793 1794 return (status); 1795 } 1796 1797 static void 1798 phy_walk_f(mdb_walk_state_t *wsp) 1799 { 1800 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 1801 } 1802 1803 static void 1804 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum, 1805 uintmax_t tag_type) 1806 { 1807 int idx; 1808 pmcwork_t work, *wp = &work; 1809 uintptr_t _wp; 1810 boolean_t printed_header = B_FALSE; 1811 uint32_t mask, mask_val, match_val; 1812 char *match_type; 1813 1814 if (index != UINT_MAX) { 1815 match_type = "index"; 1816 mask = PMCS_TAG_INDEX_MASK; 1817 mask_val = index << PMCS_TAG_INDEX_SHIFT; 1818 match_val = index; 1819 } else if (snum != UINT_MAX) { 1820 match_type = "serial number"; 1821 mask = PMCS_TAG_SERNO_MASK; 1822 mask_val = snum << PMCS_TAG_SERNO_SHIFT; 1823 match_val = snum; 1824 } else { 1825 switch (tag_type) { 1826 case PMCS_TAG_TYPE_NONE: 1827 match_type = "tag type NONE"; 1828 break; 1829 case PMCS_TAG_TYPE_CBACK: 1830 match_type = "tag type CBACK"; 1831 break; 1832 case PMCS_TAG_TYPE_WAIT: 1833 match_type = "tag type WAIT"; 1834 break; 1835 } 1836 mask = PMCS_TAG_TYPE_MASK; 1837 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT; 1838 match_val = tag_type; 1839 } 1840 1841 _wp = (uintptr_t)ss.work; 1842 1843 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 1844 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 1845 NOREAD(pmcwork_t, _wp); 1846 continue; 1847 } 1848 1849 if ((work.htag & mask) != mask_val) { 1850 continue; 1851 } 1852 1853 if (printed_header == B_FALSE) { 1854 if (tag_type) { 1855 mdb_printf("\nWork structures matching %s\n\n", 1856 match_type, match_val); 1857 } else { 1858 mdb_printf("\nWork structures matching %s of " 1859 "0x%x\n\n", match_type, match_val); 1860 } 1861 mdb_printf("%8s %10s %20s %8s %8s O D\n", 1862 "HTag", "State", "Phy Path", "Target", "Timer"); 1863 printed_header = B_TRUE; 1864 } 1865 1866 display_one_work(wp, 0, 0); 1867 } 1868 1869 if (!printed_header) { 1870 mdb_printf("No work structure matches found\n"); 1871 } 1872 } 1873 1874 static int 1875 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1876 { 1877 struct pmcs_hw ss; 1878 uintmax_t tag_type = UINT_MAX; 1879 uintmax_t snum = UINT_MAX; 1880 uintmax_t index = UINT_MAX; 1881 int args = 0; 1882 void *pmcs_state; 1883 char *state_str; 1884 struct dev_info dip; 1885 1886 if (!(flags & DCMD_ADDRSPEC)) { 1887 pmcs_state = NULL; 1888 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 1889 mdb_warn("can't read pmcs_softc_state"); 1890 return (DCMD_ERR); 1891 } 1892 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc, 1893 argv, (uintptr_t)pmcs_state) == -1) { 1894 mdb_warn("mdb_pwalk_dcmd failed"); 1895 return (DCMD_ERR); 1896 } 1897 return (DCMD_OK); 1898 } 1899 1900 if (mdb_getopts(argc, argv, 1901 'i', MDB_OPT_UINT64, &index, 1902 's', MDB_OPT_UINT64, &snum, 1903 't', MDB_OPT_UINT64, &tag_type) != argc) 1904 return (DCMD_USAGE); 1905 1906 /* 1907 * Count the number of supplied options and make sure they are 1908 * within appropriate ranges. If they're set to UINT_MAX, that means 1909 * they were not supplied, in which case reset them to 0. 1910 */ 1911 if (index != UINT_MAX) { 1912 args++; 1913 if (index > PMCS_TAG_INDEX_MASK) { 1914 mdb_warn("Index is out of range\n"); 1915 return (DCMD_USAGE); 1916 } 1917 } 1918 1919 if (tag_type != UINT_MAX) { 1920 args++; 1921 switch (tag_type) { 1922 case PMCS_TAG_TYPE_NONE: 1923 case PMCS_TAG_TYPE_CBACK: 1924 case PMCS_TAG_TYPE_WAIT: 1925 break; 1926 default: 1927 mdb_warn("Invalid tag type\n"); 1928 return (DCMD_USAGE); 1929 } 1930 } 1931 1932 if (snum != UINT_MAX) { 1933 args++; 1934 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) { 1935 mdb_warn("Serial number is out of range\n"); 1936 return (DCMD_USAGE); 1937 } 1938 } 1939 1940 /* 1941 * Make sure 1 and only 1 option is specified 1942 */ 1943 if ((args == 0) || (args > 1)) { 1944 mdb_warn("Exactly one of -i, -s and -t must be specified\n"); 1945 return (DCMD_USAGE); 1946 } 1947 1948 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 1949 NOREAD(pmcs_hw_t, addr); 1950 return (DCMD_ERR); 1951 } 1952 1953 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 1954 NOREAD(pmcs_hw_t, addr); 1955 return (DCMD_ERR); 1956 } 1957 1958 /* processing completed */ 1959 1960 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 1961 (flags & DCMD_LOOPFIRST)) { 1962 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 1963 mdb_printf("\n"); 1964 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 1965 "Address", "State", "Inst", "DIP"); 1966 mdb_printf("=================================" 1967 "============================================\n"); 1968 } 1969 1970 switch (ss.state) { 1971 case STATE_NIL: 1972 state_str = "Invalid"; 1973 break; 1974 case STATE_PROBING: 1975 state_str = "Probing"; 1976 break; 1977 case STATE_RUNNING: 1978 state_str = "Running"; 1979 break; 1980 case STATE_UNPROBING: 1981 state_str = "Unprobing"; 1982 break; 1983 case STATE_DEAD: 1984 state_str = "Dead"; 1985 break; 1986 } 1987 1988 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 1989 state_str, dip.devi_instance, ss.blocked, ss.configuring, 1990 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 1991 mdb_printf("\n"); 1992 1993 mdb_inc_indent(4); 1994 display_matching_work(ss, index, snum, tag_type); 1995 mdb_dec_indent(4); 1996 mdb_printf("\n"); 1997 1998 return (DCMD_OK); 1999 } 2000 2001 static int 2002 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2003 { 2004 void *pmcs_state; 2005 struct pmcs_hw ss; 2006 struct dev_info dip; 2007 const char *match_phy_path = NULL; 2008 uint64_t match_sas_address = 0; 2009 2010 if (!(flags & DCMD_ADDRSPEC)) { 2011 pmcs_state = NULL; 2012 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2013 mdb_warn("can't read pmcs_softc_state"); 2014 return (DCMD_ERR); 2015 } 2016 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc, 2017 argv, (uintptr_t)pmcs_state) == -1) { 2018 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2019 return (DCMD_ERR); 2020 } 2021 return (DCMD_OK); 2022 } 2023 2024 if (mdb_getopts(argc, argv, 2025 'p', MDB_OPT_STR, &match_phy_path, 2026 's', MDB_OPT_UINT64, &match_sas_address, 2027 NULL) != argc) { 2028 return (DCMD_USAGE); 2029 } 2030 2031 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2032 NOREAD(pmcs_hw_t, addr); 2033 return (DCMD_ERR); 2034 } 2035 2036 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2037 NOREAD(pmcs_hw_t, addr); 2038 return (DCMD_ERR); 2039 } 2040 2041 if (!(flags & DCMD_LOOP)) { 2042 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance, 2043 match_phy_path, match_sas_address)); 2044 } else if (flags & DCMD_LOOPFIRST) { 2045 return (pmcs_dump_tracelog(B_FALSE, 0, match_phy_path, 2046 match_sas_address)); 2047 } else { 2048 return (DCMD_OK); 2049 } 2050 } 2051 2052 static int 2053 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2054 { 2055 struct pmcs_hw ss; 2056 uint_t verbose = FALSE; 2057 uint_t phy_info = FALSE; 2058 uint_t hw_info = FALSE; 2059 uint_t target_info = FALSE; 2060 uint_t work_info = FALSE; 2061 uint_t ic_info = FALSE; 2062 uint_t iport_info = FALSE; 2063 uint_t waitqs_info = FALSE; 2064 uint_t ibq = FALSE; 2065 uint_t obq = FALSE; 2066 uint_t tgt_phy_count = FALSE; 2067 uint_t compq = FALSE; 2068 uint_t unconfigured = FALSE; 2069 int rv = DCMD_OK; 2070 void *pmcs_state; 2071 char *state_str; 2072 struct dev_info dip; 2073 2074 if (!(flags & DCMD_ADDRSPEC)) { 2075 pmcs_state = NULL; 2076 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2077 mdb_warn("can't read pmcs_softc_state"); 2078 return (DCMD_ERR); 2079 } 2080 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 2081 (uintptr_t)pmcs_state) == -1) { 2082 mdb_warn("mdb_pwalk_dcmd failed"); 2083 return (DCMD_ERR); 2084 } 2085 return (DCMD_OK); 2086 } 2087 2088 if (mdb_getopts(argc, argv, 2089 'c', MDB_OPT_SETBITS, TRUE, &compq, 2090 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 2091 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 2092 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 2093 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 2094 'q', MDB_OPT_SETBITS, TRUE, &ibq, 2095 'Q', MDB_OPT_SETBITS, TRUE, &obq, 2096 't', MDB_OPT_SETBITS, TRUE, &target_info, 2097 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 2098 'u', MDB_OPT_SETBITS, TRUE, &unconfigured, 2099 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2100 'w', MDB_OPT_SETBITS, TRUE, &work_info, 2101 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 2102 NULL) != argc) 2103 return (DCMD_USAGE); 2104 2105 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2106 NOREAD(pmcs_hw_t, addr); 2107 return (DCMD_ERR); 2108 } 2109 2110 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2111 NOREAD(pmcs_hw_t, addr); 2112 return (DCMD_ERR); 2113 } 2114 2115 /* processing completed */ 2116 2117 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2118 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 2119 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq || 2120 unconfigured) { 2121 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2122 mdb_printf("\n"); 2123 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2124 "Address", "State", "Inst", "DIP"); 2125 mdb_printf("=================================" 2126 "============================================\n"); 2127 } 2128 2129 switch (ss.state) { 2130 case STATE_NIL: 2131 state_str = "Invalid"; 2132 break; 2133 case STATE_PROBING: 2134 state_str = "Probing"; 2135 break; 2136 case STATE_RUNNING: 2137 state_str = "Running"; 2138 break; 2139 case STATE_UNPROBING: 2140 state_str = "Unprobing"; 2141 break; 2142 case STATE_DEAD: 2143 state_str = "Dead"; 2144 break; 2145 } 2146 2147 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2148 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2149 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2150 mdb_printf("\n"); 2151 2152 mdb_inc_indent(4); 2153 2154 if (waitqs_info) 2155 display_waitqs(ss, verbose); 2156 2157 if (hw_info) 2158 display_hwinfo(ss, verbose); 2159 2160 if (phy_info || tgt_phy_count) 2161 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 2162 2163 if (target_info || tgt_phy_count) 2164 display_targets(ss, verbose, tgt_phy_count); 2165 2166 if (work_info) 2167 display_work(ss, verbose); 2168 2169 if (ic_info) 2170 display_ic(ss, verbose); 2171 2172 if (ibq) 2173 display_inbound_queues(ss, verbose); 2174 2175 if (obq) 2176 display_outbound_queues(ss, verbose); 2177 2178 if (iport_info) 2179 display_iport(ss, addr, verbose); 2180 2181 if (compq) 2182 display_completion_queue(ss); 2183 2184 if (unconfigured) 2185 display_unconfigured_targets(addr); 2186 2187 mdb_dec_indent(4); 2188 2189 return (rv); 2190 } 2191 2192 void 2193 pmcs_help() 2194 { 2195 mdb_printf("Prints summary information about each pmcs instance.\n" 2196 " -c: Dump the completion queue\n" 2197 " -h: Print more detailed hardware information\n" 2198 " -i: Print interrupt coalescing information\n" 2199 " -I: Print information about each iport\n" 2200 " -l: Dump the trace log (cannot be used with other options)\n" 2201 " -p: Print information about each attached PHY\n" 2202 " -q: Dump inbound queues\n" 2203 " -Q: Dump outbound queues\n" 2204 " -t: Print information about each configured target\n" 2205 " -T: Print target and PHY count summary\n" 2206 " -u: Show SAS address of all unconfigured targets\n" 2207 " -w: Dump work structures\n" 2208 " -W: List pmcs cmds waiting on various queues\n" 2209 " -v: Add verbosity to the above options\n"); 2210 } 2211 2212 void 2213 pmcs_log_help() 2214 { 2215 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n" 2216 " -p PHY_PATH: Dump messages matching PHY_PATH\n" 2217 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n" 2218 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n" 2219 " SAS_ADDRESS can be found with ::pmcs -t " 2220 "(e.g. 5000c5000358c221)\n"); 2221 } 2222 void 2223 pmcs_tag_help() 2224 { 2225 mdb_printf("Print all work structures by matching the tag.\n" 2226 " -i index: Match tag index (0x000 - 0xfff)\n" 2227 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n" 2228 " -t tagtype: Match tag type [NONE(1), CBACK(2), " 2229 "WAIT(3)]\n"); 2230 } 2231 2232 static const mdb_dcmd_t dcmds[] = { 2233 { "pmcs", "?[-chiIpQqtTuwWv]", "print pmcs information", 2234 pmcs_dcmd, pmcs_help 2235 }, 2236 { "pmcs_log", 2237 "?[-p PHY_PATH | -s SAS_ADDRESS]", 2238 "dump pmcs log file", pmcs_log, pmcs_log_help 2239 }, 2240 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]", 2241 "Find work structures by tag type, serial number or index", 2242 pmcs_tag, pmcs_tag_help 2243 }, 2244 { NULL } 2245 }; 2246 2247 static const mdb_walker_t walkers[] = { 2248 { "pmcs_targets", "walk target structures", 2249 targets_walk_i, targets_walk_s, targets_walk_f }, 2250 { "pmcs_phys", "walk PHY structures", 2251 phy_walk_i, phy_walk_s, phy_walk_f }, 2252 { NULL } 2253 }; 2254 2255 static const mdb_modinfo_t modinfo = { 2256 MDB_API_VERSION, dcmds, walkers 2257 }; 2258 2259 const mdb_modinfo_t * 2260 _mdb_init(void) 2261 { 2262 return (&modinfo); 2263 } 2264