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