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 phyp = phyp->parent; 2113 } 2114 2115 return (parent.sibling); 2116 } 2117 2118 static int 2119 phy_walk_i(mdb_walk_state_t *wsp) 2120 { 2121 if (wsp->walk_addr == NULL) { 2122 mdb_warn("Can not perform global walk\n"); 2123 return (WALK_ERR); 2124 } 2125 2126 /* 2127 * Address provided belongs to HBA softstate. Get the targets pointer 2128 * to begin the walk. 2129 */ 2130 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 2131 sizeof (pmcs_hw_t)) { 2132 mdb_warn("Unable to read HBA softstate\n"); 2133 return (WALK_ERR); 2134 } 2135 2136 wsp->walk_addr = (uintptr_t)(ss.root_phys); 2137 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 2138 2139 return (WALK_NEXT); 2140 } 2141 2142 static int 2143 phy_walk_s(mdb_walk_state_t *wsp) 2144 { 2145 pmcs_phy_t *phyp, *nphyp; 2146 int status; 2147 2148 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 2149 wsp->walk_addr) == -1) { 2150 mdb_warn("phy_walk_s: Failed to read PHY at %p", 2151 (void *)wsp->walk_addr); 2152 return (WALK_DONE); 2153 } 2154 2155 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 2156 wsp->walk_cbdata); 2157 2158 phyp = (pmcs_phy_t *)wsp->walk_data; 2159 if (phyp->children) { 2160 wsp->walk_addr = (uintptr_t)(phyp->children); 2161 } else { 2162 wsp->walk_addr = (uintptr_t)(phyp->sibling); 2163 } 2164 2165 if (wsp->walk_addr == NULL) { 2166 /* 2167 * We reached the end of this sibling list. Trudge back up 2168 * to the parent and find the next sibling after the expander 2169 * we just finished traversing, if there is one. 2170 */ 2171 nphyp = pmcs_next_sibling(phyp); 2172 2173 if (nphyp == NULL) { 2174 return (WALK_DONE); 2175 } 2176 2177 wsp->walk_addr = (uintptr_t)nphyp; 2178 } 2179 2180 return (status); 2181 } 2182 2183 static void 2184 phy_walk_f(mdb_walk_state_t *wsp) 2185 { 2186 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 2187 } 2188 2189 static void 2190 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum, 2191 uintmax_t tag_type) 2192 { 2193 int idx; 2194 pmcwork_t work, *wp = &work; 2195 uintptr_t _wp; 2196 boolean_t printed_header = B_FALSE; 2197 uint32_t mask, mask_val, match_val; 2198 char *match_type; 2199 2200 if (index != UINT_MAX) { 2201 match_type = "index"; 2202 mask = PMCS_TAG_INDEX_MASK; 2203 mask_val = index << PMCS_TAG_INDEX_SHIFT; 2204 match_val = index; 2205 } else if (snum != UINT_MAX) { 2206 match_type = "serial number"; 2207 mask = PMCS_TAG_SERNO_MASK; 2208 mask_val = snum << PMCS_TAG_SERNO_SHIFT; 2209 match_val = snum; 2210 } else { 2211 switch (tag_type) { 2212 case PMCS_TAG_TYPE_NONE: 2213 match_type = "tag type NONE"; 2214 break; 2215 case PMCS_TAG_TYPE_CBACK: 2216 match_type = "tag type CBACK"; 2217 break; 2218 case PMCS_TAG_TYPE_WAIT: 2219 match_type = "tag type WAIT"; 2220 break; 2221 } 2222 mask = PMCS_TAG_TYPE_MASK; 2223 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT; 2224 match_val = tag_type; 2225 } 2226 2227 _wp = (uintptr_t)ss.work; 2228 2229 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 2230 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 2231 NOREAD(pmcwork_t, _wp); 2232 continue; 2233 } 2234 2235 if ((work.htag & mask) != mask_val) { 2236 continue; 2237 } 2238 2239 if (printed_header == B_FALSE) { 2240 if (tag_type) { 2241 mdb_printf("\nWork structures matching %s\n\n", 2242 match_type, match_val); 2243 } else { 2244 mdb_printf("\nWork structures matching %s of " 2245 "0x%x\n\n", match_type, match_val); 2246 } 2247 mdb_printf("%8s %10s %20s %8s %8s O D\n", 2248 "HTag", "State", "Phy Path", "Target", "Timer"); 2249 printed_header = B_TRUE; 2250 } 2251 2252 display_one_work(wp, 0, 0); 2253 } 2254 2255 if (!printed_header) { 2256 mdb_printf("No work structure matches found\n"); 2257 } 2258 } 2259 2260 static int 2261 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2262 { 2263 struct pmcs_hw ss; 2264 uintmax_t tag_type = UINT_MAX; 2265 uintmax_t snum = UINT_MAX; 2266 uintmax_t index = UINT_MAX; 2267 int args = 0; 2268 void *pmcs_state; 2269 char *state_str; 2270 struct dev_info dip; 2271 2272 if (!(flags & DCMD_ADDRSPEC)) { 2273 pmcs_state = NULL; 2274 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2275 mdb_warn("can't read pmcs_softc_state"); 2276 return (DCMD_ERR); 2277 } 2278 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc, 2279 argv, (uintptr_t)pmcs_state) == -1) { 2280 mdb_warn("mdb_pwalk_dcmd failed"); 2281 return (DCMD_ERR); 2282 } 2283 return (DCMD_OK); 2284 } 2285 2286 if (mdb_getopts(argc, argv, 2287 'i', MDB_OPT_UINT64, &index, 2288 's', MDB_OPT_UINT64, &snum, 2289 't', MDB_OPT_UINT64, &tag_type) != argc) 2290 return (DCMD_USAGE); 2291 2292 /* 2293 * Count the number of supplied options and make sure they are 2294 * within appropriate ranges. If they're set to UINT_MAX, that means 2295 * they were not supplied, in which case reset them to 0. 2296 */ 2297 if (index != UINT_MAX) { 2298 args++; 2299 if (index > PMCS_TAG_INDEX_MASK) { 2300 mdb_warn("Index is out of range\n"); 2301 return (DCMD_USAGE); 2302 } 2303 } 2304 2305 if (tag_type != UINT_MAX) { 2306 args++; 2307 switch (tag_type) { 2308 case PMCS_TAG_TYPE_NONE: 2309 case PMCS_TAG_TYPE_CBACK: 2310 case PMCS_TAG_TYPE_WAIT: 2311 break; 2312 default: 2313 mdb_warn("Invalid tag type\n"); 2314 return (DCMD_USAGE); 2315 } 2316 } 2317 2318 if (snum != UINT_MAX) { 2319 args++; 2320 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) { 2321 mdb_warn("Serial number is out of range\n"); 2322 return (DCMD_USAGE); 2323 } 2324 } 2325 2326 /* 2327 * Make sure 1 and only 1 option is specified 2328 */ 2329 if ((args == 0) || (args > 1)) { 2330 mdb_warn("Exactly one of -i, -s and -t must be specified\n"); 2331 return (DCMD_USAGE); 2332 } 2333 2334 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2335 NOREAD(pmcs_hw_t, addr); 2336 return (DCMD_ERR); 2337 } 2338 2339 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2340 NOREAD(pmcs_hw_t, addr); 2341 return (DCMD_ERR); 2342 } 2343 2344 /* processing completed */ 2345 2346 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2347 (flags & DCMD_LOOPFIRST)) { 2348 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2349 mdb_printf("\n"); 2350 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2351 "Address", "State", "Inst", "DIP"); 2352 mdb_printf("=================================" 2353 "============================================\n"); 2354 } 2355 2356 switch (ss.state) { 2357 case STATE_NIL: 2358 state_str = "Invalid"; 2359 break; 2360 case STATE_PROBING: 2361 state_str = "Probing"; 2362 break; 2363 case STATE_RUNNING: 2364 state_str = "Running"; 2365 break; 2366 case STATE_UNPROBING: 2367 state_str = "Unprobing"; 2368 break; 2369 case STATE_DEAD: 2370 state_str = "Dead"; 2371 break; 2372 case STATE_IN_RESET: 2373 state_str = "In Reset"; 2374 break; 2375 } 2376 2377 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2378 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2379 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2380 mdb_printf("\n"); 2381 2382 mdb_inc_indent(4); 2383 display_matching_work(ss, index, snum, tag_type); 2384 mdb_dec_indent(4); 2385 mdb_printf("\n"); 2386 2387 return (DCMD_OK); 2388 } 2389 2390 #ifndef _KMDB 2391 static int 2392 pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile) 2393 { 2394 uint8_t *fwlogp; 2395 int ofilefd = -1; 2396 char ofilename[MAXPATHLEN]; 2397 int rval = DCMD_OK; 2398 2399 if (ss->fwlogp == NULL) { 2400 mdb_warn("Firmware event log disabled for instance %d", 2401 instance); 2402 return (DCMD_OK); 2403 } 2404 2405 if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) > 2406 MAXPATHLEN) { 2407 mdb_warn("Output filename is too long for instance %d", 2408 instance); 2409 return (DCMD_ERR); 2410 } 2411 2412 fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP); 2413 2414 if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) { 2415 NOREAD(fwlogp, ss->fwlogp); 2416 rval = DCMD_ERR; 2417 goto cleanup; 2418 } 2419 2420 ofilefd = open(ofilename, O_WRONLY | O_CREAT, 2421 S_IRUSR | S_IRGRP | S_IROTH); 2422 if (ofilefd < 0) { 2423 mdb_warn("Unable to open '%s' to dump instance %d event log", 2424 ofilename, instance); 2425 rval = DCMD_ERR; 2426 goto cleanup; 2427 } 2428 2429 if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) { 2430 mdb_warn("Failed to write %d bytes to output file: instance %d", 2431 PMCS_FWLOG_SIZE, instance); 2432 rval = DCMD_ERR; 2433 goto cleanup; 2434 } 2435 2436 mdb_printf("Event log for instance %d written to %s\n", instance, 2437 ofilename); 2438 2439 cleanup: 2440 if (ofilefd >= 0) { 2441 close(ofilefd); 2442 } 2443 mdb_free(fwlogp, PMCS_FWLOG_SIZE); 2444 return (rval); 2445 } 2446 2447 static int 2448 pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2449 { 2450 void *pmcs_state; 2451 const char *ofile = NULL; 2452 struct pmcs_hw ss; 2453 struct dev_info dip; 2454 2455 if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) { 2456 return (DCMD_USAGE); 2457 } 2458 2459 if (ofile == NULL) { 2460 mdb_printf("No output file specified\n"); 2461 return (DCMD_USAGE); 2462 } 2463 2464 if (!(flags & DCMD_ADDRSPEC)) { 2465 pmcs_state = NULL; 2466 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2467 mdb_warn("can't read pmcs_softc_state"); 2468 return (DCMD_ERR); 2469 } 2470 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc, 2471 argv, (uintptr_t)pmcs_state) == -1) { 2472 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2473 return (DCMD_ERR); 2474 } 2475 return (DCMD_OK); 2476 } 2477 2478 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2479 NOREAD(pmcs_hw_t, addr); 2480 return (DCMD_ERR); 2481 } 2482 2483 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2484 NOREAD(pmcs_hw_t, addr); 2485 return (DCMD_ERR); 2486 } 2487 2488 return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile)); 2489 } 2490 #endif /* _KMDB */ 2491 2492 static int 2493 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2494 { 2495 void *pmcs_state; 2496 struct pmcs_hw ss; 2497 struct dev_info dip; 2498 const char *match_phy_path = NULL; 2499 uint64_t match_sas_address = 0, tail_lines = 0; 2500 2501 if (!(flags & DCMD_ADDRSPEC)) { 2502 pmcs_state = NULL; 2503 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2504 mdb_warn("can't read pmcs_softc_state"); 2505 return (DCMD_ERR); 2506 } 2507 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc, 2508 argv, (uintptr_t)pmcs_state) == -1) { 2509 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2510 return (DCMD_ERR); 2511 } 2512 return (DCMD_OK); 2513 } 2514 2515 if (mdb_getopts(argc, argv, 2516 'l', MDB_OPT_UINT64, &tail_lines, 2517 'p', MDB_OPT_STR, &match_phy_path, 2518 's', MDB_OPT_UINT64, &match_sas_address, 2519 NULL) != argc) { 2520 return (DCMD_USAGE); 2521 } 2522 2523 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2524 NOREAD(pmcs_hw_t, addr); 2525 return (DCMD_ERR); 2526 } 2527 2528 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2529 NOREAD(pmcs_hw_t, addr); 2530 return (DCMD_ERR); 2531 } 2532 2533 if (!(flags & DCMD_LOOP)) { 2534 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance, 2535 tail_lines, match_phy_path, match_sas_address)); 2536 } else if (flags & DCMD_LOOPFIRST) { 2537 return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines, 2538 match_phy_path, match_sas_address)); 2539 } else { 2540 return (DCMD_OK); 2541 } 2542 } 2543 2544 static int 2545 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2546 { 2547 struct pmcs_hw ss; 2548 uint_t verbose = FALSE; 2549 uint_t phy_info = FALSE; 2550 uint_t hw_info = FALSE; 2551 uint_t target_info = FALSE; 2552 uint_t work_info = FALSE; 2553 uint_t ic_info = FALSE; 2554 uint_t iport_info = FALSE; 2555 uint_t waitqs_info = FALSE; 2556 uint_t ibq = FALSE; 2557 uint_t obq = FALSE; 2558 uint_t tgt_phy_count = FALSE; 2559 uint_t compq = FALSE; 2560 uint_t unconfigured = FALSE; 2561 uint_t damap_info = FALSE; 2562 uint_t dtc_info = FALSE; 2563 int rv = DCMD_OK; 2564 void *pmcs_state; 2565 char *state_str; 2566 struct dev_info dip; 2567 per_iport_setting_t pis; 2568 2569 if (!(flags & DCMD_ADDRSPEC)) { 2570 pmcs_state = NULL; 2571 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2572 mdb_warn("can't read pmcs_softc_state"); 2573 return (DCMD_ERR); 2574 } 2575 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 2576 (uintptr_t)pmcs_state) == -1) { 2577 mdb_warn("mdb_pwalk_dcmd failed"); 2578 return (DCMD_ERR); 2579 } 2580 return (DCMD_OK); 2581 } 2582 2583 if (mdb_getopts(argc, argv, 2584 'c', MDB_OPT_SETBITS, TRUE, &compq, 2585 'd', MDB_OPT_SETBITS, TRUE, &dtc_info, 2586 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 2587 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 2588 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 2589 'm', MDB_OPT_SETBITS, TRUE, &damap_info, 2590 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 2591 'q', MDB_OPT_SETBITS, TRUE, &ibq, 2592 'Q', MDB_OPT_SETBITS, TRUE, &obq, 2593 't', MDB_OPT_SETBITS, TRUE, &target_info, 2594 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 2595 'u', MDB_OPT_SETBITS, TRUE, &unconfigured, 2596 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2597 'w', MDB_OPT_SETBITS, TRUE, &work_info, 2598 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 2599 NULL) != argc) 2600 return (DCMD_USAGE); 2601 2602 /* 2603 * The 'd' and 'm' options implicitly enable the 'I' option 2604 */ 2605 pis.pis_damap_info = damap_info; 2606 pis.pis_dtc_info = dtc_info; 2607 if (damap_info || dtc_info) { 2608 iport_info = TRUE; 2609 } 2610 2611 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2612 NOREAD(pmcs_hw_t, addr); 2613 return (DCMD_ERR); 2614 } 2615 2616 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2617 NOREAD(pmcs_hw_t, addr); 2618 return (DCMD_ERR); 2619 } 2620 2621 /* processing completed */ 2622 2623 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2624 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 2625 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq || 2626 unconfigured) { 2627 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2628 mdb_printf("\n"); 2629 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2630 "Address", "State", "Inst", "DIP"); 2631 mdb_printf("=================================" 2632 "============================================\n"); 2633 } 2634 2635 switch (ss.state) { 2636 case STATE_NIL: 2637 state_str = "Invalid"; 2638 break; 2639 case STATE_PROBING: 2640 state_str = "Probing"; 2641 break; 2642 case STATE_RUNNING: 2643 state_str = "Running"; 2644 break; 2645 case STATE_UNPROBING: 2646 state_str = "Unprobing"; 2647 break; 2648 case STATE_DEAD: 2649 state_str = "Dead"; 2650 break; 2651 case STATE_IN_RESET: 2652 state_str = "In Reset"; 2653 break; 2654 } 2655 2656 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2657 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2658 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2659 mdb_printf("\n"); 2660 2661 mdb_inc_indent(4); 2662 2663 if (waitqs_info) 2664 display_waitqs(ss, verbose); 2665 2666 if (hw_info) 2667 display_hwinfo(ss, verbose); 2668 2669 if (phy_info || tgt_phy_count) 2670 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 2671 2672 if (target_info || tgt_phy_count) 2673 display_targets(ss, verbose, tgt_phy_count); 2674 2675 if (work_info) 2676 display_work(ss, verbose); 2677 2678 if (ic_info) 2679 display_ic(ss, verbose); 2680 2681 if (ibq) 2682 display_inbound_queues(ss, verbose); 2683 2684 if (obq) 2685 display_outbound_queues(ss, verbose); 2686 2687 if (iport_info) 2688 display_iport(ss, addr, verbose, &pis); 2689 2690 if (compq) 2691 display_completion_queue(ss); 2692 2693 if (unconfigured) 2694 display_unconfigured_targets(addr); 2695 2696 mdb_dec_indent(4); 2697 2698 return (rv); 2699 } 2700 2701 void 2702 pmcs_help() 2703 { 2704 mdb_printf("Prints summary information about each pmcs instance.\n" 2705 " -c: Dump the completion queue\n" 2706 " -d: Print per-iport information about device tree children\n" 2707 " -h: Print more detailed hardware information\n" 2708 " -i: Print interrupt coalescing information\n" 2709 " -I: Print information about each iport\n" 2710 " -m: Print per-iport information about DAM/damap state\n" 2711 " -p: Print information about each attached PHY\n" 2712 " -q: Dump inbound queues\n" 2713 " -Q: Dump outbound queues\n" 2714 " -t: Print information about each configured target\n" 2715 " -T: Print target and PHY count summary\n" 2716 " -u: Show SAS address of all unconfigured targets\n" 2717 " -w: Dump work structures\n" 2718 " -W: List pmcs cmds waiting on various queues\n" 2719 " -v: Add verbosity to the above options\n"); 2720 } 2721 2722 void 2723 pmcs_log_help() 2724 { 2725 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n" 2726 " -l TAIL_LINES: Dump the last TAIL_LINES messages\n" 2727 " -p PHY_PATH: Dump messages matching PHY_PATH\n" 2728 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n" 2729 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n" 2730 " SAS_ADDRESS can be found with ::pmcs -t " 2731 "(e.g. 5000c5000358c221)\n"); 2732 } 2733 void 2734 pmcs_tag_help() 2735 { 2736 mdb_printf("Print all work structures by matching the tag.\n" 2737 " -i index: Match tag index (0x000 - 0xfff)\n" 2738 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n" 2739 " -t tagtype: Match tag type [NONE(1), CBACK(2), " 2740 "WAIT(3)]\n"); 2741 } 2742 2743 static const mdb_dcmd_t dcmds[] = { 2744 { "pmcs", "?[-cdhiImpQqtTuwWv]", "print pmcs information", 2745 pmcs_dcmd, pmcs_help 2746 }, 2747 { "pmcs_log", 2748 "?[-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]", 2749 "dump pmcs log file", pmcs_log, pmcs_log_help 2750 }, 2751 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]", 2752 "Find work structures by tag type, serial number or index", 2753 pmcs_tag, pmcs_tag_help 2754 }, 2755 #ifndef _KMDB 2756 { "pmcs_fwlog", 2757 "?-o output_file", 2758 "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL 2759 }, 2760 #endif /* _KMDB */ 2761 { NULL } 2762 }; 2763 2764 static const mdb_walker_t walkers[] = { 2765 { "pmcs_targets", "walk target structures", 2766 targets_walk_i, targets_walk_s, targets_walk_f }, 2767 { "pmcs_phys", "walk PHY structures", 2768 phy_walk_i, phy_walk_s, phy_walk_f }, 2769 { NULL } 2770 }; 2771 2772 static const mdb_modinfo_t modinfo = { 2773 MDB_API_VERSION, dcmds, walkers 2774 }; 2775 2776 const mdb_modinfo_t * 2777 _mdb_init(void) 2778 { 2779 return (&modinfo); 2780 } 2781