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