2 * Copyright (c) 2015 Netflix, Inc.
4 * Written by: Scott Long <scottl@freebsd.org>
6 * Copyright (c) 2008 Yahoo!, Inc.
8 * Written by: John Baldwin <jhb@FreeBSD.org>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
36 __RCSID("$FreeBSD: head/usr.sbin/mpsutil/mps_show.c 330790 2018-03-12 05:03:32Z scottl $");
38 #include <sys/param.h>
39 #include <sys/errno.h>
48 static char * get_device_speed(uint8_t rate
);
49 static char * get_device_type(uint32_t di
);
50 static int show_all(int ac
, char **av
);
51 static int show_devices(int ac
, char **av
);
52 static int show_enclosures(int ac
, char **av
);
53 static int show_expanders(int ac
, char **av
);
57 #define STANDALONE_STATE "ONLINE"
60 show_adapter(int ac
, char **av
)
62 MPI2_CONFIG_PAGE_SASIOUNIT_0
*sas0
;
63 MPI2_CONFIG_PAGE_SASIOUNIT_1
*sas1
;
64 MPI2_SAS_IO_UNIT0_PHY_DATA
*phy0
;
65 MPI2_SAS_IO_UNIT1_PHY_DATA
*phy1
;
66 MPI2_CONFIG_PAGE_MAN_0
*man0
;
67 MPI2_CONFIG_PAGE_BIOS_3
*bios3
;
68 MPI2_IOC_FACTS_REPLY
*facts
;
70 char *speed
, *minspeed
, *maxspeed
, *isdisabled
, *type
;
71 char devhandle
[5], ctrlhandle
[5];
75 warnx("show adapter: extra arguments");
79 fd
= mps_open(mps_unit
);
86 man0
= mps_read_man_page(fd
, 0, NULL
);
89 warn("Failed to get controller info");
92 if (man0
->Header
.PageLength
< sizeof(*man0
) / 4) {
93 warnx("Invalid controller info");
96 printf("mp%s%d Adapter:\n", is_mps
? "s": "r", mps_unit
);
97 printf(" Board Name: %.16s\n", man0
->BoardName
);
98 printf(" Board Assembly: %.16s\n", man0
->BoardAssembly
);
99 printf(" Chip Name: %.16s\n", man0
->ChipName
);
100 printf(" Chip Revision: %.16s\n", man0
->ChipRevision
);
103 bios3
= mps_read_config_page(fd
, MPI2_CONFIG_PAGETYPE_BIOS
, 3, 0, NULL
);
106 warn("Failed to get BIOS page 3 info");
109 v
= bios3
->BiosVersion
;
110 printf(" BIOS Revision: %d.%02d.%02d.%02d\n",
111 ((v
& 0xff000000) >> 24), ((v
&0xff0000) >> 16),
112 ((v
& 0xff00) >> 8), (v
& 0xff));
115 if ((facts
= mps_get_iocfacts(fd
)) == NULL
) {
116 printf("could not get controller IOCFacts\n");
120 v
= facts
->FWVersion
.Word
;
121 printf("Firmware Revision: %d.%02d.%02d.%02d\n",
122 ((v
& 0xff000000) >> 24), ((v
&0xff0000) >> 16),
123 ((v
& 0xff00) >> 8), (v
& 0xff));
124 printf(" Integrated RAID: %s\n",
125 (facts
->IOCCapabilities
& MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID
)
129 fd
= mps_open(mps_unit
);
136 sas0
= mps_read_extended_config_page(fd
,
137 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
138 MPI2_SASIOUNITPAGE0_PAGEVERSION
, 0, 0, &IOCStatus
);
141 warn("Error retrieving SAS IO Unit page %d", IOCStatus
);
147 sas1
= mps_read_extended_config_page(fd
,
148 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
149 MPI2_SASIOUNITPAGE1_PAGEVERSION
, 1, 0, &IOCStatus
);
152 warn("Error retrieving SAS IO Unit page %d", IOCStatus
);
159 printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
160 "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
161 for (i
= 0; i
< sas0
->NumPhys
; i
++) {
162 phy0
= &sas0
->PhyData
[i
];
163 phy1
= &sas1
->PhyData
[i
];
164 if (phy0
->PortFlags
&
165 MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS
) {
166 printf("Discovery still in progress\n");
169 if (phy0
->PhyFlags
& MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED
)
174 minspeed
= get_device_speed(phy1
->MaxMinLinkRate
);
175 maxspeed
= get_device_speed(phy1
->MaxMinLinkRate
>> 4);
176 type
= get_device_type(phy0
->ControllerPhyDeviceInfo
);
178 if (phy0
->AttachedDevHandle
!= 0) {
179 snprintf(devhandle
, 5, "%04x", phy0
->AttachedDevHandle
);
180 snprintf(ctrlhandle
, 5, "%04x",
181 phy0
->ControllerDevHandle
);
182 speed
= get_device_speed(phy0
->NegotiatedLinkRate
);
184 snprintf(devhandle
, 5, " ");
185 snprintf(ctrlhandle
, 5, " ");
188 printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
189 i
, ctrlhandle
, devhandle
, isdisabled
, speed
, minspeed
,
199 MPS_COMMAND(show
, adapter
, show_adapter
, "", "display controller information")
202 show_iocfacts(int ac
, char **av
)
204 MPI2_IOC_FACTS_REPLY
*facts
;
208 fd
= mps_open(mps_unit
);
215 if ((facts
= mps_get_iocfacts(fd
)) == NULL
) {
216 printf("could not get controller IOCFacts\n");
221 #define IOCCAP "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" \
222 "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" \
223 "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc" \
224 "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV"
226 bzero(tmpbuf
, sizeof(tmpbuf
));
227 mps_parse_flags(facts
->IOCCapabilities
, IOCCAP
, tmpbuf
, sizeof(tmpbuf
));
229 printf(" MsgVersion: %02d.%02d\n",
230 facts
->MsgVersion
>> 8, facts
->MsgVersion
& 0xff);
231 printf(" MsgLength: %d\n", facts
->MsgLength
);
232 printf(" Function: 0x%x\n", facts
->Function
);
233 printf(" HeaderVersion: %02d,%02d\n",
234 facts
->HeaderVersion
>> 8, facts
->HeaderVersion
& 0xff);
235 printf(" IOCNumber: %d\n", facts
->IOCNumber
);
236 printf(" MsgFlags: 0x%x\n", facts
->MsgFlags
);
237 printf(" VP_ID: %d\n", facts
->VP_ID
);
238 printf(" VF_ID: %d\n", facts
->VF_ID
);
239 printf(" IOCExceptions: %d\n", facts
->IOCExceptions
);
240 printf(" IOCStatus: %d\n", facts
->IOCStatus
);
241 printf(" IOCLogInfo: 0x%x\n", facts
->IOCLogInfo
);
242 printf(" MaxChainDepth: %d\n", facts
->MaxChainDepth
);
243 printf(" WhoInit: 0x%x\n", facts
->WhoInit
);
244 printf(" NumberOfPorts: %d\n", facts
->NumberOfPorts
);
245 printf(" MaxMSIxVectors: %d\n", facts
->MaxMSIxVectors
);
246 printf(" RequestCredit: %d\n", facts
->RequestCredit
);
247 printf(" ProductID: 0x%x\n", facts
->ProductID
);
248 printf(" IOCCapabilities: 0x%x %s\n", facts
->IOCCapabilities
,
250 printf(" FWVersion: 0x%08x\n", facts
->FWVersion
.Word
);
251 printf(" IOCRequestFrameSize: %d\n", facts
->IOCRequestFrameSize
);
252 printf(" MaxInitiators: %d\n", facts
->MaxInitiators
);
253 printf(" MaxTargets: %d\n", facts
->MaxTargets
);
254 printf(" MaxSasExpanders: %d\n", facts
->MaxSasExpanders
);
255 printf(" MaxEnclosures: %d\n", facts
->MaxEnclosures
);
257 bzero(tmpbuf
, sizeof(tmpbuf
));
258 mps_parse_flags(facts
->ProtocolFlags
,
259 "\4NvmeDevices\2ScsiTarget\1ScsiInitiator", tmpbuf
, sizeof(tmpbuf
));
260 printf(" ProtocolFlags: 0x%x %s\n", facts
->ProtocolFlags
, tmpbuf
);
261 printf(" HighPriorityCredit: %d\n", facts
->HighPriorityCredit
);
262 printf("MaxRepDescPostQDepth: %d\n",
263 facts
->MaxReplyDescriptorPostQueueDepth
);
264 printf(" ReplyFrameSize: %d\n", facts
->ReplyFrameSize
);
265 printf(" MaxVolumes: %d\n", facts
->MaxVolumes
);
266 printf(" MaxDevHandle: %d\n", facts
->MaxDevHandle
);
267 printf("MaxPersistentEntries: %d\n", facts
->MaxPersistentEntries
);
268 printf(" MinDevHandle: %d\n", facts
->MinDevHandle
);
274 MPS_COMMAND(show
, iocfacts
, show_iocfacts
, "", "Show IOC Facts Message");
277 show_adapters(int ac
, char **av
)
279 MPI2_CONFIG_PAGE_MAN_0
*man0
;
280 MPI2_IOC_FACTS_REPLY
*facts
;
283 printf("Device Name\t Chip Name Board Name Firmware\n");
284 for (unit
= 0; unit
< MPS_MAX_UNIT
; unit
++) {
288 facts
= mps_get_iocfacts(fd
);
291 warn("Faled to get controller iocfacts");
295 man0
= mps_read_man_page(fd
, 0, NULL
);
298 warn("Failed to get controller info");
303 if (man0
->Header
.PageLength
< sizeof(*man0
) / 4) {
304 warnx("Invalid controller info");
310 printf("/dev/mp%s%d\t%16s %16s %08x\n",
311 is_mps
? "s": "r", unit
,
312 man0
->ChipName
, man0
->BoardName
, facts
->FWVersion
.Word
);
319 MPS_COMMAND(show
, adapters
, show_adapters
, "", "Show a summary of all adapters");
322 get_device_type(uint32_t di
)
326 return ("SEP Target ");
328 return ("ATAPI Target ");
330 return ("SAS Target ");
332 return ("STP Target ");
334 return ("SMP Target ");
336 return ("SATA Target ");
338 return ("SAS Initiator ");
340 return ("SATA Initiator");
342 return ("No Device ");
343 return ("Unknown Device");
347 get_enc_type(uint32_t flags
, int *issep
)
352 switch (flags
& 0xf) {
354 type
= "Direct Attached SES-2";
358 type
= "Direct Attached SGPIO";
361 type
= "Expander SGPIO";
364 type
= "External SES-2";
368 type
= "Direct Attached GPIO";
379 mps_device_speed
[] = {
395 get_device_speed(uint8_t rate
)
400 if (rate
>= sizeof(mps_device_speed
))
403 if ((speed
= mps_device_speed
[rate
]) == NULL
)
420 "RAID Physical Disk",
432 "RAID Configuration",
433 "Driver Persistent Mapping",
436 "Extended Manufacturing"
440 get_page_name(u_int page
)
444 if (page
>= sizeof(mps_page_name
))
446 if ((name
= mps_page_name
[page
]) == NULL
)
452 show_all(int ac
, char **av
)
456 printf("Adapter:\n");
457 error
= show_adapter(ac
, av
);
458 printf("Devices:\n");
459 error
= show_devices(ac
, av
);
460 printf("Enclosures:\n");
461 error
= show_enclosures(ac
, av
);
462 printf("Expanders:\n");
463 error
= show_expanders(ac
, av
);
466 MPS_COMMAND(show
, all
, show_all
, "", "Show all devices");
469 show_devices(int ac
, char **av
)
471 MPI2_CONFIG_PAGE_SASIOUNIT_0
*sas0
;
472 MPI2_SAS_IO_UNIT0_PHY_DATA
*phydata
;
473 MPI2_CONFIG_PAGE_SAS_DEV_0
*device
;
474 MPI2_CONFIG_PAGE_EXPANDER_1
*exp1
;
475 uint16_t IOCStatus
, handle
, bus
, target
;
476 char *type
, *speed
, enchandle
[5], slot
[3], bt
[8];
478 int fd
, error
, nphys
;
480 fd
= mps_open(mps_unit
);
487 sas0
= mps_read_extended_config_page(fd
,
488 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT
,
489 MPI2_SASIOUNITPAGE0_PAGEVERSION
, 0, 0, &IOCStatus
);
492 warn("Error retrieving SAS IO Unit page %d", IOCStatus
);
495 nphys
= sas0
->NumPhys
;
497 printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
498 "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
499 "Enc", "Slot", "Wdt");
502 device
= mps_read_extended_config_page(fd
,
503 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE
,
504 MPI2_SASDEVICE0_PAGEVERSION
, 0,
505 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE
| handle
,
507 if (device
== NULL
) {
508 if (IOCStatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)
511 warn("Error retrieving device page");
515 handle
= device
->DevHandle
;
517 if (device
->ParentDevHandle
== 0x0) {
524 error
= mps_map_btdh(fd
, &handle
, &bus
, &target
);
529 if ((bus
== 0xffff) || (target
== 0xffff))
530 snprintf(bt
, sizeof(bt
), " ");
532 snprintf(bt
, sizeof(bt
), "%02d %02d", bus
, target
);
534 type
= get_device_type(device
->DeviceInfo
);
536 if (device
->PhyNum
< nphys
) {
537 phydata
= &sas0
->PhyData
[device
->PhyNum
];
538 speed
= get_device_speed(phydata
->NegotiatedLinkRate
);
539 } else if (device
->ParentDevHandle
> 0) {
540 exp1
= mps_read_extended_config_page(fd
,
541 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER
,
542 MPI2_SASEXPANDER1_PAGEVERSION
, 1,
543 MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM
|
545 MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT
) |
546 device
->ParentDevHandle
, &IOCStatus
);
548 if (IOCStatus
!= MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
) {
550 warn("Error retrieving expander page 1: 0x%x",
558 speed
= get_device_speed(exp1
->NegotiatedLinkRate
);
564 if (device
->EnclosureHandle
!= 0) {
565 snprintf(enchandle
, 5, "%04x", device
->EnclosureHandle
);
566 snprintf(slot
, 3, "%02d", device
->Slot
);
568 snprintf(enchandle
, 5, " ");
569 snprintf(slot
, 3, " ");
572 snprintf(buf
, sizeof(buf
), "%08x%08x", device
->SASAddress
.High
,
573 device
->SASAddress
.Low
);
574 printf("%-17s", buf
);
575 snprintf(buf
, sizeof(buf
), "%04x", device
->DevHandle
);
577 snprintf(buf
, sizeof(buf
), "%04x", device
->ParentDevHandle
);
578 printf("%-10s", buf
);
579 printf("%-14s%-6s%-5s%-6s%d\n", type
, speed
,
580 enchandle
, slot
, device
->MaxPortConnections
);
588 MPS_COMMAND(show
, devices
, show_devices
, "", "Show attached devices");
591 show_enclosures(int ac
, char **av
)
593 MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
*enc
;
594 char *type
, sepstr
[5];
595 uint16_t IOCStatus
, handle
;
596 int fd
, error
, issep
;
598 fd
= mps_open(mps_unit
);
605 printf("Slots Logical ID SEPHandle EncHandle Type\n");
608 enc
= mps_read_extended_config_page(fd
,
609 MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE
,
610 MPI2_SASENCLOSURE0_PAGEVERSION
, 0,
611 MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE
| handle
,
614 if (IOCStatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)
617 warn("Error retrieving enclosure page");
621 type
= get_enc_type(enc
->Flags
, &issep
);
623 snprintf(sepstr
, 5, " ");
625 snprintf(sepstr
, 5, "%04x", enc
->SEPDevHandle
);
626 printf(" %.2d %08x%08x %s %04x %s\n",
627 enc
->NumSlots
, enc
->EnclosureLogicalID
.High
,
628 enc
->EnclosureLogicalID
.Low
, sepstr
, enc
->EnclosureHandle
,
630 handle
= enc
->EnclosureHandle
;
637 MPS_COMMAND(show
, enclosures
, show_enclosures
, "", "Show attached enclosures");
640 show_expanders(int ac
, char **av
)
642 MPI2_CONFIG_PAGE_EXPANDER_0
*exp0
;
643 MPI2_CONFIG_PAGE_EXPANDER_1
*exp1
;
644 uint16_t IOCStatus
, handle
;
645 char enchandle
[5], parent
[5], rphy
[3], rhandle
[5];
646 char *speed
, *min
, *max
, *type
;
647 int fd
, error
, nphys
, i
;
649 fd
= mps_open(mps_unit
);
656 printf("NumPhys SAS Address DevHandle Parent EncHandle SAS Level\n");
659 exp0
= mps_read_extended_config_page(fd
,
660 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER
,
661 MPI2_SASEXPANDER0_PAGEVERSION
, 0,
662 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL
| handle
,
665 if (IOCStatus
== MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)
668 warn("Error retrieving expander page 0");
673 nphys
= exp0
->NumPhys
;
674 handle
= exp0
->DevHandle
;
676 if (exp0
->EnclosureHandle
== 0x00)
677 snprintf(enchandle
, 5, " ");
679 snprintf(enchandle
, 5, "%04d", exp0
->EnclosureHandle
);
680 if (exp0
->ParentDevHandle
== 0x0)
681 snprintf(parent
, 5, " ");
683 snprintf(parent
, 5, "%04x", exp0
->ParentDevHandle
);
684 printf(" %02d %08x%08x %04x %s %s %d\n",
685 exp0
->NumPhys
, exp0
->SASAddress
.High
, exp0
->SASAddress
.Low
,
686 exp0
->DevHandle
, parent
, enchandle
, exp0
->SASLevel
);
689 printf(" Phy RemotePhy DevHandle Speed Min Max Device\n");
690 for (i
= 0; i
< nphys
; i
++) {
691 exp1
= mps_read_extended_config_page(fd
,
692 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER
,
693 MPI2_SASEXPANDER1_PAGEVERSION
, 1,
694 MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM
|
695 (i
<< MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT
) |
696 exp0
->DevHandle
, &IOCStatus
);
699 MPI2_IOCSTATUS_CONFIG_INVALID_PAGE
)
700 warn("Error retrieving expander pg 1");
703 type
= get_device_type(exp1
->AttachedDeviceInfo
);
704 if ((exp1
->AttachedDeviceInfo
&0x7) == 0) {
706 snprintf(rphy
, 3, " ");
707 snprintf(rhandle
, 5, " ");
709 speed
= get_device_speed(
710 exp1
->NegotiatedLinkRate
);
711 snprintf(rphy
, 3, "%02d",
712 exp1
->AttachedPhyIdentifier
);
713 snprintf(rhandle
, 5, "%04x",
714 exp1
->AttachedDevHandle
);
716 min
= get_device_speed(exp1
->HwLinkRate
);
717 max
= get_device_speed(exp1
->HwLinkRate
>> 4);
718 printf(" %02d %s %s %s %s %s %s\n", exp1
->Phy
, rphy
, rhandle
, speed
, min
, max
, type
);
730 MPS_COMMAND(show
, expanders
, show_expanders
, "", "Show attached expanders");
733 show_cfgpage(int ac
, char **av
)
735 MPI2_CONFIG_PAGE_HEADER
*hdr
;
736 MPI2_CONFIG_EXTENDED_PAGE_HEADER
*ehdr
;
741 int fd
, error
, len
, attrs
;
742 char *pgname
, *pgattr
;
744 fd
= mps_open(mps_unit
);
757 addr
= (uint32_t)strtoul(av
[3], NULL
, 0);
759 num
= (uint8_t)strtoul(av
[2], NULL
, 0);
761 page
= (uint8_t)strtoul(av
[1], NULL
, 0);
765 warn("cfgpage: not enough arguments");
770 data
= mps_read_extended_config_page(fd
, page
, 0, num
, addr
,
773 data
= mps_read_config_page(fd
, page
, num
, addr
, &IOCStatus
);
777 warn("Error retrieving cfg page: %s\n",
778 mps_ioc_status(IOCStatus
));
784 len
= ehdr
->ExtPageLength
* 4;
785 page
= ehdr
->ExtPageType
;
786 attrs
= ehdr
->PageType
>> 4;
789 len
= hdr
->PageLength
* 4;
790 page
= hdr
->PageType
& 0xf;
791 attrs
= hdr
->PageType
>> 4;
794 pgname
= get_page_name(page
);
796 pgattr
= "Read-only";
798 pgattr
= "Read-Write";
800 pgattr
= "Read-Write Persistent";
802 pgattr
= "Unknown Page Attribute";
804 printf("Page 0x%x: %s %d, %s\n", page
, pgname
, num
, pgattr
);
805 hexdump(data
, len
, NULL
, HD_REVERSED
| 4);
811 MPS_COMMAND(show
, cfgpage
, show_cfgpage
, "page [num] [addr]", "Display config page");