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