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.
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.
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]
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
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>
36 #include <sys/types.h>
43 * We need use this to pass the settings when display_iport
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
;
51 * This structure is used for sorting work structures by the wserno
53 typedef struct wserno_list
{
56 struct wserno_list
*next
;
57 struct wserno_list
*prev
;
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)
64 static pmcs_xscsi_t
**targets
= NULL
;
65 static int target_idx
;
67 static uint32_t sas_phys
, sata_phys
, exp_phys
, num_expanders
, empty_phys
;
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
);
73 print_sas_address(pmcs_phy_t
*phy
)
77 for (idx
= 0; idx
< 8; idx
++) {
78 mdb_printf("%02x", phy
->sas_address
[idx
]);
83 pmcs_fwtime_to_systime(struct pmcs_hw ss
, uint32_t fw_hi
, uint32_t fw_lo
,
84 struct timespec
*stime
)
89 boolean_t backward_time
= B_FALSE
;
91 fwtime
= ((uint64_t)fw_hi
<< 32) | fw_lo
;
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
98 if (fwtime
>= ss
.fw_timestamp
) {
99 fwtime
-= ss
.fw_timestamp
;
101 fwtime
= ss
.fw_timestamp
- fwtime
;
102 backward_time
= B_TRUE
;
105 secs
= ((time_t)fwtime
/ NSECS_PER_SEC
);
106 nsecs
= ((long)fwtime
% NSECS_PER_SEC
);
108 stime
->tv_sec
= ss
.sys_timestamp
.tv_sec
;
109 stime
->tv_nsec
= ss
.sys_timestamp
.tv_nsec
;
112 if (stime
->tv_nsec
< nsecs
) {
114 stime
->tv_nsec
= stime
->tv_nsec
+ NSECS_PER_SEC
- nsecs
;
116 stime
->tv_nsec
-= nsecs
;
118 stime
->tv_sec
-= secs
;
120 if (stime
->tv_nsec
+ nsecs
> NSECS_PER_SEC
) {
123 stime
->tv_nsec
= (stime
->tv_nsec
+ nsecs
) % NSECS_PER_SEC
;
124 stime
->tv_sec
+= secs
;
130 display_ic(struct pmcs_hw m
, int verbose
)
134 if (mdb_readvar(&msec_per_tick
, "msec_per_tick") == -1) {
135 mdb_warn("can't read msec_per_tick");
140 mdb_printf("Interrupt coalescing timer info\n");
141 mdb_printf("-------------------------------\n");
142 if (msec_per_tick
== 0) {
143 mdb_printf("Quantum : ?? ms\n");
145 mdb_printf("Quantum : %d ms\n",
146 m
.io_intr_coal
.quantum
* msec_per_tick
);
148 mdb_printf("Timer enabled : ");
149 if (m
.io_intr_coal
.timer_on
) {
151 mdb_printf("Coalescing timer value : %d us\n",
152 m
.io_intr_coal
.intr_coal_timer
);
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
);
174 pmcs_iport_phy_walk_cb(uintptr_t addr
, const void *wdata
, void *priv
)
178 if (mdb_vread(&phy
, sizeof (struct pmcs_phy
), addr
) !=
179 sizeof (struct pmcs_phy
)) {
183 mdb_printf("%16p %2d\n", addr
, phy
.phynum
);
189 display_iport_damap(dev_info_t
*pdip
)
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 */
199 if (mdb_vread(&dip
, sizeof (struct dev_info
), (uintptr_t)pdip
) !=
200 sizeof (struct dev_info
)) {
204 if (dip
.devi_driver_data
== NULL
) {
208 if (mdb_vread(&sht
, sizeof (scsi_hba_tran_t
),
209 (uintptr_t)dip
.devi_driver_data
) != sizeof (scsi_hba_tran_t
)) {
213 if (sht
.tran_tgtmap
== NULL
) {
217 if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid
) != 0) {
221 if (mdb_ctf_offsetof(istm_ctfid
, "tgtmap_dam", &tmd_offset
) != 0) {
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
));
232 rval
= mdb_call_dcmd("damap", dam0
, DCMD_ADDRSPEC
, 0, NULL
);
234 if (rval
!= DCMD_OK
) {
240 rval
= mdb_call_dcmd("damap", dam1
, DCMD_ADDRSPEC
, 0, NULL
);
249 display_iport_di_cb(uintptr_t addr
, const void *wdata
, void *priv
)
251 uint_t
*idx
= (uint_t
*)priv
;
253 char devi_name
[MAXNAMELEN
];
254 char devi_addr
[MAXNAMELEN
];
256 if (mdb_vread(&dip
, sizeof (struct dev_info
), (uintptr_t)addr
) !=
257 sizeof (struct dev_info
)) {
261 if (mdb_readstr(devi_name
, sizeof (devi_name
),
262 (uintptr_t)dip
.devi_node_name
) == -1) {
267 if (mdb_readstr(devi_addr
, sizeof (devi_addr
),
268 (uintptr_t)dip
.devi_addr
) == -1) {
273 mdb_printf(" %3d: @%-21s%10s@\t%p::devinfo -s\n",
274 (*idx
)++, devi_addr
, devi_name
, addr
);
280 display_iport_pi_cb(uintptr_t addr
, const void *wdata
, void *priv
)
282 uint_t
*idx
= (uint_t
*)priv
;
283 struct mdi_pathinfo mpi
;
284 char pi_addr
[MAXNAMELEN
];
286 if (mdb_vread(&mpi
, sizeof (struct mdi_pathinfo
), (uintptr_t)addr
) !=
287 sizeof (struct mdi_pathinfo
)) {
291 if (mdb_readstr(pi_addr
, sizeof (pi_addr
),
292 (uintptr_t)mpi
.pi_addr
) == -1) {
297 mdb_printf(" %3d: @%-21s %p::print struct mdi_pathinfo\n",
298 (*idx
)++, pi_addr
, addr
);
303 display_iport_dtc(dev_info_t
*pdip
)
307 struct mdi_phci phci
;
311 if (mdb_vread(&dip
, sizeof (struct dev_info
), (uintptr_t)pdip
) !=
312 sizeof (struct dev_info
)) {
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");
323 * First, we dump the iport's children dev_info node information.
324 * use existing walker: devinfo_siblings
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
);
333 * Then we try to dump the iport's path_info node information.
334 * use existing walker: mdipi_phci_list
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");
343 if (phci
.ph_path_head
== NULL
) {
344 mdb_printf("\tph_path_head is NULL, no path_info\n\n");
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
);
356 display_iport_more(dev_info_t
*dip
, per_iport_setting_t
*pis
)
358 if (pis
->pis_damap_info
) {
359 (void) display_iport_damap(dip
);
362 if (pis
->pis_dtc_info
) {
363 (void) display_iport_dtc(dip
);
369 pmcs_iport_walk_cb(uintptr_t addr
, const void *wdata
, void *priv
)
371 struct pmcs_iport iport
;
375 char unit_address
[34];
376 per_iport_setting_t
*pis
= (per_iport_setting_t
*)priv
;
378 if (mdb_vread(&iport
, sizeof (struct pmcs_iport
), addr
) !=
379 sizeof (struct pmcs_iport
)) {
383 if (mdb_readstr(unit_address
, sizeof (unit_address
),
384 (uintptr_t)(iport
.ua
)) == -1) {
385 strncpy(unit_address
, "Unset", sizeof (unit_address
));
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");
393 mdb_snprintf(portid
, sizeof (portid
), "%d", iport
.portid
);
396 switch (iport
.ua_state
) {
398 ua_state
= "Inactive";
400 case UA_PEND_ACTIVATE
:
401 ua_state
= "PendActivate";
406 case UA_PEND_DEACTIVATE
:
407 ua_state
= "PendDeactivate";
410 ua_state
= "Unknown";
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
);
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
);
427 if (iport
.nphy
> 0) {
429 mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
432 (uintptr_t)(addr
+ offsetof(struct pmcs_iport
, phys
));
433 if (mdb_pwalk("list", pmcs_iport_phy_walk_cb
, NULL
,
435 mdb_warn("pmcs iport walk failed");
442 * See if we need to show more information based on 'd' or 'm' options
444 display_iport_more(iport
.dip
, pis
);
451 display_iport(struct pmcs_hw m
, uintptr_t addr
, int verbose
,
452 per_iport_setting_t
*pis
)
456 if (m
.iports_attached
) {
457 mdb_printf("Iport information:\n");
458 mdb_printf("-----------------\n");
460 mdb_printf("No Iports found.\n\n");
464 list_addr
= (uintptr_t)(addr
+ offsetof(struct pmcs_hw
, iports
));
466 if (mdb_pwalk("list", pmcs_iport_walk_cb
, pis
, list_addr
) == -1) {
467 mdb_warn("pmcs iport walk failed");
475 pmcs_utarget_walk_cb(uintptr_t addr
, const void *wdata
, void *priv
)
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",
485 if (phy
.configured
&& (phy
.target
== NULL
)) {
486 mdb_printf("SAS address: ");
487 print_sas_address(&phy
);
488 mdb_printf(" DType: ");
491 mdb_printf("%4s", "SAS");
494 mdb_printf("%4s", "SATA");
497 mdb_printf("%4s", "SMP");
500 mdb_printf("%4s", "N/A");
503 mdb_printf(" Path: %s\n", phy
.path
);
510 display_unconfigured_targets(uintptr_t addr
)
512 mdb_printf("Unconfigured target SAS address:\n\n");
514 if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb
, NULL
, addr
) == -1) {
515 mdb_warn("pmcs phys walk failed");
520 display_completion_queue(struct pmcs_hw ss
)
522 pmcs_iocomp_cb_t ccb
, *ccbp
;
525 if (ss
.iocomp_cb_head
== NULL
) {
526 mdb_printf("Completion queue is empty.\n");
530 ccbp
= ss
.iocomp_cb_head
;
531 mdb_printf("%8s %10s %20s %8s %8s O D\n",
532 "HTag", "State", "Phy Path", "Target", "Timer");
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");
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");
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
552 if (work
.state
!= PMCS_WORK_STATE_NIL
) {
553 display_one_work(&work
, 0, 0);
560 display_event_log(struct pmcs_hw ss
)
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
;
568 if (ss
.fwlogp
== NULL
) {
569 mdb_printf("There is no firmware event log.\n");
573 fwlogp
= (char *)ss
.fwlogp
;
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");
583 * Firmware event log is little-endian
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
);
592 if (fwhdr
.fw_el_signature
== PMCS_FWLOG_AAP1_SIG
) {
594 } else if (fwhdr
.fw_el_signature
== PMCS_FWLOG_IOP_SIG
) {
597 mdb_warn("Invalid firmware event log signature\n");
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
);
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
);
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");
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");
625 for (sidx
= 0; sidx
< (fwhdr
.fw_el_entry_size
/
626 sizeof (uint32_t)); sidx
++) {
627 *(swapp
+ sidx
) = LE_32(*(swapp
+ sidx
));
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
,
642 fwlogp
+= fwhdr
.fw_el_entry_size
;
643 total_size
-= fwhdr
.fw_el_entry_size
;
644 log_size
-= fwhdr
.fw_el_entry_size
;
652 mdb_free(entry
, fwhdr
.fw_el_entry_size
);
657 display_hwinfo(struct pmcs_hw m
, int verbose
)
659 struct pmcs_hw
*mp
= &m
;
662 switch (PMCS_FW_TYPE(mp
)) {
663 case PMCS_FW_TYPE_RELEASED
:
664 fwsupport
= "Released";
666 case PMCS_FW_TYPE_DEVELOPMENT
:
667 fwsupport
= "Development";
669 case PMCS_FW_TYPE_ALPHA
:
672 case PMCS_FW_TYPE_BETA
:
676 fwsupport
= "Special";
680 mdb_printf("\nHardware information:\n");
681 mdb_printf("---------------------\n");
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
),
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');
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
);
697 mdb_printf("Firmware logging: Disabled\n");
699 mdb_printf("Firmware logging: Enabled (%d)\n", m
.fwlog
);
701 if (m
.fwlog_file
== 0) {
702 mdb_printf("Firmware logfile: Not configured\n");
704 mdb_printf("Firmware logfile: Configured\n");
706 mdb_printf("AAP1 log file: %s\n", m
.fwlogfile_aap1
);
707 mdb_printf("IOP logfile: %s\n", m
.fwlogfile_iop
);
713 display_targets(struct pmcs_hw m
, int verbose
, int totals_only
)
718 uint16_t max_dev
, idx
;
719 uint32_t sas_targets
= 0, smp_targets
= 0, sata_targets
= 0;
723 if (targets
== NULL
) {
724 targets
= mdb_alloc(sizeof (targets
) * max_dev
, UM_SLEEP
);
727 if (MDB_RD(targets
, sizeof (targets
) * max_dev
, m
.targets
) == -1) {
728 NOREAD(targets
, m
.targets
);
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");
740 for (idx
= 0; idx
< max_dev
; idx
++) {
741 if (targets
[idx
] == NULL
) {
745 if (MDB_RD(&xs
, sizeof (xs
), targets
[idx
]) == -1) {
746 NOREAD(pmcs_xscsi_t
, targets
[idx
]);
751 * It has to be new or assigned to be of interest.
753 if (xs
.new == 0 && xs
.assigned
== 0) {
780 if (MDB_RD(&phy
, sizeof (phy
), xs
.phy
) == -1) {
781 NOREAD(pmcs_phy_t
, xs
.phy
);
784 mdb_printf("%4d ", idx
);
785 print_sas_address(&phy
);
786 mdb_printf(" %16p", xs
.phy
);
788 mdb_printf("%4d %16s", idx
, "<no phy avail>");
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
);
800 mdb_printf(" assigned");
803 mdb_printf(" draining");
806 mdb_printf(" reset_wait");
809 mdb_printf(" resetting");
811 if (xs
.recover_wait
) {
812 mdb_printf(" recover_wait");
815 mdb_printf(" recovering");
817 if (xs
.event_recovery
) {
818 mdb_printf(" event recovery");
820 if (xs
.special_running
) {
821 mdb_printf(" special_active");
824 mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
825 xs
.tagmap
, xs
.qdepth
);
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
);
844 work_state_to_string(uint32_t state
)
849 case PMCS_WORK_STATE_NIL
:
850 state_string
= "Free";
852 case PMCS_WORK_STATE_READY
:
853 state_string
= "Ready";
855 case PMCS_WORK_STATE_ONCHIP
:
856 state_string
= "On Chip";
858 case PMCS_WORK_STATE_INTR
:
859 state_string
= "In Intr";
861 case PMCS_WORK_STATE_IOCOMPQ
:
862 state_string
= "I/O Comp";
864 case PMCS_WORK_STATE_ABORTED
:
865 state_string
= "I/O Aborted";
867 case PMCS_WORK_STATE_TIMED_OUT
:
868 state_string
= "I/O Timed Out";
871 state_string
= "INVALID";
875 return (state_string
);
879 display_one_work(pmcwork_t
*wp
, int verbose
, int idx
)
881 char *state
, *last_state
;
887 state
= work_state_to_string(wp
->state
);
888 last_state
= work_state_to_string(wp
->last_state
);
890 if (wp
->ssp_event
&& wp
->ssp_event
!= 0xffffffff) {
891 mdb_printf("SSP event 0x%x", wp
->ssp_event
);
896 if (MDB_RD(&xs
, sizeof (xs
), wp
->xp
) == -1) {
897 NOREAD(pmcs_xscsi_t
, wp
->xp
);
903 if (MDB_RD(&phy
, sizeof (phy
), wp
->phy
) == -1) {
904 NOREAD(pmcs_phy_t
, wp
->phy
);
912 mdb_printf("%4d ", idx
);
915 mdb_printf("%08x %10s %20s N/A %8u %1d %1d ",
916 wp
->htag
, state
, path
, wp
->timer
,
917 wp
->onwire
, wp
->dead
);
919 mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
920 wp
->htag
, state
, path
, tgt
, wp
->timer
,
921 wp
->onwire
, wp
->dead
);
924 mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
925 wp
->last_htag
, last_state
, wp
->last_phy
, wp
->last_xp
,
933 display_work(struct pmcs_hw m
, int verbose
, int wserno
)
936 boolean_t header_printed
= B_FALSE
;
938 wserno_list_t
*sernop
, *sp
, *newsp
, *sphead
= NULL
;
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
);
947 mdb_printf("\nActive Work structure information:\n");
948 mdb_printf("----------------------------------\n");
951 * Read in all the work structures
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
);
961 * Sort by serial number?
964 for (idx
= 0; idx
< m
.max_cmd
; idx
++) {
965 if ((wp
+ idx
)->htag
== 0) {
966 serno
= PMCS_TAG_SERNO((wp
+ idx
)->last_htag
);
968 serno
= PMCS_TAG_SERNO((wp
+ idx
)->htag
);
971 /* Start at the beginning of the list */
973 newsp
= sernop
+ idx
;
974 /* If this is the first entry, just add it */
975 if (sphead
== NULL
) {
977 sphead
->serno
= serno
;
984 newsp
->serno
= serno
;
987 /* Find out where in the list this goes */
989 /* This item goes before sp */
990 if (serno
< sp
->serno
) {
992 newsp
->prev
= sp
->prev
;
993 if (newsp
->prev
== NULL
) {
996 newsp
->prev
->next
= newsp
;
1003 * If sp->next is NULL, this entry goes at the
1006 if (sp
->next
== NULL
) {
1018 * Now print the sorted list
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");
1027 display_one_work(wp
+ sp
->idx
, 1, sp
->idx
);
1035 * Now print the list, sorted by index
1037 for (idx
= 0; idx
< m
.max_cmd
; idx
++) {
1038 if (!verbose
&& ((wp
+ idx
)->htag
== PMCS_TAG_TYPE_FREE
)) {
1042 if (header_printed
== B_FALSE
) {
1044 mdb_printf("%4s ", "Idx");
1046 mdb_printf("%8s %10s %20s %8s %8s O D ",
1047 "HTag", "State", "Phy Path", "Target", "Timer");
1049 mdb_printf("%8s %10s %18s %18s %18s\n",
1050 "LastHTAG", "LastState", "LastPHY",
1051 "LastTgt", "LastArg");
1055 header_printed
= B_TRUE
;
1058 display_one_work(wp
+ idx
, verbose
, idx
);
1062 mdb_free(wp
, sizeof (pmcwork_t
) * m
.max_cmd
);
1063 mdb_free(sernop
, sizeof (wserno_list_t
) * m
.max_cmd
);
1067 print_spcmd(pmcs_cmd_t
*sp
, void *kaddr
, int printhdr
, int verbose
)
1070 struct scsi_pkt pkt
;
1075 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
1076 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
1078 mdb_printf("%16s %16s %16s %8s %s\n", "Command",
1079 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
1083 mdb_printf("%16p %16p %16p %08x %08x ",
1084 kaddr
, sp
->cmd_pkt
, sp
->cmd_clist
, sp
->cmd_tag
, sp
->cmd_satltag
);
1087 * If we're printing verbose, dump the CDB as well.
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");
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");
1104 for (idx
= 0; idx
< cdb_size
; idx
++) {
1105 mdb_printf("%02x ", cdb
[idx
]);
1119 display_waitqs(struct pmcs_hw m
, int verbose
)
1124 int max_dev
= m
.max_dev
;
1126 sp
= m
.dq
.stqh_first
;
1130 mdb_printf("\nDead Command Queue:\n");
1131 mdb_printf("---------------------------\n");
1133 if (MDB_RD(&s
, sizeof (s
), sp
) == -1) {
1134 NOREAD(pmcs_cmd_t
, sp
);
1137 print_spcmd(&s
, sp
, first
, verbose
);
1138 sp
= s
.cmd_next
.stqe_next
;
1142 sp
= m
.cq
.stqh_first
;
1146 mdb_printf("\nCompletion Command Queue:\n");
1147 mdb_printf("---------------------------\n");
1149 if (MDB_RD(&s
, sizeof (s
), sp
) == -1) {
1150 NOREAD(pmcs_cmd_t
, sp
);
1153 print_spcmd(&s
, sp
, first
, verbose
);
1154 sp
= s
.cmd_next
.stqe_next
;
1159 if (targets
== NULL
) {
1160 targets
= mdb_alloc(sizeof (targets
) * max_dev
, UM_SLEEP
);
1163 if (MDB_RD(targets
, sizeof (targets
) * max_dev
, m
.targets
) == -1) {
1164 NOREAD(targets
, m
.targets
);
1168 for (i
= 0; i
< max_dev
; i
++) {
1169 if (targets
[i
] == NULL
) {
1172 if (MDB_RD(&xs
, sizeof (xs
), targets
[i
]) == -1) {
1173 NOREAD(pmcs_xscsi_t
, targets
[i
]);
1176 sp
= xs
.wq
.stqh_first
;
1180 mdb_printf("\nTarget %u Wait Queue:\n",
1182 mdb_printf("---------------------------\n");
1184 if (MDB_RD(&s
, sizeof (s
), sp
) == -1) {
1185 NOREAD(pmcs_cmd_t
, sp
);
1188 print_spcmd(&s
, sp
, first
, verbose
);
1189 sp
= s
.cmd_next
.stqe_next
;
1192 sp
= xs
.aq
.stqh_first
;
1196 mdb_printf("\nTarget %u Active Queue:\n",
1198 mdb_printf("---------------------------\n");
1200 if (MDB_RD(&s
, sizeof (s
), sp
) == -1) {
1201 NOREAD(pmcs_cmd_t
, sp
);
1204 print_spcmd(&s
, sp
, first
, verbose
);
1205 sp
= s
.cmd_next
.stqe_next
;
1208 sp
= xs
.sq
.stqh_first
;
1212 mdb_printf("\nTarget %u Special Queue:\n",
1214 mdb_printf("---------------------------\n");
1216 if (MDB_RD(&s
, sizeof (s
), sp
) == -1) {
1217 NOREAD(pmcs_cmd_t
, sp
);
1220 print_spcmd(&s
, sp
, first
, verbose
);
1221 sp
= s
.cmd_next
.stqe_next
;
1230 if (qnum
< 0 || qnum
>= PMCS_NIQ
) {
1234 if (qnum
< PMCS_IQ_OTHER
) {
1245 case PMCS_OQ_IODONE
:
1247 case PMCS_OQ_GENERAL
:
1249 case PMCS_OQ_EVENTS
:
1257 iomb_cat(uint32_t cat
)
1260 case PMCS_IOMB_CAT_NET
:
1262 case PMCS_IOMB_CAT_FC
:
1264 case PMCS_IOMB_CAT_SAS
:
1266 case PMCS_IOMB_CAT_SCSI
:
1274 iomb_event(uint8_t event
)
1277 case IOP_EVENT_PHY_STOP_STATUS
:
1278 return ("PHY STOP");
1279 case IOP_EVENT_SAS_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");
1324 return ("Unknown Event");
1329 inbound_iomb_opcode(uint32_t opcode
)
1334 case PMCIN_GET_INFO
:
1335 return ("GET_INFO");
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");
1386 case PMCIN_FW_FLASH_UPDATE
:
1387 return ("FW_FLASH_UPDATE");
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");
1416 outbound_iomb_opcode(uint32_t opcode
)
1421 case PMCOUT_GET_INFO
:
1422 return ("GET_INFO");
1423 case PMCOUT_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
:
1461 case PMCOUT_GPIO_EVENT
:
1462 return ("GPIO_EVENT");
1463 case PMCOUT_GENERAL_EVENT
:
1464 return ("GENERAL_EVENT");
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");
1503 get_devid_from_ob_iomb(struct pmcs_hw ss
, uint32_t *qentryp
, uint16_t opcode
)
1505 uint32_t devid
= PMCS_INVALID_DEVICE_ID
;
1509 * These are obtained via the HTAG which is in word 1
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
: {
1523 uintptr_t _wp
, _phy
;
1526 htag
= LE_32(*(qentryp
+ 1));
1527 index
= htag
& PMCS_TAG_INDEX_MASK
;
1529 wp
= mdb_alloc(sizeof (pmcwork_t
), UM_SLEEP
);
1530 _wp
= (uintptr_t)ss
.work
+ (sizeof (pmcwork_t
) * index
);
1532 if (MDB_RD(wp
, sizeof (pmcwork_t
), _wp
) == -1) {
1533 NOREAD(pmcwork_t
, _wp
);
1534 mdb_free(wp
, sizeof (pmcwork_t
));
1538 phy
= mdb_alloc(sizeof (pmcs_phy_t
), UM_SLEEP
);
1539 if (wp
->phy
== NULL
) {
1540 _phy
= (uintptr_t)wp
->last_phy
;
1542 _phy
= (uintptr_t)wp
->phy
;
1546 * If we have a PHY, read it in and get it's handle
1549 if (MDB_RD(phy
, sizeof (*phy
), _phy
) == -1) {
1550 NOREAD(pmcs_phy_t
, phy
);
1552 devid
= phy
->device_id
;
1556 mdb_free(phy
, sizeof (pmcs_phy_t
));
1557 mdb_free(wp
, sizeof (pmcwork_t
));
1562 * The device ID is in the outbound IOMB at word 1
1564 case PMCOUT_SSP_REQUEST_RECEIVED
:
1565 devid
= LE_32(*(qentryp
+ 1)) & PMCS_DEVICE_ID_MASK
;
1569 * The device ID is in the outbound IOMB at word 2
1571 case PMCOUT_DEVICE_HANDLE_ARRIVED
:
1572 case PMCOUT_DEVICE_HANDLE_REMOVED
:
1573 devid
= LE_32(*(qentryp
+ 2)) & PMCS_DEVICE_ID_MASK
;
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
1581 case PMCOUT_GENERAL_EVENT
:
1583 * The device ID is in the outbound IOMB at word 3
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
;
1594 * Device ID is in the outbound IOMB at word 4
1596 case PMCOUT_SATA_EVENT
:
1597 case PMCOUT_SSP_EVENT
:
1598 devid
= LE_32(*(qentryp
+ 4)) & PMCS_DEVICE_ID_MASK
;
1606 iomb_is_dev_hdl_specific(uint32_t word0
, boolean_t inbound
)
1608 uint16_t opcode
= word0
& PMCS_IOMB_OPCODE_MASK
;
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
:
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
:
1663 dump_one_qentry_outbound(struct pmcs_hw ss
, uint32_t *qentryp
, int idx
,
1664 uint64_t devid_filter
)
1667 uint32_t word0
= LE_32(*qentryp
);
1668 uint32_t word1
= LE_32(*(qentryp
+ 1));
1673 * Check to see if we're filtering on a device ID
1675 if (devid_filter
!= PMCS_INVALID_DEVICE_ID
) {
1676 if (!iomb_is_dev_hdl_specific(word0
, B_FALSE
)) {
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.
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
)) {
1693 mdb_printf("Entry #%02d\n", idx
);
1696 mdb_printf("Header: 0x%08x (", word0
);
1697 if (word0
& PMCS_IOMB_VALID
) {
1698 mdb_printf("VALID, ");
1700 if (word0
& PMCS_IOMB_HIPRI
) {
1701 mdb_printf("HIPRI, ");
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
));
1715 mdb_printf("Remaining Payload:\n");
1718 for (qeidx
= 1; qeidx
< (PMCS_QENTRY_SIZE
/ 4); qeidx
++) {
1719 mdb_printf("%08x ", LE_32(*(qentryp
+ qeidx
)));
1726 display_outbound_queues(struct pmcs_hw ss
, uint64_t devid_filter
,
1732 uint32_t *qentryp
= mdb_alloc(PMCS_QENTRY_SIZE
, UM_SLEEP
);
1733 uint32_t last_consumed
, oqpi
;
1736 mdb_printf("Outbound Queues\n");
1737 mdb_printf("---------------\n");
1741 for (qidx
= 0; qidx
< PMCS_NOQ
; qidx
++) {
1742 obqp
= (uintptr_t)ss
.oqp
[qidx
];
1745 mdb_printf("No outbound queue ptr for queue #%d\n",
1750 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx
,
1753 * Chip is the producer, so read the actual producer index
1754 * and not the driver's version
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");
1763 mdb_printf("Producer index: %d Consumer index: %d\n\n",
1764 LE_32(oqpi
), ss
.oqci
[qidx
]);
1767 if (ss
.oqci
[qidx
] == 0) {
1768 last_consumed
= ss
.ioq_depth
- 1;
1770 last_consumed
= ss
.oqci
[qidx
] - 1;
1775 mdb_printf("Last processed entry:\n");
1776 if (MDB_RD(qentryp
, PMCS_QENTRY_SIZE
,
1777 (obqp
+ (PMCS_QENTRY_SIZE
* last_consumed
)))
1779 mdb_warn("Couldn't read queue entry at 0x%p\n",
1780 (obqp
+ (PMCS_QENTRY_SIZE
*
1784 dump_one_qentry_outbound(ss
, qentryp
, last_consumed
,
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
)));
1798 dump_one_qentry_outbound(ss
, qentryp
, idx
,
1807 mdb_free(qentryp
, PMCS_QENTRY_SIZE
);
1811 dump_one_qentry_inbound(uint32_t *qentryp
, int idx
, uint64_t devid_filter
)
1814 uint32_t word0
= LE_32(*qentryp
);
1815 uint32_t devid
= LE_32(*(qentryp
+ 2));
1818 * Check to see if we're filtering on a device ID
1820 if (devid_filter
!= PMCS_INVALID_DEVICE_ID
) {
1821 if (iomb_is_dev_hdl_specific(word0
, B_TRUE
)) {
1822 if (devid_filter
!= devid
) {
1830 mdb_printf("Entry #%02d\n", idx
);
1833 mdb_printf("Header: 0x%08x (", word0
);
1834 if (word0
& PMCS_IOMB_VALID
) {
1835 mdb_printf("VALID, ");
1837 if (word0
& PMCS_IOMB_HIPRI
) {
1838 mdb_printf("HIPRI, ");
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
));
1848 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp
+ 1)));
1849 mdb_printf("Remaining Payload:\n");
1852 for (qeidx
= 2; qeidx
< (PMCS_QENTRY_SIZE
/ 4); qeidx
++) {
1853 mdb_printf("%08x ", LE_32(*(qentryp
+ qeidx
)));
1860 display_inbound_queues(struct pmcs_hw ss
, uint64_t devid_filter
, uint_t verbose
)
1862 int idx
, qidx
, iqci
, last_consumed
;
1864 uint32_t *qentryp
= mdb_alloc(PMCS_QENTRY_SIZE
, UM_SLEEP
);
1868 mdb_printf("Inbound Queues\n");
1869 mdb_printf("--------------\n");
1873 for (qidx
= 0; qidx
< PMCS_NIQ
; qidx
++) {
1874 ibqp
= (uintptr_t)ss
.iqp
[qidx
];
1877 mdb_printf("No inbound queue ptr for queue #%d\n",
1882 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx
,
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");
1892 mdb_printf("Producer index: %d Consumer index: %d\n\n",
1893 ss
.shadow_iqpi
[qidx
], iqci
);
1897 last_consumed
= ss
.ioq_depth
- 1;
1899 last_consumed
= iqci
- 1;
1903 mdb_printf("Last processed entry:\n");
1904 if (MDB_RD(qentryp
, PMCS_QENTRY_SIZE
,
1905 (ibqp
+ (PMCS_QENTRY_SIZE
* last_consumed
)))
1907 mdb_warn("Couldn't read queue entry at 0x%p\n",
1908 (ibqp
+ (PMCS_QENTRY_SIZE
*
1912 dump_one_qentry_inbound(qentryp
, last_consumed
,
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
)));
1926 dump_one_qentry_inbound(qentryp
, idx
, devid_filter
);
1934 mdb_free(qentryp
, PMCS_QENTRY_SIZE
);
1938 * phy is our copy of the PHY structure. phyp is the pointer to the actual
1939 * kernel PHY data structure
1942 display_phy(struct pmcs_phy phy
, struct pmcs_phy
*phyp
, int verbose
,
1945 char *dtype
, *speed
;
1953 char route_attr
, route_method
;
1955 switch (phy
.dtype
) {
1961 if (phy
.configured
) {
1967 if (phy
.configured
) {
1973 if (phy
.configured
) {
1979 if (phy
.dtype
== NOTHING
) {
1981 } else if ((phy
.dtype
== EXPANDER
) && phy
.configured
) {
1989 switch (phy
.link_rate
) {
1990 case SAS_LINK_RATE_1_5GBIT
:
1993 case SAS_LINK_RATE_3GBIT
:
1996 case SAS_LINK_RATE_6GBIT
:
2004 if ((phy
.dtype
!= NOTHING
) || verbose
) {
2005 print_sas_address(&phy
);
2007 if (phy
.device_id
!= PMCS_INVALID_DEVICE_ID
) {
2008 mdb_printf(" %3d %4d %6s %4s ",
2009 phy
.device_id
, phy
.phynum
, speed
, dtype
);
2011 mdb_printf(" N/A %4d %6s %4s ",
2012 phy
.phynum
, speed
, dtype
);
2016 if (phy
.abort_sent
) {
2019 if (phy
.abort_pending
) {
2022 if (phy
.configured
) {
2032 switch (phy
.routing_attr
) {
2033 case SMP_ROUTING_DIRECT
:
2036 case SMP_ROUTING_SUBTRACTIVE
:
2039 case SMP_ROUTING_TABLE
:
2047 switch (phy
.routing_method
) {
2048 case SMP_ROUTING_DIRECT
:
2051 case SMP_ROUTING_SUBTRACTIVE
:
2054 case SMP_ROUTING_TABLE
:
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
);
2068 mdb_printf("Path: %s\n", phy
.path
);
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
2076 uintptr_t tphyp
= (uintptr_t)phyp
;
2079 switch (phy
.dtype
) {
2081 if (!phy
.configured
) {
2084 mdb_printf("REPORT GENERAL response: %p::"
2085 "print smp_report_general_resp_t\n",
2086 (tphyp
+ offsetof(struct pmcs_phy
,
2091 mdb_printf("DISCOVER response: %p::"
2092 "print smp_discover_resp_t\n",
2093 (tphyp
+ offsetof(struct pmcs_phy
,
2105 display_phys(struct pmcs_hw ss
, int verbose
, struct pmcs_phy
*parent
, int level
,
2109 pmcs_phy_t
*pphy
= parent
;
2113 if (parent
== NULL
) {
2114 pphy
= (pmcs_phy_t
*)ss
.root_phys
;
2116 pphy
= (pmcs_phy_t
*)parent
;
2129 mdb_printf("PHY information\n");
2131 mdb_printf("--------\n");
2132 mdb_printf("Level %2d\n", level
);
2133 mdb_printf("--------\n");
2134 mdb_printf("SAS Address Hdl Phy# Speed Type ");
2137 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
2145 if (MDB_RD(&phy
, sizeof (phy
), (uintptr_t)pphy
) == -1) {
2146 NOREAD(pmcs_phy_t
, phy
);
2150 display_phy(phy
, pphy
, verbose
, totals_only
);
2153 display_phys(ss
, verbose
, phy
.children
, level
+ 1,
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
);
2173 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
2175 (sas_phys
+ sata_phys
+ num_expanders
),
2176 sas_phys
, sata_phys
, num_expanders
);
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".
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.
2190 #define MAX_INST_STRLEN 8
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
)
2196 pmcs_tbuf_t
*tbuf_addr
;
2199 boolean_t wrap
, elem_filtered
;
2200 uint_t start_idx
, elems_to_print
, idx
, tbuf_num_elems
;
2202 char elem_inst
[MAX_INST_STRLEN
], ei_idx
;
2204 uint8_t *sas_addressp
;
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");
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");
2218 /* Get the current index */
2219 if (mdb_readvar(&tbuf_idx
, "pmcs_tbuf_idx") == -1) {
2220 mdb_warn("can't read pmcs_tbuf_idx");
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");
2231 * On little-endian systems, the SAS address passed in will be
2232 * byte swapped. Take care of that here.
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));
2244 sas_addr
= sas_address
;
2246 sas_addressp
= (uint8_t *)&sas_addr
;
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
;
2253 /* Figure out where we start and stop */
2256 /* Do we need to wrap backwards? */
2257 if (tail_lines
> tbuf_idx
) {
2258 start_idx
= tbuf_num_elems
- (tail_lines
-
2261 start_idx
= tbuf_idx
- tail_lines
;
2263 elems_to_print
= tail_lines
;
2265 start_idx
= tbuf_idx
;
2266 elems_to_print
= tbuf_num_elems
;
2269 if (tail_lines
> tbuf_idx
) {
2270 tail_lines
= tbuf_idx
;
2273 start_idx
= tbuf_idx
- tail_lines
;
2274 elems_to_print
= tail_lines
;
2277 elems_to_print
= tbuf_idx
;
2283 /* Dump the buffer contents */
2284 while (elems_to_print
!= 0) {
2285 if (MDB_RD(&tbuf
, sizeof (pmcs_tbuf_t
), (tbuf_addr
+ idx
))
2287 NOREAD(tbuf
, (tbuf_addr
+ idx
));
2292 * Check for filtering on HBA instance
2294 elem_filtered
= B_FALSE
;
2298 /* Skip the driver name */
2299 while (*bufp
< '0' || *bufp
> '9') {
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
;
2310 elem_inst
[ei_idx
] = 0;
2312 /* Get the instance */
2313 if ((int)mdb_strtoull(elem_inst
) != instance
) {
2314 elem_filtered
= B_TRUE
;
2318 if (!elem_filtered
&& (phy_path
|| sas_address
)) {
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.
2326 elem_filtered
= B_TRUE
;
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
;
2334 if (sas_address
!= 0) {
2335 if (memcmp(sas_addressp
, tbuf
.phy_sas_address
,
2337 elem_filtered
= B_FALSE
;
2342 if (!elem_filtered
) {
2344 * If the -v flag was given, print the firmware
2345 * timestamp along with the clock time
2347 mdb_printf("%Y.%09ld ", tbuf
.timestamp
);
2349 mdb_printf("(0x%" PRIx64
") ",
2352 mdb_printf("%s\n", tbuf
.buf
);
2356 if (++idx
== tbuf_num_elems
) {
2368 targets_walk_i(mdb_walk_state_t
*wsp
)
2370 if (wsp
->walk_addr
== NULL
) {
2371 mdb_warn("Can not perform global walk\n");
2376 * Address provided belongs to HBA softstate. Get the targets pointer
2377 * to begin the walk.
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");
2385 if (targets
== NULL
) {
2386 targets
= mdb_alloc(sizeof (targets
) * ss
.max_dev
, UM_SLEEP
);
2389 if (MDB_RD(targets
, sizeof (targets
) * ss
.max_dev
, ss
.targets
) == -1) {
2390 NOREAD(targets
, ss
.targets
);
2395 wsp
->walk_addr
= (uintptr_t)(targets
[0]);
2396 wsp
->walk_data
= mdb_alloc(sizeof (pmcs_xscsi_t
), UM_SLEEP
);
2402 targets_walk_s(mdb_walk_state_t
*wsp
)
2406 if (target_idx
== ss
.max_dev
) {
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
);
2416 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
2420 wsp
->walk_addr
= (uintptr_t)(targets
[++target_idx
]);
2421 } while ((wsp
->walk_addr
== NULL
) && (target_idx
< ss
.max_dev
));
2423 if (target_idx
== ss
.max_dev
) {
2431 targets_walk_f(mdb_walk_state_t
*wsp
)
2433 mdb_free(wsp
->walk_data
, sizeof (pmcs_xscsi_t
));
2438 pmcs_next_sibling(pmcs_phy_t
*phyp
)
2443 * First, if this is a root PHY, there are no more siblings
2445 if (phyp
->level
== 0) {
2450 * Otherwise, next sibling is the parent's sibling
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
);
2460 if (parent
.sibling
!= NULL
) {
2465 * If this PHY's sibling is NULL and it's a root phy,
2468 if (parent
.level
== 0) {
2472 phyp
= phyp
->parent
;
2475 return (parent
.sibling
);
2479 phy_walk_i(mdb_walk_state_t
*wsp
)
2481 if (wsp
->walk_addr
== NULL
) {
2482 mdb_warn("Can not perform global walk\n");
2487 * Address provided belongs to HBA softstate. Get the targets pointer
2488 * to begin the walk.
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");
2496 wsp
->walk_addr
= (uintptr_t)(ss
.root_phys
);
2497 wsp
->walk_data
= mdb_alloc(sizeof (pmcs_phy_t
), UM_SLEEP
);
2503 phy_walk_s(mdb_walk_state_t
*wsp
)
2505 pmcs_phy_t
*phyp
, *nphyp
;
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
);
2515 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
2518 phyp
= (pmcs_phy_t
*)wsp
->walk_data
;
2519 if (phyp
->children
) {
2520 wsp
->walk_addr
= (uintptr_t)(phyp
->children
);
2522 wsp
->walk_addr
= (uintptr_t)(phyp
->sibling
);
2525 if (wsp
->walk_addr
== NULL
) {
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.
2531 nphyp
= pmcs_next_sibling(phyp
);
2533 if (nphyp
== NULL
) {
2537 wsp
->walk_addr
= (uintptr_t)nphyp
;
2544 phy_walk_f(mdb_walk_state_t
*wsp
)
2546 mdb_free(wsp
->walk_data
, sizeof (pmcs_phy_t
));
2550 display_matching_work(struct pmcs_hw ss
, uintmax_t index
, uintmax_t snum
,
2554 pmcwork_t work
, *wp
= &work
;
2556 boolean_t printed_header
= B_FALSE
;
2557 uint32_t mask
, mask_val
, match_val
;
2560 if (index
!= UINT_MAX
) {
2561 match_type
= "index";
2562 mask
= PMCS_TAG_INDEX_MASK
;
2563 mask_val
= index
<< PMCS_TAG_INDEX_SHIFT
;
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
;
2572 case PMCS_TAG_TYPE_NONE
:
2573 match_type
= "tag type NONE";
2575 case PMCS_TAG_TYPE_CBACK
:
2576 match_type
= "tag type CBACK";
2578 case PMCS_TAG_TYPE_WAIT
:
2579 match_type
= "tag type WAIT";
2582 mask
= PMCS_TAG_TYPE_MASK
;
2583 mask_val
= tag_type
<< PMCS_TAG_TYPE_SHIFT
;
2584 match_val
= tag_type
;
2587 _wp
= (uintptr_t)ss
.work
;
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
);
2595 if ((work
.htag
& mask
) != mask_val
) {
2599 if (printed_header
== B_FALSE
) {
2601 mdb_printf("\nWork structures matching %s\n\n",
2602 match_type
, match_val
);
2604 mdb_printf("\nWork structures matching %s of "
2605 "0x%x\n\n", match_type
, match_val
);
2607 mdb_printf("%8s %10s %20s %8s %8s O D\n",
2608 "HTag", "State", "Phy Path", "Target", "Timer");
2609 printed_header
= B_TRUE
;
2612 display_one_work(wp
, 0, 0);
2615 if (!printed_header
) {
2616 mdb_printf("No work structure matches found\n");
2621 pmcs_tag(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2624 uintmax_t tag_type
= UINT_MAX
;
2625 uintmax_t snum
= UINT_MAX
;
2626 uintmax_t index
= UINT_MAX
;
2630 struct dev_info dip
;
2632 if (!(flags
& DCMD_ADDRSPEC
)) {
2634 if (mdb_readvar(&pmcs_state
, "pmcs_softc_state") == -1) {
2635 mdb_warn("can't read pmcs_softc_state");
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");
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
);
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.
2657 if (index
!= UINT_MAX
) {
2659 if (index
> PMCS_TAG_INDEX_MASK
) {
2660 mdb_warn("Index is out of range\n");
2661 return (DCMD_USAGE
);
2665 if (tag_type
!= UINT_MAX
) {
2668 case PMCS_TAG_TYPE_NONE
:
2669 case PMCS_TAG_TYPE_CBACK
:
2670 case PMCS_TAG_TYPE_WAIT
:
2673 mdb_warn("Invalid tag type\n");
2674 return (DCMD_USAGE
);
2678 if (snum
!= UINT_MAX
) {
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
);
2687 * Make sure 1 and only 1 option is specified
2689 if ((args
== 0) || (args
> 1)) {
2690 mdb_warn("Exactly one of -i, -s and -t must be specified\n");
2691 return (DCMD_USAGE
);
2694 if (MDB_RD(&ss
, sizeof (ss
), addr
) == -1) {
2695 NOREAD(pmcs_hw_t
, addr
);
2699 if (MDB_RD(&dip
, sizeof (struct dev_info
), ss
.dip
) == -1) {
2700 NOREAD(pmcs_hw_t
, addr
);
2704 /* processing completed */
2706 if (((flags
& DCMD_ADDRSPEC
) && !(flags
& DCMD_LOOP
)) ||
2707 (flags
& DCMD_LOOPFIRST
)) {
2708 if ((flags
& DCMD_LOOP
) && !(flags
& DCMD_LOOPFIRST
))
2710 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
2711 "Address", "State", "Inst", "DIP");
2712 mdb_printf("================================="
2713 "============================================\n");
2718 state_str
= "Invalid";
2721 state_str
= "Probing";
2724 state_str
= "Running";
2726 case STATE_UNPROBING
:
2727 state_str
= "Unprobing";
2732 case STATE_IN_RESET
:
2733 state_str
= "In Reset";
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
);
2743 display_matching_work(ss
, index
, snum
, tag_type
);
2752 pmcs_dump_fwlog(struct pmcs_hw
*ss
, int instance
, const char *ofile
)
2756 char ofilename
[MAXPATHLEN
];
2759 if (ss
->fwlogp
== NULL
) {
2760 mdb_warn("Firmware event log disabled for instance %d",
2765 if (snprintf(ofilename
, MAXPATHLEN
, "%s%d", ofile
, instance
) >
2767 mdb_warn("Output filename is too long for instance %d",
2772 fwlogp
= mdb_alloc(PMCS_FWLOG_SIZE
, UM_SLEEP
);
2774 if (MDB_RD(fwlogp
, PMCS_FWLOG_SIZE
, ss
->fwlogp
) == -1) {
2775 NOREAD(fwlogp
, ss
->fwlogp
);
2780 ofilefd
= open(ofilename
, O_WRONLY
| O_CREAT
,
2781 S_IRUSR
| S_IRGRP
| S_IROTH
);
2783 mdb_warn("Unable to open '%s' to dump instance %d event log",
2784 ofilename
, instance
);
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
);
2796 mdb_printf("Event log for instance %d written to %s\n", instance
,
2803 mdb_free(fwlogp
, PMCS_FWLOG_SIZE
);
2808 pmcs_fwlog(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2811 const char *ofile
= NULL
;
2813 struct dev_info dip
;
2815 if (mdb_getopts(argc
, argv
, 'o', MDB_OPT_STR
, &ofile
, NULL
) != argc
) {
2816 return (DCMD_USAGE
);
2819 if (ofile
== NULL
) {
2820 mdb_printf("No output file specified\n");
2821 return (DCMD_USAGE
);
2824 if (!(flags
& DCMD_ADDRSPEC
)) {
2826 if (mdb_readvar(&pmcs_state
, "pmcs_softc_state") == -1) {
2827 mdb_warn("can't read pmcs_softc_state");
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");
2838 if (MDB_RD(&ss
, sizeof (ss
), addr
) == -1) {
2839 NOREAD(pmcs_hw_t
, addr
);
2843 if (MDB_RD(&dip
, sizeof (struct dev_info
), ss
.dip
) == -1) {
2844 NOREAD(pmcs_hw_t
, addr
);
2848 return (pmcs_dump_fwlog(&ss
, dip
.devi_instance
, ofile
));
2853 pmcs_log(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
2857 struct dev_info dip
;
2858 const char *match_phy_path
= NULL
;
2859 uint64_t match_sas_address
= 0, tail_lines
= 0;
2862 if (!(flags
& DCMD_ADDRSPEC
)) {
2864 if (mdb_readvar(&pmcs_state
, "pmcs_softc_state") == -1) {
2865 mdb_warn("can't read pmcs_softc_state");
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");
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
,
2882 return (DCMD_USAGE
);
2885 if (MDB_RD(&ss
, sizeof (ss
), addr
) == -1) {
2886 NOREAD(pmcs_hw_t
, addr
);
2890 if (MDB_RD(&dip
, sizeof (struct dev_info
), ss
.dip
) == -1) {
2891 NOREAD(pmcs_hw_t
, addr
);
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
));
2907 pmcs_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
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
;
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
;
2933 struct dev_info dip
;
2934 per_iport_setting_t pis
;
2936 if (!(flags
& DCMD_ADDRSPEC
)) {
2938 if (mdb_readvar(&pmcs_state
, "pmcs_softc_state") == -1) {
2939 mdb_warn("can't read pmcs_softc_state");
2942 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc
, argv
,
2943 (uintptr_t)pmcs_state
) == -1) {
2944 mdb_warn("mdb_pwalk_dcmd failed");
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
,
2970 return (DCMD_USAGE
);
2973 * The 'd' and 'm' options implicitly enable the 'I' option
2975 pis
.pis_damap_info
= damap_info
;
2976 pis
.pis_dtc_info
= dtc_info
;
2977 if (damap_info
|| dtc_info
) {
2982 * The -D option is meaningless without -q and/or -Q, and implies
2986 devid
= (uint64_t)pdevid
& 0xffffffff;
2988 mdb_printf("-D requires either -q or -Q\n");
2989 return (DCMD_USAGE
);
2991 if (devid
> PMCS_DEVICE_ID_MASK
) {
2992 mdb_printf("Device ID invalid\n");
2993 return (DCMD_USAGE
);
2998 if (MDB_RD(&ss
, sizeof (ss
), addr
) == -1) {
2999 NOREAD(pmcs_hw_t
, addr
);
3003 if (MDB_RD(&dip
, sizeof (struct dev_info
), ss
.dip
) == -1) {
3004 NOREAD(pmcs_hw_t
, addr
);
3008 /* processing completed */
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
))
3016 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
3017 "Address", "State", "Inst", "DIP");
3018 mdb_printf("================================="
3019 "============================================\n");
3024 state_str
= "Invalid";
3027 state_str
= "Probing";
3030 state_str
= "Running";
3032 case STATE_UNPROBING
:
3033 state_str
= "Unprobing";
3038 case STATE_IN_RESET
:
3039 state_str
= "In Reset";
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
);
3051 display_waitqs(ss
, verbose
);
3054 display_hwinfo(ss
, verbose
);
3056 if (phy_info
|| tgt_phy_count
)
3057 display_phys(ss
, verbose
, NULL
, 0, tgt_phy_count
);
3059 if (target_info
|| tgt_phy_count
)
3060 display_targets(ss
, verbose
, tgt_phy_count
);
3062 if (work_info
|| wserno
)
3063 display_work(ss
, verbose
, wserno
);
3066 display_ic(ss
, verbose
);
3069 display_inbound_queues(ss
, devid
, verbose
);
3072 display_outbound_queues(ss
, devid
, verbose
);
3075 display_iport(ss
, addr
, verbose
, &pis
);
3078 display_completion_queue(ss
);
3081 display_unconfigured_targets(addr
);
3084 display_event_log(ss
);
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");
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");
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), "
3136 static const mdb_dcmd_t dcmds
[] = {
3137 { "pmcs", "?[-cdehiImpQqtTuwWv] [-D <device ID>]",
3138 "print pmcs information", pmcs_dcmd
, pmcs_help
3141 "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
3142 "dump pmcs log file", pmcs_log
, pmcs_log_help
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
3151 "dump pmcs firmware event log to output_file", pmcs_fwlog
, NULL
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
},
3165 static const mdb_modinfo_t modinfo
= {
3166 MDB_API_VERSION
, dcmds
, walkers
3169 const mdb_modinfo_t
*