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