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