]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mpsutil/mps_show.c
dwc: Rename if_dwc.h to dwc1000_reg.h
[FreeBSD/FreeBSD.git] / usr.sbin / mpsutil / mps_show.c
1 /*-
2  * Copyright (c) 2015 Netflix, Inc.
3  * Written by: Scott Long <scottl@freebsd.org>
4  *
5  * Copyright (c) 2008 Yahoo!, Inc.
6  * All rights reserved.
7  * Written by: John Baldwin <jhb@FreeBSD.org>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 #include <sys/param.h>
36 #include <sys/errno.h>
37 #include <sys/endian.h>
38 #include <err.h>
39 #include <libutil.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include "mpsutil.h"
45
46 static char * get_device_speed(uint8_t rate);
47 static char * get_device_type(uint32_t di);
48 static int show_all(int ac, char **av);
49 static int show_devices(int ac, char **av);
50 static int show_enclosures(int ac, char **av);
51 static int show_expanders(int ac, char **av);
52
53 MPS_TABLE(top, show);
54
55 #define STANDALONE_STATE        "ONLINE"
56
57 static int
58 show_adapter(int ac, char **av)
59 {
60         const char* pcie_speed[] = { "2.5", "5.0", "8.0" };
61         const char* temp_units[] = { "", "F", "C" };
62         const char* ioc_speeds[] = { "", "Full", "Half", "Quarter", "Eighth" };
63
64         MPI2_CONFIG_PAGE_SASIOUNIT_0    *sas0;
65         MPI2_CONFIG_PAGE_SASIOUNIT_1    *sas1;
66         MPI2_SAS_IO_UNIT0_PHY_DATA      *phy0;
67         MPI2_SAS_IO_UNIT1_PHY_DATA      *phy1;
68         MPI2_CONFIG_PAGE_MAN_0 *man0;
69         MPI2_CONFIG_PAGE_BIOS_3 *bios3;
70         MPI2_CONFIG_PAGE_IO_UNIT_1 *iounit1;
71         MPI2_CONFIG_PAGE_IO_UNIT_7 *iounit7;
72         MPI2_IOC_FACTS_REPLY *facts;
73         U16 IOCStatus;
74         char *speed, *minspeed, *maxspeed, *isdisabled, *type;
75         char devhandle[8], ctrlhandle[8];
76         int error, fd, v, i;
77
78         if (ac != 1) {
79                 warnx("show adapter: extra arguments");
80                 return (EINVAL);
81         }
82
83         fd = mps_open(mps_unit);
84         if (fd < 0) {
85                 error = errno;
86                 warn("mps_open");
87                 return (error);
88         }
89
90         man0 = mps_read_man_page(fd, 0, NULL);
91         if (man0 == NULL) {
92                 error = errno;
93                 warn("Failed to get controller info");
94                 return (error);
95         }
96         if (man0->Header.PageLength < sizeof(*man0) / 4) {
97                 warnx("Invalid controller info");
98                 return (EINVAL);
99         }
100         printf("mp%s%d Adapter:\n", is_mps ? "s": "r", mps_unit);
101         printf("       Board Name: %.16s\n", man0->BoardName);
102         printf("   Board Assembly: %.16s\n", man0->BoardAssembly);
103         printf("        Chip Name: %.16s\n", man0->ChipName);
104         printf("    Chip Revision: %.16s\n", man0->ChipRevision);
105         free(man0);
106
107         bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
108         if (bios3 == NULL) {
109                 error = errno;
110                 warn("Failed to get BIOS page 3 info");
111                 return (error);
112         }
113         v = le32toh(bios3->BiosVersion);
114         printf("    BIOS Revision: %d.%02d.%02d.%02d\n",
115             ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
116             ((v & 0xff00) >> 8), (v & 0xff));
117         free(bios3);
118
119         if ((facts = mps_get_iocfacts(fd)) == NULL) {
120                 printf("could not get controller IOCFacts\n");
121                 close(fd);
122                 return (errno);
123         }
124         v = facts->FWVersion.Word;
125         printf("Firmware Revision: %d.%02d.%02d.%02d\n",
126             ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
127             ((v & 0xff00) >> 8), (v & 0xff));
128         printf("  Integrated RAID: %s\n",
129             (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
130             ? "yes" : "no");
131         free(facts);
132
133         iounit1 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IO_UNIT, 1, 0, NULL);
134         if (iounit1 == NULL) {
135                 error = errno;
136                 warn("Failed to get IOUNIT page 1 info");
137                 return (error);
138         }
139         printf("         SATA NCQ: %s\n",
140                 ((iounit1->Flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE) == 0) ?
141                 "ENABLED" : "DISABLED");
142         free(iounit1);
143
144         iounit7 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IO_UNIT, 7, 0, NULL);
145         if (iounit7 == NULL) {
146                 error = errno;
147                 warn("Failed to get IOUNIT page 7 info");
148                 return (error);
149         }
150         printf(" PCIe Width/Speed: x%d (%s GB/sec)\n", iounit7->PCIeWidth,
151                 pcie_speed[iounit7->PCIeSpeed]);
152         printf("        IOC Speed: %s\n", ioc_speeds[iounit7->IOCSpeed]);
153         printf("      Temperature: ");
154         if (iounit7->IOCTemperatureUnits == MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT)
155                 printf("Unknown/Unsupported\n");
156         else
157                 printf("%d %s\n", iounit7->IOCTemperature,
158                         temp_units[iounit7->IOCTemperatureUnits]);
159         free(iounit7);
160
161         fd = mps_open(mps_unit);
162         if (fd < 0) {
163                 error = errno;
164                 warn("mps_open");
165                 return (error);
166         }
167
168         sas0 = mps_read_extended_config_page(fd,
169             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
170             MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
171         if (sas0 == NULL) {
172                 error = errno;
173                 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
174                 free(sas0);
175                 close(fd);
176                 return (error);
177         }
178
179         sas1 = mps_read_extended_config_page(fd,
180             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
181             MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
182         if (sas1 == NULL) {
183                 error = errno;
184                 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
185                 free(sas0);
186                 close(fd);
187                 return (error);
188         }
189         printf("\n");
190
191         printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
192             "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
193         for (i = 0; i < sas0->NumPhys; i++) {
194                 phy0 = &sas0->PhyData[i];
195                 phy1 = &sas1->PhyData[i];
196                 if (phy0->PortFlags &
197                      MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
198                         printf("Discovery still in progress\n");
199                         continue;
200                 }
201                 if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
202                         isdisabled = "Y";
203                 else
204                         isdisabled = "N";
205
206                 minspeed = get_device_speed(phy1->MaxMinLinkRate);
207                 maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
208                 type = get_device_type(le32toh(phy0->ControllerPhyDeviceInfo));
209
210                 if (le16toh(phy0->AttachedDevHandle) != 0) {
211                         snprintf(devhandle, sizeof(devhandle), "%04x",
212                             le16toh(phy0->AttachedDevHandle));
213                         snprintf(ctrlhandle, sizeof(ctrlhandle), "%04x",
214                             le16toh(phy0->ControllerDevHandle));
215                         speed = get_device_speed(phy0->NegotiatedLinkRate);
216                 } else {
217                         snprintf(devhandle, sizeof(devhandle), "    ");
218                         snprintf(ctrlhandle, sizeof(ctrlhandle), "    ");
219                         speed = "     ";
220                 }
221                 printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
222                     i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
223                     maxspeed, type);
224         }
225         free(sas0);
226         free(sas1);
227         printf("\n");
228         close(fd);
229         return (0);
230 }
231
232 MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
233
234 static int
235 show_iocfacts(int ac, char **av)
236 {
237         MPI2_IOC_FACTS_REPLY *facts;
238         uint8_t *fb;
239         char tmpbuf[128];
240         int error, fd;
241
242         fd = mps_open(mps_unit);
243         if (fd < 0) {
244                 error = errno;
245                 warn("mps_open");
246                 return (error);
247         }
248
249         if ((facts = mps_get_iocfacts(fd)) == NULL) {
250                 printf("could not get controller IOCFacts\n");
251                 close(fd);
252                 return (errno);
253         }
254
255         fb = (uint8_t *)facts;
256
257 #define IOCCAP "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" \
258     "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" \
259     "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc" \
260     "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV"
261
262         bzero(tmpbuf, sizeof(tmpbuf));
263         mps_parse_flags(facts->IOCCapabilities, IOCCAP, tmpbuf, sizeof(tmpbuf));
264
265         printf("          MsgVersion: %d.%d\n",
266             facts->MsgVersion >> 8, facts->MsgVersion & 0xff);
267         printf("           MsgLength: %d\n", facts->MsgLength);
268         printf("            Function: 0x%x\n", facts->Function);
269         printf("       HeaderVersion: %02d,%02d\n",
270             facts->HeaderVersion >> 8, facts->HeaderVersion & 0xff);
271         printf("           IOCNumber: %d\n", facts->IOCNumber);
272         printf("            MsgFlags: 0x%x\n", facts->MsgFlags);
273         printf("               VP_ID: %d\n", facts->VP_ID);
274         printf("               VF_ID: %d\n", facts->VF_ID);
275         printf("       IOCExceptions: %d\n", facts->IOCExceptions);
276         printf("           IOCStatus: %d\n", facts->IOCStatus);
277         printf("          IOCLogInfo: 0x%x\n", facts->IOCLogInfo);
278         printf("       MaxChainDepth: %d\n", facts->MaxChainDepth);
279         printf("             WhoInit: 0x%x\n", facts->WhoInit);
280         printf("       NumberOfPorts: %d\n", facts->NumberOfPorts);
281         printf("      MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
282         printf("       RequestCredit: %d\n", facts->RequestCredit);
283         printf("           ProductID: 0x%x\n", facts->ProductID);
284         printf("     IOCCapabilities: 0x%x %s\n", facts->IOCCapabilities,
285             tmpbuf);
286         printf("           FWVersion: %02d.%02d.%02d.%02d\n",
287             facts->FWVersion.Struct.Major, facts->FWVersion.Struct.Minor,
288             facts->FWVersion.Struct.Unit, facts->FWVersion.Struct.Dev);
289         printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
290         if (is_mps == 0)
291                 printf(" MaxChainSegmentSize: %d\n", (uint16_t)(fb[0x26]));
292         printf("       MaxInitiators: %d\n", facts->MaxInitiators);
293         printf("          MaxTargets: %d\n", facts->MaxTargets);
294         printf("     MaxSasExpanders: %d\n", facts->MaxSasExpanders);
295         printf("       MaxEnclosures: %d\n", facts->MaxEnclosures);
296
297         bzero(tmpbuf, sizeof(tmpbuf));
298         mps_parse_flags(facts->ProtocolFlags,
299             "\4NvmeDevices\2ScsiTarget\1ScsiInitiator", tmpbuf, sizeof(tmpbuf));
300         printf("       ProtocolFlags: 0x%x %s\n", facts->ProtocolFlags, tmpbuf);
301         printf("  HighPriorityCredit: %d\n", facts->HighPriorityCredit);
302         printf("MaxRepDescPostQDepth: %d\n",
303             facts->MaxReplyDescriptorPostQueueDepth);
304         printf("      ReplyFrameSize: %d\n", facts->ReplyFrameSize);
305         printf("          MaxVolumes: %d\n", facts->MaxVolumes);
306         printf("        MaxDevHandle: %d\n", facts->MaxDevHandle);
307         printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
308         printf("        MinDevHandle: %d\n", facts->MinDevHandle);
309         if (is_mps == 0)
310                 printf(" CurrentHostPageSize: %d\n", (uint8_t)(fb[0x3e]));
311
312         free(facts);
313         return (0);
314 }
315
316 MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
317
318 static int
319 show_adapters(int ac, char **av)
320 {
321         MPI2_CONFIG_PAGE_MAN_0 *man0;
322         MPI2_IOC_FACTS_REPLY *facts;
323         int unit, fd, error;
324
325         printf("Device Name\t      Chip Name        Board Name        Firmware\n");
326         for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
327                 fd = mps_open(unit);
328                 if (fd < 0)
329                         continue;
330                 facts = mps_get_iocfacts(fd);
331                 if (facts == NULL) {
332                         error = errno;
333                         warn("Faled to get controller iocfacts");
334                         close(fd);
335                         return (error);
336                 }
337                 man0 = mps_read_man_page(fd, 0, NULL);
338                 if (man0 == NULL) {
339                         error = errno;
340                         warn("Failed to get controller info");
341                         close(fd);
342                         free(facts);
343                         return (error);
344                 }
345                 if (man0->Header.PageLength < sizeof(*man0) / 4) {
346                         warnx("Invalid controller info");
347                         close(fd);
348                         free(man0);
349                         free(facts);
350                         return (EINVAL);
351                 }
352                 printf("/dev/mp%s%d\t%16s %16s        %08x\n",
353                     is_mps ? "s": "r", unit,
354                     man0->ChipName, man0->BoardName, facts->FWVersion.Word);
355                 free(man0);
356                 free(facts);
357                 close(fd);
358         }
359         return (0);
360 }
361 MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
362
363 static char *
364 get_device_type(uint32_t di)
365 {
366
367         if (di & 0x4000)
368                 return ("SEP Target    ");
369         if (di & 0x2000)
370                 return ("ATAPI Target  ");
371         if (di & 0x400)
372                 return ("SAS Target    ");
373         if (di & 0x200)
374                 return ("STP Target    ");
375         if (di & 0x100)
376                 return ("SMP Target    ");
377         if (di & 0x80)
378                 return ("SATA Target   ");
379         if (di & 0x70)
380                 return ("SAS Initiator ");
381         if (di & 0x8)
382                 return ("SATA Initiator");
383         if ((di & 0x7) == 0)
384                 return ("No Device     ");
385         return ("Unknown Device");
386 }
387
388 static char *
389 get_enc_type(uint32_t flags, int *issep)
390 {
391         char *type;
392
393         *issep = 0;
394         switch (flags & 0xf) {
395         case 0x01:
396                 type = "Direct Attached SES-2";
397                 *issep = 1;
398                 break;
399         case 0x02:
400                 type = "Direct Attached SGPIO";
401                 break;
402         case 0x03:
403                 type = "Expander SGPIO";
404                 break;
405         case 0x04:
406                 type = "External SES-2";
407                 *issep = 1;
408                 break;
409         case 0x05:
410                 type = "Direct Attached GPIO";
411                 break;
412         case 0x0:
413         default:
414                 return ("Unknown");
415         }
416
417         return (type);
418 }
419
420 static char *
421 mps_device_speed[] = {
422         NULL,
423         NULL,
424         NULL,
425         NULL,
426         NULL,
427         NULL,
428         NULL,
429         NULL,
430         "1.5",
431         "3.0",
432         "6.0",
433         "12 "
434 };
435
436 static char *
437 get_device_speed(uint8_t rate)
438 {
439         char *speed;
440
441         rate &= 0xf;
442         if (rate >= sizeof(mps_device_speed))
443                 return ("Unk");
444
445         if ((speed = mps_device_speed[rate]) == NULL)
446                 return ("???");
447         return (speed);
448 }
449
450 static char *
451 mps_page_name[] = {
452         "IO Unit",
453         "IOC",
454         "BIOS",
455         NULL,
456         NULL,
457         NULL,
458         NULL,
459         NULL,
460         "RAID Volume",
461         "Manufacturing",
462         "RAID Physical Disk",
463         NULL,
464         NULL,
465         NULL,
466         NULL,
467         NULL,
468         "SAS IO Unit",
469         "SAS Expander",
470         "SAS Device",
471         "SAS PHY",
472         "Log",
473         "Enclosure",
474         "RAID Configuration",
475         "Driver Persistent Mapping",
476         "SAS Port",
477         "Ethernet Port",
478         "Extended Manufacturing"
479 };
480
481 static char *
482 get_page_name(u_int page)
483 {
484         char *name;
485
486         if (page >= sizeof(mps_page_name))
487                 return ("Unknown");
488         if ((name = mps_page_name[page]) == NULL)
489                 return ("Unknown");
490         return (name);
491 }
492
493 static int
494 show_all(int ac, char **av)
495 {
496         int error;
497
498         printf("Adapter:\n");
499         error = show_adapter(ac, av);
500         printf("Devices:\n");
501         error = show_devices(ac, av);
502         printf("Enclosures:\n");
503         error = show_enclosures(ac, av);
504         printf("Expanders:\n");
505         error = show_expanders(ac, av);
506         return (error);
507 }
508 MPS_COMMAND(show, all, show_all, "", "Show all devices");
509
510 static int
511 show_devices(int ac, char **av)
512 {
513         MPI2_CONFIG_PAGE_SASIOUNIT_0    *sas0;
514         MPI2_SAS_IO_UNIT0_PHY_DATA      *phydata;
515         MPI2_CONFIG_PAGE_SAS_DEV_0      *device;
516         MPI2_CONFIG_PAGE_EXPANDER_1     *exp1;
517         uint16_t IOCStatus, handle, bus, target;
518         char *type, *speed, enchandle[8], slot[8], bt[16];
519         char buf[256];
520         int fd, error, nphys;
521
522         fd = mps_open(mps_unit);
523         if (fd < 0) {
524                 error = errno;
525                 warn("mps_open");
526                 return (error);
527         }
528
529         sas0 = mps_read_extended_config_page(fd,
530             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
531             MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
532         if (sas0 == NULL) {
533                 error = errno;
534                 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
535                 return (error);
536         }
537         nphys = sas0->NumPhys;
538
539         printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
540             "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
541             "Enc", "Slot", "Wdt");
542         handle = 0xffff;
543         while (1) {
544                 device = mps_read_extended_config_page(fd,
545                     MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
546                     MPI2_SASDEVICE0_PAGEVERSION, 0,
547                     MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
548                     &IOCStatus);
549                 if (device == NULL) {
550                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
551                                 break;
552                         error = errno;
553                         warn("Error retrieving device page");
554                         close(fd);
555                         return (error);
556                 }
557                 handle = le16toh(device->DevHandle);
558
559                 if (device->ParentDevHandle == 0x0) {
560                         free(device);
561                         continue;
562                 }
563
564                 bus = 0xffff;
565                 target = 0xffff;
566                 error = mps_map_btdh(fd, &handle, &bus, &target);
567                 if (error) {
568                         free(device);
569                         continue;
570                 }
571                 if ((bus == 0xffff) || (target == 0xffff))
572                         snprintf(bt, sizeof(bt), "       ");
573                 else
574                         snprintf(bt, sizeof(bt), "%02d   %02d", bus, target);
575
576                 type = get_device_type(le32toh(device->DeviceInfo));
577
578                 if (device->DeviceInfo & 0x800) {       /* Direct Attached */
579                         if (device->PhyNum < nphys) {
580                                 phydata = &sas0->PhyData[device->PhyNum];
581                                 speed = get_device_speed(phydata->NegotiatedLinkRate);
582                         } else
583                                 speed = "";
584                 } else if (device->ParentDevHandle > 0) {
585                         exp1 = mps_read_extended_config_page(fd,
586                             MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
587                             MPI2_SASEXPANDER1_PAGEVERSION, 1,
588                             MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
589                             (device->PhyNum <<
590                             MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
591                             le16toh(device->ParentDevHandle), &IOCStatus);
592                         if (exp1 == NULL) {
593                                 if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
594                                         error = errno;
595                                         warn("Error retrieving expander page 1: 0x%x",
596                                             IOCStatus);
597                                         close(fd);
598                                         free(device);
599                                         return (error);
600                                 }
601                                 speed = "";
602                         } else {
603                                 speed = get_device_speed(exp1->NegotiatedLinkRate);
604                                 free(exp1);
605                         }
606                 } else
607                         speed = "";
608
609                 if (device->EnclosureHandle != 0) {
610                         snprintf(enchandle, sizeof(enchandle), "%04x", le16toh(device->EnclosureHandle));
611                         snprintf(slot, sizeof(slot), "%02d", le16toh(device->Slot));
612                 } else {
613                         snprintf(enchandle, sizeof(enchandle), "    ");
614                         snprintf(slot, sizeof(slot), "  ");
615                 }
616                 printf("%-10s", bt);
617                 snprintf(buf, sizeof(buf), "%08x%08x", le32toh(device->SASAddress.High),
618                     le32toh(device->SASAddress.Low));
619                 printf("%-17s", buf);
620                 snprintf(buf, sizeof(buf), "%04x", le16toh(device->DevHandle));
621                 printf("%-8s", buf);
622                 snprintf(buf, sizeof(buf), "%04x", le16toh(device->ParentDevHandle));
623                 printf("%-10s", buf);
624                 printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
625                     enchandle, slot, device->MaxPortConnections);
626                 free(device);
627         }
628         printf("\n");
629         free(sas0);
630         close(fd);
631         return (0);
632 }
633 MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
634
635 static int
636 show_enclosures(int ac, char **av)
637 {
638         MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
639         char *type, sepstr[8];
640         uint16_t IOCStatus, handle;
641         int fd, error, issep;
642
643         fd = mps_open(mps_unit);
644         if (fd < 0) {
645                 error = errno;
646                 warn("mps_open");
647                 return (error);
648         }
649
650         printf("Slots      Logical ID     SEPHandle  EncHandle    Type\n");
651         handle = 0xffff;
652         while (1) {
653                 enc = mps_read_extended_config_page(fd,
654                     MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
655                     MPI2_SASENCLOSURE0_PAGEVERSION, 0,
656                     MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
657                     &IOCStatus);
658                 if (enc == NULL) {
659                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
660                                 break;
661                         error = errno;
662                         warn("Error retrieving enclosure page");
663                         close(fd);
664                         return (error);
665                 }
666                 type = get_enc_type(le16toh(enc->Flags), &issep);
667                 if (issep == 0)
668                         snprintf(sepstr, sizeof(sepstr), "    ");
669                 else
670                         snprintf(sepstr, sizeof(sepstr), "%04x", le16toh(enc->SEPDevHandle));
671                 printf("  %.2d    %08x%08x    %s       %04x     %s\n",
672                     le16toh(enc->NumSlots), le32toh(enc->EnclosureLogicalID.High),
673                     le32toh(enc->EnclosureLogicalID.Low), sepstr, le16toh(enc->EnclosureHandle),
674                     type);
675                 handle = le16toh(enc->EnclosureHandle);
676                 free(enc);
677         }
678         printf("\n");
679         close(fd);
680         return (0);
681 }
682 MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
683
684 static int
685 show_expanders(int ac, char **av)
686 {
687         MPI2_CONFIG_PAGE_EXPANDER_0     *exp0;
688         MPI2_CONFIG_PAGE_EXPANDER_1     *exp1;
689         uint16_t IOCStatus, handle;
690         char enchandle[8], parent[8], rphy[4], rhandle[8];
691         char *speed, *min, *max, *type;
692         int fd, error, nphys, i;
693
694         fd = mps_open(mps_unit);
695         if (fd < 0) {
696                 error = errno;
697                 warn("mps_open");
698                 return (error);
699         }
700
701         printf("NumPhys   SAS Address     DevHandle   Parent  EncHandle  SAS Level\n");
702         handle = 0xffff;
703         while (1) {
704                 exp0 = mps_read_extended_config_page(fd,
705                     MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
706                     MPI2_SASEXPANDER0_PAGEVERSION, 0,
707                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
708                     &IOCStatus);
709                 if (exp0 == NULL) {
710                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
711                                 break;
712                         error = errno;
713                         warn("Error retrieving expander page 0");
714                         close(fd);
715                         return (error);
716                 }
717
718                 nphys = exp0->NumPhys;
719                 handle = le16toh(exp0->DevHandle);
720
721                 if (exp0->EnclosureHandle == 0x00)
722                         snprintf(enchandle, sizeof(enchandle), "    ");
723                 else
724                         snprintf(enchandle, sizeof(enchandle), "%04d", le16toh(exp0->EnclosureHandle));
725                 if (exp0->ParentDevHandle == 0x0)
726                         snprintf(parent, sizeof(parent), "    ");
727                 else
728                         snprintf(parent, sizeof(parent), "%04x", le16toh(exp0->ParentDevHandle));
729                 printf("  %02d    %08x%08x    %04x       %s     %s       %d\n",
730                     exp0->NumPhys, le32toh(exp0->SASAddress.High), le32toh(exp0->SASAddress.Low),
731                     le16toh(exp0->DevHandle), parent, enchandle, exp0->SASLevel);
732
733                 printf("\n");
734                 printf("     Phy  RemotePhy  DevHandle  Speed  Min   Max    Device\n");
735                 for (i = 0; i < nphys; i++) {
736                         exp1 = mps_read_extended_config_page(fd,
737                             MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
738                             MPI2_SASEXPANDER1_PAGEVERSION, 1,
739                             MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
740                             (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
741                             exp0->DevHandle, &IOCStatus);
742                         if (exp1 == NULL) {
743                                 if (IOCStatus !=
744                                     MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
745                                         warn("Error retrieving expander pg 1");
746                                 continue;
747                         }
748                         type = get_device_type(le32toh(exp1->AttachedDeviceInfo));
749                         if ((le32toh(exp1->AttachedDeviceInfo) &0x7) == 0) {
750                                 speed = "   ";
751                                 snprintf(rphy, sizeof(rphy), "  ");
752                                 snprintf(rhandle, sizeof(rhandle), "    ");
753                         } else {
754                                 speed = get_device_speed(
755                                     exp1->NegotiatedLinkRate);
756                                 snprintf(rphy, sizeof(rphy), "%02d",
757                                     exp1->AttachedPhyIdentifier);
758                                 snprintf(rhandle, sizeof(rhandle), "%04x",
759                                     le16toh(exp1->AttachedDevHandle));
760                         }
761                         min = get_device_speed(exp1->HwLinkRate);
762                         max = get_device_speed(exp1->HwLinkRate >> 4);
763                         printf("     %02d      %s        %s      %s   %s   %s   %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
764
765                         free(exp1);
766                 }
767                 free(exp0);
768         }
769
770         printf("\n");
771         close(fd);
772         return (0);
773 }
774
775 MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
776
777 static int
778 show_cfgpage(int ac, char **av)
779 {
780         MPI2_CONFIG_PAGE_HEADER *hdr;
781         MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
782         void *data;
783         uint32_t addr;
784         uint16_t IOCStatus;
785         uint8_t page, num;
786         int fd, error, len, attrs;
787         char *pgname, *pgattr;
788
789         fd = mps_open(mps_unit);
790         if (fd < 0) {
791                 error = errno;
792                 warn("mps_open");
793                 return (error);
794         }
795
796         addr = 0;
797         num = 0;
798         page = 0;
799
800         switch (ac) {
801         case 4:
802                 addr = htole32((uint32_t)strtoul(av[3], NULL, 0));
803         case 3:
804                 num = (uint8_t)strtoul(av[2], NULL, 0);
805         case 2:
806                 page = (uint8_t)strtoul(av[1], NULL, 0);
807                 break;
808         default:
809                 errno = EINVAL;
810                 warn("cfgpage: not enough arguments");
811                 return (EINVAL);
812         }
813
814         if (page >= 0x10)
815                 data = mps_read_extended_config_page(fd, page, 0, num, addr,
816                     &IOCStatus);
817          else 
818                 data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
819
820         if (data == NULL) {
821                 error = errno;
822                 warn("Error retrieving cfg page: %s\n",
823                     mps_ioc_status(IOCStatus));
824                 return (error);
825         }
826
827         if (page >= 0x10) {
828                 ehdr = data;
829                 len = le16toh(ehdr->ExtPageLength) * 4;
830                 page = ehdr->ExtPageType;
831                 attrs = ehdr->PageType >> 4;
832         } else {
833                 hdr = data;
834                 len = hdr->PageLength * 4;
835                 page = hdr->PageType & 0xf;
836                 attrs = hdr->PageType >> 4;
837         }
838
839         pgname = get_page_name(page);
840         if (attrs == 0)
841                 pgattr = "Read-only";
842         else if (attrs == 1)
843                 pgattr = "Read-Write";
844         else if (attrs == 2)
845                 pgattr = "Read-Write Persistent";
846         else
847                 pgattr = "Unknown Page Attribute";
848
849         printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
850         hexdump(data, len, NULL, HD_REVERSED | 4);
851         free(data);
852         close(fd);
853         return (0);
854 }
855
856 MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");