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 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\n", 755 wp->last_htag, last_state, wp->last_phy, wp->last_xp); 756 } else { 757 mdb_printf("\n"); 758 } 759 } 760 761 static void 762 display_work(struct pmcs_hw m, int verbose) 763 { 764 int idx; 765 boolean_t header_printed = B_FALSE; 766 pmcwork_t work, *wp = &work; 767 uintptr_t _wp; 768 769 mdb_printf("\nActive Work structure information:\n"); 770 mdb_printf("----------------------------------\n"); 771 772 _wp = (uintptr_t)m.work; 773 774 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 775 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 776 NOREAD(pmcwork_t, _wp); 777 continue; 778 } 779 780 if (!verbose && (wp->htag == PMCS_TAG_TYPE_FREE)) { 781 continue; 782 } 783 784 if (header_printed == B_FALSE) { 785 if (verbose) { 786 mdb_printf("%4s ", "Idx"); 787 } 788 mdb_printf("%8s %10s %20s %8s %8s O D ", 789 "HTag", "State", "Phy Path", "Target", "Timer"); 790 if (verbose) { 791 mdb_printf("%8s %10s %18s %18s\n", "LastHTAG", 792 "LastState", "LastPHY", "LastTgt"); 793 } else { 794 mdb_printf("\n"); 795 } 796 header_printed = B_TRUE; 797 } 798 799 display_one_work(wp, verbose, idx); 800 } 801 } 802 803 static void 804 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose) 805 { 806 int cdb_size, idx; 807 struct scsi_pkt pkt; 808 uchar_t cdb[256]; 809 810 if (printhdr) { 811 if (verbose) { 812 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command", 813 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 814 } else { 815 mdb_printf("%16s %16s %16s %8s %s\n", "Command", 816 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 817 } 818 } 819 820 mdb_printf("%16p %16p %16p %08x %08x ", 821 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag); 822 823 /* 824 * If we're printing verbose, dump the CDB as well. 825 */ 826 if (verbose) { 827 if (sp->cmd_pkt) { 828 if (mdb_vread(&pkt, sizeof (struct scsi_pkt), 829 (uintptr_t)sp->cmd_pkt) != 830 sizeof (struct scsi_pkt)) { 831 mdb_warn("Unable to read SCSI pkt\n"); 832 return; 833 } 834 cdb_size = pkt.pkt_cdblen; 835 if (mdb_vread(&cdb[0], cdb_size, 836 (uintptr_t)pkt.pkt_cdbp) != cdb_size) { 837 mdb_warn("Unable to read CDB\n"); 838 return; 839 } 840 841 for (idx = 0; idx < cdb_size; idx++) { 842 mdb_printf("%02x ", cdb[idx]); 843 } 844 } else { 845 mdb_printf("N/A"); 846 } 847 848 mdb_printf("\n"); 849 } else { 850 mdb_printf("\n"); 851 } 852 } 853 854 /*ARGSUSED1*/ 855 static void 856 display_waitqs(struct pmcs_hw m, int verbose) 857 { 858 pmcs_cmd_t *sp, s; 859 pmcs_xscsi_t xs; 860 int first, i; 861 int max_dev = m.max_dev; 862 863 sp = m.dq.stqh_first; 864 first = 1; 865 while (sp) { 866 if (first) { 867 mdb_printf("\nDead Command Queue:\n"); 868 mdb_printf("---------------------------\n"); 869 } 870 if (MDB_RD(&s, sizeof (s), sp) == -1) { 871 NOREAD(pmcs_cmd_t, sp); 872 break; 873 } 874 print_spcmd(&s, sp, first, verbose); 875 sp = s.cmd_next.stqe_next; 876 first = 0; 877 } 878 879 sp = m.cq.stqh_first; 880 first = 1; 881 while (sp) { 882 if (first) { 883 mdb_printf("\nCompletion Command Queue:\n"); 884 mdb_printf("---------------------------\n"); 885 } 886 if (MDB_RD(&s, sizeof (s), sp) == -1) { 887 NOREAD(pmcs_cmd_t, sp); 888 break; 889 } 890 print_spcmd(&s, sp, first, verbose); 891 sp = s.cmd_next.stqe_next; 892 first = 0; 893 } 894 895 896 if (targets == NULL) { 897 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 898 } 899 900 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 901 NOREAD(targets, m.targets); 902 return; 903 } 904 905 for (i = 0; i < max_dev; i++) { 906 if (targets[i] == NULL) { 907 continue; 908 } 909 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) { 910 NOREAD(pmcs_xscsi_t, targets[i]); 911 continue; 912 } 913 sp = xs.wq.stqh_first; 914 first = 1; 915 while (sp) { 916 if (first) { 917 mdb_printf("\nTarget %u Wait Queue:\n", 918 xs.target_num); 919 mdb_printf("---------------------------\n"); 920 } 921 if (MDB_RD(&s, sizeof (s), sp) == -1) { 922 NOREAD(pmcs_cmd_t, sp); 923 break; 924 } 925 print_spcmd(&s, sp, first, verbose); 926 sp = s.cmd_next.stqe_next; 927 first = 0; 928 } 929 sp = xs.aq.stqh_first; 930 first = 1; 931 while (sp) { 932 if (first) { 933 mdb_printf("\nTarget %u Active Queue:\n", 934 xs.target_num); 935 mdb_printf("---------------------------\n"); 936 } 937 if (MDB_RD(&s, sizeof (s), sp) == -1) { 938 NOREAD(pmcs_cmd_t, sp); 939 break; 940 } 941 print_spcmd(&s, sp, first, verbose); 942 sp = s.cmd_next.stqe_next; 943 first = 0; 944 } 945 sp = xs.sq.stqh_first; 946 first = 1; 947 while (sp) { 948 if (first) { 949 mdb_printf("\nTarget %u Special Queue:\n", 950 xs.target_num); 951 mdb_printf("---------------------------\n"); 952 } 953 if (MDB_RD(&s, sizeof (s), sp) == -1) { 954 NOREAD(pmcs_cmd_t, sp); 955 break; 956 } 957 print_spcmd(&s, sp, first, verbose); 958 sp = s.cmd_next.stqe_next; 959 first = 0; 960 } 961 } 962 } 963 964 static char * 965 ibq_type(int qnum) 966 { 967 if (qnum < 0 || qnum >= PMCS_NIQ) { 968 return ("UNKNOWN"); 969 } 970 971 if (qnum < PMCS_IQ_OTHER) { 972 return ("I/O"); 973 } 974 975 return ("Other"); 976 } 977 978 static char * 979 obq_type(int qnum) 980 { 981 switch (qnum) { 982 case PMCS_OQ_IODONE: 983 return ("I/O"); 984 break; 985 case PMCS_OQ_GENERAL: 986 return ("General"); 987 break; 988 case PMCS_OQ_EVENTS: 989 return ("Events"); 990 break; 991 default: 992 return ("UNKNOWN"); 993 } 994 } 995 996 static char * 997 iomb_cat(uint32_t cat) 998 { 999 switch (cat) { 1000 case PMCS_IOMB_CAT_NET: 1001 return ("NET"); 1002 break; 1003 case PMCS_IOMB_CAT_FC: 1004 return ("FC"); 1005 break; 1006 case PMCS_IOMB_CAT_SAS: 1007 return ("SAS"); 1008 break; 1009 case PMCS_IOMB_CAT_SCSI: 1010 return ("SCSI"); 1011 break; 1012 default: 1013 return ("???"); 1014 } 1015 } 1016 1017 static char * 1018 inbound_iomb_opcode(uint32_t opcode) 1019 { 1020 switch (opcode) { 1021 case PMCIN_ECHO: 1022 return ("ECHO"); 1023 break; 1024 case PMCIN_GET_INFO: 1025 return ("GET_INFO"); 1026 break; 1027 case PMCIN_GET_VPD: 1028 return ("GET_VPD"); 1029 break; 1030 case PMCIN_PHY_START: 1031 return ("PHY_START"); 1032 break; 1033 case PMCIN_PHY_STOP: 1034 return ("PHY_STOP"); 1035 break; 1036 case PMCIN_SSP_INI_IO_START: 1037 return ("INI_IO_START"); 1038 break; 1039 case PMCIN_SSP_INI_TM_START: 1040 return ("INI_TM_START"); 1041 break; 1042 case PMCIN_SSP_INI_EXT_IO_START: 1043 return ("INI_EXT_IO_START"); 1044 break; 1045 case PMCIN_DEVICE_HANDLE_ACCEPT: 1046 return ("DEVICE_HANDLE_ACCEPT"); 1047 break; 1048 case PMCIN_SSP_TGT_IO_START: 1049 return ("TGT_IO_START"); 1050 break; 1051 case PMCIN_SSP_TGT_RESPONSE_START: 1052 return ("TGT_RESPONSE_START"); 1053 break; 1054 case PMCIN_SSP_INI_EDC_EXT_IO_START: 1055 return ("INI_EDC_EXT_IO_START"); 1056 break; 1057 case PMCIN_SSP_INI_EDC_EXT_IO_START1: 1058 return ("INI_EDC_EXT_IO_START1"); 1059 break; 1060 case PMCIN_SSP_TGT_EDC_IO_START: 1061 return ("TGT_EDC_IO_START"); 1062 break; 1063 case PMCIN_SSP_ABORT: 1064 return ("SSP_ABORT"); 1065 break; 1066 case PMCIN_DEREGISTER_DEVICE_HANDLE: 1067 return ("DEREGISTER_DEVICE_HANDLE"); 1068 break; 1069 case PMCIN_GET_DEVICE_HANDLE: 1070 return ("GET_DEVICE_HANDLE"); 1071 break; 1072 case PMCIN_SMP_REQUEST: 1073 return ("SMP_REQUEST"); 1074 break; 1075 case PMCIN_SMP_RESPONSE: 1076 return ("SMP_RESPONSE"); 1077 break; 1078 case PMCIN_SMP_ABORT: 1079 return ("SMP_ABORT"); 1080 break; 1081 case PMCIN_ASSISTED_DISCOVERY: 1082 return ("ASSISTED_DISCOVERY"); 1083 break; 1084 case PMCIN_REGISTER_DEVICE: 1085 return ("REGISTER_DEVICE"); 1086 break; 1087 case PMCIN_SATA_HOST_IO_START: 1088 return ("SATA_HOST_IO_START"); 1089 break; 1090 case PMCIN_SATA_ABORT: 1091 return ("SATA_ABORT"); 1092 break; 1093 case PMCIN_LOCAL_PHY_CONTROL: 1094 return ("LOCAL_PHY_CONTROL"); 1095 break; 1096 case PMCIN_GET_DEVICE_INFO: 1097 return ("GET_DEVICE_INFO"); 1098 break; 1099 case PMCIN_TWI: 1100 return ("TWI"); 1101 break; 1102 case PMCIN_FW_FLASH_UPDATE: 1103 return ("FW_FLASH_UPDATE"); 1104 break; 1105 case PMCIN_SET_VPD: 1106 return ("SET_VPD"); 1107 break; 1108 case PMCIN_GPIO: 1109 return ("GPIO"); 1110 break; 1111 case PMCIN_SAS_DIAG_MODE_START_END: 1112 return ("SAS_DIAG_MODE_START_END"); 1113 break; 1114 case PMCIN_SAS_DIAG_EXECUTE: 1115 return ("SAS_DIAG_EXECUTE"); 1116 break; 1117 case PMCIN_SAW_HW_EVENT_ACK: 1118 return ("SAS_HW_EVENT_ACK"); 1119 break; 1120 case PMCIN_GET_TIME_STAMP: 1121 return ("GET_TIME_STAMP"); 1122 break; 1123 case PMCIN_PORT_CONTROL: 1124 return ("PORT_CONTROL"); 1125 break; 1126 case PMCIN_GET_NVMD_DATA: 1127 return ("GET_NVMD_DATA"); 1128 break; 1129 case PMCIN_SET_NVMD_DATA: 1130 return ("SET_NVMD_DATA"); 1131 break; 1132 case PMCIN_SET_DEVICE_STATE: 1133 return ("SET_DEVICE_STATE"); 1134 break; 1135 case PMCIN_GET_DEVICE_STATE: 1136 return ("GET_DEVICE_STATE"); 1137 break; 1138 default: 1139 return ("UNKNOWN"); 1140 break; 1141 } 1142 } 1143 1144 static char * 1145 outbound_iomb_opcode(uint32_t opcode) 1146 { 1147 switch (opcode) { 1148 case PMCOUT_ECHO: 1149 return ("ECHO"); 1150 break; 1151 case PMCOUT_GET_INFO: 1152 return ("GET_INFO"); 1153 break; 1154 case PMCOUT_GET_VPD: 1155 return ("GET_VPD"); 1156 break; 1157 case PMCOUT_SAS_HW_EVENT: 1158 return ("SAS_HW_EVENT"); 1159 break; 1160 case PMCOUT_SSP_COMPLETION: 1161 return ("SSP_COMPLETION"); 1162 break; 1163 case PMCOUT_SMP_COMPLETION: 1164 return ("SMP_COMPLETION"); 1165 break; 1166 case PMCOUT_LOCAL_PHY_CONTROL: 1167 return ("LOCAL_PHY_CONTROL"); 1168 break; 1169 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT: 1170 return ("SAS_ASSISTED_DISCOVERY_SENT"); 1171 break; 1172 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT: 1173 return ("SATA_ASSISTED_DISCOVERY_SENT"); 1174 break; 1175 case PMCOUT_DEVICE_REGISTRATION: 1176 return ("DEVICE_REGISTRATION"); 1177 break; 1178 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1179 return ("DEREGISTER_DEVICE_HANDLE"); 1180 break; 1181 case PMCOUT_GET_DEVICE_HANDLE: 1182 return ("GET_DEVICE_HANDLE"); 1183 break; 1184 case PMCOUT_SATA_COMPLETION: 1185 return ("SATA_COMPLETION"); 1186 break; 1187 case PMCOUT_SATA_EVENT: 1188 return ("SATA_EVENT"); 1189 break; 1190 case PMCOUT_SSP_EVENT: 1191 return ("SSP_EVENT"); 1192 break; 1193 case PMCOUT_DEVICE_HANDLE_ARRIVED: 1194 return ("DEVICE_HANDLE_ARRIVED"); 1195 break; 1196 case PMCOUT_SMP_REQUEST_RECEIVED: 1197 return ("SMP_REQUEST_RECEIVED"); 1198 break; 1199 case PMCOUT_SSP_REQUEST_RECEIVED: 1200 return ("SSP_REQUEST_RECEIVED"); 1201 break; 1202 case PMCOUT_DEVICE_INFO: 1203 return ("DEVICE_INFO"); 1204 break; 1205 case PMCOUT_FW_FLASH_UPDATE: 1206 return ("FW_FLASH_UPDATE"); 1207 break; 1208 case PMCOUT_SET_VPD: 1209 return ("SET_VPD"); 1210 break; 1211 case PMCOUT_GPIO: 1212 return ("GPIO"); 1213 break; 1214 case PMCOUT_GPIO_EVENT: 1215 return ("GPIO_EVENT"); 1216 break; 1217 case PMCOUT_GENERAL_EVENT: 1218 return ("GENERAL_EVENT"); 1219 break; 1220 case PMCOUT_TWI: 1221 return ("TWI"); 1222 break; 1223 case PMCOUT_SSP_ABORT: 1224 return ("SSP_ABORT"); 1225 break; 1226 case PMCOUT_SATA_ABORT: 1227 return ("SATA_ABORT"); 1228 break; 1229 case PMCOUT_SAS_DIAG_MODE_START_END: 1230 return ("SAS_DIAG_MODE_START_END"); 1231 break; 1232 case PMCOUT_SAS_DIAG_EXECUTE: 1233 return ("SAS_DIAG_EXECUTE"); 1234 break; 1235 case PMCOUT_GET_TIME_STAMP: 1236 return ("GET_TIME_STAMP"); 1237 break; 1238 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1239 return ("SAS_HW_EVENT_ACK_ACK"); 1240 break; 1241 case PMCOUT_PORT_CONTROL: 1242 return ("PORT_CONTROL"); 1243 break; 1244 case PMCOUT_SKIP_ENTRIES: 1245 return ("SKIP_ENTRIES"); 1246 break; 1247 case PMCOUT_SMP_ABORT: 1248 return ("SMP_ABORT"); 1249 break; 1250 case PMCOUT_GET_NVMD_DATA: 1251 return ("GET_NVMD_DATA"); 1252 break; 1253 case PMCOUT_SET_NVMD_DATA: 1254 return ("SET_NVMD_DATA"); 1255 break; 1256 case PMCOUT_DEVICE_HANDLE_REMOVED: 1257 return ("DEVICE_HANDLE_REMOVED"); 1258 break; 1259 case PMCOUT_SET_DEVICE_STATE: 1260 return ("SET_DEVICE_STATE"); 1261 break; 1262 case PMCOUT_GET_DEVICE_STATE: 1263 return ("GET_DEVICE_STATE"); 1264 break; 1265 case PMCOUT_SET_DEVICE_INFO: 1266 return ("SET_DEVICE_INFO"); 1267 break; 1268 default: 1269 return ("UNKNOWN"); 1270 break; 1271 } 1272 } 1273 1274 static void 1275 dump_one_qentry_outbound(uint32_t *qentryp, int idx) 1276 { 1277 int qeidx; 1278 uint32_t word0 = LE_32(*qentryp); 1279 1280 mdb_printf("Entry #%02d\n", idx); 1281 mdb_inc_indent(2); 1282 1283 mdb_printf("Header: 0x%08x (", word0); 1284 if (word0 & PMCS_IOMB_VALID) { 1285 mdb_printf("VALID, "); 1286 } 1287 if (word0 & PMCS_IOMB_HIPRI) { 1288 mdb_printf("HIPRI, "); 1289 } 1290 mdb_printf("OBID=%d, ", 1291 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1292 mdb_printf("CAT=%s, ", 1293 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1294 mdb_printf("OPCODE=%s", 1295 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1296 mdb_printf(")\n"); 1297 1298 mdb_printf("Remaining Payload:\n"); 1299 1300 mdb_inc_indent(2); 1301 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1302 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1303 } 1304 mdb_printf("\n"); 1305 mdb_dec_indent(4); 1306 } 1307 1308 static void 1309 display_outbound_queues(struct pmcs_hw ss, uint_t verbose) 1310 { 1311 int idx, qidx; 1312 uintptr_t obqp; 1313 uint32_t *cip; 1314 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1315 uint32_t last_consumed, oqpi; 1316 1317 mdb_printf("\n"); 1318 mdb_printf("Outbound Queues\n"); 1319 mdb_printf("---------------\n"); 1320 1321 mdb_inc_indent(2); 1322 1323 for (qidx = 0; qidx < PMCS_NOQ; qidx++) { 1324 obqp = (uintptr_t)ss.oqp[qidx]; 1325 1326 if (obqp == NULL) { 1327 mdb_printf("No outbound queue ptr for queue #%d\n", 1328 qidx); 1329 continue; 1330 } 1331 1332 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx, 1333 obq_type(qidx)); 1334 /* 1335 * Chip is the producer, so read the actual producer index 1336 * and not the driver's version 1337 */ 1338 cip = (uint32_t *)((void *)ss.cip); 1339 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET + 1340 (qidx * 4)) == -1) { 1341 mdb_warn("Couldn't read oqpi\n"); 1342 break; 1343 } 1344 1345 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1346 LE_32(oqpi), ss.oqci[qidx]); 1347 mdb_inc_indent(2); 1348 1349 if (ss.oqci[qidx] == 0) { 1350 last_consumed = ss.ioq_depth - 1; 1351 } else { 1352 last_consumed = ss.oqci[qidx] - 1; 1353 } 1354 1355 1356 if (!verbose) { 1357 mdb_printf("Last processed entry:\n"); 1358 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1359 (obqp + (PMCS_QENTRY_SIZE * last_consumed))) 1360 == -1) { 1361 mdb_warn("Couldn't read queue entry at 0x%p\n", 1362 (obqp + (PMCS_QENTRY_SIZE * 1363 last_consumed))); 1364 break; 1365 } 1366 dump_one_qentry_outbound(qentryp, last_consumed); 1367 mdb_printf("\n"); 1368 mdb_dec_indent(2); 1369 continue; 1370 } 1371 1372 for (idx = 0; idx < ss.ioq_depth; idx++) { 1373 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1374 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1375 mdb_warn("Couldn't read queue entry at 0x%p\n", 1376 (obqp + (PMCS_QENTRY_SIZE * idx))); 1377 break; 1378 } 1379 dump_one_qentry_outbound(qentryp, idx); 1380 } 1381 1382 mdb_printf("\n"); 1383 mdb_dec_indent(2); 1384 } 1385 1386 mdb_dec_indent(2); 1387 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1388 } 1389 1390 static void 1391 dump_one_qentry_inbound(uint32_t *qentryp, int idx) 1392 { 1393 int qeidx; 1394 uint32_t word0 = LE_32(*qentryp); 1395 1396 mdb_printf("Entry #%02d\n", idx); 1397 mdb_inc_indent(2); 1398 1399 mdb_printf("Header: 0x%08x (", word0); 1400 if (word0 & PMCS_IOMB_VALID) { 1401 mdb_printf("VALID, "); 1402 } 1403 if (word0 & PMCS_IOMB_HIPRI) { 1404 mdb_printf("HIPRI, "); 1405 } 1406 mdb_printf("OBID=%d, ", 1407 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1408 mdb_printf("CAT=%s, ", 1409 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1410 mdb_printf("OPCODE=%s", 1411 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1412 mdb_printf(")\n"); 1413 1414 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1))); 1415 mdb_printf("Remaining Payload:\n"); 1416 1417 mdb_inc_indent(2); 1418 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1419 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1420 } 1421 mdb_printf("\n"); 1422 mdb_dec_indent(4); 1423 } 1424 1425 static void 1426 display_inbound_queues(struct pmcs_hw ss, uint_t verbose) 1427 { 1428 int idx, qidx, iqci, last_consumed; 1429 uintptr_t ibqp; 1430 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1431 uint32_t *cip; 1432 1433 mdb_printf("\n"); 1434 mdb_printf("Inbound Queues\n"); 1435 mdb_printf("--------------\n"); 1436 1437 mdb_inc_indent(2); 1438 1439 for (qidx = 0; qidx < PMCS_NIQ; qidx++) { 1440 ibqp = (uintptr_t)ss.iqp[qidx]; 1441 1442 if (ibqp == NULL) { 1443 mdb_printf("No inbound queue ptr for queue #%d\n", 1444 qidx); 1445 continue; 1446 } 1447 1448 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx, 1449 ibq_type(qidx)); 1450 1451 cip = (uint32_t *)((void *)ss.cip); 1452 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) { 1453 mdb_warn("Couldn't read iqci\n"); 1454 break; 1455 } 1456 iqci = LE_32(iqci); 1457 1458 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1459 ss.shadow_iqpi[qidx], iqci); 1460 mdb_inc_indent(2); 1461 1462 if (iqci == 0) { 1463 last_consumed = ss.ioq_depth - 1; 1464 } else { 1465 last_consumed = iqci - 1; 1466 } 1467 1468 if (!verbose) { 1469 mdb_printf("Last processed entry:\n"); 1470 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1471 (ibqp + (PMCS_QENTRY_SIZE * last_consumed))) 1472 == -1) { 1473 mdb_warn("Couldn't read queue entry at 0x%p\n", 1474 (ibqp + (PMCS_QENTRY_SIZE * 1475 last_consumed))); 1476 break; 1477 } 1478 dump_one_qentry_inbound(qentryp, last_consumed); 1479 mdb_printf("\n"); 1480 mdb_dec_indent(2); 1481 continue; 1482 } 1483 1484 for (idx = 0; idx < ss.ioq_depth; idx++) { 1485 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1486 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1487 mdb_warn("Couldn't read queue entry at 0x%p\n", 1488 (ibqp + (PMCS_QENTRY_SIZE * idx))); 1489 break; 1490 } 1491 dump_one_qentry_inbound(qentryp, idx); 1492 } 1493 1494 mdb_printf("\n"); 1495 mdb_dec_indent(2); 1496 } 1497 1498 mdb_dec_indent(2); 1499 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1500 } 1501 1502 static void 1503 display_phy(struct pmcs_phy phy, int verbose, int totals_only) 1504 { 1505 char *dtype, *speed; 1506 char *yes = "Yes"; 1507 char *no = "No"; 1508 char *cfgd = no; 1509 char *apend = no; 1510 char *asent = no; 1511 char *dead = no; 1512 char *changed = no; 1513 1514 switch (phy.dtype) { 1515 case NOTHING: 1516 dtype = "None"; 1517 break; 1518 case SATA: 1519 dtype = "SATA"; 1520 if (phy.configured) { 1521 ++sata_phys; 1522 } 1523 break; 1524 case SAS: 1525 dtype = "SAS"; 1526 if (phy.configured) { 1527 ++sas_phys; 1528 } 1529 break; 1530 case EXPANDER: 1531 dtype = "EXP"; 1532 if (phy.configured) { 1533 ++exp_phys; 1534 } 1535 break; 1536 } 1537 1538 if (phy.dtype == NOTHING) { 1539 empty_phys++; 1540 } else if ((phy.dtype == EXPANDER) && phy.configured) { 1541 num_expanders++; 1542 } 1543 1544 if (totals_only) { 1545 return; 1546 } 1547 1548 switch (phy.link_rate) { 1549 case SAS_LINK_RATE_1_5GBIT: 1550 speed = "1.5Gb/s"; 1551 break; 1552 case SAS_LINK_RATE_3GBIT: 1553 speed = "3 Gb/s"; 1554 break; 1555 case SAS_LINK_RATE_6GBIT: 1556 speed = "6 Gb/s"; 1557 break; 1558 default: 1559 speed = "N/A"; 1560 break; 1561 } 1562 1563 if ((phy.dtype != NOTHING) || verbose) { 1564 print_sas_address(&phy); 1565 1566 if (phy.device_id != PMCS_INVALID_DEVICE_ID) { 1567 mdb_printf(" %3d %4d %6s %4s ", 1568 phy.device_id, phy.phynum, speed, dtype); 1569 } else { 1570 mdb_printf(" N/A %4d %6s %4s ", 1571 phy.phynum, speed, dtype); 1572 } 1573 1574 if (verbose) { 1575 if (phy.abort_sent) { 1576 asent = yes; 1577 } 1578 if (phy.abort_pending) { 1579 apend = yes; 1580 } 1581 if (phy.configured) { 1582 cfgd = yes; 1583 } 1584 if (phy.dead) { 1585 dead = yes; 1586 } 1587 if (phy.changed) { 1588 changed = yes; 1589 } 1590 1591 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d " 1592 "0x%p ", cfgd, apend, asent, 1593 changed, dead, phy.ref_count, phy.phy_lock); 1594 } 1595 1596 mdb_printf("Path: %s\n", phy.path); 1597 } 1598 } 1599 1600 static void 1601 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level, 1602 int totals_only) 1603 { 1604 pmcs_phy_t phy; 1605 pmcs_phy_t *pphy = parent; 1606 1607 mdb_inc_indent(3); 1608 1609 if (parent == NULL) { 1610 pphy = (pmcs_phy_t *)ss.root_phys; 1611 } else { 1612 pphy = (pmcs_phy_t *)parent; 1613 } 1614 1615 if (level == 0) { 1616 sas_phys = 0; 1617 sata_phys = 0; 1618 exp_phys = 0; 1619 num_expanders = 0; 1620 empty_phys = 0; 1621 } 1622 1623 if (!totals_only) { 1624 if (level == 0) { 1625 mdb_printf("PHY information\n"); 1626 } 1627 mdb_printf("--------\n"); 1628 mdb_printf("Level %2d\n", level); 1629 mdb_printf("--------\n"); 1630 mdb_printf("SAS Address Hdl Phy# Speed Type "); 1631 1632 if (verbose) { 1633 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref Lock\n"); 1634 } else { 1635 mdb_printf("\n"); 1636 } 1637 } 1638 1639 while (pphy) { 1640 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) { 1641 NOREAD(pmcs_phy_t, phy); 1642 break; 1643 } 1644 1645 display_phy(phy, verbose, totals_only); 1646 1647 if (phy.children) { 1648 display_phys(ss, verbose, phy.children, level + 1, 1649 totals_only); 1650 if (!totals_only) { 1651 mdb_printf("\n"); 1652 } 1653 } 1654 1655 pphy = phy.sibling; 1656 } 1657 1658 mdb_dec_indent(3); 1659 1660 if (level == 0) { 1661 if (verbose) { 1662 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) " 1663 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:", 1664 (sas_phys + sata_phys + num_expanders), 1665 sas_phys, sata_phys, num_expanders, 1666 (exp_phys - num_expanders), empty_phys); 1667 } else { 1668 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 1669 "Occupied PHYs:", 1670 (sas_phys + sata_phys + num_expanders), 1671 sas_phys, sata_phys, num_expanders); 1672 } 1673 } 1674 } 1675 1676 /* 1677 * filter is used to indicate whether we are filtering log messages based 1678 * on "instance". The other filtering (based on options) depends on the 1679 * values that are passed in for "sas_addr" and "phy_path". 1680 * 1681 * MAX_INST_STRLEN is the largest string size from which we will attempt 1682 * to convert to an instance number. The string will be formed up as 1683 * "0t<inst>\0" so that mdb_strtoull can parse it properly. 1684 */ 1685 #define MAX_INST_STRLEN 8 1686 1687 static int 1688 pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines, 1689 const char *phy_path, uint64_t sas_address) 1690 { 1691 pmcs_tbuf_t *tbuf_addr; 1692 uint_t tbuf_idx; 1693 pmcs_tbuf_t tbuf; 1694 boolean_t wrap, elem_filtered; 1695 uint_t start_idx, elems_to_print, idx, tbuf_num_elems; 1696 char *bufp; 1697 char elem_inst[MAX_INST_STRLEN], ei_idx; 1698 uint64_t sas_addr; 1699 uint8_t *sas_addressp; 1700 1701 /* Get the address of the first element */ 1702 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) { 1703 mdb_warn("can't read pmcs_tbuf"); 1704 return (DCMD_ERR); 1705 } 1706 1707 /* Get the total number */ 1708 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) { 1709 mdb_warn("can't read pmcs_tbuf_num_elems"); 1710 return (DCMD_ERR); 1711 } 1712 1713 /* Get the current index */ 1714 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) { 1715 mdb_warn("can't read pmcs_tbuf_idx"); 1716 return (DCMD_ERR); 1717 } 1718 1719 /* Indicator as to whether the buffer has wrapped */ 1720 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) { 1721 mdb_warn("can't read pmcs_tbuf_wrap"); 1722 return (DCMD_ERR); 1723 } 1724 1725 /* 1726 * On little-endian systems, the SAS address passed in will be 1727 * byte swapped. Take care of that here. 1728 */ 1729 #if defined(_LITTLE_ENDIAN) 1730 sas_addr = ((sas_address << 56) | 1731 ((sas_address << 40) & 0xff000000000000ULL) | 1732 ((sas_address << 24) & 0xff0000000000ULL) | 1733 ((sas_address << 8) & 0xff00000000ULL) | 1734 ((sas_address >> 8) & 0xff000000ULL) | 1735 ((sas_address >> 24) & 0xff0000ULL) | 1736 ((sas_address >> 40) & 0xff00ULL) | 1737 (sas_address >> 56)); 1738 #else 1739 sas_addr = sas_address; 1740 #endif 1741 sas_addressp = (uint8_t *)&sas_addr; 1742 1743 /* Ensure the tail number isn't greater than the size of the log */ 1744 if (tail_lines > tbuf_num_elems) { 1745 tail_lines = tbuf_num_elems; 1746 } 1747 1748 /* Figure out where we start and stop */ 1749 if (wrap) { 1750 if (tail_lines) { 1751 /* Do we need to wrap backwards? */ 1752 if (tail_lines > tbuf_idx) { 1753 start_idx = tbuf_num_elems - (tail_lines - 1754 tbuf_idx); 1755 } else { 1756 start_idx = tbuf_idx - tail_lines; 1757 } 1758 elems_to_print = tail_lines; 1759 } else { 1760 start_idx = tbuf_idx; 1761 elems_to_print = tbuf_num_elems; 1762 } 1763 } else { 1764 if (tail_lines > tbuf_idx) { 1765 tail_lines = tbuf_idx; 1766 } 1767 if (tail_lines) { 1768 start_idx = tbuf_idx - tail_lines; 1769 elems_to_print = tail_lines; 1770 } else { 1771 start_idx = 0; 1772 elems_to_print = tbuf_idx; 1773 } 1774 } 1775 1776 idx = start_idx; 1777 1778 /* Dump the buffer contents */ 1779 while (elems_to_print != 0) { 1780 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx)) 1781 == -1) { 1782 NOREAD(tbuf, (tbuf_addr + idx)); 1783 return (DCMD_ERR); 1784 } 1785 1786 /* 1787 * Check for filtering on HBA instance 1788 */ 1789 elem_filtered = B_FALSE; 1790 1791 if (filter) { 1792 bufp = tbuf.buf; 1793 /* Skip the driver name */ 1794 while (*bufp < '0' || *bufp > '9') { 1795 bufp++; 1796 } 1797 1798 ei_idx = 0; 1799 elem_inst[ei_idx++] = '0'; 1800 elem_inst[ei_idx++] = 't'; 1801 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) { 1802 elem_inst[ei_idx++] = *bufp; 1803 bufp++; 1804 } 1805 elem_inst[ei_idx] = 0; 1806 1807 /* Get the instance */ 1808 if ((int)mdb_strtoull(elem_inst) != instance) { 1809 elem_filtered = B_TRUE; 1810 } 1811 } 1812 1813 if (!elem_filtered && (phy_path || sas_address)) { 1814 /* 1815 * This message is not being filtered by HBA instance. 1816 * Now check to see if we're filtering based on 1817 * PHY path or SAS address. 1818 * Filtering is an "OR" operation. So, if any of the 1819 * criteria matches, this message will be printed. 1820 */ 1821 elem_filtered = B_TRUE; 1822 1823 if (phy_path != NULL) { 1824 if (strncmp(phy_path, tbuf.phy_path, 1825 PMCS_TBUF_UA_MAX_SIZE) == 0) { 1826 elem_filtered = B_FALSE; 1827 } 1828 } 1829 if (sas_address != 0) { 1830 if (memcmp(sas_addressp, tbuf.phy_sas_address, 1831 8) == 0) { 1832 elem_filtered = B_FALSE; 1833 } 1834 } 1835 } 1836 1837 if (!elem_filtered) { 1838 mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf); 1839 } 1840 1841 --elems_to_print; 1842 if (++idx == tbuf_num_elems) { 1843 idx = 0; 1844 } 1845 } 1846 1847 return (DCMD_OK); 1848 } 1849 1850 /* 1851 * Walkers 1852 */ 1853 static int 1854 targets_walk_i(mdb_walk_state_t *wsp) 1855 { 1856 if (wsp->walk_addr == NULL) { 1857 mdb_warn("Can not perform global walk\n"); 1858 return (WALK_ERR); 1859 } 1860 1861 /* 1862 * Address provided belongs to HBA softstate. Get the targets pointer 1863 * to begin the walk. 1864 */ 1865 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1866 sizeof (pmcs_hw_t)) { 1867 mdb_warn("Unable to read HBA softstate\n"); 1868 return (WALK_ERR); 1869 } 1870 1871 if (targets == NULL) { 1872 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP); 1873 } 1874 1875 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) { 1876 NOREAD(targets, ss.targets); 1877 return (WALK_ERR); 1878 } 1879 1880 target_idx = 0; 1881 wsp->walk_addr = (uintptr_t)(targets[0]); 1882 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP); 1883 1884 return (WALK_NEXT); 1885 } 1886 1887 static int 1888 targets_walk_s(mdb_walk_state_t *wsp) 1889 { 1890 int status; 1891 1892 if (target_idx == ss.max_dev) { 1893 return (WALK_DONE); 1894 } 1895 1896 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t), 1897 wsp->walk_addr) == -1) { 1898 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr); 1899 return (WALK_DONE); 1900 } 1901 1902 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1903 wsp->walk_cbdata); 1904 1905 do { 1906 wsp->walk_addr = (uintptr_t)(targets[++target_idx]); 1907 } while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev)); 1908 1909 if (target_idx == ss.max_dev) { 1910 return (WALK_DONE); 1911 } 1912 1913 return (status); 1914 } 1915 1916 static void 1917 targets_walk_f(mdb_walk_state_t *wsp) 1918 { 1919 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t)); 1920 } 1921 1922 1923 static pmcs_phy_t * 1924 pmcs_next_sibling(pmcs_phy_t *phyp) 1925 { 1926 pmcs_phy_t parent; 1927 1928 /* 1929 * First, if this is a root PHY, there are no more siblings 1930 */ 1931 if (phyp->level == 0) { 1932 return (NULL); 1933 } 1934 1935 /* 1936 * Otherwise, next sibling is the parent's sibling 1937 */ 1938 while (phyp->level > 0) { 1939 if (mdb_vread(&parent, sizeof (pmcs_phy_t), 1940 (uintptr_t)phyp->parent) == -1) { 1941 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p", 1942 (void *)phyp->parent); 1943 return (NULL); 1944 } 1945 1946 if (parent.sibling != NULL) { 1947 break; 1948 } 1949 1950 phyp = phyp->parent; 1951 } 1952 1953 return (parent.sibling); 1954 } 1955 1956 static int 1957 phy_walk_i(mdb_walk_state_t *wsp) 1958 { 1959 if (wsp->walk_addr == NULL) { 1960 mdb_warn("Can not perform global walk\n"); 1961 return (WALK_ERR); 1962 } 1963 1964 /* 1965 * Address provided belongs to HBA softstate. Get the targets pointer 1966 * to begin the walk. 1967 */ 1968 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 1969 sizeof (pmcs_hw_t)) { 1970 mdb_warn("Unable to read HBA softstate\n"); 1971 return (WALK_ERR); 1972 } 1973 1974 wsp->walk_addr = (uintptr_t)(ss.root_phys); 1975 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 1976 1977 return (WALK_NEXT); 1978 } 1979 1980 static int 1981 phy_walk_s(mdb_walk_state_t *wsp) 1982 { 1983 pmcs_phy_t *phyp, *nphyp; 1984 int status; 1985 1986 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 1987 wsp->walk_addr) == -1) { 1988 mdb_warn("phy_walk_s: Failed to read PHY at %p", 1989 (void *)wsp->walk_addr); 1990 return (WALK_DONE); 1991 } 1992 1993 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1994 wsp->walk_cbdata); 1995 1996 phyp = (pmcs_phy_t *)wsp->walk_data; 1997 if (phyp->children) { 1998 wsp->walk_addr = (uintptr_t)(phyp->children); 1999 } else { 2000 wsp->walk_addr = (uintptr_t)(phyp->sibling); 2001 } 2002 2003 if (wsp->walk_addr == NULL) { 2004 /* 2005 * We reached the end of this sibling list. Trudge back up 2006 * to the parent and find the next sibling after the expander 2007 * we just finished traversing, if there is one. 2008 */ 2009 nphyp = pmcs_next_sibling(phyp); 2010 2011 if (nphyp == NULL) { 2012 return (WALK_DONE); 2013 } 2014 2015 wsp->walk_addr = (uintptr_t)nphyp; 2016 } 2017 2018 return (status); 2019 } 2020 2021 static void 2022 phy_walk_f(mdb_walk_state_t *wsp) 2023 { 2024 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 2025 } 2026 2027 static void 2028 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum, 2029 uintmax_t tag_type) 2030 { 2031 int idx; 2032 pmcwork_t work, *wp = &work; 2033 uintptr_t _wp; 2034 boolean_t printed_header = B_FALSE; 2035 uint32_t mask, mask_val, match_val; 2036 char *match_type; 2037 2038 if (index != UINT_MAX) { 2039 match_type = "index"; 2040 mask = PMCS_TAG_INDEX_MASK; 2041 mask_val = index << PMCS_TAG_INDEX_SHIFT; 2042 match_val = index; 2043 } else if (snum != UINT_MAX) { 2044 match_type = "serial number"; 2045 mask = PMCS_TAG_SERNO_MASK; 2046 mask_val = snum << PMCS_TAG_SERNO_SHIFT; 2047 match_val = snum; 2048 } else { 2049 switch (tag_type) { 2050 case PMCS_TAG_TYPE_NONE: 2051 match_type = "tag type NONE"; 2052 break; 2053 case PMCS_TAG_TYPE_CBACK: 2054 match_type = "tag type CBACK"; 2055 break; 2056 case PMCS_TAG_TYPE_WAIT: 2057 match_type = "tag type WAIT"; 2058 break; 2059 } 2060 mask = PMCS_TAG_TYPE_MASK; 2061 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT; 2062 match_val = tag_type; 2063 } 2064 2065 _wp = (uintptr_t)ss.work; 2066 2067 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 2068 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 2069 NOREAD(pmcwork_t, _wp); 2070 continue; 2071 } 2072 2073 if ((work.htag & mask) != mask_val) { 2074 continue; 2075 } 2076 2077 if (printed_header == B_FALSE) { 2078 if (tag_type) { 2079 mdb_printf("\nWork structures matching %s\n\n", 2080 match_type, match_val); 2081 } else { 2082 mdb_printf("\nWork structures matching %s of " 2083 "0x%x\n\n", match_type, match_val); 2084 } 2085 mdb_printf("%8s %10s %20s %8s %8s O D\n", 2086 "HTag", "State", "Phy Path", "Target", "Timer"); 2087 printed_header = B_TRUE; 2088 } 2089 2090 display_one_work(wp, 0, 0); 2091 } 2092 2093 if (!printed_header) { 2094 mdb_printf("No work structure matches found\n"); 2095 } 2096 } 2097 2098 static int 2099 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2100 { 2101 struct pmcs_hw ss; 2102 uintmax_t tag_type = UINT_MAX; 2103 uintmax_t snum = UINT_MAX; 2104 uintmax_t index = UINT_MAX; 2105 int args = 0; 2106 void *pmcs_state; 2107 char *state_str; 2108 struct dev_info dip; 2109 2110 if (!(flags & DCMD_ADDRSPEC)) { 2111 pmcs_state = NULL; 2112 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2113 mdb_warn("can't read pmcs_softc_state"); 2114 return (DCMD_ERR); 2115 } 2116 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc, 2117 argv, (uintptr_t)pmcs_state) == -1) { 2118 mdb_warn("mdb_pwalk_dcmd failed"); 2119 return (DCMD_ERR); 2120 } 2121 return (DCMD_OK); 2122 } 2123 2124 if (mdb_getopts(argc, argv, 2125 'i', MDB_OPT_UINT64, &index, 2126 's', MDB_OPT_UINT64, &snum, 2127 't', MDB_OPT_UINT64, &tag_type) != argc) 2128 return (DCMD_USAGE); 2129 2130 /* 2131 * Count the number of supplied options and make sure they are 2132 * within appropriate ranges. If they're set to UINT_MAX, that means 2133 * they were not supplied, in which case reset them to 0. 2134 */ 2135 if (index != UINT_MAX) { 2136 args++; 2137 if (index > PMCS_TAG_INDEX_MASK) { 2138 mdb_warn("Index is out of range\n"); 2139 return (DCMD_USAGE); 2140 } 2141 } 2142 2143 if (tag_type != UINT_MAX) { 2144 args++; 2145 switch (tag_type) { 2146 case PMCS_TAG_TYPE_NONE: 2147 case PMCS_TAG_TYPE_CBACK: 2148 case PMCS_TAG_TYPE_WAIT: 2149 break; 2150 default: 2151 mdb_warn("Invalid tag type\n"); 2152 return (DCMD_USAGE); 2153 } 2154 } 2155 2156 if (snum != UINT_MAX) { 2157 args++; 2158 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) { 2159 mdb_warn("Serial number is out of range\n"); 2160 return (DCMD_USAGE); 2161 } 2162 } 2163 2164 /* 2165 * Make sure 1 and only 1 option is specified 2166 */ 2167 if ((args == 0) || (args > 1)) { 2168 mdb_warn("Exactly one of -i, -s and -t must be specified\n"); 2169 return (DCMD_USAGE); 2170 } 2171 2172 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2173 NOREAD(pmcs_hw_t, addr); 2174 return (DCMD_ERR); 2175 } 2176 2177 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2178 NOREAD(pmcs_hw_t, addr); 2179 return (DCMD_ERR); 2180 } 2181 2182 /* processing completed */ 2183 2184 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2185 (flags & DCMD_LOOPFIRST)) { 2186 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2187 mdb_printf("\n"); 2188 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2189 "Address", "State", "Inst", "DIP"); 2190 mdb_printf("=================================" 2191 "============================================\n"); 2192 } 2193 2194 switch (ss.state) { 2195 case STATE_NIL: 2196 state_str = "Invalid"; 2197 break; 2198 case STATE_PROBING: 2199 state_str = "Probing"; 2200 break; 2201 case STATE_RUNNING: 2202 state_str = "Running"; 2203 break; 2204 case STATE_UNPROBING: 2205 state_str = "Unprobing"; 2206 break; 2207 case STATE_DEAD: 2208 state_str = "Dead"; 2209 break; 2210 } 2211 2212 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2213 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2214 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2215 mdb_printf("\n"); 2216 2217 mdb_inc_indent(4); 2218 display_matching_work(ss, index, snum, tag_type); 2219 mdb_dec_indent(4); 2220 mdb_printf("\n"); 2221 2222 return (DCMD_OK); 2223 } 2224 2225 static int 2226 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2227 { 2228 void *pmcs_state; 2229 struct pmcs_hw ss; 2230 struct dev_info dip; 2231 const char *match_phy_path = NULL; 2232 uint64_t match_sas_address = 0, tail_lines = 0; 2233 2234 if (!(flags & DCMD_ADDRSPEC)) { 2235 pmcs_state = NULL; 2236 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2237 mdb_warn("can't read pmcs_softc_state"); 2238 return (DCMD_ERR); 2239 } 2240 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc, 2241 argv, (uintptr_t)pmcs_state) == -1) { 2242 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2243 return (DCMD_ERR); 2244 } 2245 return (DCMD_OK); 2246 } 2247 2248 if (mdb_getopts(argc, argv, 2249 'l', MDB_OPT_UINT64, &tail_lines, 2250 'p', MDB_OPT_STR, &match_phy_path, 2251 's', MDB_OPT_UINT64, &match_sas_address, 2252 NULL) != argc) { 2253 return (DCMD_USAGE); 2254 } 2255 2256 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2257 NOREAD(pmcs_hw_t, addr); 2258 return (DCMD_ERR); 2259 } 2260 2261 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2262 NOREAD(pmcs_hw_t, addr); 2263 return (DCMD_ERR); 2264 } 2265 2266 if (!(flags & DCMD_LOOP)) { 2267 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance, 2268 tail_lines, match_phy_path, match_sas_address)); 2269 } else if (flags & DCMD_LOOPFIRST) { 2270 return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines, 2271 match_phy_path, match_sas_address)); 2272 } else { 2273 return (DCMD_OK); 2274 } 2275 } 2276 2277 static int 2278 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2279 { 2280 struct pmcs_hw ss; 2281 uint_t verbose = FALSE; 2282 uint_t phy_info = FALSE; 2283 uint_t hw_info = FALSE; 2284 uint_t target_info = FALSE; 2285 uint_t work_info = FALSE; 2286 uint_t ic_info = FALSE; 2287 uint_t iport_info = FALSE; 2288 uint_t waitqs_info = FALSE; 2289 uint_t ibq = FALSE; 2290 uint_t obq = FALSE; 2291 uint_t tgt_phy_count = FALSE; 2292 uint_t compq = FALSE; 2293 uint_t unconfigured = FALSE; 2294 uint_t damap_info = FALSE; 2295 uint_t dtc_info = FALSE; 2296 int rv = DCMD_OK; 2297 void *pmcs_state; 2298 char *state_str; 2299 struct dev_info dip; 2300 per_iport_setting_t pis; 2301 2302 if (!(flags & DCMD_ADDRSPEC)) { 2303 pmcs_state = NULL; 2304 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2305 mdb_warn("can't read pmcs_softc_state"); 2306 return (DCMD_ERR); 2307 } 2308 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 2309 (uintptr_t)pmcs_state) == -1) { 2310 mdb_warn("mdb_pwalk_dcmd failed"); 2311 return (DCMD_ERR); 2312 } 2313 return (DCMD_OK); 2314 } 2315 2316 if (mdb_getopts(argc, argv, 2317 'c', MDB_OPT_SETBITS, TRUE, &compq, 2318 'd', MDB_OPT_SETBITS, TRUE, &dtc_info, 2319 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 2320 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 2321 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 2322 'm', MDB_OPT_SETBITS, TRUE, &damap_info, 2323 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 2324 'q', MDB_OPT_SETBITS, TRUE, &ibq, 2325 'Q', MDB_OPT_SETBITS, TRUE, &obq, 2326 't', MDB_OPT_SETBITS, TRUE, &target_info, 2327 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 2328 'u', MDB_OPT_SETBITS, TRUE, &unconfigured, 2329 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2330 'w', MDB_OPT_SETBITS, TRUE, &work_info, 2331 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 2332 NULL) != argc) 2333 return (DCMD_USAGE); 2334 2335 /* 2336 * The 'd' and 'm' options implicitly enable the 'I' option 2337 */ 2338 pis.pis_damap_info = damap_info; 2339 pis.pis_dtc_info = dtc_info; 2340 if (damap_info || dtc_info) { 2341 iport_info = TRUE; 2342 } 2343 2344 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2345 NOREAD(pmcs_hw_t, addr); 2346 return (DCMD_ERR); 2347 } 2348 2349 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2350 NOREAD(pmcs_hw_t, addr); 2351 return (DCMD_ERR); 2352 } 2353 2354 /* processing completed */ 2355 2356 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2357 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 2358 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq || 2359 unconfigured) { 2360 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2361 mdb_printf("\n"); 2362 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2363 "Address", "State", "Inst", "DIP"); 2364 mdb_printf("=================================" 2365 "============================================\n"); 2366 } 2367 2368 switch (ss.state) { 2369 case STATE_NIL: 2370 state_str = "Invalid"; 2371 break; 2372 case STATE_PROBING: 2373 state_str = "Probing"; 2374 break; 2375 case STATE_RUNNING: 2376 state_str = "Running"; 2377 break; 2378 case STATE_UNPROBING: 2379 state_str = "Unprobing"; 2380 break; 2381 case STATE_DEAD: 2382 state_str = "Dead"; 2383 break; 2384 } 2385 2386 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2387 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2388 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2389 mdb_printf("\n"); 2390 2391 mdb_inc_indent(4); 2392 2393 if (waitqs_info) 2394 display_waitqs(ss, verbose); 2395 2396 if (hw_info) 2397 display_hwinfo(ss, verbose); 2398 2399 if (phy_info || tgt_phy_count) 2400 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 2401 2402 if (target_info || tgt_phy_count) 2403 display_targets(ss, verbose, tgt_phy_count); 2404 2405 if (work_info) 2406 display_work(ss, verbose); 2407 2408 if (ic_info) 2409 display_ic(ss, verbose); 2410 2411 if (ibq) 2412 display_inbound_queues(ss, verbose); 2413 2414 if (obq) 2415 display_outbound_queues(ss, verbose); 2416 2417 if (iport_info) 2418 display_iport(ss, addr, verbose, &pis); 2419 2420 if (compq) 2421 display_completion_queue(ss); 2422 2423 if (unconfigured) 2424 display_unconfigured_targets(addr); 2425 2426 mdb_dec_indent(4); 2427 2428 return (rv); 2429 } 2430 2431 void 2432 pmcs_help() 2433 { 2434 mdb_printf("Prints summary information about each pmcs instance.\n" 2435 " -c: Dump the completion queue\n" 2436 " -d: Print per-iport information about device tree children\n" 2437 " -h: Print more detailed hardware information\n" 2438 " -i: Print interrupt coalescing information\n" 2439 " -I: Print information about each iport\n" 2440 " -m: Print per-iport information about DAM/damap state\n" 2441 " -p: Print information about each attached PHY\n" 2442 " -q: Dump inbound queues\n" 2443 " -Q: Dump outbound queues\n" 2444 " -t: Print information about each configured target\n" 2445 " -T: Print target and PHY count summary\n" 2446 " -u: Show SAS address of all unconfigured targets\n" 2447 " -w: Dump work structures\n" 2448 " -W: List pmcs cmds waiting on various queues\n" 2449 " -v: Add verbosity to the above options\n"); 2450 } 2451 2452 void 2453 pmcs_log_help() 2454 { 2455 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n" 2456 " -l TAIL_LINES: Dump the last TAIL_LINES messages\n" 2457 " -p PHY_PATH: Dump messages matching PHY_PATH\n" 2458 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n" 2459 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n" 2460 " SAS_ADDRESS can be found with ::pmcs -t " 2461 "(e.g. 5000c5000358c221)\n"); 2462 } 2463 void 2464 pmcs_tag_help() 2465 { 2466 mdb_printf("Print all work structures by matching the tag.\n" 2467 " -i index: Match tag index (0x000 - 0xfff)\n" 2468 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n" 2469 " -t tagtype: Match tag type [NONE(1), CBACK(2), " 2470 "WAIT(3)]\n"); 2471 } 2472 2473 static const mdb_dcmd_t dcmds[] = { 2474 { "pmcs", "?[-cdhiImpQqtTuwWv]", "print pmcs information", 2475 pmcs_dcmd, pmcs_help 2476 }, 2477 { "pmcs_log", 2478 "?[-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]", 2479 "dump pmcs log file", pmcs_log, pmcs_log_help 2480 }, 2481 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]", 2482 "Find work structures by tag type, serial number or index", 2483 pmcs_tag, pmcs_tag_help 2484 }, 2485 { NULL } 2486 }; 2487 2488 static const mdb_walker_t walkers[] = { 2489 { "pmcs_targets", "walk target structures", 2490 targets_walk_i, targets_walk_s, targets_walk_f }, 2491 { "pmcs_phys", "walk PHY structures", 2492 phy_walk_i, phy_walk_s, phy_walk_f }, 2493 { NULL } 2494 }; 2495 2496 static const mdb_modinfo_t modinfo = { 2497 MDB_API_VERSION, dcmds, walkers 2498 }; 2499 2500 const mdb_modinfo_t * 2501 _mdb_init(void) 2502 { 2503 return (&modinfo); 2504 } 2505