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 } 775 776 if (totals_only) { 777 continue; 778 } 779 780 if (xs.phy) { 781 if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) { 782 NOREAD(pmcs_phy_t, xs.phy); 783 continue; 784 } 785 mdb_printf("%4d ", idx); 786 print_sas_address(&phy); 787 mdb_printf(" %16p", xs.phy); 788 } else { 789 mdb_printf("%4d %16s", idx, "<no phy avail>"); 790 } 791 mdb_printf(" %5s", dtype); 792 mdb_printf(" %4d", xs.actv_pkts); 793 mdb_printf(" %6d", xs.actv_cnt); 794 mdb_printf(" %2d", xs.dev_state); 795 796 if (verbose) { 797 if (xs.new) { 798 mdb_printf(" new"); 799 } 800 if (xs.assigned) { 801 mdb_printf(" assigned"); 802 } 803 if (xs.draining) { 804 mdb_printf(" draining"); 805 } 806 if (xs.reset_wait) { 807 mdb_printf(" reset_wait"); 808 } 809 if (xs.resetting) { 810 mdb_printf(" resetting"); 811 } 812 if (xs.recover_wait) { 813 mdb_printf(" recover_wait"); 814 } 815 if (xs.recovering) { 816 mdb_printf(" recovering"); 817 } 818 if (xs.event_recovery) { 819 mdb_printf(" event recovery"); 820 } 821 if (xs.special_running) { 822 mdb_printf(" special_active"); 823 } 824 if (xs.ncq) { 825 mdb_printf(" ncq_tagmap=0x%x qdepth=%d", 826 xs.tagmap, xs.qdepth); 827 } else if (xs.pio) { 828 mdb_printf(" pio"); 829 } 830 } 831 832 mdb_printf("\n"); 833 } 834 835 if (!totals_only) { 836 mdb_printf("\n"); 837 } 838 839 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 840 "Configured targets:", (sas_targets + sata_targets + smp_targets), 841 sas_targets, sata_targets, smp_targets); 842 } 843 844 static char * 845 work_state_to_string(uint32_t state) 846 { 847 char *state_string; 848 849 switch (state) { 850 case PMCS_WORK_STATE_NIL: 851 state_string = "Free"; 852 break; 853 case PMCS_WORK_STATE_READY: 854 state_string = "Ready"; 855 break; 856 case PMCS_WORK_STATE_ONCHIP: 857 state_string = "On Chip"; 858 break; 859 case PMCS_WORK_STATE_INTR: 860 state_string = "In Intr"; 861 break; 862 case PMCS_WORK_STATE_IOCOMPQ: 863 state_string = "I/O Comp"; 864 break; 865 case PMCS_WORK_STATE_ABORTED: 866 state_string = "I/O Aborted"; 867 break; 868 case PMCS_WORK_STATE_TIMED_OUT: 869 state_string = "I/O Timed Out"; 870 break; 871 default: 872 state_string = "INVALID"; 873 break; 874 } 875 876 return (state_string); 877 } 878 879 static void 880 display_one_work(pmcwork_t *wp, int verbose, int idx) 881 { 882 char *state, *last_state; 883 char *path; 884 pmcs_xscsi_t xs; 885 pmcs_phy_t phy; 886 int tgt; 887 888 state = work_state_to_string(wp->state); 889 last_state = work_state_to_string(wp->last_state); 890 891 if (wp->ssp_event && wp->ssp_event != 0xffffffff) { 892 mdb_printf("SSP event 0x%x", wp->ssp_event); 893 } 894 895 tgt = -1; 896 if (wp->xp) { 897 if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) { 898 NOREAD(pmcs_xscsi_t, wp->xp); 899 } else { 900 tgt = xs.target_num; 901 } 902 } 903 if (wp->phy) { 904 if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) { 905 NOREAD(pmcs_phy_t, wp->phy); 906 } 907 path = phy.path; 908 } else { 909 path = "N/A"; 910 } 911 912 if (verbose) { 913 mdb_printf("%4d ", idx); 914 } 915 if (tgt == -1) { 916 mdb_printf("%08x %10s %20s N/A %8u %1d %1d ", 917 wp->htag, state, path, wp->timer, 918 wp->onwire, wp->dead); 919 } else { 920 mdb_printf("%08x %10s %20s %8d %8u %1d %1d ", 921 wp->htag, state, path, tgt, wp->timer, 922 wp->onwire, wp->dead); 923 } 924 if (verbose) { 925 mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n", 926 wp->last_htag, last_state, wp->last_phy, wp->last_xp, 927 wp->last_arg); 928 } else { 929 mdb_printf("\n"); 930 } 931 } 932 933 static void 934 display_work(struct pmcs_hw m, int verbose, int wserno) 935 { 936 int idx; 937 boolean_t header_printed = B_FALSE; 938 pmcwork_t *wp; 939 wserno_list_t *sernop, *sp, *newsp, *sphead = NULL; 940 uintptr_t _wp; 941 int serno; 942 943 wp = mdb_alloc(sizeof (pmcwork_t) * m.max_cmd, UM_SLEEP); 944 _wp = (uintptr_t)m.work; 945 sernop = mdb_alloc(sizeof (wserno_list_t) * m.max_cmd, UM_SLEEP); 946 bzero(sernop, sizeof (wserno_list_t) * m.max_cmd); 947 948 mdb_printf("\nActive Work structure information:\n"); 949 mdb_printf("----------------------------------\n"); 950 951 /* 952 * Read in all the work structures 953 */ 954 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 955 if (MDB_RD(wp + idx, sizeof (pmcwork_t), _wp) == -1) { 956 NOREAD(pmcwork_t, _wp); 957 continue; 958 } 959 } 960 961 /* 962 * Sort by serial number? 963 */ 964 if (wserno) { 965 for (idx = 0; idx < m.max_cmd; idx++) { 966 if ((wp + idx)->htag == 0) { 967 serno = PMCS_TAG_SERNO((wp + idx)->last_htag); 968 } else { 969 serno = PMCS_TAG_SERNO((wp + idx)->htag); 970 } 971 972 /* Start at the beginning of the list */ 973 sp = sphead; 974 newsp = sernop + idx; 975 /* If this is the first entry, just add it */ 976 if (sphead == NULL) { 977 sphead = sernop; 978 sphead->serno = serno; 979 sphead->idx = idx; 980 sphead->next = NULL; 981 sphead->prev = NULL; 982 continue; 983 } 984 985 newsp->serno = serno; 986 newsp->idx = idx; 987 988 /* Find out where in the list this goes */ 989 while (sp) { 990 /* This item goes before sp */ 991 if (serno < sp->serno) { 992 newsp->next = sp; 993 newsp->prev = sp->prev; 994 if (newsp->prev == NULL) { 995 sphead = newsp; 996 } else { 997 newsp->prev->next = newsp; 998 } 999 sp->prev = newsp; 1000 break; 1001 } 1002 1003 /* 1004 * If sp->next is NULL, this entry goes at the 1005 * end of the list 1006 */ 1007 if (sp->next == NULL) { 1008 sp->next = newsp; 1009 newsp->next = NULL; 1010 newsp->prev = sp; 1011 break; 1012 } 1013 1014 sp = sp->next; 1015 } 1016 } 1017 1018 /* 1019 * Now print the sorted list 1020 */ 1021 mdb_printf(" Idx %8s %10s %20s %8s %8s O D ", 1022 "HTag", "State", "Phy Path", "Target", "Timer"); 1023 mdb_printf("%8s %10s %18s %18s %18s\n", "LastHTAG", 1024 "LastState", "LastPHY", "LastTgt", "LastArg"); 1025 1026 sp = sphead; 1027 while (sp) { 1028 display_one_work(wp + sp->idx, 1, sp->idx); 1029 sp = sp->next; 1030 } 1031 1032 goto out; 1033 } 1034 1035 /* 1036 * Now print the list, sorted by index 1037 */ 1038 for (idx = 0; idx < m.max_cmd; idx++) { 1039 if (!verbose && ((wp + idx)->htag == PMCS_TAG_TYPE_FREE)) { 1040 continue; 1041 } 1042 1043 if (header_printed == B_FALSE) { 1044 if (verbose) { 1045 mdb_printf("%4s ", "Idx"); 1046 } 1047 mdb_printf("%8s %10s %20s %8s %8s O D ", 1048 "HTag", "State", "Phy Path", "Target", "Timer"); 1049 if (verbose) { 1050 mdb_printf("%8s %10s %18s %18s %18s\n", 1051 "LastHTAG", "LastState", "LastPHY", 1052 "LastTgt", "LastArg"); 1053 } else { 1054 mdb_printf("\n"); 1055 } 1056 header_printed = B_TRUE; 1057 } 1058 1059 display_one_work(wp + idx, verbose, idx); 1060 } 1061 1062 out: 1063 mdb_free(wp, sizeof (pmcwork_t) * m.max_cmd); 1064 mdb_free(sernop, sizeof (wserno_list_t) * m.max_cmd); 1065 } 1066 1067 static void 1068 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose) 1069 { 1070 int cdb_size, idx; 1071 struct scsi_pkt pkt; 1072 uchar_t cdb[256]; 1073 1074 if (printhdr) { 1075 if (verbose) { 1076 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command", 1077 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 1078 } else { 1079 mdb_printf("%16s %16s %16s %8s %s\n", "Command", 1080 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag"); 1081 } 1082 } 1083 1084 mdb_printf("%16p %16p %16p %08x %08x ", 1085 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag); 1086 1087 /* 1088 * If we're printing verbose, dump the CDB as well. 1089 */ 1090 if (verbose) { 1091 if (sp->cmd_pkt) { 1092 if (mdb_vread(&pkt, sizeof (struct scsi_pkt), 1093 (uintptr_t)sp->cmd_pkt) != 1094 sizeof (struct scsi_pkt)) { 1095 mdb_warn("Unable to read SCSI pkt\n"); 1096 return; 1097 } 1098 cdb_size = pkt.pkt_cdblen; 1099 if (mdb_vread(&cdb[0], cdb_size, 1100 (uintptr_t)pkt.pkt_cdbp) != cdb_size) { 1101 mdb_warn("Unable to read CDB\n"); 1102 return; 1103 } 1104 1105 for (idx = 0; idx < cdb_size; idx++) { 1106 mdb_printf("%02x ", cdb[idx]); 1107 } 1108 } else { 1109 mdb_printf("N/A"); 1110 } 1111 1112 mdb_printf("\n"); 1113 } else { 1114 mdb_printf("\n"); 1115 } 1116 } 1117 1118 /*ARGSUSED1*/ 1119 static void 1120 display_waitqs(struct pmcs_hw m, int verbose) 1121 { 1122 pmcs_cmd_t *sp, s; 1123 pmcs_xscsi_t xs; 1124 int first, i; 1125 int max_dev = m.max_dev; 1126 1127 sp = m.dq.stqh_first; 1128 first = 1; 1129 while (sp) { 1130 if (first) { 1131 mdb_printf("\nDead Command Queue:\n"); 1132 mdb_printf("---------------------------\n"); 1133 } 1134 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1135 NOREAD(pmcs_cmd_t, sp); 1136 break; 1137 } 1138 print_spcmd(&s, sp, first, verbose); 1139 sp = s.cmd_next.stqe_next; 1140 first = 0; 1141 } 1142 1143 sp = m.cq.stqh_first; 1144 first = 1; 1145 while (sp) { 1146 if (first) { 1147 mdb_printf("\nCompletion Command Queue:\n"); 1148 mdb_printf("---------------------------\n"); 1149 } 1150 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1151 NOREAD(pmcs_cmd_t, sp); 1152 break; 1153 } 1154 print_spcmd(&s, sp, first, verbose); 1155 sp = s.cmd_next.stqe_next; 1156 first = 0; 1157 } 1158 1159 1160 if (targets == NULL) { 1161 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP); 1162 } 1163 1164 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) { 1165 NOREAD(targets, m.targets); 1166 return; 1167 } 1168 1169 for (i = 0; i < max_dev; i++) { 1170 if (targets[i] == NULL) { 1171 continue; 1172 } 1173 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) { 1174 NOREAD(pmcs_xscsi_t, targets[i]); 1175 continue; 1176 } 1177 sp = xs.wq.stqh_first; 1178 first = 1; 1179 while (sp) { 1180 if (first) { 1181 mdb_printf("\nTarget %u Wait Queue:\n", 1182 xs.target_num); 1183 mdb_printf("---------------------------\n"); 1184 } 1185 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1186 NOREAD(pmcs_cmd_t, sp); 1187 break; 1188 } 1189 print_spcmd(&s, sp, first, verbose); 1190 sp = s.cmd_next.stqe_next; 1191 first = 0; 1192 } 1193 sp = xs.aq.stqh_first; 1194 first = 1; 1195 while (sp) { 1196 if (first) { 1197 mdb_printf("\nTarget %u Active Queue:\n", 1198 xs.target_num); 1199 mdb_printf("---------------------------\n"); 1200 } 1201 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1202 NOREAD(pmcs_cmd_t, sp); 1203 break; 1204 } 1205 print_spcmd(&s, sp, first, verbose); 1206 sp = s.cmd_next.stqe_next; 1207 first = 0; 1208 } 1209 sp = xs.sq.stqh_first; 1210 first = 1; 1211 while (sp) { 1212 if (first) { 1213 mdb_printf("\nTarget %u Special Queue:\n", 1214 xs.target_num); 1215 mdb_printf("---------------------------\n"); 1216 } 1217 if (MDB_RD(&s, sizeof (s), sp) == -1) { 1218 NOREAD(pmcs_cmd_t, sp); 1219 break; 1220 } 1221 print_spcmd(&s, sp, first, verbose); 1222 sp = s.cmd_next.stqe_next; 1223 first = 0; 1224 } 1225 } 1226 } 1227 1228 static char * 1229 ibq_type(int qnum) 1230 { 1231 if (qnum < 0 || qnum >= PMCS_NIQ) { 1232 return ("UNKNOWN"); 1233 } 1234 1235 if (qnum < PMCS_IQ_OTHER) { 1236 return ("I/O"); 1237 } 1238 1239 return ("Other"); 1240 } 1241 1242 static char * 1243 obq_type(int qnum) 1244 { 1245 switch (qnum) { 1246 case PMCS_OQ_IODONE: 1247 return ("I/O"); 1248 case PMCS_OQ_GENERAL: 1249 return ("General"); 1250 case PMCS_OQ_EVENTS: 1251 return ("Events"); 1252 default: 1253 return ("UNKNOWN"); 1254 } 1255 } 1256 1257 static char * 1258 iomb_cat(uint32_t cat) 1259 { 1260 switch (cat) { 1261 case PMCS_IOMB_CAT_NET: 1262 return ("NET"); 1263 case PMCS_IOMB_CAT_FC: 1264 return ("FC"); 1265 case PMCS_IOMB_CAT_SAS: 1266 return ("SAS"); 1267 case PMCS_IOMB_CAT_SCSI: 1268 return ("SCSI"); 1269 default: 1270 return ("???"); 1271 } 1272 } 1273 1274 static char * 1275 iomb_event(uint8_t event) 1276 { 1277 switch (event) { 1278 case IOP_EVENT_PHY_STOP_STATUS: 1279 return ("PHY STOP"); 1280 case IOP_EVENT_SAS_PHY_UP: 1281 return ("PHY UP"); 1282 case IOP_EVENT_SATA_PHY_UP: 1283 return ("SATA PHY UP"); 1284 case IOP_EVENT_SATA_SPINUP_HOLD: 1285 return ("SATA SPINUP HOLD"); 1286 case IOP_EVENT_PHY_DOWN: 1287 return ("PHY DOWN"); 1288 case IOP_EVENT_BROADCAST_CHANGE: 1289 return ("BROADCAST CHANGE"); 1290 case IOP_EVENT_BROADCAST_SES: 1291 return ("BROADCAST SES"); 1292 case IOP_EVENT_PHY_ERR_INBOUND_CRC: 1293 return ("INBOUND CRC ERROR"); 1294 case IOP_EVENT_HARD_RESET_RECEIVED: 1295 return ("HARD RESET"); 1296 case IOP_EVENT_EVENT_ID_FRAME_TIMO: 1297 return ("IDENTIFY FRAME TIMEOUT"); 1298 case IOP_EVENT_BROADCAST_EXP: 1299 return ("BROADCAST EXPANDER"); 1300 case IOP_EVENT_PHY_START_STATUS: 1301 return ("PHY START"); 1302 case IOP_EVENT_PHY_ERR_INVALID_DWORD: 1303 return ("INVALID DWORD"); 1304 case IOP_EVENT_PHY_ERR_DISPARITY_ERROR: 1305 return ("DISPARITY ERROR"); 1306 case IOP_EVENT_PHY_ERR_CODE_VIOLATION: 1307 return ("CODE VIOLATION"); 1308 case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN: 1309 return ("LOSS OF DWORD SYNC"); 1310 case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD: 1311 return ("PHY RESET FAILED"); 1312 case IOP_EVENT_PORT_RECOVERY_TIMER_TMO: 1313 return ("PORT RECOVERY TIMEOUT"); 1314 case IOP_EVENT_PORT_RECOVER: 1315 return ("PORT RECOVERY"); 1316 case IOP_EVENT_PORT_RESET_TIMER_TMO: 1317 return ("PORT RESET TIMEOUT"); 1318 case IOP_EVENT_PORT_RESET_COMPLETE: 1319 return ("PORT RESET COMPLETE"); 1320 case IOP_EVENT_BROADCAST_ASYNC_EVENT: 1321 return ("BROADCAST ASYNC"); 1322 case IOP_EVENT_IT_NEXUS_LOSS: 1323 return ("I/T NEXUS LOSS"); 1324 default: 1325 return ("Unknown Event"); 1326 } 1327 } 1328 1329 static char * 1330 inbound_iomb_opcode(uint32_t opcode) 1331 { 1332 switch (opcode) { 1333 case PMCIN_ECHO: 1334 return ("ECHO"); 1335 case PMCIN_GET_INFO: 1336 return ("GET_INFO"); 1337 case PMCIN_GET_VPD: 1338 return ("GET_VPD"); 1339 case PMCIN_PHY_START: 1340 return ("PHY_START"); 1341 case PMCIN_PHY_STOP: 1342 return ("PHY_STOP"); 1343 case PMCIN_SSP_INI_IO_START: 1344 return ("INI_IO_START"); 1345 case PMCIN_SSP_INI_TM_START: 1346 return ("INI_TM_START"); 1347 case PMCIN_SSP_INI_EXT_IO_START: 1348 return ("INI_EXT_IO_START"); 1349 case PMCIN_DEVICE_HANDLE_ACCEPT: 1350 return ("DEVICE_HANDLE_ACCEPT"); 1351 case PMCIN_SSP_TGT_IO_START: 1352 return ("TGT_IO_START"); 1353 case PMCIN_SSP_TGT_RESPONSE_START: 1354 return ("TGT_RESPONSE_START"); 1355 case PMCIN_SSP_INI_EDC_EXT_IO_START: 1356 return ("INI_EDC_EXT_IO_START"); 1357 case PMCIN_SSP_INI_EDC_EXT_IO_START1: 1358 return ("INI_EDC_EXT_IO_START1"); 1359 case PMCIN_SSP_TGT_EDC_IO_START: 1360 return ("TGT_EDC_IO_START"); 1361 case PMCIN_SSP_ABORT: 1362 return ("SSP_ABORT"); 1363 case PMCIN_DEREGISTER_DEVICE_HANDLE: 1364 return ("DEREGISTER_DEVICE_HANDLE"); 1365 case PMCIN_GET_DEVICE_HANDLE: 1366 return ("GET_DEVICE_HANDLE"); 1367 case PMCIN_SMP_REQUEST: 1368 return ("SMP_REQUEST"); 1369 case PMCIN_SMP_RESPONSE: 1370 return ("SMP_RESPONSE"); 1371 case PMCIN_SMP_ABORT: 1372 return ("SMP_ABORT"); 1373 case PMCIN_ASSISTED_DISCOVERY: 1374 return ("ASSISTED_DISCOVERY"); 1375 case PMCIN_REGISTER_DEVICE: 1376 return ("REGISTER_DEVICE"); 1377 case PMCIN_SATA_HOST_IO_START: 1378 return ("SATA_HOST_IO_START"); 1379 case PMCIN_SATA_ABORT: 1380 return ("SATA_ABORT"); 1381 case PMCIN_LOCAL_PHY_CONTROL: 1382 return ("LOCAL_PHY_CONTROL"); 1383 case PMCIN_GET_DEVICE_INFO: 1384 return ("GET_DEVICE_INFO"); 1385 case PMCIN_TWI: 1386 return ("TWI"); 1387 case PMCIN_FW_FLASH_UPDATE: 1388 return ("FW_FLASH_UPDATE"); 1389 case PMCIN_SET_VPD: 1390 return ("SET_VPD"); 1391 case PMCIN_GPIO: 1392 return ("GPIO"); 1393 case PMCIN_SAS_DIAG_MODE_START_END: 1394 return ("SAS_DIAG_MODE_START_END"); 1395 case PMCIN_SAS_DIAG_EXECUTE: 1396 return ("SAS_DIAG_EXECUTE"); 1397 case PMCIN_SAS_HW_EVENT_ACK: 1398 return ("SAS_HW_EVENT_ACK"); 1399 case PMCIN_GET_TIME_STAMP: 1400 return ("GET_TIME_STAMP"); 1401 case PMCIN_PORT_CONTROL: 1402 return ("PORT_CONTROL"); 1403 case PMCIN_GET_NVMD_DATA: 1404 return ("GET_NVMD_DATA"); 1405 case PMCIN_SET_NVMD_DATA: 1406 return ("SET_NVMD_DATA"); 1407 case PMCIN_SET_DEVICE_STATE: 1408 return ("SET_DEVICE_STATE"); 1409 case PMCIN_GET_DEVICE_STATE: 1410 return ("GET_DEVICE_STATE"); 1411 default: 1412 return ("UNKNOWN"); 1413 } 1414 } 1415 1416 static char * 1417 outbound_iomb_opcode(uint32_t opcode) 1418 { 1419 switch (opcode) { 1420 case PMCOUT_ECHO: 1421 return ("ECHO"); 1422 case PMCOUT_GET_INFO: 1423 return ("GET_INFO"); 1424 case PMCOUT_GET_VPD: 1425 return ("GET_VPD"); 1426 case PMCOUT_SAS_HW_EVENT: 1427 return ("SAS_HW_EVENT"); 1428 case PMCOUT_SSP_COMPLETION: 1429 return ("SSP_COMPLETION"); 1430 case PMCOUT_SMP_COMPLETION: 1431 return ("SMP_COMPLETION"); 1432 case PMCOUT_LOCAL_PHY_CONTROL: 1433 return ("LOCAL_PHY_CONTROL"); 1434 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT: 1435 return ("SAS_ASSISTED_DISCOVERY_SENT"); 1436 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT: 1437 return ("SATA_ASSISTED_DISCOVERY_SENT"); 1438 case PMCOUT_DEVICE_REGISTRATION: 1439 return ("DEVICE_REGISTRATION"); 1440 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1441 return ("DEREGISTER_DEVICE_HANDLE"); 1442 case PMCOUT_GET_DEVICE_HANDLE: 1443 return ("GET_DEVICE_HANDLE"); 1444 case PMCOUT_SATA_COMPLETION: 1445 return ("SATA_COMPLETION"); 1446 case PMCOUT_SATA_EVENT: 1447 return ("SATA_EVENT"); 1448 case PMCOUT_SSP_EVENT: 1449 return ("SSP_EVENT"); 1450 case PMCOUT_DEVICE_HANDLE_ARRIVED: 1451 return ("DEVICE_HANDLE_ARRIVED"); 1452 case PMCOUT_SSP_REQUEST_RECEIVED: 1453 return ("SSP_REQUEST_RECEIVED"); 1454 case PMCOUT_DEVICE_INFO: 1455 return ("DEVICE_INFO"); 1456 case PMCOUT_FW_FLASH_UPDATE: 1457 return ("FW_FLASH_UPDATE"); 1458 case PMCOUT_SET_VPD: 1459 return ("SET_VPD"); 1460 case PMCOUT_GPIO: 1461 return ("GPIO"); 1462 case PMCOUT_GPIO_EVENT: 1463 return ("GPIO_EVENT"); 1464 case PMCOUT_GENERAL_EVENT: 1465 return ("GENERAL_EVENT"); 1466 case PMCOUT_TWI: 1467 return ("TWI"); 1468 case PMCOUT_SSP_ABORT: 1469 return ("SSP_ABORT"); 1470 case PMCOUT_SATA_ABORT: 1471 return ("SATA_ABORT"); 1472 case PMCOUT_SAS_DIAG_MODE_START_END: 1473 return ("SAS_DIAG_MODE_START_END"); 1474 case PMCOUT_SAS_DIAG_EXECUTE: 1475 return ("SAS_DIAG_EXECUTE"); 1476 case PMCOUT_GET_TIME_STAMP: 1477 return ("GET_TIME_STAMP"); 1478 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1479 return ("SAS_HW_EVENT_ACK_ACK"); 1480 case PMCOUT_PORT_CONTROL: 1481 return ("PORT_CONTROL"); 1482 case PMCOUT_SKIP_ENTRIES: 1483 return ("SKIP_ENTRIES"); 1484 case PMCOUT_SMP_ABORT: 1485 return ("SMP_ABORT"); 1486 case PMCOUT_GET_NVMD_DATA: 1487 return ("GET_NVMD_DATA"); 1488 case PMCOUT_SET_NVMD_DATA: 1489 return ("SET_NVMD_DATA"); 1490 case PMCOUT_DEVICE_HANDLE_REMOVED: 1491 return ("DEVICE_HANDLE_REMOVED"); 1492 case PMCOUT_SET_DEVICE_STATE: 1493 return ("SET_DEVICE_STATE"); 1494 case PMCOUT_GET_DEVICE_STATE: 1495 return ("GET_DEVICE_STATE"); 1496 case PMCOUT_SET_DEVICE_INFO: 1497 return ("SET_DEVICE_INFO"); 1498 default: 1499 return ("UNKNOWN"); 1500 } 1501 } 1502 1503 static uint32_t 1504 get_devid_from_ob_iomb(struct pmcs_hw ss, uint32_t *qentryp, uint16_t opcode) 1505 { 1506 uint32_t devid = PMCS_INVALID_DEVICE_ID; 1507 1508 switch (opcode) { 1509 /* 1510 * These are obtained via the HTAG which is in word 1 1511 */ 1512 case PMCOUT_SSP_COMPLETION: 1513 case PMCOUT_SMP_COMPLETION: 1514 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1515 case PMCOUT_GET_DEVICE_HANDLE: 1516 case PMCOUT_SATA_COMPLETION: 1517 case PMCOUT_SSP_ABORT: 1518 case PMCOUT_SATA_ABORT: 1519 case PMCOUT_SMP_ABORT: 1520 case PMCOUT_SAS_HW_EVENT_ACK_ACK: { 1521 uint32_t htag; 1522 pmcwork_t *wp; 1523 pmcs_phy_t *phy; 1524 uintptr_t _wp, _phy; 1525 uint16_t index; 1526 1527 htag = LE_32(*(qentryp + 1)); 1528 index = htag & PMCS_TAG_INDEX_MASK; 1529 1530 wp = mdb_alloc(sizeof (pmcwork_t), UM_SLEEP); 1531 _wp = (uintptr_t)ss.work + (sizeof (pmcwork_t) * index); 1532 1533 if (MDB_RD(wp, sizeof (pmcwork_t), _wp) == -1) { 1534 NOREAD(pmcwork_t, _wp); 1535 mdb_free(wp, sizeof (pmcwork_t)); 1536 break; 1537 } 1538 1539 phy = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 1540 if (wp->phy == NULL) { 1541 _phy = (uintptr_t)wp->last_phy; 1542 } else { 1543 _phy = (uintptr_t)wp->phy; 1544 } 1545 1546 /* 1547 * If we have a PHY, read it in and get it's handle 1548 */ 1549 if (_phy != 0) { 1550 if (MDB_RD(phy, sizeof (*phy), _phy) == -1) { 1551 NOREAD(pmcs_phy_t, phy); 1552 } else { 1553 devid = phy->device_id; 1554 } 1555 } 1556 1557 mdb_free(phy, sizeof (pmcs_phy_t)); 1558 mdb_free(wp, sizeof (pmcwork_t)); 1559 break; 1560 } 1561 1562 /* 1563 * The device ID is in the outbound IOMB at word 1 1564 */ 1565 case PMCOUT_SSP_REQUEST_RECEIVED: 1566 devid = LE_32(*(qentryp + 1)) & PMCS_DEVICE_ID_MASK; 1567 break; 1568 1569 /* 1570 * The device ID is in the outbound IOMB at word 2 1571 */ 1572 case PMCOUT_DEVICE_HANDLE_ARRIVED: 1573 case PMCOUT_DEVICE_HANDLE_REMOVED: 1574 devid = LE_32(*(qentryp + 2)) & PMCS_DEVICE_ID_MASK; 1575 break; 1576 1577 /* 1578 * In this (very rare - never seen it) state, the device ID 1579 * comes from the HTAG in the inbound IOMB, which would be word 1580 * 3 in the outbound IOMB 1581 */ 1582 case PMCOUT_GENERAL_EVENT: 1583 /* 1584 * The device ID is in the outbound IOMB at word 3 1585 */ 1586 case PMCOUT_DEVICE_REGISTRATION: 1587 case PMCOUT_DEVICE_INFO: 1588 case PMCOUT_SET_DEVICE_STATE: 1589 case PMCOUT_GET_DEVICE_STATE: 1590 case PMCOUT_SET_DEVICE_INFO: 1591 devid = LE_32(*(qentryp + 3)) & PMCS_DEVICE_ID_MASK; 1592 break; 1593 1594 /* 1595 * Device ID is in the outbound IOMB at word 4 1596 */ 1597 case PMCOUT_SATA_EVENT: 1598 case PMCOUT_SSP_EVENT: 1599 devid = LE_32(*(qentryp + 4)) & PMCS_DEVICE_ID_MASK; 1600 break; 1601 } 1602 1603 return (devid); 1604 } 1605 1606 static boolean_t 1607 iomb_is_dev_hdl_specific(uint32_t word0, boolean_t inbound) 1608 { 1609 uint16_t opcode = word0 & PMCS_IOMB_OPCODE_MASK; 1610 1611 if (inbound) { 1612 switch (opcode) { 1613 case PMCIN_SSP_INI_IO_START: 1614 case PMCIN_SSP_INI_TM_START: 1615 case PMCIN_SSP_INI_EXT_IO_START: 1616 case PMCIN_SSP_TGT_IO_START: 1617 case PMCIN_SSP_TGT_RESPONSE_START: 1618 case PMCIN_SSP_ABORT: 1619 case PMCIN_DEREGISTER_DEVICE_HANDLE: 1620 case PMCIN_SMP_REQUEST: 1621 case PMCIN_SMP_RESPONSE: 1622 case PMCIN_SMP_ABORT: 1623 case PMCIN_ASSISTED_DISCOVERY: 1624 case PMCIN_SATA_HOST_IO_START: 1625 case PMCIN_SATA_ABORT: 1626 case PMCIN_GET_DEVICE_INFO: 1627 case PMCIN_SET_DEVICE_STATE: 1628 case PMCIN_GET_DEVICE_STATE: 1629 return (B_TRUE); 1630 } 1631 1632 return (B_FALSE); 1633 } 1634 1635 switch (opcode) { 1636 case PMCOUT_SSP_COMPLETION: 1637 case PMCOUT_SMP_COMPLETION: 1638 case PMCOUT_DEVICE_REGISTRATION: 1639 case PMCOUT_DEREGISTER_DEVICE_HANDLE: 1640 case PMCOUT_GET_DEVICE_HANDLE: 1641 case PMCOUT_SATA_COMPLETION: 1642 case PMCOUT_SATA_EVENT: 1643 case PMCOUT_SSP_EVENT: 1644 case PMCOUT_DEVICE_HANDLE_ARRIVED: 1645 case PMCOUT_SSP_REQUEST_RECEIVED: 1646 case PMCOUT_DEVICE_INFO: 1647 case PMCOUT_FW_FLASH_UPDATE: 1648 case PMCOUT_GENERAL_EVENT: 1649 case PMCOUT_SSP_ABORT: 1650 case PMCOUT_SATA_ABORT: 1651 case PMCOUT_SAS_HW_EVENT_ACK_ACK: 1652 case PMCOUT_SMP_ABORT: 1653 case PMCOUT_DEVICE_HANDLE_REMOVED: 1654 case PMCOUT_SET_DEVICE_STATE: 1655 case PMCOUT_GET_DEVICE_STATE: 1656 case PMCOUT_SET_DEVICE_INFO: 1657 return (B_TRUE); 1658 } 1659 1660 return (B_FALSE); 1661 } 1662 1663 static void 1664 dump_one_qentry_outbound(struct pmcs_hw ss, uint32_t *qentryp, int idx, 1665 uint64_t devid_filter) 1666 { 1667 int qeidx; 1668 uint32_t word0 = LE_32(*qentryp); 1669 uint32_t word1 = LE_32(*(qentryp + 1)); 1670 uint8_t iop_event; 1671 uint32_t devid; 1672 1673 /* 1674 * Check to see if we're filtering on a device ID 1675 */ 1676 if (devid_filter != PMCS_INVALID_DEVICE_ID) { 1677 if (!iomb_is_dev_hdl_specific(word0, B_FALSE)) { 1678 return; 1679 } 1680 1681 /* 1682 * Go find the device id. It might be in the outbound 1683 * IOMB or we may have to go find the work structure and 1684 * get it from there. 1685 */ 1686 devid = get_devid_from_ob_iomb(ss, qentryp, 1687 word0 & PMCS_IOMB_OPCODE_MASK); 1688 if ((devid == PMCS_INVALID_DEVICE_ID) || 1689 (devid_filter != devid)) { 1690 return; 1691 } 1692 } 1693 1694 mdb_printf("Entry #%02d\n", idx); 1695 mdb_inc_indent(2); 1696 1697 mdb_printf("Header: 0x%08x (", word0); 1698 if (word0 & PMCS_IOMB_VALID) { 1699 mdb_printf("VALID, "); 1700 } 1701 if (word0 & PMCS_IOMB_HIPRI) { 1702 mdb_printf("HIPRI, "); 1703 } 1704 mdb_printf("OBID=%d, ", 1705 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1706 mdb_printf("CAT=%s, ", 1707 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1708 mdb_printf("OPCODE=%s", 1709 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1710 if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) { 1711 iop_event = IOP_EVENT_EVENT(word1); 1712 mdb_printf(" <%s>", iomb_event(iop_event)); 1713 } 1714 mdb_printf(")\n"); 1715 1716 mdb_printf("Remaining Payload:\n"); 1717 1718 mdb_inc_indent(2); 1719 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1720 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1721 } 1722 mdb_printf("\n"); 1723 mdb_dec_indent(4); 1724 } 1725 1726 static void 1727 display_outbound_queues(struct pmcs_hw ss, uint64_t devid_filter, 1728 uint_t verbose) 1729 { 1730 int idx, qidx; 1731 uintptr_t obqp; 1732 uint32_t *cip; 1733 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1734 uint32_t last_consumed, oqpi; 1735 1736 mdb_printf("\n"); 1737 mdb_printf("Outbound Queues\n"); 1738 mdb_printf("---------------\n"); 1739 1740 mdb_inc_indent(2); 1741 1742 for (qidx = 0; qidx < PMCS_NOQ; qidx++) { 1743 obqp = (uintptr_t)ss.oqp[qidx]; 1744 1745 if (obqp == 0) { 1746 mdb_printf("No outbound queue ptr for queue #%d\n", 1747 qidx); 1748 continue; 1749 } 1750 1751 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx, 1752 obq_type(qidx)); 1753 /* 1754 * Chip is the producer, so read the actual producer index 1755 * and not the driver's version 1756 */ 1757 cip = (uint32_t *)((void *)ss.cip); 1758 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET + 1759 (qidx * 4)) == -1) { 1760 mdb_warn("Couldn't read oqpi\n"); 1761 break; 1762 } 1763 1764 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1765 LE_32(oqpi), ss.oqci[qidx]); 1766 mdb_inc_indent(2); 1767 1768 if (ss.oqci[qidx] == 0) { 1769 last_consumed = ss.ioq_depth - 1; 1770 } else { 1771 last_consumed = ss.oqci[qidx] - 1; 1772 } 1773 1774 1775 if (!verbose) { 1776 mdb_printf("Last processed entry:\n"); 1777 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1778 (obqp + (PMCS_QENTRY_SIZE * last_consumed))) 1779 == -1) { 1780 mdb_warn("Couldn't read queue entry at 0x%p\n", 1781 (obqp + (PMCS_QENTRY_SIZE * 1782 last_consumed))); 1783 break; 1784 } 1785 dump_one_qentry_outbound(ss, qentryp, last_consumed, 1786 devid_filter); 1787 mdb_printf("\n"); 1788 mdb_dec_indent(2); 1789 continue; 1790 } 1791 1792 for (idx = 0; idx < ss.ioq_depth; idx++) { 1793 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1794 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1795 mdb_warn("Couldn't read queue entry at 0x%p\n", 1796 (obqp + (PMCS_QENTRY_SIZE * idx))); 1797 break; 1798 } 1799 dump_one_qentry_outbound(ss, qentryp, idx, 1800 devid_filter); 1801 } 1802 1803 mdb_printf("\n"); 1804 mdb_dec_indent(2); 1805 } 1806 1807 mdb_dec_indent(2); 1808 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1809 } 1810 1811 static void 1812 dump_one_qentry_inbound(uint32_t *qentryp, int idx, uint64_t devid_filter) 1813 { 1814 int qeidx; 1815 uint32_t word0 = LE_32(*qentryp); 1816 uint32_t devid = LE_32(*(qentryp + 2)); 1817 1818 /* 1819 * Check to see if we're filtering on a device ID 1820 */ 1821 if (devid_filter != PMCS_INVALID_DEVICE_ID) { 1822 if (iomb_is_dev_hdl_specific(word0, B_TRUE)) { 1823 if (devid_filter != devid) { 1824 return; 1825 } 1826 } else { 1827 return; 1828 } 1829 } 1830 1831 mdb_printf("Entry #%02d\n", idx); 1832 mdb_inc_indent(2); 1833 1834 mdb_printf("Header: 0x%08x (", word0); 1835 if (word0 & PMCS_IOMB_VALID) { 1836 mdb_printf("VALID, "); 1837 } 1838 if (word0 & PMCS_IOMB_HIPRI) { 1839 mdb_printf("HIPRI, "); 1840 } 1841 mdb_printf("OBID=%d, ", 1842 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT); 1843 mdb_printf("CAT=%s, ", 1844 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT)); 1845 mdb_printf("OPCODE=%s", 1846 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK)); 1847 mdb_printf(")\n"); 1848 1849 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1))); 1850 mdb_printf("Remaining Payload:\n"); 1851 1852 mdb_inc_indent(2); 1853 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) { 1854 mdb_printf("%08x ", LE_32(*(qentryp + qeidx))); 1855 } 1856 mdb_printf("\n"); 1857 mdb_dec_indent(4); 1858 } 1859 1860 static void 1861 display_inbound_queues(struct pmcs_hw ss, uint64_t devid_filter, uint_t verbose) 1862 { 1863 int idx, qidx, iqci, last_consumed; 1864 uintptr_t ibqp; 1865 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP); 1866 uint32_t *cip; 1867 1868 mdb_printf("\n"); 1869 mdb_printf("Inbound Queues\n"); 1870 mdb_printf("--------------\n"); 1871 1872 mdb_inc_indent(2); 1873 1874 for (qidx = 0; qidx < PMCS_NIQ; qidx++) { 1875 ibqp = (uintptr_t)ss.iqp[qidx]; 1876 1877 if (ibqp == 0) { 1878 mdb_printf("No inbound queue ptr for queue #%d\n", 1879 qidx); 1880 continue; 1881 } 1882 1883 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx, 1884 ibq_type(qidx)); 1885 1886 cip = (uint32_t *)((void *)ss.cip); 1887 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) { 1888 mdb_warn("Couldn't read iqci\n"); 1889 break; 1890 } 1891 iqci = LE_32(iqci); 1892 1893 mdb_printf("Producer index: %d Consumer index: %d\n\n", 1894 ss.shadow_iqpi[qidx], iqci); 1895 mdb_inc_indent(2); 1896 1897 if (iqci == 0) { 1898 last_consumed = ss.ioq_depth - 1; 1899 } else { 1900 last_consumed = iqci - 1; 1901 } 1902 1903 if (!verbose) { 1904 mdb_printf("Last processed entry:\n"); 1905 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1906 (ibqp + (PMCS_QENTRY_SIZE * last_consumed))) 1907 == -1) { 1908 mdb_warn("Couldn't read queue entry at 0x%p\n", 1909 (ibqp + (PMCS_QENTRY_SIZE * 1910 last_consumed))); 1911 break; 1912 } 1913 dump_one_qentry_inbound(qentryp, last_consumed, 1914 devid_filter); 1915 mdb_printf("\n"); 1916 mdb_dec_indent(2); 1917 continue; 1918 } 1919 1920 for (idx = 0; idx < ss.ioq_depth; idx++) { 1921 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE, 1922 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) { 1923 mdb_warn("Couldn't read queue entry at 0x%p\n", 1924 (ibqp + (PMCS_QENTRY_SIZE * idx))); 1925 break; 1926 } 1927 dump_one_qentry_inbound(qentryp, idx, devid_filter); 1928 } 1929 1930 mdb_printf("\n"); 1931 mdb_dec_indent(2); 1932 } 1933 1934 mdb_dec_indent(2); 1935 mdb_free(qentryp, PMCS_QENTRY_SIZE); 1936 } 1937 1938 /* 1939 * phy is our copy of the PHY structure. phyp is the pointer to the actual 1940 * kernel PHY data structure 1941 */ 1942 static void 1943 display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose, 1944 int totals_only) 1945 { 1946 char *dtype, *speed; 1947 char *yes = "Yes"; 1948 char *no = "No"; 1949 char *cfgd = no; 1950 char *apend = no; 1951 char *asent = no; 1952 char *dead = no; 1953 char *changed = no; 1954 char route_attr, route_method; 1955 1956 switch (phy.dtype) { 1957 case NOTHING: 1958 dtype = "None"; 1959 break; 1960 case SATA: 1961 dtype = "SATA"; 1962 if (phy.configured) { 1963 ++sata_phys; 1964 } 1965 break; 1966 case SAS: 1967 dtype = "SAS"; 1968 if (phy.configured) { 1969 ++sas_phys; 1970 } 1971 break; 1972 case EXPANDER: 1973 dtype = "EXP"; 1974 if (phy.configured) { 1975 ++exp_phys; 1976 } 1977 break; 1978 } 1979 1980 if (phy.dtype == NOTHING) { 1981 empty_phys++; 1982 } else if ((phy.dtype == EXPANDER) && phy.configured) { 1983 num_expanders++; 1984 } 1985 1986 if (totals_only) { 1987 return; 1988 } 1989 1990 switch (phy.link_rate) { 1991 case SAS_LINK_RATE_1_5GBIT: 1992 speed = "1.5Gb/s"; 1993 break; 1994 case SAS_LINK_RATE_3GBIT: 1995 speed = "3 Gb/s"; 1996 break; 1997 case SAS_LINK_RATE_6GBIT: 1998 speed = "6 Gb/s"; 1999 break; 2000 default: 2001 speed = "N/A"; 2002 break; 2003 } 2004 2005 if ((phy.dtype != NOTHING) || verbose) { 2006 print_sas_address(&phy); 2007 2008 if (phy.device_id != PMCS_INVALID_DEVICE_ID) { 2009 mdb_printf(" %3d %4d %6s %4s ", 2010 phy.device_id, phy.phynum, speed, dtype); 2011 } else { 2012 mdb_printf(" N/A %4d %6s %4s ", 2013 phy.phynum, speed, dtype); 2014 } 2015 2016 if (verbose) { 2017 if (phy.abort_sent) { 2018 asent = yes; 2019 } 2020 if (phy.abort_pending) { 2021 apend = yes; 2022 } 2023 if (phy.configured) { 2024 cfgd = yes; 2025 } 2026 if (phy.dead) { 2027 dead = yes; 2028 } 2029 if (phy.changed) { 2030 changed = yes; 2031 } 2032 2033 switch (phy.routing_attr) { 2034 case SMP_ROUTING_DIRECT: 2035 route_attr = 'D'; 2036 break; 2037 case SMP_ROUTING_SUBTRACTIVE: 2038 route_attr = 'S'; 2039 break; 2040 case SMP_ROUTING_TABLE: 2041 route_attr = 'T'; 2042 break; 2043 default: 2044 route_attr = '?'; 2045 break; 2046 } 2047 2048 switch (phy.routing_method) { 2049 case SMP_ROUTING_DIRECT: 2050 route_method = 'D'; 2051 break; 2052 case SMP_ROUTING_SUBTRACTIVE: 2053 route_method = 'S'; 2054 break; 2055 case SMP_ROUTING_TABLE: 2056 route_method = 'T'; 2057 break; 2058 default: 2059 route_attr = '?'; 2060 break; 2061 } 2062 2063 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d " 2064 "%1d 0x%p ", cfgd, apend, asent, changed, dead, 2065 phy.ref_count, route_attr, route_method, 2066 phy.enum_attempts, phy.reenumerate, phy.phy_lock); 2067 } 2068 2069 mdb_printf("Path: %s\n", phy.path); 2070 2071 /* 2072 * In verbose mode, on the next line print the drill down 2073 * info to see either the DISCOVER response or the REPORT 2074 * GENERAL response depending on the PHY's dtype 2075 */ 2076 if (verbose) { 2077 uintptr_t tphyp = (uintptr_t)phyp; 2078 2079 mdb_inc_indent(4); 2080 switch (phy.dtype) { 2081 case EXPANDER: 2082 if (!phy.configured) { 2083 break; 2084 } 2085 mdb_printf("REPORT GENERAL response: %p::" 2086 "print smp_report_general_resp_t\n", 2087 (tphyp + offsetof(struct pmcs_phy, 2088 rg_resp))); 2089 break; 2090 case SAS: 2091 case SATA: 2092 mdb_printf("DISCOVER response: %p::" 2093 "print smp_discover_resp_t\n", 2094 (tphyp + offsetof(struct pmcs_phy, 2095 disc_resp))); 2096 break; 2097 default: 2098 break; 2099 } 2100 mdb_dec_indent(4); 2101 } 2102 } 2103 } 2104 2105 static void 2106 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level, 2107 int totals_only) 2108 { 2109 pmcs_phy_t phy; 2110 pmcs_phy_t *pphy = parent; 2111 2112 mdb_inc_indent(3); 2113 2114 if (parent == NULL) { 2115 pphy = (pmcs_phy_t *)ss.root_phys; 2116 } else { 2117 pphy = (pmcs_phy_t *)parent; 2118 } 2119 2120 if (level == 0) { 2121 sas_phys = 0; 2122 sata_phys = 0; 2123 exp_phys = 0; 2124 num_expanders = 0; 2125 empty_phys = 0; 2126 } 2127 2128 if (!totals_only) { 2129 if (level == 0) { 2130 mdb_printf("PHY information\n"); 2131 } 2132 mdb_printf("--------\n"); 2133 mdb_printf("Level %2d\n", level); 2134 mdb_printf("--------\n"); 2135 mdb_printf("SAS Address Hdl Phy# Speed Type "); 2136 2137 if (verbose) { 2138 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R " 2139 "Lock\n"); 2140 } else { 2141 mdb_printf("\n"); 2142 } 2143 } 2144 2145 while (pphy) { 2146 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) { 2147 NOREAD(pmcs_phy_t, phy); 2148 break; 2149 } 2150 2151 display_phy(phy, pphy, verbose, totals_only); 2152 2153 if (phy.children) { 2154 display_phys(ss, verbose, phy.children, level + 1, 2155 totals_only); 2156 if (!totals_only) { 2157 mdb_printf("\n"); 2158 } 2159 } 2160 2161 pphy = phy.sibling; 2162 } 2163 2164 mdb_dec_indent(3); 2165 2166 if (level == 0) { 2167 if (verbose) { 2168 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) " 2169 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:", 2170 (sas_phys + sata_phys + num_expanders), 2171 sas_phys, sata_phys, num_expanders, 2172 (exp_phys - num_expanders), empty_phys); 2173 } else { 2174 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n", 2175 "Occupied PHYs:", 2176 (sas_phys + sata_phys + num_expanders), 2177 sas_phys, sata_phys, num_expanders); 2178 } 2179 } 2180 } 2181 2182 /* 2183 * filter is used to indicate whether we are filtering log messages based 2184 * on "instance". The other filtering (based on options) depends on the 2185 * values that are passed in for "sas_addr" and "phy_path". 2186 * 2187 * MAX_INST_STRLEN is the largest string size from which we will attempt 2188 * to convert to an instance number. The string will be formed up as 2189 * "0t<inst>\0" so that mdb_strtoull can parse it properly. 2190 */ 2191 #define MAX_INST_STRLEN 8 2192 2193 static int 2194 pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines, 2195 const char *phy_path, uint64_t sas_address, uint64_t verbose) 2196 { 2197 pmcs_tbuf_t *tbuf_addr; 2198 uint_t tbuf_idx; 2199 pmcs_tbuf_t tbuf; 2200 boolean_t wrap, elem_filtered; 2201 uint_t start_idx, elems_to_print, idx, tbuf_num_elems; 2202 char *bufp; 2203 char elem_inst[MAX_INST_STRLEN], ei_idx; 2204 uint64_t sas_addr; 2205 uint8_t *sas_addressp; 2206 2207 /* Get the address of the first element */ 2208 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) { 2209 mdb_warn("can't read pmcs_tbuf"); 2210 return (DCMD_ERR); 2211 } 2212 2213 /* Get the total number */ 2214 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) { 2215 mdb_warn("can't read pmcs_tbuf_num_elems"); 2216 return (DCMD_ERR); 2217 } 2218 2219 /* Get the current index */ 2220 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) { 2221 mdb_warn("can't read pmcs_tbuf_idx"); 2222 return (DCMD_ERR); 2223 } 2224 2225 /* Indicator as to whether the buffer has wrapped */ 2226 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) { 2227 mdb_warn("can't read pmcs_tbuf_wrap"); 2228 return (DCMD_ERR); 2229 } 2230 2231 /* 2232 * On little-endian systems, the SAS address passed in will be 2233 * byte swapped. Take care of that here. 2234 */ 2235 #if defined(_LITTLE_ENDIAN) 2236 sas_addr = ((sas_address << 56) | 2237 ((sas_address << 40) & 0xff000000000000ULL) | 2238 ((sas_address << 24) & 0xff0000000000ULL) | 2239 ((sas_address << 8) & 0xff00000000ULL) | 2240 ((sas_address >> 8) & 0xff000000ULL) | 2241 ((sas_address >> 24) & 0xff0000ULL) | 2242 ((sas_address >> 40) & 0xff00ULL) | 2243 (sas_address >> 56)); 2244 #else 2245 sas_addr = sas_address; 2246 #endif 2247 sas_addressp = (uint8_t *)&sas_addr; 2248 2249 /* Ensure the tail number isn't greater than the size of the log */ 2250 if (tail_lines > tbuf_num_elems) { 2251 tail_lines = tbuf_num_elems; 2252 } 2253 2254 /* Figure out where we start and stop */ 2255 if (wrap) { 2256 if (tail_lines) { 2257 /* Do we need to wrap backwards? */ 2258 if (tail_lines > tbuf_idx) { 2259 start_idx = tbuf_num_elems - (tail_lines - 2260 tbuf_idx); 2261 } else { 2262 start_idx = tbuf_idx - tail_lines; 2263 } 2264 elems_to_print = tail_lines; 2265 } else { 2266 start_idx = tbuf_idx; 2267 elems_to_print = tbuf_num_elems; 2268 } 2269 } else { 2270 if (tail_lines > tbuf_idx) { 2271 tail_lines = tbuf_idx; 2272 } 2273 if (tail_lines) { 2274 start_idx = tbuf_idx - tail_lines; 2275 elems_to_print = tail_lines; 2276 } else { 2277 start_idx = 0; 2278 elems_to_print = tbuf_idx; 2279 } 2280 } 2281 2282 idx = start_idx; 2283 2284 /* Dump the buffer contents */ 2285 while (elems_to_print != 0) { 2286 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx)) 2287 == -1) { 2288 NOREAD(tbuf, (tbuf_addr + idx)); 2289 return (DCMD_ERR); 2290 } 2291 2292 /* 2293 * Check for filtering on HBA instance 2294 */ 2295 elem_filtered = B_FALSE; 2296 2297 if (filter) { 2298 bufp = tbuf.buf; 2299 /* Skip the driver name */ 2300 while (*bufp < '0' || *bufp > '9') { 2301 bufp++; 2302 } 2303 2304 ei_idx = 0; 2305 elem_inst[ei_idx++] = '0'; 2306 elem_inst[ei_idx++] = 't'; 2307 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) { 2308 elem_inst[ei_idx++] = *bufp; 2309 bufp++; 2310 } 2311 elem_inst[ei_idx] = 0; 2312 2313 /* Get the instance */ 2314 if ((int)mdb_strtoull(elem_inst) != instance) { 2315 elem_filtered = B_TRUE; 2316 } 2317 } 2318 2319 if (!elem_filtered && (phy_path || sas_address)) { 2320 /* 2321 * This message is not being filtered by HBA instance. 2322 * Now check to see if we're filtering based on 2323 * PHY path or SAS address. 2324 * Filtering is an "OR" operation. So, if any of the 2325 * criteria matches, this message will be printed. 2326 */ 2327 elem_filtered = B_TRUE; 2328 2329 if (phy_path != NULL) { 2330 if (strncmp(phy_path, tbuf.phy_path, 2331 PMCS_TBUF_UA_MAX_SIZE) == 0) { 2332 elem_filtered = B_FALSE; 2333 } 2334 } 2335 if (sas_address != 0) { 2336 if (memcmp(sas_addressp, tbuf.phy_sas_address, 2337 8) == 0) { 2338 elem_filtered = B_FALSE; 2339 } 2340 } 2341 } 2342 2343 if (!elem_filtered) { 2344 /* 2345 * If the -v flag was given, print the firmware 2346 * timestamp along with the clock time 2347 */ 2348 mdb_printf("%Y.%09ld ", tbuf.timestamp); 2349 if (verbose) { 2350 mdb_printf("(0x%" PRIx64 ") ", 2351 tbuf.fw_timestamp); 2352 } 2353 mdb_printf("%s\n", tbuf.buf); 2354 } 2355 2356 --elems_to_print; 2357 if (++idx == tbuf_num_elems) { 2358 idx = 0; 2359 } 2360 } 2361 2362 return (DCMD_OK); 2363 } 2364 2365 /* 2366 * Walkers 2367 */ 2368 static int 2369 targets_walk_i(mdb_walk_state_t *wsp) 2370 { 2371 if (wsp->walk_addr == 0) { 2372 mdb_warn("Can not perform global walk\n"); 2373 return (WALK_ERR); 2374 } 2375 2376 /* 2377 * Address provided belongs to HBA softstate. Get the targets pointer 2378 * to begin the walk. 2379 */ 2380 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 2381 sizeof (pmcs_hw_t)) { 2382 mdb_warn("Unable to read HBA softstate\n"); 2383 return (WALK_ERR); 2384 } 2385 2386 if (targets == NULL) { 2387 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP); 2388 } 2389 2390 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) { 2391 NOREAD(targets, ss.targets); 2392 return (WALK_ERR); 2393 } 2394 2395 target_idx = 0; 2396 wsp->walk_addr = (uintptr_t)(targets[0]); 2397 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP); 2398 2399 return (WALK_NEXT); 2400 } 2401 2402 static int 2403 targets_walk_s(mdb_walk_state_t *wsp) 2404 { 2405 int status; 2406 2407 if (target_idx == ss.max_dev) { 2408 return (WALK_DONE); 2409 } 2410 2411 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t), 2412 wsp->walk_addr) == -1) { 2413 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr); 2414 return (WALK_DONE); 2415 } 2416 2417 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 2418 wsp->walk_cbdata); 2419 2420 do { 2421 wsp->walk_addr = (uintptr_t)(targets[++target_idx]); 2422 } while ((wsp->walk_addr == 0) && (target_idx < ss.max_dev)); 2423 2424 if (target_idx == ss.max_dev) { 2425 return (WALK_DONE); 2426 } 2427 2428 return (status); 2429 } 2430 2431 static void 2432 targets_walk_f(mdb_walk_state_t *wsp) 2433 { 2434 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t)); 2435 } 2436 2437 2438 static pmcs_phy_t * 2439 pmcs_next_sibling(pmcs_phy_t *phyp) 2440 { 2441 pmcs_phy_t parent; 2442 2443 /* 2444 * First, if this is a root PHY, there are no more siblings 2445 */ 2446 if (phyp->level == 0) { 2447 return (NULL); 2448 } 2449 2450 /* 2451 * Otherwise, next sibling is the parent's sibling 2452 */ 2453 while (phyp->level > 0) { 2454 if (mdb_vread(&parent, sizeof (pmcs_phy_t), 2455 (uintptr_t)phyp->parent) == -1) { 2456 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p", 2457 (void *)phyp->parent); 2458 return (NULL); 2459 } 2460 2461 if (parent.sibling != NULL) { 2462 break; 2463 } 2464 2465 /* 2466 * If this PHY's sibling is NULL and it's a root phy, 2467 * we're done. 2468 */ 2469 if (parent.level == 0) { 2470 return (NULL); 2471 } 2472 2473 phyp = phyp->parent; 2474 } 2475 2476 return (parent.sibling); 2477 } 2478 2479 static int 2480 phy_walk_i(mdb_walk_state_t *wsp) 2481 { 2482 if (wsp->walk_addr == 0) { 2483 mdb_warn("Can not perform global walk\n"); 2484 return (WALK_ERR); 2485 } 2486 2487 /* 2488 * Address provided belongs to HBA softstate. Get the targets pointer 2489 * to begin the walk. 2490 */ 2491 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) != 2492 sizeof (pmcs_hw_t)) { 2493 mdb_warn("Unable to read HBA softstate\n"); 2494 return (WALK_ERR); 2495 } 2496 2497 wsp->walk_addr = (uintptr_t)(ss.root_phys); 2498 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP); 2499 2500 return (WALK_NEXT); 2501 } 2502 2503 static int 2504 phy_walk_s(mdb_walk_state_t *wsp) 2505 { 2506 pmcs_phy_t *phyp, *nphyp; 2507 int status; 2508 2509 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t), 2510 wsp->walk_addr) == -1) { 2511 mdb_warn("phy_walk_s: Failed to read PHY at %p", 2512 (void *)wsp->walk_addr); 2513 return (WALK_DONE); 2514 } 2515 2516 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 2517 wsp->walk_cbdata); 2518 2519 phyp = (pmcs_phy_t *)wsp->walk_data; 2520 if (phyp->children) { 2521 wsp->walk_addr = (uintptr_t)(phyp->children); 2522 } else { 2523 wsp->walk_addr = (uintptr_t)(phyp->sibling); 2524 } 2525 2526 if (wsp->walk_addr == 0) { 2527 /* 2528 * We reached the end of this sibling list. Trudge back up 2529 * to the parent and find the next sibling after the expander 2530 * we just finished traversing, if there is one. 2531 */ 2532 nphyp = pmcs_next_sibling(phyp); 2533 2534 if (nphyp == NULL) { 2535 return (WALK_DONE); 2536 } 2537 2538 wsp->walk_addr = (uintptr_t)nphyp; 2539 } 2540 2541 return (status); 2542 } 2543 2544 static void 2545 phy_walk_f(mdb_walk_state_t *wsp) 2546 { 2547 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t)); 2548 } 2549 2550 static void 2551 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum, 2552 uintmax_t tag_type) 2553 { 2554 int idx; 2555 pmcwork_t work, *wp = &work; 2556 uintptr_t _wp; 2557 boolean_t printed_header = B_FALSE; 2558 uint32_t mask, mask_val, match_val; 2559 char *match_type; 2560 2561 if (index != UINT_MAX) { 2562 match_type = "index"; 2563 mask = PMCS_TAG_INDEX_MASK; 2564 mask_val = index << PMCS_TAG_INDEX_SHIFT; 2565 match_val = index; 2566 } else if (snum != UINT_MAX) { 2567 match_type = "serial number"; 2568 mask = PMCS_TAG_SERNO_MASK; 2569 mask_val = snum << PMCS_TAG_SERNO_SHIFT; 2570 match_val = snum; 2571 } else { 2572 switch (tag_type) { 2573 case PMCS_TAG_TYPE_NONE: 2574 match_type = "tag type NONE"; 2575 break; 2576 case PMCS_TAG_TYPE_CBACK: 2577 match_type = "tag type CBACK"; 2578 break; 2579 case PMCS_TAG_TYPE_WAIT: 2580 match_type = "tag type WAIT"; 2581 break; 2582 } 2583 mask = PMCS_TAG_TYPE_MASK; 2584 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT; 2585 match_val = tag_type; 2586 } 2587 2588 _wp = (uintptr_t)ss.work; 2589 2590 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) { 2591 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) { 2592 NOREAD(pmcwork_t, _wp); 2593 continue; 2594 } 2595 2596 if ((work.htag & mask) != mask_val) { 2597 continue; 2598 } 2599 2600 if (printed_header == B_FALSE) { 2601 if (tag_type) { 2602 mdb_printf("\nWork structures matching %s\n\n", 2603 match_type, match_val); 2604 } else { 2605 mdb_printf("\nWork structures matching %s of " 2606 "0x%x\n\n", match_type, match_val); 2607 } 2608 mdb_printf("%8s %10s %20s %8s %8s O D\n", 2609 "HTag", "State", "Phy Path", "Target", "Timer"); 2610 printed_header = B_TRUE; 2611 } 2612 2613 display_one_work(wp, 0, 0); 2614 } 2615 2616 if (!printed_header) { 2617 mdb_printf("No work structure matches found\n"); 2618 } 2619 } 2620 2621 static int 2622 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2623 { 2624 struct pmcs_hw ss; 2625 uintmax_t tag_type = UINT_MAX; 2626 uintmax_t snum = UINT_MAX; 2627 uintmax_t index = UINT_MAX; 2628 int args = 0; 2629 void *pmcs_state; 2630 char *state_str; 2631 struct dev_info dip; 2632 2633 if (!(flags & DCMD_ADDRSPEC)) { 2634 pmcs_state = NULL; 2635 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2636 mdb_warn("can't read pmcs_softc_state"); 2637 return (DCMD_ERR); 2638 } 2639 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc, 2640 argv, (uintptr_t)pmcs_state) == -1) { 2641 mdb_warn("mdb_pwalk_dcmd failed"); 2642 return (DCMD_ERR); 2643 } 2644 return (DCMD_OK); 2645 } 2646 2647 if (mdb_getopts(argc, argv, 2648 'i', MDB_OPT_UINT64, &index, 2649 's', MDB_OPT_UINT64, &snum, 2650 't', MDB_OPT_UINT64, &tag_type, 2651 NULL) != argc) 2652 return (DCMD_USAGE); 2653 2654 /* 2655 * Count the number of supplied options and make sure they are 2656 * within appropriate ranges. If they're set to UINT_MAX, that means 2657 * they were not supplied, in which case reset them to 0. 2658 */ 2659 if (index != UINT_MAX) { 2660 args++; 2661 if (index > PMCS_TAG_INDEX_MASK) { 2662 mdb_warn("Index is out of range\n"); 2663 return (DCMD_USAGE); 2664 } 2665 } 2666 2667 if (tag_type != UINT_MAX) { 2668 args++; 2669 switch (tag_type) { 2670 case PMCS_TAG_TYPE_NONE: 2671 case PMCS_TAG_TYPE_CBACK: 2672 case PMCS_TAG_TYPE_WAIT: 2673 break; 2674 default: 2675 mdb_warn("Invalid tag type\n"); 2676 return (DCMD_USAGE); 2677 } 2678 } 2679 2680 if (snum != UINT_MAX) { 2681 args++; 2682 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) { 2683 mdb_warn("Serial number is out of range\n"); 2684 return (DCMD_USAGE); 2685 } 2686 } 2687 2688 /* 2689 * Make sure 1 and only 1 option is specified 2690 */ 2691 if ((args == 0) || (args > 1)) { 2692 mdb_warn("Exactly one of -i, -s and -t must be specified\n"); 2693 return (DCMD_USAGE); 2694 } 2695 2696 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2697 NOREAD(pmcs_hw_t, addr); 2698 return (DCMD_ERR); 2699 } 2700 2701 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2702 NOREAD(pmcs_hw_t, addr); 2703 return (DCMD_ERR); 2704 } 2705 2706 /* processing completed */ 2707 2708 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 2709 (flags & DCMD_LOOPFIRST)) { 2710 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 2711 mdb_printf("\n"); 2712 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 2713 "Address", "State", "Inst", "DIP"); 2714 mdb_printf("=================================" 2715 "============================================\n"); 2716 } 2717 2718 switch (ss.state) { 2719 case STATE_NIL: 2720 state_str = "Invalid"; 2721 break; 2722 case STATE_PROBING: 2723 state_str = "Probing"; 2724 break; 2725 case STATE_RUNNING: 2726 state_str = "Running"; 2727 break; 2728 case STATE_UNPROBING: 2729 state_str = "Unprobing"; 2730 break; 2731 case STATE_DEAD: 2732 state_str = "Dead"; 2733 break; 2734 case STATE_IN_RESET: 2735 state_str = "In Reset"; 2736 break; 2737 } 2738 2739 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 2740 state_str, dip.devi_instance, ss.blocked, ss.configuring, 2741 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 2742 mdb_printf("\n"); 2743 2744 mdb_inc_indent(4); 2745 display_matching_work(ss, index, snum, tag_type); 2746 mdb_dec_indent(4); 2747 mdb_printf("\n"); 2748 2749 return (DCMD_OK); 2750 } 2751 2752 #ifndef _KMDB 2753 static int 2754 pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile) 2755 { 2756 uint8_t *fwlogp; 2757 int ofilefd = -1; 2758 char ofilename[MAXPATHLEN]; 2759 int rval = DCMD_OK; 2760 2761 if (ss->fwlogp == NULL) { 2762 mdb_warn("Firmware event log disabled for instance %d", 2763 instance); 2764 return (DCMD_OK); 2765 } 2766 2767 if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) > 2768 MAXPATHLEN) { 2769 mdb_warn("Output filename is too long for instance %d", 2770 instance); 2771 return (DCMD_ERR); 2772 } 2773 2774 fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP); 2775 2776 if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) { 2777 NOREAD(fwlogp, ss->fwlogp); 2778 rval = DCMD_ERR; 2779 goto cleanup; 2780 } 2781 2782 ofilefd = open(ofilename, O_WRONLY | O_CREAT, 2783 S_IRUSR | S_IRGRP | S_IROTH); 2784 if (ofilefd < 0) { 2785 mdb_warn("Unable to open '%s' to dump instance %d event log", 2786 ofilename, instance); 2787 rval = DCMD_ERR; 2788 goto cleanup; 2789 } 2790 2791 if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) { 2792 mdb_warn("Failed to write %d bytes to output file: instance %d", 2793 PMCS_FWLOG_SIZE, instance); 2794 rval = DCMD_ERR; 2795 goto cleanup; 2796 } 2797 2798 mdb_printf("Event log for instance %d written to %s\n", instance, 2799 ofilename); 2800 2801 cleanup: 2802 if (ofilefd >= 0) { 2803 close(ofilefd); 2804 } 2805 mdb_free(fwlogp, PMCS_FWLOG_SIZE); 2806 return (rval); 2807 } 2808 2809 static int 2810 pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2811 { 2812 void *pmcs_state; 2813 const char *ofile = NULL; 2814 struct pmcs_hw ss; 2815 struct dev_info dip; 2816 2817 if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) { 2818 return (DCMD_USAGE); 2819 } 2820 2821 if (ofile == NULL) { 2822 mdb_printf("No output file specified\n"); 2823 return (DCMD_USAGE); 2824 } 2825 2826 if (!(flags & DCMD_ADDRSPEC)) { 2827 pmcs_state = NULL; 2828 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2829 mdb_warn("can't read pmcs_softc_state"); 2830 return (DCMD_ERR); 2831 } 2832 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc, 2833 argv, (uintptr_t)pmcs_state) == -1) { 2834 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2835 return (DCMD_ERR); 2836 } 2837 return (DCMD_OK); 2838 } 2839 2840 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2841 NOREAD(pmcs_hw_t, addr); 2842 return (DCMD_ERR); 2843 } 2844 2845 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2846 NOREAD(pmcs_hw_t, addr); 2847 return (DCMD_ERR); 2848 } 2849 2850 return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile)); 2851 } 2852 #endif /* _KMDB */ 2853 2854 static int 2855 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2856 { 2857 void *pmcs_state; 2858 struct pmcs_hw ss; 2859 struct dev_info dip; 2860 const char *match_phy_path = NULL; 2861 uint64_t match_sas_address = 0, tail_lines = 0; 2862 uint_t verbose = 0; 2863 2864 if (!(flags & DCMD_ADDRSPEC)) { 2865 pmcs_state = NULL; 2866 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2867 mdb_warn("can't read pmcs_softc_state"); 2868 return (DCMD_ERR); 2869 } 2870 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc, 2871 argv, (uintptr_t)pmcs_state) == -1) { 2872 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log"); 2873 return (DCMD_ERR); 2874 } 2875 return (DCMD_OK); 2876 } 2877 2878 if (mdb_getopts(argc, argv, 2879 'l', MDB_OPT_UINT64, &tail_lines, 2880 'p', MDB_OPT_STR, &match_phy_path, 2881 's', MDB_OPT_UINT64, &match_sas_address, 2882 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2883 NULL) != argc) { 2884 return (DCMD_USAGE); 2885 } 2886 2887 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 2888 NOREAD(pmcs_hw_t, addr); 2889 return (DCMD_ERR); 2890 } 2891 2892 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 2893 NOREAD(pmcs_hw_t, addr); 2894 return (DCMD_ERR); 2895 } 2896 2897 if (!(flags & DCMD_LOOP)) { 2898 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance, 2899 tail_lines, match_phy_path, match_sas_address, verbose)); 2900 } else if (flags & DCMD_LOOPFIRST) { 2901 return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines, 2902 match_phy_path, match_sas_address, verbose)); 2903 } else { 2904 return (DCMD_OK); 2905 } 2906 } 2907 2908 static int 2909 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2910 { 2911 struct pmcs_hw ss; 2912 uint_t verbose = FALSE; 2913 uint_t phy_info = FALSE; 2914 uint_t hw_info = FALSE; 2915 uint_t target_info = FALSE; 2916 uint_t work_info = FALSE; 2917 uint_t ic_info = FALSE; 2918 uint_t iport_info = FALSE; 2919 uint_t waitqs_info = FALSE; 2920 uint_t ibq = FALSE; 2921 uint_t obq = FALSE; 2922 uint_t tgt_phy_count = FALSE; 2923 uint_t compq = FALSE; 2924 uint_t unconfigured = FALSE; 2925 uint_t damap_info = FALSE; 2926 uint_t dtc_info = FALSE; 2927 uint_t wserno = FALSE; 2928 uint_t fwlog = FALSE; 2929 boolean_t devid_filter = FALSE; 2930 uintptr_t pdevid; 2931 uint32_t devid; 2932 int rv = DCMD_OK; 2933 void *pmcs_state; 2934 char *state_str; 2935 struct dev_info dip; 2936 per_iport_setting_t pis; 2937 2938 if (!(flags & DCMD_ADDRSPEC)) { 2939 pmcs_state = NULL; 2940 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) { 2941 mdb_warn("can't read pmcs_softc_state"); 2942 return (DCMD_ERR); 2943 } 2944 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv, 2945 (uintptr_t)pmcs_state) == -1) { 2946 mdb_warn("mdb_pwalk_dcmd failed"); 2947 return (DCMD_ERR); 2948 } 2949 return (DCMD_OK); 2950 } 2951 2952 if (mdb_getopts(argc, argv, 2953 'c', MDB_OPT_SETBITS, TRUE, &compq, 2954 'd', MDB_OPT_SETBITS, TRUE, &dtc_info, 2955 'D', MDB_OPT_UINTPTR_SET, &devid_filter, &pdevid, 2956 'e', MDB_OPT_SETBITS, TRUE, &fwlog, 2957 'h', MDB_OPT_SETBITS, TRUE, &hw_info, 2958 'i', MDB_OPT_SETBITS, TRUE, &ic_info, 2959 'I', MDB_OPT_SETBITS, TRUE, &iport_info, 2960 'm', MDB_OPT_SETBITS, TRUE, &damap_info, 2961 'p', MDB_OPT_SETBITS, TRUE, &phy_info, 2962 'q', MDB_OPT_SETBITS, TRUE, &ibq, 2963 'Q', MDB_OPT_SETBITS, TRUE, &obq, 2964 's', MDB_OPT_SETBITS, TRUE, &wserno, 2965 't', MDB_OPT_SETBITS, TRUE, &target_info, 2966 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count, 2967 'u', MDB_OPT_SETBITS, TRUE, &unconfigured, 2968 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2969 'w', MDB_OPT_SETBITS, TRUE, &work_info, 2970 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info, 2971 NULL) != argc) 2972 return (DCMD_USAGE); 2973 2974 /* 2975 * The 'd' and 'm' options implicitly enable the 'I' option 2976 */ 2977 pis.pis_damap_info = damap_info; 2978 pis.pis_dtc_info = dtc_info; 2979 if (damap_info || dtc_info) { 2980 iport_info = TRUE; 2981 } 2982 2983 /* 2984 * The -D option is meaningless without -q and/or -Q, and implies 2985 * verbosity. 2986 */ 2987 if (devid_filter) { 2988 devid = (uint64_t)pdevid & 0xffffffff; 2989 if (!ibq && !obq) { 2990 mdb_printf("-D requires either -q or -Q\n"); 2991 return (DCMD_USAGE); 2992 } 2993 if (devid > PMCS_DEVICE_ID_MASK) { 2994 mdb_printf("Device ID invalid\n"); 2995 return (DCMD_USAGE); 2996 } 2997 verbose = TRUE; 2998 } 2999 3000 if (MDB_RD(&ss, sizeof (ss), addr) == -1) { 3001 NOREAD(pmcs_hw_t, addr); 3002 return (DCMD_ERR); 3003 } 3004 3005 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) { 3006 NOREAD(pmcs_hw_t, addr); 3007 return (DCMD_ERR); 3008 } 3009 3010 /* processing completed */ 3011 3012 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || 3013 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info || 3014 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq || 3015 unconfigured || fwlog) { 3016 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) 3017 mdb_printf("\n"); 3018 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n", 3019 "Address", "State", "Inst", "DIP"); 3020 mdb_printf("=================================" 3021 "============================================\n"); 3022 } 3023 3024 switch (ss.state) { 3025 case STATE_NIL: 3026 state_str = "Invalid"; 3027 break; 3028 case STATE_PROBING: 3029 state_str = "Probing"; 3030 break; 3031 case STATE_RUNNING: 3032 state_str = "Running"; 3033 break; 3034 case STATE_UNPROBING: 3035 state_str = "Unprobing"; 3036 break; 3037 case STATE_DEAD: 3038 state_str = "Dead"; 3039 break; 3040 case STATE_IN_RESET: 3041 state_str = "In Reset"; 3042 break; 3043 } 3044 3045 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr, 3046 state_str, dip.devi_instance, ss.blocked, ss.configuring, 3047 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip); 3048 mdb_printf("\n"); 3049 3050 mdb_inc_indent(4); 3051 3052 if (waitqs_info) 3053 display_waitqs(ss, verbose); 3054 3055 if (hw_info) 3056 display_hwinfo(ss, verbose); 3057 3058 if (phy_info || tgt_phy_count) 3059 display_phys(ss, verbose, NULL, 0, tgt_phy_count); 3060 3061 if (target_info || tgt_phy_count) 3062 display_targets(ss, verbose, tgt_phy_count); 3063 3064 if (work_info || wserno) 3065 display_work(ss, verbose, wserno); 3066 3067 if (ic_info) 3068 display_ic(ss, verbose); 3069 3070 if (ibq) 3071 display_inbound_queues(ss, devid, verbose); 3072 3073 if (obq) 3074 display_outbound_queues(ss, devid, verbose); 3075 3076 if (iport_info) 3077 display_iport(ss, addr, verbose, &pis); 3078 3079 if (compq) 3080 display_completion_queue(ss); 3081 3082 if (unconfigured) 3083 display_unconfigured_targets(addr); 3084 3085 if (fwlog) 3086 display_event_log(ss); 3087 3088 mdb_dec_indent(4); 3089 3090 return (rv); 3091 } 3092 3093 void 3094 pmcs_help() 3095 { 3096 mdb_printf("Prints summary information about each pmcs instance.\n" 3097 " -c: Dump the completion queue\n" 3098 " -d: Print per-iport information about device tree children\n" 3099 " -D <device ID>: With -q/-Q, filter by device handle\n" 3100 " -e: Display the in-memory firmware event log\n" 3101 " -h: Print more detailed hardware information\n" 3102 " -i: Print interrupt coalescing information\n" 3103 " -I: Print information about each iport\n" 3104 " -m: Print per-iport information about DAM/damap state\n" 3105 " -p: Print information about each attached PHY\n" 3106 " -q: Dump inbound queues\n" 3107 " -Q: Dump outbound queues\n" 3108 " -s: Dump all work structures sorted by serial number\n" 3109 " -t: Print information about each configured target\n" 3110 " -T: Print target and PHY count summary\n" 3111 " -u: Show SAS address of all unconfigured targets\n" 3112 " -w: Dump work structures\n" 3113 " -W: List pmcs cmds waiting on various queues\n" 3114 " -v: Add verbosity to the above options\n"); 3115 } 3116 3117 void 3118 pmcs_log_help() 3119 { 3120 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n" 3121 " -l TAIL_LINES: Dump the last TAIL_LINES messages\n" 3122 " -p PHY_PATH: Dump messages matching PHY_PATH\n" 3123 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n" 3124 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n" 3125 " SAS_ADDRESS can be found with ::pmcs -t " 3126 "(e.g. 5000c5000358c221)\n"); 3127 } 3128 void 3129 pmcs_tag_help() 3130 { 3131 mdb_printf("Print all work structures by matching the tag.\n" 3132 " -i index: Match tag index (0x000 - 0xfff)\n" 3133 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n" 3134 " -t tagtype: Match tag type [NONE(1), CBACK(2), " 3135 "WAIT(3)]\n"); 3136 } 3137 3138 static const mdb_dcmd_t dcmds[] = { 3139 { "pmcs", "?[-cdehiImpQqtTuwWv] [-D <device ID>]", 3140 "print pmcs information", pmcs_dcmd, pmcs_help 3141 }, 3142 { "pmcs_log", 3143 "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]", 3144 "dump pmcs log file", pmcs_log, pmcs_log_help 3145 }, 3146 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]", 3147 "Find work structures by tag type, serial number or index", 3148 pmcs_tag, pmcs_tag_help 3149 }, 3150 #ifndef _KMDB 3151 { "pmcs_fwlog", 3152 "?-o output_file", 3153 "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL 3154 }, 3155 #endif /* _KMDB */ 3156 { NULL } 3157 }; 3158 3159 static const mdb_walker_t walkers[] = { 3160 { "pmcs_targets", "walk target structures", 3161 targets_walk_i, targets_walk_s, targets_walk_f }, 3162 { "pmcs_phys", "walk PHY structures", 3163 phy_walk_i, phy_walk_s, phy_walk_f }, 3164 { NULL } 3165 }; 3166 3167 static const mdb_modinfo_t modinfo = { 3168 MDB_API_VERSION, dcmds, walkers 3169 }; 3170 3171 const mdb_modinfo_t * 3172 _mdb_init(void) 3173 { 3174 return (&modinfo); 3175 } 3176