pmcs.c revision e71c81d1003489d75b970c7d0a3a33772608b3ab
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <limits.h>
#include <sys/mdb_modapi.h>
#include <sys/byteorder.h>
#ifndef _KMDB
#include <fcntl.h>
#include <unistd.h>
#endif /* _KMDB */
/*
* We need use this to pass the settings when display_iport
*/
typedef struct per_iport_setting {
static int target_idx;
static void
{
int idx;
}
}
/*ARGSUSED*/
static void
{
int msec_per_tick;
mdb_warn("can't read msec_per_tick");
msec_per_tick = 0;
}
mdb_printf("\n");
mdb_printf("Interrupt coalescing timer info\n");
mdb_printf("-------------------------------\n");
if (msec_per_tick == 0) {
mdb_printf("Quantum : ?? ms\n");
} else {
mdb_printf("Quantum : %d ms\n",
}
mdb_printf("Timer enabled : ");
if (m.io_intr_coal.timer_on) {
mdb_printf("Yes\n");
mdb_printf("Coalescing timer value : %d us\n",
} else {
mdb_printf("No\n");
}
mdb_printf("Total nsecs between interrupts: %ld\n",
mdb_printf("Time of last I/O interrupt : %ld\n",
mdb_printf("Number of I/O interrupts : %d\n",
mdb_printf("Number of I/O completions : %d\n",
mdb_printf("Max I/O completion interrupts : %d\n",
mdb_printf("Measured ECHO int latency : %d ns\n",
mdb_printf("Interrupt threshold : %d\n",
}
/*ARGSUSED*/
static int
{
sizeof (struct pmcs_phy)) {
return (DCMD_ERR);
}
return (0);
}
static int
{
sizeof (struct dev_info)) {
return (rval);
}
return (rval);
}
return (rval);
}
return (rval);
}
return (rval);
}
return (rval);
}
tmd_offset /= NBBY;
mdb_printf("\n");
return (rval);
}
}
mdb_printf("\n");
}
return (rval);
}
/* ARGSUSED */
static int
{
char devi_name[MAXNAMELEN];
char devi_addr[MAXNAMELEN];
sizeof (struct dev_info)) {
return (DCMD_ERR);
}
devi_name[0] = '?';
}
devi_addr[0] = '?';
}
mdb_printf(" %3d: @%-21s%10s@\t%p::devinfo -s\n",
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
struct mdi_pathinfo mpi;
char pi_addr[MAXNAMELEN];
sizeof (struct mdi_pathinfo)) {
return (DCMD_ERR);
}
pi_addr[0] = '?';
}
mdb_printf(" %3d: @%-21s %p::print struct mdi_pathinfo\n",
return (DCMD_OK);
}
static int
{
sizeof (struct dev_info)) {
return (rval);
}
mdb_printf("Device tree children - dev_info:\n");
mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
goto skip_di;
}
/*
* First, we dump the iport's children dev_info node information.
* use existing walker: devinfo_siblings
*/
mdb_printf("\t#: @unit-address name@\tdrill-down\n");
mdb_printf("\n");
/*
* Then we try to dump the iport's path_info node information.
* use existing walker: mdipi_phci_list
*/
mdb_printf("Device tree children - path_info:\n");
mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
return (rval);
}
mdb_printf("\tph_path_head is NULL, no path_info\n\n");
return (rval);
}
mdb_printf("\t#: @unit-address drill-down\n");
mdb_printf("\n");
return (rval);
}
static void
{
if (pis->pis_damap_info) {
(void) display_iport_damap(dip);
}
if (pis->pis_dtc_info) {
(void) display_iport_dtc(dip);
}
}
/*ARGSUSED*/
static int
{
struct pmcs_iport iport;
char *ua_state;
char portid[4];
char unit_address[34];
sizeof (struct pmcs_iport)) {
return (DCMD_ERR);
}
}
} else {
}
case UA_INACTIVE:
ua_state = "Inactive";
break;
case UA_PEND_ACTIVATE:
ua_state = "PendActivate";
break;
case UA_ACTIVE:
ua_state = "Active";
break;
case UA_PEND_DEACTIVATE:
ua_state = "PendDeactivate";
break;
default:
ua_state = "Unknown";
}
/* Standard iport unit address */
"PortID", "NumPhys", "DIP\n");
} else {
/* Temporary iport unit address */
"UA State", "PortID", "NumPhys", "DIP\n");
}
mdb_inc_indent(4);
mdb_inc_indent(2);
list_addr) == -1) {
mdb_warn("pmcs iport walk failed");
}
mdb_dec_indent(6);
mdb_printf("\n");
}
/*
* See if we need to show more information based on 'd' or 'm' options
*/
return (0);
}
/*ARGSUSED*/
static void
{
if (m.iports_attached) {
mdb_printf("Iport information:\n");
mdb_printf("-----------------\n");
} else {
mdb_printf("No Iports found.\n\n");
return;
}
mdb_warn("pmcs iport walk failed");
}
mdb_printf("\n");
}
/* ARGSUSED */
static int
{
mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
(void *)addr);
return (DCMD_ERR);
}
mdb_printf("SAS address: ");
mdb_printf(" DType: ");
case SAS:
break;
case SATA:
break;
case EXPANDER:
break;
default:
break;
}
}
return (0);
}
static void
{
mdb_printf("Unconfigured target SAS address:\n\n");
mdb_warn("pmcs phys walk failed");
}
}
static void
{
mdb_printf("Completion queue is empty.\n");
return;
}
mdb_printf("%8s %10s %20s %8s %8s O D\n",
"HTag", "State", "Phy Path", "Target", "Timer");
while (ccbp) {
mdb_warn("Unable to read completion queue entry\n");
return;
}
!= sizeof (pmcwork_t)) {
mdb_warn("Unable to read work structure\n");
return;
}
/*
* Only print the work structure if it's still active. If
* it's not, it's been completed since we started looking at
* it.
*/
display_one_work(&work, 0, 0);
}
}
}
/*ARGSUSED*/
static void
{
char *fwsupport;
switch (PMCS_FW_TYPE(mp)) {
case PMCS_FW_TYPE_RELEASED:
fwsupport = "Released";
break;
case PMCS_FW_TYPE_DEVELOPMENT:
fwsupport = "Development";
break;
case PMCS_FW_TYPE_ALPHA:
fwsupport = "Alpha";
break;
case PMCS_FW_TYPE_BETA:
fwsupport = "Beta";
break;
default:
fwsupport = "Special";
break;
}
mdb_printf("\nHardware information:\n");
mdb_printf("---------------------\n");
mdb_printf("Firmware version: %x.%x.%x (%s)\n",
if (m.fwlog == 0) {
mdb_printf("Firmware logging: Disabled\n");
} else {
}
}
static void
{
char *dtype;
}
return;
}
if (!totals_only) {
mdb_printf("\nTarget information:\n");
mdb_printf("---------------------------------------\n");
"PHY Address", "DType", "Actv", "OnChip", "DS");
mdb_printf("\n");
}
continue;
}
continue;
}
/*
* It has to be new or assigned to be of interest.
*/
continue;
}
case NOTHING:
dtype = "None";
break;
case SATA:
dtype = "SATA";
sata_targets++;
break;
case SAS:
dtype = "SAS";
sas_targets++;
break;
case EXPANDER:
dtype = "SMP";
smp_targets++;
break;
}
if (totals_only) {
continue;
}
continue;
}
} else {
}
if (verbose) {
mdb_printf(" new");
}
mdb_printf(" assigned");
}
mdb_printf(" draining");
}
if (xs.reset_wait) {
mdb_printf(" reset_wait");
}
mdb_printf(" resetting");
}
if (xs.recover_wait) {
mdb_printf(" recover_wait");
}
if (xs.recovering) {
mdb_printf(" recovering");
}
if (xs.event_recovery) {
mdb_printf(" event recovery");
}
if (xs.special_running) {
mdb_printf(" special_active");
}
mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
mdb_printf(" pio");
}
}
mdb_printf("\n");
}
if (!totals_only) {
mdb_printf("\n");
}
mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
}
static char *
{
char *state_string;
switch (state) {
case PMCS_WORK_STATE_NIL:
state_string = "Free";
break;
case PMCS_WORK_STATE_READY:
state_string = "Ready";
break;
case PMCS_WORK_STATE_ONCHIP:
state_string = "On Chip";
break;
case PMCS_WORK_STATE_INTR:
state_string = "In Intr";
break;
case PMCS_WORK_STATE_IOCOMPQ:
state_string = "I/O Comp";
break;
case PMCS_WORK_STATE_ABORTED:
state_string = "I/O Aborted";
break;
state_string = "I/O Timed Out";
break;
default:
state_string = "INVALID";
break;
}
return (state_string);
}
static void
{
char *state, *last_state;
char *path;
int tgt;
}
tgt = -1;
} else {
}
}
}
} else {
path = "N/A";
}
if (verbose) {
}
if (tgt == -1) {
mdb_printf("%08x %10s %20s N/A %8u %1d %1d ",
} else {
mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
}
if (verbose) {
mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
} else {
mdb_printf("\n");
}
}
static void
{
int idx;
mdb_printf("\nActive Work structure information:\n");
mdb_printf("----------------------------------\n");
continue;
}
continue;
}
if (header_printed == B_FALSE) {
if (verbose) {
}
mdb_printf("%8s %10s %20s %8s %8s O D ",
"HTag", "State", "Phy Path", "Target", "Timer");
if (verbose) {
mdb_printf("%8s %10s %18s %18s %18s\n",
"LastHTAG", "LastState", "LastPHY",
"LastTgt", "LastArg");
} else {
mdb_printf("\n");
}
}
}
}
static void
{
if (printhdr) {
if (verbose) {
"SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
} else {
"SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
}
}
mdb_printf("%16p %16p %16p %08x %08x ",
/*
* If we're printing verbose, dump the CDB as well.
*/
if (verbose) {
sizeof (struct scsi_pkt)) {
mdb_warn("Unable to read SCSI pkt\n");
return;
}
mdb_warn("Unable to read CDB\n");
return;
}
}
} else {
mdb_printf("N/A");
}
mdb_printf("\n");
} else {
mdb_printf("\n");
}
}
/*ARGSUSED1*/
static void
{
pmcs_cmd_t *sp, s;
int first, i;
first = 1;
while (sp) {
if (first) {
mdb_printf("\nDead Command Queue:\n");
mdb_printf("---------------------------\n");
}
break;
}
first = 0;
}
first = 1;
while (sp) {
if (first) {
mdb_printf("\nCompletion Command Queue:\n");
mdb_printf("---------------------------\n");
}
break;
}
first = 0;
}
}
return;
}
for (i = 0; i < max_dev; i++) {
continue;
}
continue;
}
first = 1;
while (sp) {
if (first) {
mdb_printf("\nTarget %u Wait Queue:\n",
xs.target_num);
mdb_printf("---------------------------\n");
}
break;
}
first = 0;
}
first = 1;
while (sp) {
if (first) {
mdb_printf("\nTarget %u Active Queue:\n",
xs.target_num);
mdb_printf("---------------------------\n");
}
break;
}
first = 0;
}
first = 1;
while (sp) {
if (first) {
mdb_printf("\nTarget %u Special Queue:\n",
xs.target_num);
mdb_printf("---------------------------\n");
}
break;
}
first = 0;
}
}
}
static char *
{
return ("UNKNOWN");
}
if (qnum < PMCS_IQ_OTHER) {
return ("I/O");
}
return ("Other");
}
static char *
{
switch (qnum) {
case PMCS_OQ_IODONE:
return ("I/O");
break;
case PMCS_OQ_GENERAL:
return ("General");
break;
case PMCS_OQ_EVENTS:
return ("Events");
break;
default:
return ("UNKNOWN");
}
}
static char *
{
switch (cat) {
case PMCS_IOMB_CAT_NET:
return ("NET");
break;
case PMCS_IOMB_CAT_FC:
return ("FC");
break;
case PMCS_IOMB_CAT_SAS:
return ("SAS");
break;
case PMCS_IOMB_CAT_SCSI:
return ("SCSI");
break;
default:
return ("???");
}
}
static char *
{
switch (event) {
return ("PHY STOP");
break;
case IOP_EVENT_SAS_PHY_UP:
return ("PHY UP");
break;
case IOP_EVENT_SATA_PHY_UP:
return ("SATA PHY UP");
break;
return ("SATA SPINUP HOLD");
break;
case IOP_EVENT_PHY_DOWN:
return ("PHY DOWN");
break;
return ("BROADCAST CHANGE");
break;
case IOP_EVENT_BROADCAST_SES:
return ("BROADCAST SES");
break;
return ("INBOUND CRC ERROR");
break;
return ("HARD RESET");
break;
return ("IDENTIFY FRAME TIMEOUT");
break;
case IOP_EVENT_BROADCAST_EXP:
return ("BROADCAST EXPANDER");
break;
return ("PHY START");
break;
return ("INVALID DWORD");
break;
return ("DISPARITY ERROR");
break;
return ("CODE VIOLATION");
break;
return ("LOSS OF DWORD SYNC");
break;
return ("PHY RESET FAILED");
break;
return ("PORT RECOVERY TIMEOUT");
break;
case IOP_EVENT_PORT_RECOVER:
return ("PORT RECOVERY");
break;
return ("PORT RESET TIMEOUT");
break;
return ("PORT RESET COMPLETE");
break;
return ("BROADCAST ASYNC");
break;
case IOP_EVENT_IT_NEXUS_LOSS:
return ("I/T NEXUS LOSS");
break;
default:
return ("Unknown Event");
}
}
static char *
{
switch (opcode) {
case PMCIN_ECHO:
return ("ECHO");
break;
case PMCIN_GET_INFO:
return ("GET_INFO");
break;
case PMCIN_GET_VPD:
return ("GET_VPD");
break;
case PMCIN_PHY_START:
return ("PHY_START");
break;
case PMCIN_PHY_STOP:
return ("PHY_STOP");
break;
case PMCIN_SSP_INI_IO_START:
return ("INI_IO_START");
break;
case PMCIN_SSP_INI_TM_START:
return ("INI_TM_START");
break;
return ("INI_EXT_IO_START");
break;
return ("DEVICE_HANDLE_ACCEPT");
break;
case PMCIN_SSP_TGT_IO_START:
return ("TGT_IO_START");
break;
return ("TGT_RESPONSE_START");
break;
return ("INI_EDC_EXT_IO_START");
break;
return ("INI_EDC_EXT_IO_START1");
break;
return ("TGT_EDC_IO_START");
break;
case PMCIN_SSP_ABORT:
return ("SSP_ABORT");
break;
return ("DEREGISTER_DEVICE_HANDLE");
break;
case PMCIN_GET_DEVICE_HANDLE:
return ("GET_DEVICE_HANDLE");
break;
case PMCIN_SMP_REQUEST:
return ("SMP_REQUEST");
break;
case PMCIN_SMP_RESPONSE:
return ("SMP_RESPONSE");
break;
case PMCIN_SMP_ABORT:
return ("SMP_ABORT");
break;
case PMCIN_ASSISTED_DISCOVERY:
return ("ASSISTED_DISCOVERY");
break;
case PMCIN_REGISTER_DEVICE:
return ("REGISTER_DEVICE");
break;
case PMCIN_SATA_HOST_IO_START:
return ("SATA_HOST_IO_START");
break;
case PMCIN_SATA_ABORT:
return ("SATA_ABORT");
break;
case PMCIN_LOCAL_PHY_CONTROL:
return ("LOCAL_PHY_CONTROL");
break;
case PMCIN_GET_DEVICE_INFO:
return ("GET_DEVICE_INFO");
break;
case PMCIN_TWI:
return ("TWI");
break;
case PMCIN_FW_FLASH_UPDATE:
return ("FW_FLASH_UPDATE");
break;
case PMCIN_SET_VPD:
return ("SET_VPD");
break;
case PMCIN_GPIO:
return ("GPIO");
break;
return ("SAS_DIAG_MODE_START_END");
break;
case PMCIN_SAS_DIAG_EXECUTE:
return ("SAS_DIAG_EXECUTE");
break;
case PMCIN_SAW_HW_EVENT_ACK:
return ("SAS_HW_EVENT_ACK");
break;
case PMCIN_GET_TIME_STAMP:
return ("GET_TIME_STAMP");
break;
case PMCIN_PORT_CONTROL:
return ("PORT_CONTROL");
break;
case PMCIN_GET_NVMD_DATA:
return ("GET_NVMD_DATA");
break;
case PMCIN_SET_NVMD_DATA:
return ("SET_NVMD_DATA");
break;
case PMCIN_SET_DEVICE_STATE:
return ("SET_DEVICE_STATE");
break;
case PMCIN_GET_DEVICE_STATE:
return ("GET_DEVICE_STATE");
break;
default:
return ("UNKNOWN");
break;
}
}
static char *
{
switch (opcode) {
case PMCOUT_ECHO:
return ("ECHO");
break;
case PMCOUT_GET_INFO:
return ("GET_INFO");
break;
case PMCOUT_GET_VPD:
return ("GET_VPD");
break;
case PMCOUT_SAS_HW_EVENT:
return ("SAS_HW_EVENT");
break;
case PMCOUT_SSP_COMPLETION:
return ("SSP_COMPLETION");
break;
case PMCOUT_SMP_COMPLETION:
return ("SMP_COMPLETION");
break;
case PMCOUT_LOCAL_PHY_CONTROL:
return ("LOCAL_PHY_CONTROL");
break;
return ("SAS_ASSISTED_DISCOVERY_SENT");
break;
return ("SATA_ASSISTED_DISCOVERY_SENT");
break;
return ("DEVICE_REGISTRATION");
break;
return ("DEREGISTER_DEVICE_HANDLE");
break;
case PMCOUT_GET_DEVICE_HANDLE:
return ("GET_DEVICE_HANDLE");
break;
case PMCOUT_SATA_COMPLETION:
return ("SATA_COMPLETION");
break;
case PMCOUT_SATA_EVENT:
return ("SATA_EVENT");
break;
case PMCOUT_SSP_EVENT:
return ("SSP_EVENT");
break;
return ("DEVICE_HANDLE_ARRIVED");
break;
return ("SMP_REQUEST_RECEIVED");
break;
return ("SSP_REQUEST_RECEIVED");
break;
case PMCOUT_DEVICE_INFO:
return ("DEVICE_INFO");
break;
case PMCOUT_FW_FLASH_UPDATE:
return ("FW_FLASH_UPDATE");
break;
case PMCOUT_SET_VPD:
return ("SET_VPD");
break;
case PMCOUT_GPIO:
return ("GPIO");
break;
case PMCOUT_GPIO_EVENT:
return ("GPIO_EVENT");
break;
case PMCOUT_GENERAL_EVENT:
return ("GENERAL_EVENT");
break;
case PMCOUT_TWI:
return ("TWI");
break;
case PMCOUT_SSP_ABORT:
return ("SSP_ABORT");
break;
case PMCOUT_SATA_ABORT:
return ("SATA_ABORT");
break;
return ("SAS_DIAG_MODE_START_END");
break;
case PMCOUT_SAS_DIAG_EXECUTE:
return ("SAS_DIAG_EXECUTE");
break;
case PMCOUT_GET_TIME_STAMP:
return ("GET_TIME_STAMP");
break;
return ("SAS_HW_EVENT_ACK_ACK");
break;
case PMCOUT_PORT_CONTROL:
return ("PORT_CONTROL");
break;
case PMCOUT_SKIP_ENTRIES:
return ("SKIP_ENTRIES");
break;
case PMCOUT_SMP_ABORT:
return ("SMP_ABORT");
break;
case PMCOUT_GET_NVMD_DATA:
return ("GET_NVMD_DATA");
break;
case PMCOUT_SET_NVMD_DATA:
return ("SET_NVMD_DATA");
break;
return ("DEVICE_HANDLE_REMOVED");
break;
case PMCOUT_SET_DEVICE_STATE:
return ("SET_DEVICE_STATE");
break;
case PMCOUT_GET_DEVICE_STATE:
return ("GET_DEVICE_STATE");
break;
case PMCOUT_SET_DEVICE_INFO:
return ("SET_DEVICE_INFO");
break;
default:
return ("UNKNOWN");
break;
}
}
static void
{
int qeidx;
mdb_inc_indent(2);
if (word0 & PMCS_IOMB_VALID) {
mdb_printf("VALID, ");
}
if (word0 & PMCS_IOMB_HIPRI) {
mdb_printf("HIPRI, ");
}
mdb_printf("OBID=%d, ",
mdb_printf("CAT=%s, ",
mdb_printf("OPCODE=%s",
}
mdb_printf(")\n");
mdb_printf("Remaining Payload:\n");
mdb_inc_indent(2);
}
mdb_printf("\n");
mdb_dec_indent(4);
}
static void
{
mdb_printf("\n");
mdb_printf("Outbound Queues\n");
mdb_printf("---------------\n");
mdb_inc_indent(2);
mdb_printf("No outbound queue ptr for queue #%d\n",
qidx);
continue;
}
/*
* Chip is the producer, so read the actual producer index
* and not the driver's version
*/
mdb_warn("Couldn't read oqpi\n");
break;
}
mdb_printf("Producer index: %d Consumer index: %d\n\n",
mdb_inc_indent(2);
} else {
}
if (!verbose) {
mdb_printf("Last processed entry:\n");
== -1) {
mdb_warn("Couldn't read queue entry at 0x%p\n",
(obqp + (PMCS_QENTRY_SIZE *
last_consumed)));
break;
}
mdb_printf("\n");
mdb_dec_indent(2);
continue;
}
mdb_warn("Couldn't read queue entry at 0x%p\n",
break;
}
}
mdb_printf("\n");
mdb_dec_indent(2);
}
mdb_dec_indent(2);
}
static void
{
int qeidx;
mdb_inc_indent(2);
if (word0 & PMCS_IOMB_VALID) {
mdb_printf("VALID, ");
}
if (word0 & PMCS_IOMB_HIPRI) {
mdb_printf("HIPRI, ");
}
mdb_printf("OBID=%d, ",
mdb_printf("CAT=%s, ",
mdb_printf("OPCODE=%s",
mdb_printf(")\n");
mdb_printf("Remaining Payload:\n");
mdb_inc_indent(2);
}
mdb_printf("\n");
mdb_dec_indent(4);
}
static void
{
mdb_printf("\n");
mdb_printf("Inbound Queues\n");
mdb_printf("--------------\n");
mdb_inc_indent(2);
mdb_printf("No inbound queue ptr for queue #%d\n",
qidx);
continue;
}
mdb_warn("Couldn't read iqci\n");
break;
}
mdb_printf("Producer index: %d Consumer index: %d\n\n",
mdb_inc_indent(2);
if (iqci == 0) {
} else {
}
if (!verbose) {
mdb_printf("Last processed entry:\n");
== -1) {
mdb_warn("Couldn't read queue entry at 0x%p\n",
(ibqp + (PMCS_QENTRY_SIZE *
last_consumed)));
break;
}
mdb_printf("\n");
mdb_dec_indent(2);
continue;
}
mdb_warn("Couldn't read queue entry at 0x%p\n",
break;
}
}
mdb_printf("\n");
mdb_dec_indent(2);
}
mdb_dec_indent(2);
}
/*
* phy is our copy of the PHY structure. phyp is the pointer to the actual
* kernel PHY data structure
*/
static void
int totals_only)
{
char *yes = "Yes";
char *no = "No";
char route_attr, route_method;
case NOTHING:
dtype = "None";
break;
case SATA:
dtype = "SATA";
if (phy.configured) {
++sata_phys;
}
break;
case SAS:
dtype = "SAS";
if (phy.configured) {
++sas_phys;
}
break;
case EXPANDER:
dtype = "EXP";
if (phy.configured) {
++exp_phys;
}
break;
}
empty_phys++;
}
if (totals_only) {
return;
}
case SAS_LINK_RATE_1_5GBIT:
speed = "1.5Gb/s";
break;
case SAS_LINK_RATE_3GBIT:
speed = "3 Gb/s";
break;
case SAS_LINK_RATE_6GBIT:
speed = "6 Gb/s";
break;
default:
speed = "N/A";
break;
}
mdb_printf(" %3d %4d %6s %4s ",
} else {
mdb_printf(" N/A %4d %6s %4s ",
}
if (verbose) {
if (phy.abort_sent) {
}
if (phy.abort_pending) {
}
if (phy.configured) {
}
}
}
switch (phy.routing_attr) {
case SMP_ROUTING_DIRECT:
route_attr = 'D';
break;
case SMP_ROUTING_SUBTRACTIVE:
route_attr = 'S';
break;
case SMP_ROUTING_TABLE:
route_attr = 'T';
break;
default:
route_attr = '?';
break;
}
switch (phy.routing_method) {
case SMP_ROUTING_DIRECT:
route_method = 'D';
break;
case SMP_ROUTING_SUBTRACTIVE:
route_method = 'S';
break;
case SMP_ROUTING_TABLE:
route_method = 'T';
break;
default:
route_attr = '?';
break;
}
mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d "
}
/*
* In verbose mode, on the next line print the drill down
* info to see either the DISCOVER response or the REPORT
* GENERAL response depending on the PHY's dtype
*/
if (verbose) {
mdb_inc_indent(4);
case EXPANDER:
if (!phy.configured) {
break;
}
mdb_printf("REPORT GENERAL response: %p::"
"print smp_report_general_resp_t\n",
rg_resp)));
break;
case SAS:
case SATA:
mdb_printf("DISCOVER response: %p::"
"print smp_discover_resp_t\n",
disc_resp)));
break;
default:
break;
}
mdb_dec_indent(4);
}
}
}
static void
int totals_only)
{
mdb_inc_indent(3);
} else {
}
if (level == 0) {
sas_phys = 0;
sata_phys = 0;
exp_phys = 0;
num_expanders = 0;
empty_phys = 0;
}
if (!totals_only) {
if (level == 0) {
mdb_printf("PHY information\n");
}
mdb_printf("--------\n");
mdb_printf("--------\n");
mdb_printf("SAS Address Hdl Phy# Speed Type ");
if (verbose) {
mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
"Lock\n");
} else {
mdb_printf("\n");
}
}
while (pphy) {
break;
}
if (!totals_only) {
mdb_printf("\n");
}
}
}
mdb_dec_indent(3);
if (level == 0) {
if (verbose) {
mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
"(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
} else {
mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
"Occupied PHYs:",
}
}
}
/*
* filter is used to indicate whether we are filtering log messages based
* on "instance". The other filtering (based on options) depends on the
* values that are passed in for "sas_addr" and "phy_path".
*
* MAX_INST_STRLEN is the largest string size from which we will attempt
* to convert to an instance number. The string will be formed up as
* "0t<inst>\0" so that mdb_strtoull can parse it properly.
*/
#define MAX_INST_STRLEN 8
static int
{
char *bufp;
/* Get the address of the first element */
mdb_warn("can't read pmcs_tbuf");
return (DCMD_ERR);
}
/* Get the total number */
mdb_warn("can't read pmcs_tbuf_num_elems");
return (DCMD_ERR);
}
/* Get the current index */
mdb_warn("can't read pmcs_tbuf_idx");
return (DCMD_ERR);
}
/* Indicator as to whether the buffer has wrapped */
mdb_warn("can't read pmcs_tbuf_wrap");
return (DCMD_ERR);
}
/*
* On little-endian systems, the SAS address passed in will be
* byte swapped. Take care of that here.
*/
#if defined(_LITTLE_ENDIAN)
(sas_address >> 56));
#else
#endif
/* Ensure the tail number isn't greater than the size of the log */
if (tail_lines > tbuf_num_elems) {
}
/* Figure out where we start and stop */
if (wrap) {
if (tail_lines) {
/* Do we need to wrap backwards? */
if (tail_lines > tbuf_idx) {
tbuf_idx);
} else {
}
} else {
}
} else {
if (tail_lines > tbuf_idx) {
}
if (tail_lines) {
} else {
start_idx = 0;
}
}
/* Dump the buffer contents */
while (elems_to_print != 0) {
== -1) {
return (DCMD_ERR);
}
/*
* Check for filtering on HBA instance
*/
if (filter) {
/* Skip the driver name */
bufp++;
}
ei_idx = 0;
bufp++;
}
/* Get the instance */
}
}
/*
* This message is not being filtered by HBA instance.
* Now check to see if we're filtering based on
* PHY path or SAS address.
* Filtering is an "OR" operation. So, if any of the
* criteria matches, this message will be printed.
*/
PMCS_TBUF_UA_MAX_SIZE) == 0) {
}
}
if (sas_address != 0) {
8) == 0) {
}
}
}
if (!elem_filtered) {
}
if (++idx == tbuf_num_elems) {
idx = 0;
}
}
return (DCMD_OK);
}
/*
* Walkers
*/
static int
{
mdb_warn("Can not perform global walk\n");
return (WALK_ERR);
}
/*
* Address provided belongs to HBA softstate. Get the targets pointer
* to begin the walk.
*/
sizeof (pmcs_hw_t)) {
mdb_warn("Unable to read HBA softstate\n");
return (WALK_ERR);
}
}
return (WALK_ERR);
}
target_idx = 0;
return (WALK_NEXT);
}
static int
{
int status;
return (WALK_DONE);
}
return (WALK_DONE);
}
wsp->walk_cbdata);
do {
return (WALK_DONE);
}
return (status);
}
static void
{
}
static pmcs_phy_t *
{
/*
* First, if this is a root PHY, there are no more siblings
*/
return (NULL);
}
/*
* Otherwise, next sibling is the parent's sibling
*/
mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
return (NULL);
}
break;
}
/*
* If this PHY's sibling is NULL and it's a root phy,
* we're done.
*/
return (NULL);
}
}
}
static int
{
mdb_warn("Can not perform global walk\n");
return (WALK_ERR);
}
/*
* Address provided belongs to HBA softstate. Get the targets pointer
* to begin the walk.
*/
sizeof (pmcs_hw_t)) {
mdb_warn("Unable to read HBA softstate\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
int status;
mdb_warn("phy_walk_s: Failed to read PHY at %p",
return (WALK_DONE);
}
wsp->walk_cbdata);
} else {
}
/*
* We reached the end of this sibling list. Trudge back up
* to the parent and find the next sibling after the expander
* we just finished traversing, if there is one.
*/
return (WALK_DONE);
}
}
return (status);
}
static void
{
}
static void
{
int idx;
char *match_type;
match_type = "index";
match_type = "serial number";
} else {
switch (tag_type) {
case PMCS_TAG_TYPE_NONE:
match_type = "tag type NONE";
break;
case PMCS_TAG_TYPE_CBACK:
match_type = "tag type CBACK";
break;
case PMCS_TAG_TYPE_WAIT:
match_type = "tag type WAIT";
break;
}
}
continue;
}
continue;
}
if (printed_header == B_FALSE) {
if (tag_type) {
mdb_printf("\nWork structures matching %s\n\n",
} else {
mdb_printf("\nWork structures matching %s of "
}
mdb_printf("%8s %10s %20s %8s %8s O D\n",
"HTag", "State", "Phy Path", "Target", "Timer");
}
display_one_work(wp, 0, 0);
}
if (!printed_header) {
mdb_printf("No work structure matches found\n");
}
}
static int
{
int args = 0;
void *pmcs_state;
char *state_str;
if (!(flags & DCMD_ADDRSPEC)) {
pmcs_state = NULL;
mdb_warn("can't read pmcs_softc_state");
return (DCMD_ERR);
}
mdb_warn("mdb_pwalk_dcmd failed");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
/*
* Count the number of supplied options and make sure they are
* within appropriate ranges. If they're set to UINT_MAX, that means
* they were not supplied, in which case reset them to 0.
*/
args++;
if (index > PMCS_TAG_INDEX_MASK) {
mdb_warn("Index is out of range\n");
return (DCMD_USAGE);
}
}
args++;
switch (tag_type) {
case PMCS_TAG_TYPE_NONE:
case PMCS_TAG_TYPE_CBACK:
case PMCS_TAG_TYPE_WAIT:
break;
default:
mdb_warn("Invalid tag type\n");
return (DCMD_USAGE);
}
}
args++;
mdb_warn("Serial number is out of range\n");
return (DCMD_USAGE);
}
}
/*
* Make sure 1 and only 1 option is specified
*/
mdb_warn("Exactly one of -i, -s and -t must be specified\n");
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
/* processing completed */
(flags & DCMD_LOOPFIRST)) {
mdb_printf("\n");
mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
"Address", "State", "Inst", "DIP");
mdb_printf("================================="
"============================================\n");
}
case STATE_NIL:
state_str = "Invalid";
break;
case STATE_PROBING:
state_str = "Probing";
break;
case STATE_RUNNING:
state_str = "Running";
break;
case STATE_UNPROBING:
state_str = "Unprobing";
break;
case STATE_DEAD:
state_str = "Dead";
break;
case STATE_IN_RESET:
state_str = "In Reset";
break;
}
mdb_printf("\n");
mdb_inc_indent(4);
mdb_dec_indent(4);
mdb_printf("\n");
return (DCMD_OK);
}
#ifndef _KMDB
static int
{
int ofilefd = -1;
char ofilename[MAXPATHLEN];
mdb_warn("Firmware event log disabled for instance %d",
instance);
return (DCMD_OK);
}
MAXPATHLEN) {
mdb_warn("Output filename is too long for instance %d",
instance);
return (DCMD_ERR);
}
goto cleanup;
}
if (ofilefd < 0) {
mdb_warn("Unable to open '%s' to dump instance %d event log",
goto cleanup;
}
mdb_warn("Failed to write %d bytes to output file: instance %d",
goto cleanup;
}
if (ofilefd >= 0) {
}
return (rval);
}
static int
{
void *pmcs_state;
return (DCMD_USAGE);
}
mdb_printf("No output file specified\n");
return (DCMD_USAGE);
}
if (!(flags & DCMD_ADDRSPEC)) {
pmcs_state = NULL;
mdb_warn("can't read pmcs_softc_state");
return (DCMD_ERR);
}
mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
}
#endif /* _KMDB */
static int
{
void *pmcs_state;
const char *match_phy_path = NULL;
if (!(flags & DCMD_ADDRSPEC)) {
pmcs_state = NULL;
mdb_warn("can't read pmcs_softc_state");
return (DCMD_ERR);
}
mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
} else if (flags & DCMD_LOOPFIRST) {
} else {
return (DCMD_OK);
}
}
static int
{
void *pmcs_state;
char *state_str;
if (!(flags & DCMD_ADDRSPEC)) {
pmcs_state = NULL;
mdb_warn("can't read pmcs_softc_state");
return (DCMD_ERR);
}
mdb_warn("mdb_pwalk_dcmd failed");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
/*
* The 'd' and 'm' options implicitly enable the 'I' option
*/
if (damap_info || dtc_info) {
iport_info = TRUE;
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
/* processing completed */
unconfigured) {
mdb_printf("\n");
mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
"Address", "State", "Inst", "DIP");
mdb_printf("================================="
"============================================\n");
}
case STATE_NIL:
state_str = "Invalid";
break;
case STATE_PROBING:
state_str = "Probing";
break;
case STATE_RUNNING:
state_str = "Running";
break;
case STATE_UNPROBING:
state_str = "Unprobing";
break;
case STATE_DEAD:
state_str = "Dead";
break;
case STATE_IN_RESET:
state_str = "In Reset";
break;
}
mdb_printf("\n");
mdb_inc_indent(4);
if (waitqs_info)
if (hw_info)
if (phy_info || tgt_phy_count)
if (target_info || tgt_phy_count)
if (work_info)
if (ic_info)
if (ibq)
if (obq)
if (iport_info)
if (compq)
if (unconfigured)
mdb_dec_indent(4);
return (rv);
}
void
{
mdb_printf("Prints summary information about each pmcs instance.\n"
" -c: Dump the completion queue\n"
" -d: Print per-iport information about device tree children\n"
" -h: Print more detailed hardware information\n"
" -i: Print interrupt coalescing information\n"
" -I: Print information about each iport\n"
" -p: Print information about each attached PHY\n"
" -q: Dump inbound queues\n"
" -Q: Dump outbound queues\n"
" -t: Print information about each configured target\n"
" -T: Print target and PHY count summary\n"
" -u: Show SAS address of all unconfigured targets\n"
" -w: Dump work structures\n"
" -W: List pmcs cmds waiting on various queues\n"
" -v: Add verbosity to the above options\n");
}
void
{
mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
" -l TAIL_LINES: Dump the last TAIL_LINES messages\n"
" -p PHY_PATH: Dump messages matching PHY_PATH\n"
" -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n"
"Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
" SAS_ADDRESS can be found with ::pmcs -t "
"(e.g. 5000c5000358c221)\n");
}
void
{
mdb_printf("Print all work structures by matching the tag.\n"
" -i index: Match tag index (0x000 - 0xfff)\n"
" -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
" -t tagtype: Match tag type [NONE(1), CBACK(2), "
"WAIT(3)]\n");
}
static const mdb_dcmd_t dcmds[] = {
{ "pmcs", "?[-cdhiImpQqtTuwWv]", "print pmcs information",
},
{ "pmcs_log",
"?[-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
},
{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
"Find work structures by tag type, serial number or index",
},
#ifndef _KMDB
{ "pmcs_fwlog",
"?-o output_file",
},
#endif /* _KMDB */
{ NULL }
};
static const mdb_walker_t walkers[] = {
{ "pmcs_targets", "walk target structures",
{ "pmcs_phys", "walk PHY structures",
{ NULL }
};
static const mdb_modinfo_t modinfo = {
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}