xref: /freebsd/usr.sbin/mpsutil/mps_show.c (revision d56ce5915c41517ccc7de2510daec200e100ef68)
129b76e53SScott Long /*-
2883bb7e9SScott Long  * Copyright (c) 2015 Netflix, Inc.
3883bb7e9SScott Long  * Written by: Scott Long <scottl@freebsd.org>
4883bb7e9SScott Long  *
529b76e53SScott Long  * Copyright (c) 2008 Yahoo!, Inc.
629b76e53SScott Long  * All rights reserved.
729b76e53SScott Long  * Written by: John Baldwin <jhb@FreeBSD.org>
829b76e53SScott Long  *
929b76e53SScott Long  * Redistribution and use in source and binary forms, with or without
1029b76e53SScott Long  * modification, are permitted provided that the following conditions
1129b76e53SScott Long  * are met:
1229b76e53SScott Long  * 1. Redistributions of source code must retain the above copyright
1329b76e53SScott Long  *    notice, this list of conditions and the following disclaimer.
1429b76e53SScott Long  * 2. Redistributions in binary form must reproduce the above copyright
1529b76e53SScott Long  *    notice, this list of conditions and the following disclaimer in the
1629b76e53SScott Long  *    documentation and/or other materials provided with the distribution.
1729b76e53SScott Long  * 3. Neither the name of the author nor the names of any co-contributors
1829b76e53SScott Long  *    may be used to endorse or promote products derived from this software
1929b76e53SScott Long  *    without specific prior written permission.
2029b76e53SScott Long  *
2129b76e53SScott Long  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2229b76e53SScott Long  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329b76e53SScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429b76e53SScott Long  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2529b76e53SScott Long  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629b76e53SScott Long  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729b76e53SScott Long  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829b76e53SScott Long  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929b76e53SScott Long  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029b76e53SScott Long  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129b76e53SScott Long  * SUCH DAMAGE.
3229b76e53SScott Long  */
3329b76e53SScott Long 
3429b76e53SScott Long #include <sys/param.h>
3529b76e53SScott Long #include <sys/errno.h>
36fc9780fdSAlfredo Dal'Ava Junior #include <sys/endian.h>
3729b76e53SScott Long #include <err.h>
3829b76e53SScott Long #include <stdio.h>
3929b76e53SScott Long #include <stdlib.h>
4029b76e53SScott Long #include <string.h>
4129b76e53SScott Long #include <unistd.h>
4229b76e53SScott Long #include "mpsutil.h"
4329b76e53SScott Long 
4429b76e53SScott Long static char * get_device_speed(uint8_t rate);
4529b76e53SScott Long static char * get_device_type(uint32_t di);
4629b76e53SScott Long static int show_all(int ac, char **av);
4729b76e53SScott Long static int show_devices(int ac, char **av);
4829b76e53SScott Long static int show_enclosures(int ac, char **av);
4929b76e53SScott Long static int show_expanders(int ac, char **av);
5029b76e53SScott Long 
5129b76e53SScott Long MPS_TABLE(top, show);
5229b76e53SScott Long 
5329b76e53SScott Long #define	STANDALONE_STATE	"ONLINE"
5429b76e53SScott Long 
5529b76e53SScott Long static int
show_adapter(int ac,char ** av)5629b76e53SScott Long show_adapter(int ac, char **av)
5729b76e53SScott Long {
58*7bca09e2SAlexander Motin 	const char* pcie_speed[] = { "2.5", "5.0", "8.0", "16.0", "32.0" };
59e2ea6942SDaniel Austin 	const char* temp_units[] = { "", "F", "C" };
60e2ea6942SDaniel Austin 	const char* ioc_speeds[] = { "", "Full", "Half", "Quarter", "Eighth" };
61e2ea6942SDaniel Austin 
6229b76e53SScott Long 	MPI2_CONFIG_PAGE_SASIOUNIT_0	*sas0;
6329b76e53SScott Long 	MPI2_CONFIG_PAGE_SASIOUNIT_1	*sas1;
6429b76e53SScott Long 	MPI2_SAS_IO_UNIT0_PHY_DATA	*phy0;
6529b76e53SScott Long 	MPI2_SAS_IO_UNIT1_PHY_DATA	*phy1;
6629b76e53SScott Long 	MPI2_CONFIG_PAGE_MAN_0 *man0;
6729b76e53SScott Long 	MPI2_CONFIG_PAGE_BIOS_3 *bios3;
68e2ea6942SDaniel Austin 	MPI2_CONFIG_PAGE_IO_UNIT_1 *iounit1;
69e2ea6942SDaniel Austin 	MPI2_CONFIG_PAGE_IO_UNIT_7 *iounit7;
7029b76e53SScott Long 	MPI2_IOC_FACTS_REPLY *facts;
7129b76e53SScott Long 	U16 IOCStatus;
7229b76e53SScott Long 	char *speed, *minspeed, *maxspeed, *isdisabled, *type;
73f5b00833SAlexander Motin 	char devhandle[8], ctrlhandle[8];
7429b76e53SScott Long 	int error, fd, v, i;
7529b76e53SScott Long 
7629b76e53SScott Long 	if (ac != 1) {
7729b76e53SScott Long 		warnx("show adapter: extra arguments");
7829b76e53SScott Long 		return (EINVAL);
7929b76e53SScott Long 	}
8029b76e53SScott Long 
8129b76e53SScott Long 	fd = mps_open(mps_unit);
8229b76e53SScott Long 	if (fd < 0) {
8329b76e53SScott Long 		error = errno;
8429b76e53SScott Long 		warn("mps_open");
8529b76e53SScott Long 		return (error);
8629b76e53SScott Long 	}
8729b76e53SScott Long 
8829b76e53SScott Long 	man0 = mps_read_man_page(fd, 0, NULL);
8929b76e53SScott Long 	if (man0 == NULL) {
9029b76e53SScott Long 		error = errno;
9129b76e53SScott Long 		warn("Failed to get controller info");
9229b76e53SScott Long 		return (error);
9329b76e53SScott Long 	}
9429b76e53SScott Long 	if (man0->Header.PageLength < sizeof(*man0) / 4) {
9529b76e53SScott Long 		warnx("Invalid controller info");
9629b76e53SScott Long 		return (EINVAL);
9729b76e53SScott Long 	}
983f4fe35dSBaptiste Daroussin 	printf("mp%s%d Adapter:\n", is_mps ? "s": "r", mps_unit);
9929b76e53SScott Long 	printf("       Board Name: %.16s\n", man0->BoardName);
10029b76e53SScott Long 	printf("   Board Assembly: %.16s\n", man0->BoardAssembly);
10129b76e53SScott Long 	printf("        Chip Name: %.16s\n", man0->ChipName);
10229b76e53SScott Long 	printf("    Chip Revision: %.16s\n", man0->ChipRevision);
10329b76e53SScott Long 	free(man0);
10429b76e53SScott Long 
10529b76e53SScott Long 	bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
10629b76e53SScott Long 	if (bios3 == NULL) {
10729b76e53SScott Long 		error = errno;
10829b76e53SScott Long 		warn("Failed to get BIOS page 3 info");
10929b76e53SScott Long 		return (error);
11029b76e53SScott Long 	}
111fc9780fdSAlfredo Dal'Ava Junior 	v = le32toh(bios3->BiosVersion);
11229b76e53SScott Long 	printf("    BIOS Revision: %d.%02d.%02d.%02d\n",
11329b76e53SScott Long 	    ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
11429b76e53SScott Long 	    ((v & 0xff00) >> 8), (v & 0xff));
11529b76e53SScott Long 	free(bios3);
11629b76e53SScott Long 
11729b76e53SScott Long 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
11829b76e53SScott Long 		printf("could not get controller IOCFacts\n");
11929b76e53SScott Long 		close(fd);
12029b76e53SScott Long 		return (errno);
12129b76e53SScott Long 	}
12229b76e53SScott Long 	v = facts->FWVersion.Word;
12329b76e53SScott Long 	printf("Firmware Revision: %d.%02d.%02d.%02d\n",
12429b76e53SScott Long 	    ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
12529b76e53SScott Long 	    ((v & 0xff00) >> 8), (v & 0xff));
12629b76e53SScott Long 	printf("  Integrated RAID: %s\n",
12729b76e53SScott Long 	    (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
12829b76e53SScott Long 	    ? "yes" : "no");
12929b76e53SScott Long 	free(facts);
13029b76e53SScott Long 
131e2ea6942SDaniel Austin 	iounit1 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IO_UNIT, 1, 0, NULL);
132e2ea6942SDaniel Austin 	if (iounit1 == NULL) {
133e2ea6942SDaniel Austin 		error = errno;
134e2ea6942SDaniel Austin 		warn("Failed to get IOUNIT page 1 info");
135e2ea6942SDaniel Austin 		return (error);
136e2ea6942SDaniel Austin 	}
137e2ea6942SDaniel Austin 	printf("         SATA NCQ: %s\n",
138e2ea6942SDaniel Austin 		((iounit1->Flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE) == 0) ?
139e2ea6942SDaniel Austin 		"ENABLED" : "DISABLED");
140e2ea6942SDaniel Austin 	free(iounit1);
141e2ea6942SDaniel Austin 
142e2ea6942SDaniel Austin 	iounit7 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IO_UNIT, 7, 0, NULL);
143e2ea6942SDaniel Austin 	if (iounit7 == NULL) {
144e2ea6942SDaniel Austin 		error = errno;
145e2ea6942SDaniel Austin 		warn("Failed to get IOUNIT page 7 info");
146e2ea6942SDaniel Austin 		return (error);
147e2ea6942SDaniel Austin 	}
148e2ea6942SDaniel Austin 	printf(" PCIe Width/Speed: x%d (%s GB/sec)\n", iounit7->PCIeWidth,
149e2ea6942SDaniel Austin 		pcie_speed[iounit7->PCIeSpeed]);
150e2ea6942SDaniel Austin 	printf("        IOC Speed: %s\n", ioc_speeds[iounit7->IOCSpeed]);
151e2ea6942SDaniel Austin 	printf("      Temperature: ");
152e2ea6942SDaniel Austin 	if (iounit7->IOCTemperatureUnits == MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT)
153e2ea6942SDaniel Austin 		printf("Unknown/Unsupported\n");
154e2ea6942SDaniel Austin 	else
155e2ea6942SDaniel Austin 		printf("%d %s\n", iounit7->IOCTemperature,
156e2ea6942SDaniel Austin 			temp_units[iounit7->IOCTemperatureUnits]);
157e2ea6942SDaniel Austin 	free(iounit7);
158e2ea6942SDaniel Austin 
15929b76e53SScott Long 	fd = mps_open(mps_unit);
16029b76e53SScott Long 	if (fd < 0) {
16129b76e53SScott Long 		error = errno;
16229b76e53SScott Long 		warn("mps_open");
16329b76e53SScott Long 		return (error);
16429b76e53SScott Long 	}
16529b76e53SScott Long 
16629b76e53SScott Long 	sas0 = mps_read_extended_config_page(fd,
16729b76e53SScott Long 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
16829b76e53SScott Long 	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
16929b76e53SScott Long 	if (sas0 == NULL) {
17029b76e53SScott Long 		error = errno;
17129b76e53SScott Long 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
1720ce8c4a3SBaptiste Daroussin 		free(sas0);
1730ce8c4a3SBaptiste Daroussin 		close(fd);
17429b76e53SScott Long 		return (error);
17529b76e53SScott Long 	}
17629b76e53SScott Long 
17729b76e53SScott Long 	sas1 = mps_read_extended_config_page(fd,
17829b76e53SScott Long 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
17929b76e53SScott Long 	    MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
1800ce8c4a3SBaptiste Daroussin 	if (sas1 == NULL) {
18129b76e53SScott Long 		error = errno;
18229b76e53SScott Long 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
1830ce8c4a3SBaptiste Daroussin 		free(sas0);
1840ce8c4a3SBaptiste Daroussin 		close(fd);
18529b76e53SScott Long 		return (error);
18629b76e53SScott Long 	}
18729b76e53SScott Long 	printf("\n");
18829b76e53SScott Long 
1899b51f857SBaptiste Daroussin 	printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
1909b51f857SBaptiste Daroussin 	    "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
19129b76e53SScott Long 	for (i = 0; i < sas0->NumPhys; i++) {
19229b76e53SScott Long 		phy0 = &sas0->PhyData[i];
19329b76e53SScott Long 		phy1 = &sas1->PhyData[i];
19429b76e53SScott Long 		if (phy0->PortFlags &
19529b76e53SScott Long 		     MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
19629b76e53SScott Long 			printf("Discovery still in progress\n");
19729b76e53SScott Long 			continue;
19829b76e53SScott Long 		}
19929b76e53SScott Long 		if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
20029b76e53SScott Long 			isdisabled = "Y";
20129b76e53SScott Long 		else
20229b76e53SScott Long 			isdisabled = "N";
20329b76e53SScott Long 
20429b76e53SScott Long 		minspeed = get_device_speed(phy1->MaxMinLinkRate);
20529b76e53SScott Long 		maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
206fc9780fdSAlfredo Dal'Ava Junior 		type = get_device_type(le32toh(phy0->ControllerPhyDeviceInfo));
20729b76e53SScott Long 
208fc9780fdSAlfredo Dal'Ava Junior 		if (le16toh(phy0->AttachedDevHandle) != 0) {
209f5b00833SAlexander Motin 			snprintf(devhandle, sizeof(devhandle), "%04x",
210f5b00833SAlexander Motin 			    le16toh(phy0->AttachedDevHandle));
211f5b00833SAlexander Motin 			snprintf(ctrlhandle, sizeof(ctrlhandle), "%04x",
212fc9780fdSAlfredo Dal'Ava Junior 			    le16toh(phy0->ControllerDevHandle));
21329b76e53SScott Long 			speed = get_device_speed(phy0->NegotiatedLinkRate);
21429b76e53SScott Long 		} else {
215f5b00833SAlexander Motin 			snprintf(devhandle, sizeof(devhandle), "    ");
216f5b00833SAlexander Motin 			snprintf(ctrlhandle, sizeof(ctrlhandle), "    ");
21729b76e53SScott Long 			speed = "     ";
21829b76e53SScott Long 		}
2199b51f857SBaptiste Daroussin 		printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
2209b51f857SBaptiste Daroussin 		    i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
22129b76e53SScott Long 		    maxspeed, type);
22229b76e53SScott Long 	}
22329b76e53SScott Long 	free(sas0);
22429b76e53SScott Long 	free(sas1);
22529b76e53SScott Long 	printf("\n");
22629b76e53SScott Long 	close(fd);
22729b76e53SScott Long 	return (0);
22829b76e53SScott Long }
22929b76e53SScott Long 
23029b76e53SScott Long MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
23129b76e53SScott Long 
23229b76e53SScott Long static int
show_iocfacts(int ac,char ** av)23329b76e53SScott Long show_iocfacts(int ac, char **av)
23429b76e53SScott Long {
23529b76e53SScott Long 	MPI2_IOC_FACTS_REPLY *facts;
2363859e5c3SScott Long 	uint8_t *fb;
237b3995bb8SScott Long 	char tmpbuf[128];
23829b76e53SScott Long 	int error, fd;
23929b76e53SScott Long 
24029b76e53SScott Long 	fd = mps_open(mps_unit);
24129b76e53SScott Long 	if (fd < 0) {
24229b76e53SScott Long 		error = errno;
24329b76e53SScott Long 		warn("mps_open");
24429b76e53SScott Long 		return (error);
24529b76e53SScott Long 	}
24629b76e53SScott Long 
24729b76e53SScott Long 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
24829b76e53SScott Long 		printf("could not get controller IOCFacts\n");
24929b76e53SScott Long 		close(fd);
25029b76e53SScott Long 		return (errno);
25129b76e53SScott Long 	}
25229b76e53SScott Long 
2533859e5c3SScott Long 	fb = (uint8_t *)facts;
2543859e5c3SScott Long 
255b3995bb8SScott Long #define IOCCAP "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" \
256b3995bb8SScott Long     "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" \
257b3995bb8SScott Long     "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc" \
258b3995bb8SScott Long     "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV"
259b3995bb8SScott Long 
260b3995bb8SScott Long 	bzero(tmpbuf, sizeof(tmpbuf));
261b3995bb8SScott Long 	mps_parse_flags(facts->IOCCapabilities, IOCCAP, tmpbuf, sizeof(tmpbuf));
262b3995bb8SScott Long 
263b041593aSScott Long 	printf("          MsgVersion: %d.%d\n",
264e8262ee8SScott Long 	    facts->MsgVersion >> 8, facts->MsgVersion & 0xff);
265e8262ee8SScott Long 	printf("           MsgLength: %d\n", facts->MsgLength);
266e8262ee8SScott Long 	printf("            Function: 0x%x\n", facts->Function);
267e8262ee8SScott Long 	printf("       HeaderVersion: %02d,%02d\n",
268e8262ee8SScott Long 	    facts->HeaderVersion >> 8, facts->HeaderVersion & 0xff);
269e8262ee8SScott Long 	printf("           IOCNumber: %d\n", facts->IOCNumber);
270e8262ee8SScott Long 	printf("            MsgFlags: 0x%x\n", facts->MsgFlags);
271e8262ee8SScott Long 	printf("               VP_ID: %d\n", facts->VP_ID);
272e8262ee8SScott Long 	printf("               VF_ID: %d\n", facts->VF_ID);
273e8262ee8SScott Long 	printf("       IOCExceptions: %d\n", facts->IOCExceptions);
274e8262ee8SScott Long 	printf("           IOCStatus: %d\n", facts->IOCStatus);
275e8262ee8SScott Long 	printf("          IOCLogInfo: 0x%x\n", facts->IOCLogInfo);
27629b76e53SScott Long 	printf("       MaxChainDepth: %d\n", facts->MaxChainDepth);
27729b76e53SScott Long 	printf("             WhoInit: 0x%x\n", facts->WhoInit);
27829b76e53SScott Long 	printf("       NumberOfPorts: %d\n", facts->NumberOfPorts);
27929b76e53SScott Long 	printf("      MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
28029b76e53SScott Long 	printf("       RequestCredit: %d\n", facts->RequestCredit);
28129b76e53SScott Long 	printf("           ProductID: 0x%x\n", facts->ProductID);
282b3995bb8SScott Long 	printf("     IOCCapabilities: 0x%x %s\n", facts->IOCCapabilities,
283b3995bb8SScott Long 	    tmpbuf);
284b041593aSScott Long 	printf("           FWVersion: %02d.%02d.%02d.%02d\n",
285b041593aSScott Long 	    facts->FWVersion.Struct.Major, facts->FWVersion.Struct.Minor,
286b041593aSScott Long 	    facts->FWVersion.Struct.Unit, facts->FWVersion.Struct.Dev);
28729b76e53SScott Long 	printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
2883859e5c3SScott Long 	if (is_mps == 0)
2893859e5c3SScott Long 		printf(" MaxChainSegmentSize: %d\n", (uint16_t)(fb[0x26]));
29029b76e53SScott Long 	printf("       MaxInitiators: %d\n", facts->MaxInitiators);
29129b76e53SScott Long 	printf("          MaxTargets: %d\n", facts->MaxTargets);
29229b76e53SScott Long 	printf("     MaxSasExpanders: %d\n", facts->MaxSasExpanders);
29329b76e53SScott Long 	printf("       MaxEnclosures: %d\n", facts->MaxEnclosures);
294b3995bb8SScott Long 
295b3995bb8SScott Long 	bzero(tmpbuf, sizeof(tmpbuf));
296b3995bb8SScott Long 	mps_parse_flags(facts->ProtocolFlags,
297b3995bb8SScott Long 	    "\4NvmeDevices\2ScsiTarget\1ScsiInitiator", tmpbuf, sizeof(tmpbuf));
298b3995bb8SScott Long 	printf("       ProtocolFlags: 0x%x %s\n", facts->ProtocolFlags, tmpbuf);
29929b76e53SScott Long 	printf("  HighPriorityCredit: %d\n", facts->HighPriorityCredit);
30029b76e53SScott Long 	printf("MaxRepDescPostQDepth: %d\n",
30129b76e53SScott Long 	    facts->MaxReplyDescriptorPostQueueDepth);
30229b76e53SScott Long 	printf("      ReplyFrameSize: %d\n", facts->ReplyFrameSize);
30329b76e53SScott Long 	printf("          MaxVolumes: %d\n", facts->MaxVolumes);
30429b76e53SScott Long 	printf("        MaxDevHandle: %d\n", facts->MaxDevHandle);
30529b76e53SScott Long 	printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
30629b76e53SScott Long 	printf("        MinDevHandle: %d\n", facts->MinDevHandle);
3073859e5c3SScott Long 	if (is_mps == 0)
3083859e5c3SScott Long 		printf(" CurrentHostPageSize: %d\n", (uint8_t)(fb[0x3e]));
30929b76e53SScott Long 
31029b76e53SScott Long 	free(facts);
31129b76e53SScott Long 	return (0);
31229b76e53SScott Long }
31329b76e53SScott Long 
31429b76e53SScott Long MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
31529b76e53SScott Long 
31629b76e53SScott Long static int
show_adapters(int ac,char ** av)31729b76e53SScott Long show_adapters(int ac, char **av)
31829b76e53SScott Long {
31929b76e53SScott Long 	MPI2_CONFIG_PAGE_MAN_0 *man0;
32029b76e53SScott Long 	MPI2_IOC_FACTS_REPLY *facts;
32129b76e53SScott Long 	int unit, fd, error;
32229b76e53SScott Long 
32329b76e53SScott Long 	printf("Device Name\t      Chip Name        Board Name        Firmware\n");
32429b76e53SScott Long 	for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
32529b76e53SScott Long 		fd = mps_open(unit);
32629b76e53SScott Long 		if (fd < 0)
32729b76e53SScott Long 			continue;
32829b76e53SScott Long 		facts = mps_get_iocfacts(fd);
32929b76e53SScott Long 		if (facts == NULL) {
33029b76e53SScott Long 			error = errno;
33129b76e53SScott Long 			warn("Faled to get controller iocfacts");
33229b76e53SScott Long 			close(fd);
33329b76e53SScott Long 			return (error);
33429b76e53SScott Long 		}
33529b76e53SScott Long 		man0 = mps_read_man_page(fd, 0, NULL);
33629b76e53SScott Long 		if (man0 == NULL) {
33729b76e53SScott Long 			error = errno;
33829b76e53SScott Long 			warn("Failed to get controller info");
33929b76e53SScott Long 			close(fd);
3400ce8c4a3SBaptiste Daroussin 			free(facts);
34129b76e53SScott Long 			return (error);
34229b76e53SScott Long 		}
34329b76e53SScott Long 		if (man0->Header.PageLength < sizeof(*man0) / 4) {
34429b76e53SScott Long 			warnx("Invalid controller info");
34529b76e53SScott Long 			close(fd);
34629b76e53SScott Long 			free(man0);
3470ce8c4a3SBaptiste Daroussin 			free(facts);
34829b76e53SScott Long 			return (EINVAL);
34929b76e53SScott Long 		}
35048f31f4fSBaptiste Daroussin 		printf("/dev/mp%s%d\t%16s %16s        %08x\n",
35148f31f4fSBaptiste Daroussin 		    is_mps ? "s": "r", unit,
35229b76e53SScott Long 		    man0->ChipName, man0->BoardName, facts->FWVersion.Word);
35329b76e53SScott Long 		free(man0);
35429b76e53SScott Long 		free(facts);
35529b76e53SScott Long 		close(fd);
35629b76e53SScott Long 	}
35729b76e53SScott Long 	return (0);
35829b76e53SScott Long }
35929b76e53SScott Long MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
36029b76e53SScott Long 
36129b76e53SScott Long static char *
get_device_type(uint32_t di)36229b76e53SScott Long get_device_type(uint32_t di)
36329b76e53SScott Long {
36429b76e53SScott Long 
36529b76e53SScott Long 	if (di & 0x4000)
36629b76e53SScott Long 		return ("SEP Target    ");
36729b76e53SScott Long 	if (di & 0x2000)
36829b76e53SScott Long 		return ("ATAPI Target  ");
36929b76e53SScott Long 	if (di & 0x400)
37029b76e53SScott Long 		return ("SAS Target    ");
37129b76e53SScott Long 	if (di & 0x200)
37229b76e53SScott Long 		return ("STP Target    ");
37329b76e53SScott Long 	if (di & 0x100)
37429b76e53SScott Long 		return ("SMP Target    ");
37529b76e53SScott Long 	if (di & 0x80)
37629b76e53SScott Long 		return ("SATA Target   ");
37729b76e53SScott Long 	if (di & 0x70)
37829b76e53SScott Long 		return ("SAS Initiator ");
37929b76e53SScott Long 	if (di & 0x8)
38029b76e53SScott Long 		return ("SATA Initiator");
38129b76e53SScott Long 	if ((di & 0x7) == 0)
38229b76e53SScott Long 		return ("No Device     ");
38329b76e53SScott Long 	return ("Unknown Device");
38429b76e53SScott Long }
38529b76e53SScott Long 
38629b76e53SScott Long static char *
get_enc_type(uint32_t flags,int * issep)38729b76e53SScott Long get_enc_type(uint32_t flags, int *issep)
38829b76e53SScott Long {
38929b76e53SScott Long 	char *type;
39029b76e53SScott Long 
39129b76e53SScott Long 	*issep = 0;
39229b76e53SScott Long 	switch (flags & 0xf) {
39329b76e53SScott Long 	case 0x01:
39429b76e53SScott Long 		type = "Direct Attached SES-2";
39529b76e53SScott Long 		*issep = 1;
39629b76e53SScott Long 		break;
39729b76e53SScott Long 	case 0x02:
39829b76e53SScott Long 		type = "Direct Attached SGPIO";
39929b76e53SScott Long 		break;
40029b76e53SScott Long 	case 0x03:
40129b76e53SScott Long 		type = "Expander SGPIO";
40229b76e53SScott Long 		break;
40329b76e53SScott Long 	case 0x04:
40429b76e53SScott Long 		type = "External SES-2";
40529b76e53SScott Long 		*issep = 1;
40629b76e53SScott Long 		break;
40729b76e53SScott Long 	case 0x05:
40829b76e53SScott Long 		type = "Direct Attached GPIO";
40929b76e53SScott Long 		break;
41029b76e53SScott Long 	case 0x0:
41129b76e53SScott Long 	default:
41229b76e53SScott Long 		return ("Unknown");
41329b76e53SScott Long 	}
41429b76e53SScott Long 
41529b76e53SScott Long 	return (type);
41629b76e53SScott Long }
41729b76e53SScott Long 
41829b76e53SScott Long static char *
41929b76e53SScott Long mps_device_speed[] = {
42029b76e53SScott Long 	NULL,
42129b76e53SScott Long 	NULL,
42229b76e53SScott Long 	NULL,
42329b76e53SScott Long 	NULL,
42429b76e53SScott Long 	NULL,
42529b76e53SScott Long 	NULL,
42629b76e53SScott Long 	NULL,
42729b76e53SScott Long 	NULL,
42829b76e53SScott Long 	"1.5",
42929b76e53SScott Long 	"3.0",
43029b76e53SScott Long 	"6.0",
43129b76e53SScott Long 	"12 "
43229b76e53SScott Long };
43329b76e53SScott Long 
43429b76e53SScott Long static char *
get_device_speed(uint8_t rate)43529b76e53SScott Long get_device_speed(uint8_t rate)
43629b76e53SScott Long {
43729b76e53SScott Long 	char *speed;
43829b76e53SScott Long 
43929b76e53SScott Long 	rate &= 0xf;
44029b76e53SScott Long 	if (rate >= sizeof(mps_device_speed))
44129b76e53SScott Long 		return ("Unk");
44229b76e53SScott Long 
44329b76e53SScott Long 	if ((speed = mps_device_speed[rate]) == NULL)
44429b76e53SScott Long 		return ("???");
44529b76e53SScott Long 	return (speed);
44629b76e53SScott Long }
44729b76e53SScott Long 
44829b76e53SScott Long static char *
44929b76e53SScott Long mps_page_name[] = {
45029b76e53SScott Long 	"IO Unit",
45129b76e53SScott Long 	"IOC",
45229b76e53SScott Long 	"BIOS",
45329b76e53SScott Long 	NULL,
45429b76e53SScott Long 	NULL,
45529b76e53SScott Long 	NULL,
45629b76e53SScott Long 	NULL,
45729b76e53SScott Long 	NULL,
45829b76e53SScott Long 	"RAID Volume",
45929b76e53SScott Long 	"Manufacturing",
46029b76e53SScott Long 	"RAID Physical Disk",
46129b76e53SScott Long 	NULL,
46229b76e53SScott Long 	NULL,
46329b76e53SScott Long 	NULL,
46429b76e53SScott Long 	NULL,
46529b76e53SScott Long 	NULL,
46629b76e53SScott Long 	"SAS IO Unit",
46729b76e53SScott Long 	"SAS Expander",
46829b76e53SScott Long 	"SAS Device",
46929b76e53SScott Long 	"SAS PHY",
47029b76e53SScott Long 	"Log",
47129b76e53SScott Long 	"Enclosure",
47229b76e53SScott Long 	"RAID Configuration",
47329b76e53SScott Long 	"Driver Persistent Mapping",
47429b76e53SScott Long 	"SAS Port",
47529b76e53SScott Long 	"Ethernet Port",
47629b76e53SScott Long 	"Extended Manufacturing"
47729b76e53SScott Long };
47829b76e53SScott Long 
47929b76e53SScott Long static char *
get_page_name(u_int page)48029b76e53SScott Long get_page_name(u_int page)
48129b76e53SScott Long {
48229b76e53SScott Long 	char *name;
48329b76e53SScott Long 
48429b76e53SScott Long 	if (page >= sizeof(mps_page_name))
48529b76e53SScott Long 		return ("Unknown");
48629b76e53SScott Long 	if ((name = mps_page_name[page]) == NULL)
48729b76e53SScott Long 		return ("Unknown");
48829b76e53SScott Long 	return (name);
48929b76e53SScott Long }
49029b76e53SScott Long 
49129b76e53SScott Long static int
show_all(int ac,char ** av)49229b76e53SScott Long show_all(int ac, char **av)
49329b76e53SScott Long {
49429b76e53SScott Long 	int error;
49529b76e53SScott Long 
49629b76e53SScott Long 	printf("Adapter:\n");
49729b76e53SScott Long 	error = show_adapter(ac, av);
49829b76e53SScott Long 	printf("Devices:\n");
49929b76e53SScott Long 	error = show_devices(ac, av);
50029b76e53SScott Long 	printf("Enclosures:\n");
50129b76e53SScott Long 	error = show_enclosures(ac, av);
50229b76e53SScott Long 	printf("Expanders:\n");
50329b76e53SScott Long 	error = show_expanders(ac, av);
50429b76e53SScott Long 	return (error);
50529b76e53SScott Long }
50629b76e53SScott Long MPS_COMMAND(show, all, show_all, "", "Show all devices");
50729b76e53SScott Long 
50829b76e53SScott Long static int
show_devices(int ac,char ** av)50929b76e53SScott Long show_devices(int ac, char **av)
51029b76e53SScott Long {
51129b76e53SScott Long 	MPI2_CONFIG_PAGE_SASIOUNIT_0	*sas0;
51229b76e53SScott Long 	MPI2_SAS_IO_UNIT0_PHY_DATA	*phydata;
51329b76e53SScott Long 	MPI2_CONFIG_PAGE_SAS_DEV_0	*device;
51429b76e53SScott Long 	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
51529b76e53SScott Long 	uint16_t IOCStatus, handle, bus, target;
516f5b00833SAlexander Motin 	char *type, *speed, enchandle[8], slot[8], bt[16];
5179b51f857SBaptiste Daroussin 	char buf[256];
51829b76e53SScott Long 	int fd, error, nphys;
51929b76e53SScott Long 
52029b76e53SScott Long 	fd = mps_open(mps_unit);
52129b76e53SScott Long 	if (fd < 0) {
52229b76e53SScott Long 		error = errno;
52329b76e53SScott Long 		warn("mps_open");
52429b76e53SScott Long 		return (error);
52529b76e53SScott Long 	}
52629b76e53SScott Long 
52729b76e53SScott Long 	sas0 = mps_read_extended_config_page(fd,
52829b76e53SScott Long 	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
52929b76e53SScott Long 	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
53029b76e53SScott Long 	if (sas0 == NULL) {
53129b76e53SScott Long 		error = errno;
53229b76e53SScott Long 		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
53329b76e53SScott Long 		return (error);
53429b76e53SScott Long 	}
53529b76e53SScott Long 	nphys = sas0->NumPhys;
53629b76e53SScott Long 
5379b51f857SBaptiste Daroussin 	printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
5389b51f857SBaptiste Daroussin 	    "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
5399b51f857SBaptiste Daroussin 	    "Enc", "Slot", "Wdt");
54029b76e53SScott Long 	handle = 0xffff;
54129b76e53SScott Long 	while (1) {
54229b76e53SScott Long 		device = mps_read_extended_config_page(fd,
54329b76e53SScott Long 		    MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
54429b76e53SScott Long 		    MPI2_SASDEVICE0_PAGEVERSION, 0,
54529b76e53SScott Long 		    MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
54629b76e53SScott Long 		    &IOCStatus);
54729b76e53SScott Long 		if (device == NULL) {
54829b76e53SScott Long 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
54929b76e53SScott Long 				break;
55029b76e53SScott Long 			error = errno;
55129b76e53SScott Long 			warn("Error retrieving device page");
5520ce8c4a3SBaptiste Daroussin 			close(fd);
55329b76e53SScott Long 			return (error);
55429b76e53SScott Long 		}
555fc9780fdSAlfredo Dal'Ava Junior 		handle = le16toh(device->DevHandle);
55629b76e53SScott Long 
55729b76e53SScott Long 		if (device->ParentDevHandle == 0x0) {
55829b76e53SScott Long 			free(device);
55929b76e53SScott Long 			continue;
56029b76e53SScott Long 		}
56129b76e53SScott Long 
56229b76e53SScott Long 		bus = 0xffff;
56329b76e53SScott Long 		target = 0xffff;
56429b76e53SScott Long 		error = mps_map_btdh(fd, &handle, &bus, &target);
56529b76e53SScott Long 		if (error) {
56629b76e53SScott Long 			free(device);
56729b76e53SScott Long 			continue;
56829b76e53SScott Long 		}
56929b76e53SScott Long 		if ((bus == 0xffff) || (target == 0xffff))
5709b51f857SBaptiste Daroussin 			snprintf(bt, sizeof(bt), "       ");
57129b76e53SScott Long 		else
5729b51f857SBaptiste Daroussin 			snprintf(bt, sizeof(bt), "%02d   %02d", bus, target);
57329b76e53SScott Long 
574fc9780fdSAlfredo Dal'Ava Junior 		type = get_device_type(le32toh(device->DeviceInfo));
57529b76e53SScott Long 
576bce02a0eSAlexander Motin 		if (device->DeviceInfo & 0x800) {	/* Direct Attached */
57729b76e53SScott Long 			if (device->PhyNum < nphys) {
57829b76e53SScott Long 				phydata = &sas0->PhyData[device->PhyNum];
57929b76e53SScott Long 				speed = get_device_speed(phydata->NegotiatedLinkRate);
580bce02a0eSAlexander Motin 			} else
581bce02a0eSAlexander Motin 				speed = "";
58229b76e53SScott Long 		} else if (device->ParentDevHandle > 0) {
58329b76e53SScott Long 			exp1 = mps_read_extended_config_page(fd,
58429b76e53SScott Long 			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
58529b76e53SScott Long 			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
58629b76e53SScott Long 			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
58729b76e53SScott Long 			    (device->PhyNum <<
58829b76e53SScott Long 			    MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
589fc9780fdSAlfredo Dal'Ava Junior 			    le16toh(device->ParentDevHandle), &IOCStatus);
59029b76e53SScott Long 			if (exp1 == NULL) {
59129b76e53SScott Long 				if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
59229b76e53SScott Long 					error = errno;
59329b76e53SScott Long 					warn("Error retrieving expander page 1: 0x%x",
59429b76e53SScott Long 					    IOCStatus);
5950ce8c4a3SBaptiste Daroussin 					close(fd);
5960ce8c4a3SBaptiste Daroussin 					free(device);
59729b76e53SScott Long 					return (error);
59829b76e53SScott Long 				}
59929b76e53SScott Long 				speed = "";
60029b76e53SScott Long 			} else {
60129b76e53SScott Long 				speed = get_device_speed(exp1->NegotiatedLinkRate);
60229b76e53SScott Long 				free(exp1);
60329b76e53SScott Long 			}
60429b76e53SScott Long 		} else
60529b76e53SScott Long 			speed = "";
60629b76e53SScott Long 
60729b76e53SScott Long 		if (device->EnclosureHandle != 0) {
608f5b00833SAlexander Motin 			snprintf(enchandle, sizeof(enchandle), "%04x", le16toh(device->EnclosureHandle));
609f5b00833SAlexander Motin 			snprintf(slot, sizeof(slot), "%02d", le16toh(device->Slot));
61029b76e53SScott Long 		} else {
611f5b00833SAlexander Motin 			snprintf(enchandle, sizeof(enchandle), "    ");
612f5b00833SAlexander Motin 			snprintf(slot, sizeof(slot), "  ");
61329b76e53SScott Long 		}
6149b51f857SBaptiste Daroussin 		printf("%-10s", bt);
615fc9780fdSAlfredo Dal'Ava Junior 		snprintf(buf, sizeof(buf), "%08x%08x", le32toh(device->SASAddress.High),
616fc9780fdSAlfredo Dal'Ava Junior 		    le32toh(device->SASAddress.Low));
6179b51f857SBaptiste Daroussin 		printf("%-17s", buf);
618fc9780fdSAlfredo Dal'Ava Junior 		snprintf(buf, sizeof(buf), "%04x", le16toh(device->DevHandle));
6199b51f857SBaptiste Daroussin 		printf("%-8s", buf);
620fc9780fdSAlfredo Dal'Ava Junior 		snprintf(buf, sizeof(buf), "%04x", le16toh(device->ParentDevHandle));
6219b51f857SBaptiste Daroussin 		printf("%-10s", buf);
6229b51f857SBaptiste Daroussin 		printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
62329b76e53SScott Long 		    enchandle, slot, device->MaxPortConnections);
62429b76e53SScott Long 		free(device);
62529b76e53SScott Long 	}
62629b76e53SScott Long 	printf("\n");
62729b76e53SScott Long 	free(sas0);
62829b76e53SScott Long 	close(fd);
62929b76e53SScott Long 	return (0);
63029b76e53SScott Long }
63129b76e53SScott Long MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
63229b76e53SScott Long 
63329b76e53SScott Long static int
show_enclosures(int ac,char ** av)63429b76e53SScott Long show_enclosures(int ac, char **av)
63529b76e53SScott Long {
63629b76e53SScott Long 	MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
637f5b00833SAlexander Motin 	char *type, sepstr[8];
63829b76e53SScott Long 	uint16_t IOCStatus, handle;
63929b76e53SScott Long 	int fd, error, issep;
64029b76e53SScott Long 
64129b76e53SScott Long 	fd = mps_open(mps_unit);
64229b76e53SScott Long 	if (fd < 0) {
64329b76e53SScott Long 		error = errno;
64429b76e53SScott Long 		warn("mps_open");
64529b76e53SScott Long 		return (error);
64629b76e53SScott Long 	}
64729b76e53SScott Long 
64829b76e53SScott Long 	printf("Slots      Logical ID     SEPHandle  EncHandle    Type\n");
64929b76e53SScott Long 	handle = 0xffff;
65029b76e53SScott Long 	while (1) {
65129b76e53SScott Long 		enc = mps_read_extended_config_page(fd,
65229b76e53SScott Long 		    MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
65329b76e53SScott Long 		    MPI2_SASENCLOSURE0_PAGEVERSION, 0,
65429b76e53SScott Long 		    MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
65529b76e53SScott Long 		    &IOCStatus);
65629b76e53SScott Long 		if (enc == NULL) {
65729b76e53SScott Long 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
65829b76e53SScott Long 				break;
65929b76e53SScott Long 			error = errno;
66029b76e53SScott Long 			warn("Error retrieving enclosure page");
6610ce8c4a3SBaptiste Daroussin 			close(fd);
66229b76e53SScott Long 			return (error);
66329b76e53SScott Long 		}
664fc9780fdSAlfredo Dal'Ava Junior 		type = get_enc_type(le16toh(enc->Flags), &issep);
66529b76e53SScott Long 		if (issep == 0)
666f5b00833SAlexander Motin 			snprintf(sepstr, sizeof(sepstr), "    ");
66729b76e53SScott Long 		else
668f5b00833SAlexander Motin 			snprintf(sepstr, sizeof(sepstr), "%04x", le16toh(enc->SEPDevHandle));
66929b76e53SScott Long 		printf("  %.2d    %08x%08x    %s       %04x     %s\n",
670fc9780fdSAlfredo Dal'Ava Junior 		    le16toh(enc->NumSlots), le32toh(enc->EnclosureLogicalID.High),
671fc9780fdSAlfredo Dal'Ava Junior 		    le32toh(enc->EnclosureLogicalID.Low), sepstr, le16toh(enc->EnclosureHandle),
67229b76e53SScott Long 		    type);
673fc9780fdSAlfredo Dal'Ava Junior 		handle = le16toh(enc->EnclosureHandle);
67429b76e53SScott Long 		free(enc);
67529b76e53SScott Long 	}
67629b76e53SScott Long 	printf("\n");
67729b76e53SScott Long 	close(fd);
67829b76e53SScott Long 	return (0);
67929b76e53SScott Long }
68029b76e53SScott Long MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
68129b76e53SScott Long 
68229b76e53SScott Long static int
show_expanders(int ac,char ** av)68329b76e53SScott Long show_expanders(int ac, char **av)
68429b76e53SScott Long {
68529b76e53SScott Long 	MPI2_CONFIG_PAGE_EXPANDER_0	*exp0;
68629b76e53SScott Long 	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
68729b76e53SScott Long 	uint16_t IOCStatus, handle;
688f5b00833SAlexander Motin 	char enchandle[8], parent[8], rphy[4], rhandle[8];
68929b76e53SScott Long 	char *speed, *min, *max, *type;
69029b76e53SScott Long 	int fd, error, nphys, i;
69129b76e53SScott Long 
69229b76e53SScott Long 	fd = mps_open(mps_unit);
69329b76e53SScott Long 	if (fd < 0) {
69429b76e53SScott Long 		error = errno;
69529b76e53SScott Long 		warn("mps_open");
69629b76e53SScott Long 		return (error);
69729b76e53SScott Long 	}
69829b76e53SScott Long 
69929b76e53SScott Long 	printf("NumPhys   SAS Address     DevHandle   Parent  EncHandle  SAS Level\n");
70029b76e53SScott Long 	handle = 0xffff;
70129b76e53SScott Long 	while (1) {
70229b76e53SScott Long 		exp0 = mps_read_extended_config_page(fd,
70329b76e53SScott Long 		    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
70429b76e53SScott Long 		    MPI2_SASEXPANDER0_PAGEVERSION, 0,
70529b76e53SScott Long 		    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
70629b76e53SScott Long 		    &IOCStatus);
70729b76e53SScott Long 		if (exp0 == NULL) {
70829b76e53SScott Long 			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
70929b76e53SScott Long 				break;
71029b76e53SScott Long 			error = errno;
71129b76e53SScott Long 			warn("Error retrieving expander page 0");
7120ce8c4a3SBaptiste Daroussin 			close(fd);
71329b76e53SScott Long 			return (error);
71429b76e53SScott Long 		}
71529b76e53SScott Long 
71629b76e53SScott Long 		nphys = exp0->NumPhys;
717fc9780fdSAlfredo Dal'Ava Junior 		handle = le16toh(exp0->DevHandle);
71829b76e53SScott Long 
71929b76e53SScott Long 		if (exp0->EnclosureHandle == 0x00)
720f5b00833SAlexander Motin 			snprintf(enchandle, sizeof(enchandle), "    ");
72129b76e53SScott Long 		else
722f5b00833SAlexander Motin 			snprintf(enchandle, sizeof(enchandle), "%04d", le16toh(exp0->EnclosureHandle));
72329b76e53SScott Long 		if (exp0->ParentDevHandle == 0x0)
724f5b00833SAlexander Motin 			snprintf(parent, sizeof(parent), "    ");
72529b76e53SScott Long 		else
726f5b00833SAlexander Motin 			snprintf(parent, sizeof(parent), "%04x", le16toh(exp0->ParentDevHandle));
72729b76e53SScott Long 		printf("  %02d    %08x%08x    %04x       %s     %s       %d\n",
728fc9780fdSAlfredo Dal'Ava Junior 		    exp0->NumPhys, le32toh(exp0->SASAddress.High), le32toh(exp0->SASAddress.Low),
729fc9780fdSAlfredo Dal'Ava Junior 		    le16toh(exp0->DevHandle), parent, enchandle, exp0->SASLevel);
73029b76e53SScott Long 
73129b76e53SScott Long 		printf("\n");
73229b76e53SScott Long 		printf("     Phy  RemotePhy  DevHandle  Speed  Min   Max    Device\n");
73329b76e53SScott Long 		for (i = 0; i < nphys; i++) {
73429b76e53SScott Long 			exp1 = mps_read_extended_config_page(fd,
73529b76e53SScott Long 			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
73629b76e53SScott Long 			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
73729b76e53SScott Long 			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
73829b76e53SScott Long 			    (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
73929b76e53SScott Long 			    exp0->DevHandle, &IOCStatus);
74029b76e53SScott Long 			if (exp1 == NULL) {
74129b76e53SScott Long 				if (IOCStatus !=
74229b76e53SScott Long 				    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
74329b76e53SScott Long 					warn("Error retrieving expander pg 1");
74429b76e53SScott Long 				continue;
74529b76e53SScott Long 			}
746fc9780fdSAlfredo Dal'Ava Junior 			type = get_device_type(le32toh(exp1->AttachedDeviceInfo));
747fc9780fdSAlfredo Dal'Ava Junior 			if ((le32toh(exp1->AttachedDeviceInfo) &0x7) == 0) {
74829b76e53SScott Long 				speed = "   ";
749f5b00833SAlexander Motin 				snprintf(rphy, sizeof(rphy), "  ");
750f5b00833SAlexander Motin 				snprintf(rhandle, sizeof(rhandle), "    ");
75129b76e53SScott Long 			} else {
75229b76e53SScott Long 				speed = get_device_speed(
75329b76e53SScott Long 				    exp1->NegotiatedLinkRate);
754f5b00833SAlexander Motin 				snprintf(rphy, sizeof(rphy), "%02d",
75529b76e53SScott Long 				    exp1->AttachedPhyIdentifier);
756f5b00833SAlexander Motin 				snprintf(rhandle, sizeof(rhandle), "%04x",
757fc9780fdSAlfredo Dal'Ava Junior 				    le16toh(exp1->AttachedDevHandle));
75829b76e53SScott Long 			}
75929b76e53SScott Long 			min = get_device_speed(exp1->HwLinkRate);
76029b76e53SScott Long 			max = get_device_speed(exp1->HwLinkRate >> 4);
76129b76e53SScott Long 			printf("     %02d      %s        %s      %s   %s   %s   %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
76229b76e53SScott Long 
76329b76e53SScott Long 			free(exp1);
76429b76e53SScott Long 		}
76529b76e53SScott Long 		free(exp0);
76629b76e53SScott Long 	}
76729b76e53SScott Long 
76829b76e53SScott Long 	printf("\n");
76929b76e53SScott Long 	close(fd);
77029b76e53SScott Long 	return (0);
77129b76e53SScott Long }
77229b76e53SScott Long 
77329b76e53SScott Long MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
77429b76e53SScott Long 
77529b76e53SScott Long static int
show_cfgpage(int ac,char ** av)77629b76e53SScott Long show_cfgpage(int ac, char **av)
77729b76e53SScott Long {
77829b76e53SScott Long 	MPI2_CONFIG_PAGE_HEADER *hdr;
77929b76e53SScott Long 	MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
78029b76e53SScott Long 	void *data;
78129b76e53SScott Long 	uint32_t addr;
78229b76e53SScott Long 	uint16_t IOCStatus;
78329b76e53SScott Long 	uint8_t page, num;
78429b76e53SScott Long 	int fd, error, len, attrs;
78529b76e53SScott Long 	char *pgname, *pgattr;
78629b76e53SScott Long 
78729b76e53SScott Long 	fd = mps_open(mps_unit);
78829b76e53SScott Long 	if (fd < 0) {
78929b76e53SScott Long 		error = errno;
79029b76e53SScott Long 		warn("mps_open");
79129b76e53SScott Long 		return (error);
79229b76e53SScott Long 	}
79329b76e53SScott Long 
79429b76e53SScott Long 	addr = 0;
79529b76e53SScott Long 	num = 0;
79629b76e53SScott Long 	page = 0;
79729b76e53SScott Long 
79829b76e53SScott Long 	switch (ac) {
79929b76e53SScott Long 	case 4:
800fc9780fdSAlfredo Dal'Ava Junior 		addr = htole32((uint32_t)strtoul(av[3], NULL, 0));
80129b76e53SScott Long 	case 3:
80229b76e53SScott Long 		num = (uint8_t)strtoul(av[2], NULL, 0);
80329b76e53SScott Long 	case 2:
80429b76e53SScott Long 		page = (uint8_t)strtoul(av[1], NULL, 0);
80529b76e53SScott Long 		break;
80629b76e53SScott Long 	default:
80729b76e53SScott Long 		errno = EINVAL;
80829b76e53SScott Long 		warn("cfgpage: not enough arguments");
80929b76e53SScott Long 		return (EINVAL);
81029b76e53SScott Long 	}
81129b76e53SScott Long 
81229b76e53SScott Long 	if (page >= 0x10)
81329b76e53SScott Long 		data = mps_read_extended_config_page(fd, page, 0, num, addr,
81429b76e53SScott Long 		    &IOCStatus);
81529b76e53SScott Long 	 else
81629b76e53SScott Long 		data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
81729b76e53SScott Long 
81829b76e53SScott Long 	if (data == NULL) {
81929b76e53SScott Long 		error = errno;
82029b76e53SScott Long 		warn("Error retrieving cfg page: %s\n",
82129b76e53SScott Long 		    mps_ioc_status(IOCStatus));
82229b76e53SScott Long 		return (error);
82329b76e53SScott Long 	}
82429b76e53SScott Long 
82529b76e53SScott Long 	if (page >= 0x10) {
82629b76e53SScott Long 		ehdr = data;
827fc9780fdSAlfredo Dal'Ava Junior 		len = le16toh(ehdr->ExtPageLength) * 4;
82829b76e53SScott Long 		page = ehdr->ExtPageType;
82929b76e53SScott Long 		attrs = ehdr->PageType >> 4;
83029b76e53SScott Long 	} else {
83129b76e53SScott Long 		hdr = data;
83229b76e53SScott Long 		len = hdr->PageLength * 4;
83329b76e53SScott Long 		page = hdr->PageType & 0xf;
83429b76e53SScott Long 		attrs = hdr->PageType >> 4;
83529b76e53SScott Long 	}
83629b76e53SScott Long 
83729b76e53SScott Long 	pgname = get_page_name(page);
83829b76e53SScott Long 	if (attrs == 0)
83929b76e53SScott Long 		pgattr = "Read-only";
84029b76e53SScott Long 	else if (attrs == 1)
84129b76e53SScott Long 		pgattr = "Read-Write";
84229b76e53SScott Long 	else if (attrs == 2)
84329b76e53SScott Long 		pgattr = "Read-Write Persistent";
84429b76e53SScott Long 	else
84529b76e53SScott Long 		pgattr = "Unknown Page Attribute";
84629b76e53SScott Long 
84729b76e53SScott Long 	printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
84829b76e53SScott Long 	hexdump(data, len, NULL, HD_REVERSED | 4);
84929b76e53SScott Long 	free(data);
8500ce8c4a3SBaptiste Daroussin 	close(fd);
85129b76e53SScott Long 	return (0);
85229b76e53SScott Long }
85329b76e53SScott Long 
85429b76e53SScott Long MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");
855