mps_show.c revision 297590
1/*-
2 * Copyright (c) 2015 Netflix, Inc.
3 * All rights reserved.
4 * Written by: Scott Long <scottl@freebsd.org>
5 *
6 * Copyright (c) 2008 Yahoo!, Inc.
7 * All rights reserved.
8 * Written by: John Baldwin <jhb@FreeBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__RCSID("$FreeBSD: stable/10/usr.sbin/mpsutil/mps_show.c 297590 2016-04-05 20:34:20Z sbruno $");
37
38#include <sys/param.h>
39#include <sys/errno.h>
40#include <err.h>
41#include <libutil.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46#include "mpsutil.h"
47
48static char * get_device_speed(uint8_t rate);
49static char * get_device_type(uint32_t di);
50static int show_all(int ac, char **av);
51static int show_devices(int ac, char **av);
52static int show_enclosures(int ac, char **av);
53static int show_expanders(int ac, char **av);
54
55MPS_TABLE(top, show);
56
57#define	STANDALONE_STATE	"ONLINE"
58
59static int
60show_adapter(int ac, char **av)
61{
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;
69	U16 IOCStatus;
70	char *speed, *minspeed, *maxspeed, *isdisabled, *type;
71	char devhandle[5], ctrlhandle[5];
72	int error, fd, v, i;
73
74	if (ac != 1) {
75		warnx("show adapter: extra arguments");
76		return (EINVAL);
77	}
78
79	fd = mps_open(mps_unit);
80	if (fd < 0) {
81		error = errno;
82		warn("mps_open");
83		return (error);
84	}
85
86	man0 = mps_read_man_page(fd, 0, NULL);
87	if (man0 == NULL) {
88		error = errno;
89		warn("Failed to get controller info");
90		return (error);
91	}
92	if (man0->Header.PageLength < sizeof(*man0) / 4) {
93		warnx("Invalid controller info");
94		return (EINVAL);
95	}
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);
101	free(man0);
102
103	bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
104	if (bios3 == NULL) {
105		error = errno;
106		warn("Failed to get BIOS page 3 info");
107		return (error);
108	}
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));
113	free(bios3);
114
115	if ((facts = mps_get_iocfacts(fd)) == NULL) {
116		printf("could not get controller IOCFacts\n");
117		close(fd);
118		return (errno);
119	}
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)
126	    ? "yes" : "no");
127	free(facts);
128
129	fd = mps_open(mps_unit);
130	if (fd < 0) {
131		error = errno;
132		warn("mps_open");
133		return (error);
134	}
135
136	sas0 = mps_read_extended_config_page(fd,
137	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
138	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
139	if (sas0 == NULL) {
140		error = errno;
141		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
142		return (error);
143	}
144
145	sas1 = mps_read_extended_config_page(fd,
146	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
147	    MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
148	if (sas0 == NULL) {
149		error = errno;
150		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
151		return (error);
152	}
153	printf("\n");
154
155	printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
156	    "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
157	for (i = 0; i < sas0->NumPhys; i++) {
158		phy0 = &sas0->PhyData[i];
159		phy1 = &sas1->PhyData[i];
160		if (phy0->PortFlags &
161		     MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
162			printf("Discovery still in progress\n");
163			continue;
164		}
165		if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
166			isdisabled = "Y";
167		else
168			isdisabled = "N";
169
170		minspeed = get_device_speed(phy1->MaxMinLinkRate);
171		maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
172		type = get_device_type(phy0->ControllerPhyDeviceInfo);
173
174		if (phy0->AttachedDevHandle != 0) {
175			snprintf(devhandle, 5, "%04x", phy0->AttachedDevHandle);
176			snprintf(ctrlhandle, 5, "%04x",
177			    phy0->ControllerDevHandle);
178			speed = get_device_speed(phy0->NegotiatedLinkRate);
179		} else {
180			snprintf(devhandle, 5, "    ");
181			snprintf(ctrlhandle, 5, "    ");
182			speed = "     ";
183		}
184		printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
185		    i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
186		    maxspeed, type);
187	}
188	free(sas0);
189	free(sas1);
190	printf("\n");
191	close(fd);
192	return (0);
193}
194
195MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
196
197static int
198show_iocfacts(int ac, char **av)
199{
200	MPI2_IOC_FACTS_REPLY *facts;
201	int error, fd;
202
203	fd = mps_open(mps_unit);
204	if (fd < 0) {
205		error = errno;
206		warn("mps_open");
207		return (error);
208	}
209
210	if ((facts = mps_get_iocfacts(fd)) == NULL) {
211		printf("could not get controller IOCFacts\n");
212		close(fd);
213		return (errno);
214	}
215
216	printf("       MaxChainDepth: %d\n", facts->MaxChainDepth);
217	printf("             WhoInit: 0x%x\n", facts->WhoInit);
218	printf("       NumberOfPorts: %d\n", facts->NumberOfPorts);
219	printf("      MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
220	printf("       RequestCredit: %d\n", facts->RequestCredit);
221	printf("           ProductID: 0x%x\n", facts->ProductID);
222	printf("     IOCCapabilities: 0x%x\n", facts->IOCCapabilities);
223	printf("           FWVersion: 0x%08x\n", facts->FWVersion.Word);
224	printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
225	printf("       MaxInitiators: %d\n", facts->MaxInitiators);
226	printf("          MaxTargets: %d\n", facts->MaxTargets);
227	printf("     MaxSasExpanders: %d\n", facts->MaxSasExpanders);
228	printf("       MaxEnclosures: %d\n", facts->MaxEnclosures);
229	printf("       ProtocolFlags: 0x%x\n", facts->ProtocolFlags);
230	printf("  HighPriorityCredit: %d\n", facts->HighPriorityCredit);
231	printf("MaxRepDescPostQDepth: %d\n",
232	    facts->MaxReplyDescriptorPostQueueDepth);
233	printf("      ReplyFrameSize: %d\n", facts->ReplyFrameSize);
234	printf("          MaxVolumes: %d\n", facts->MaxVolumes);
235	printf("        MaxDevHandle: %d\n", facts->MaxDevHandle);
236	printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
237	printf("        MinDevHandle: %d\n", facts->MinDevHandle);
238
239	free(facts);
240	return (0);
241}
242
243MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
244
245static int
246show_adapters(int ac, char **av)
247{
248	MPI2_CONFIG_PAGE_MAN_0 *man0;
249	MPI2_IOC_FACTS_REPLY *facts;
250	int unit, fd, error;
251
252	printf("Device Name\t      Chip Name        Board Name        Firmware\n");
253	for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
254		fd = mps_open(unit);
255		if (fd < 0)
256			continue;
257		facts = mps_get_iocfacts(fd);
258		if (facts == NULL) {
259			error = errno;
260			warn("Faled to get controller iocfacts");
261			close(fd);
262			return (error);
263		}
264		man0 = mps_read_man_page(fd, 0, NULL);
265		if (man0 == NULL) {
266			error = errno;
267			warn("Failed to get controller info");
268			close(fd);
269			return (error);
270		}
271		if (man0->Header.PageLength < sizeof(*man0) / 4) {
272			warnx("Invalid controller info");
273			close(fd);
274			free(man0);
275			return (EINVAL);
276		}
277		printf("/dev/mp%s%d\t%16s %16s        %08x\n",
278		    is_mps ? "s": "r", unit,
279		    man0->ChipName, man0->BoardName, facts->FWVersion.Word);
280		free(man0);
281		free(facts);
282		close(fd);
283	}
284	return (0);
285}
286MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
287
288static char *
289get_device_type(uint32_t di)
290{
291
292	if (di & 0x4000)
293		return ("SEP Target    ");
294	if (di & 0x2000)
295		return ("ATAPI Target  ");
296	if (di & 0x400)
297		return ("SAS Target    ");
298	if (di & 0x200)
299		return ("STP Target    ");
300	if (di & 0x100)
301		return ("SMP Target    ");
302	if (di & 0x80)
303		return ("SATA Target   ");
304	if (di & 0x70)
305		return ("SAS Initiator ");
306	if (di & 0x8)
307		return ("SATA Initiator");
308	if ((di & 0x7) == 0)
309		return ("No Device     ");
310	return ("Unknown Device");
311}
312
313static char *
314get_enc_type(uint32_t flags, int *issep)
315{
316	char *type;
317
318	*issep = 0;
319	switch (flags & 0xf) {
320	case 0x01:
321		type = "Direct Attached SES-2";
322		*issep = 1;
323		break;
324	case 0x02:
325		type = "Direct Attached SGPIO";
326		break;
327	case 0x03:
328		type = "Expander SGPIO";
329		break;
330	case 0x04:
331		type = "External SES-2";
332		*issep = 1;
333		break;
334	case 0x05:
335		type = "Direct Attached GPIO";
336		break;
337	case 0x0:
338	default:
339		return ("Unknown");
340	}
341
342	return (type);
343}
344
345static char *
346mps_device_speed[] = {
347	NULL,
348	NULL,
349	NULL,
350	NULL,
351	NULL,
352	NULL,
353	NULL,
354	NULL,
355	"1.5",
356	"3.0",
357	"6.0",
358	"12 "
359};
360
361static char *
362get_device_speed(uint8_t rate)
363{
364	char *speed;
365
366	rate &= 0xf;
367	if (rate >= sizeof(mps_device_speed))
368		return ("Unk");
369
370	if ((speed = mps_device_speed[rate]) == NULL)
371		return ("???");
372	return (speed);
373}
374
375static char *
376mps_page_name[] = {
377	"IO Unit",
378	"IOC",
379	"BIOS",
380	NULL,
381	NULL,
382	NULL,
383	NULL,
384	NULL,
385	"RAID Volume",
386	"Manufacturing",
387	"RAID Physical Disk",
388	NULL,
389	NULL,
390	NULL,
391	NULL,
392	NULL,
393	"SAS IO Unit",
394	"SAS Expander",
395	"SAS Device",
396	"SAS PHY",
397	"Log",
398	"Enclosure",
399	"RAID Configuration",
400	"Driver Persistent Mapping",
401	"SAS Port",
402	"Ethernet Port",
403	"Extended Manufacturing"
404};
405
406static char *
407get_page_name(u_int page)
408{
409	char *name;
410
411	if (page >= sizeof(mps_page_name))
412		return ("Unknown");
413	if ((name = mps_page_name[page]) == NULL)
414		return ("Unknown");
415	return (name);
416}
417
418static int
419show_all(int ac, char **av)
420{
421	int error;
422
423	printf("Adapter:\n");
424	error = show_adapter(ac, av);
425	printf("Devices:\n");
426	error = show_devices(ac, av);
427	printf("Enclosures:\n");
428	error = show_enclosures(ac, av);
429	printf("Expanders:\n");
430	error = show_expanders(ac, av);
431	return (error);
432}
433MPS_COMMAND(show, all, show_all, "", "Show all devices");
434
435static int
436show_devices(int ac, char **av)
437{
438	MPI2_CONFIG_PAGE_SASIOUNIT_0	*sas0;
439	MPI2_SAS_IO_UNIT0_PHY_DATA	*phydata;
440	MPI2_CONFIG_PAGE_SAS_DEV_0	*device;
441	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
442	uint16_t IOCStatus, handle, bus, target;
443	char *type, *speed, enchandle[5], slot[3], bt[8];
444	char buf[256];
445	int fd, error, nphys;
446
447	fd = mps_open(mps_unit);
448	if (fd < 0) {
449		error = errno;
450		warn("mps_open");
451		return (error);
452	}
453
454	sas0 = mps_read_extended_config_page(fd,
455	    MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
456	    MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
457	if (sas0 == NULL) {
458		error = errno;
459		warn("Error retrieving SAS IO Unit page %d", IOCStatus);
460		return (error);
461	}
462	nphys = sas0->NumPhys;
463
464	printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
465	    "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
466	    "Enc", "Slot", "Wdt");
467	handle = 0xffff;
468	while (1) {
469		device = mps_read_extended_config_page(fd,
470		    MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
471		    MPI2_SASDEVICE0_PAGEVERSION, 0,
472		    MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
473		    &IOCStatus);
474		if (device == NULL) {
475			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
476				break;
477			error = errno;
478			warn("Error retrieving device page");
479			return (error);
480		}
481		handle = device->DevHandle;
482
483		if (device->ParentDevHandle == 0x0) {
484			free(device);
485			continue;
486		}
487
488		bus = 0xffff;
489		target = 0xffff;
490		error = mps_map_btdh(fd, &handle, &bus, &target);
491		if (error) {
492			free(device);
493			continue;
494		}
495		if ((bus == 0xffff) || (target == 0xffff))
496			snprintf(bt, sizeof(bt), "       ");
497		else
498			snprintf(bt, sizeof(bt), "%02d   %02d", bus, target);
499
500		type = get_device_type(device->DeviceInfo);
501
502		if (device->PhyNum < nphys) {
503			phydata = &sas0->PhyData[device->PhyNum];
504			speed = get_device_speed(phydata->NegotiatedLinkRate);
505		} else if (device->ParentDevHandle > 0) {
506			exp1 = mps_read_extended_config_page(fd,
507			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
508			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
509			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
510			    (device->PhyNum <<
511			    MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
512			    device->ParentDevHandle, &IOCStatus);
513			if (exp1 == NULL) {
514				if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
515					error = errno;
516					warn("Error retrieving expander page 1: 0x%x",
517					    IOCStatus);
518					return (error);
519				}
520				speed = " ";
521			} else {
522				speed = get_device_speed(exp1->NegotiatedLinkRate);
523				free(exp1);
524			}
525		} else
526			speed = " ";
527
528		if (device->EnclosureHandle != 0) {
529			snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
530			snprintf(slot, 3, "%02d", device->Slot);
531		} else {
532			snprintf(enchandle, 5, "    ");
533			snprintf(slot, 3, "  ");
534		}
535		printf("%-10s", bt);
536		snprintf(buf, sizeof(buf), "%08x%08x", device->SASAddress.High,
537		    device->SASAddress.Low);
538		printf("%-17s", buf);
539		snprintf(buf, sizeof(buf), "%04x", device->DevHandle);
540		printf("%-8s", buf);
541		snprintf(buf, sizeof(buf), "%04x", device->ParentDevHandle);
542		printf("%-10s", buf);
543		printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
544		    enchandle, slot, device->MaxPortConnections);
545		free(device);
546	}
547	printf("\n");
548	free(sas0);
549	close(fd);
550	return (0);
551}
552MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
553
554static int
555show_enclosures(int ac, char **av)
556{
557	MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
558	char *type, sepstr[5];
559	uint16_t IOCStatus, handle;
560	int fd, error, issep;
561
562	fd = mps_open(mps_unit);
563	if (fd < 0) {
564		error = errno;
565		warn("mps_open");
566		return (error);
567	}
568
569	printf("Slots      Logical ID     SEPHandle  EncHandle    Type\n");
570	handle = 0xffff;
571	while (1) {
572		enc = mps_read_extended_config_page(fd,
573		    MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
574		    MPI2_SASENCLOSURE0_PAGEVERSION, 0,
575		    MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
576		    &IOCStatus);
577		if (enc == NULL) {
578			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
579				break;
580			error = errno;
581			warn("Error retrieving enclosure page");
582			return (error);
583		}
584		type = get_enc_type(enc->Flags, &issep);
585		if (issep == 0)
586			snprintf(sepstr, 5, "    ");
587		else
588			snprintf(sepstr, 5, "%04x", enc->SEPDevHandle);
589		printf("  %.2d    %08x%08x    %s       %04x     %s\n",
590		    enc->NumSlots, enc->EnclosureLogicalID.High,
591		    enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle,
592		    type);
593		handle = enc->EnclosureHandle;
594		free(enc);
595	}
596	printf("\n");
597	close(fd);
598	return (0);
599}
600MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
601
602static int
603show_expanders(int ac, char **av)
604{
605	MPI2_CONFIG_PAGE_EXPANDER_0	*exp0;
606	MPI2_CONFIG_PAGE_EXPANDER_1	*exp1;
607	uint16_t IOCStatus, handle;
608	char enchandle[5], parent[5], rphy[3], rhandle[5];
609	char *speed, *min, *max, *type;
610	int fd, error, nphys, i;
611
612	fd = mps_open(mps_unit);
613	if (fd < 0) {
614		error = errno;
615		warn("mps_open");
616		return (error);
617	}
618
619	printf("NumPhys   SAS Address     DevHandle   Parent  EncHandle  SAS Level\n");
620	handle = 0xffff;
621	while (1) {
622		exp0 = mps_read_extended_config_page(fd,
623		    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
624		    MPI2_SASEXPANDER0_PAGEVERSION, 0,
625		    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
626		    &IOCStatus);
627		if (exp0 == NULL) {
628			if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
629				break;
630			error = errno;
631			warn("Error retrieving expander page 0");
632			return (error);
633		}
634
635		nphys = exp0->NumPhys;
636		handle = exp0->DevHandle;
637
638		if (exp0->EnclosureHandle == 0x00)
639			snprintf(enchandle, 5, "    ");
640		else
641			snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
642		if (exp0->ParentDevHandle == 0x0)
643			snprintf(parent, 5, "    ");
644		else
645			snprintf(parent, 5, "%04x", exp0->ParentDevHandle);
646		printf("  %02d    %08x%08x    %04x       %s     %s       %d\n",
647		    exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low,
648		    exp0->DevHandle, parent, enchandle, exp0->SASLevel);
649
650		printf("\n");
651		printf("     Phy  RemotePhy  DevHandle  Speed   Min    Max    Device\n");
652		for (i = 0; i < nphys; i++) {
653			exp1 = mps_read_extended_config_page(fd,
654			    MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
655			    MPI2_SASEXPANDER1_PAGEVERSION, 1,
656			    MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
657			    (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
658			    exp0->DevHandle, &IOCStatus);
659			if (exp1 == NULL) {
660				if (IOCStatus !=
661				    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
662					warn("Error retrieving expander pg 1");
663				continue;
664			}
665			type = get_device_type(exp1->AttachedDeviceInfo);
666			if ((exp1->AttachedDeviceInfo &0x7) == 0) {
667				speed = "     ";
668				snprintf(rphy, 3, "  ");
669				snprintf(rhandle, 5, "     ");
670			} else {
671				speed = get_device_speed(
672				    exp1->NegotiatedLinkRate);
673				snprintf(rphy, 3, "%02d",
674				    exp1->AttachedPhyIdentifier);
675				snprintf(rhandle, 5, "%04x",
676				    exp1->AttachedDevHandle);
677			}
678			min = get_device_speed(exp1->HwLinkRate);
679			max = get_device_speed(exp1->HwLinkRate >> 4);
680			printf("     %02d     %s         %s     %s  %s  %s  %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
681
682			free(exp1);
683		}
684		free(exp0);
685	}
686
687	printf("\n");
688	close(fd);
689	return (0);
690}
691
692MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
693
694static int
695show_cfgpage(int ac, char **av)
696{
697	MPI2_CONFIG_PAGE_HEADER *hdr;
698	MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
699	void *data;
700	uint32_t addr;
701	uint16_t IOCStatus;
702	uint8_t page, num;
703	int fd, error, len, attrs;
704	char *pgname, *pgattr;
705
706	fd = mps_open(mps_unit);
707	if (fd < 0) {
708		error = errno;
709		warn("mps_open");
710		return (error);
711	}
712
713	addr = 0;
714	num = 0;
715	page = 0;
716
717	switch (ac) {
718	case 4:
719		addr = (uint32_t)strtoul(av[3], NULL, 0);
720	case 3:
721		num = (uint8_t)strtoul(av[2], NULL, 0);
722	case 2:
723		page = (uint8_t)strtoul(av[1], NULL, 0);
724		break;
725	default:
726		errno = EINVAL;
727		warn("cfgpage: not enough arguments");
728		return (EINVAL);
729	}
730
731	if (page >= 0x10)
732		data = mps_read_extended_config_page(fd, page, 0, num, addr,
733		    &IOCStatus);
734	 else
735		data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
736
737	if (data == NULL) {
738		error = errno;
739		warn("Error retrieving cfg page: %s\n",
740		    mps_ioc_status(IOCStatus));
741		return (error);
742	}
743
744	if (page >= 0x10) {
745		ehdr = data;
746		len = ehdr->ExtPageLength * 4;
747		page = ehdr->ExtPageType;
748		attrs = ehdr->PageType >> 4;
749	} else {
750		hdr = data;
751		len = hdr->PageLength * 4;
752		page = hdr->PageType & 0xf;
753		attrs = hdr->PageType >> 4;
754	}
755
756	pgname = get_page_name(page);
757	if (attrs == 0)
758		pgattr = "Read-only";
759	else if (attrs == 1)
760		pgattr = "Read-Write";
761	else if (attrs == 2)
762		pgattr = "Read-Write Persistent";
763	else
764		pgattr = "Unknown Page Attribute";
765
766	printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
767	hexdump(data, len, NULL, HD_REVERSED | 4);
768	free(data);
769	return (0);
770}
771
772MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");
773