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