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