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