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