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