]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mpsutil/mps_show.c
Add two missing eventhandler.h headers
[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: %02d.%02d\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: 0x%08x\n", facts->FWVersion.Word);
250         printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
251         printf("       MaxInitiators: %d\n", facts->MaxInitiators);
252         printf("          MaxTargets: %d\n", facts->MaxTargets);
253         printf("     MaxSasExpanders: %d\n", facts->MaxSasExpanders);
254         printf("       MaxEnclosures: %d\n", facts->MaxEnclosures);
255
256         bzero(tmpbuf, sizeof(tmpbuf));
257         mps_parse_flags(facts->ProtocolFlags,
258             "\4NvmeDevices\2ScsiTarget\1ScsiInitiator", tmpbuf, sizeof(tmpbuf));
259         printf("       ProtocolFlags: 0x%x %s\n", facts->ProtocolFlags, tmpbuf);
260         printf("  HighPriorityCredit: %d\n", facts->HighPriorityCredit);
261         printf("MaxRepDescPostQDepth: %d\n",
262             facts->MaxReplyDescriptorPostQueueDepth);
263         printf("      ReplyFrameSize: %d\n", facts->ReplyFrameSize);
264         printf("          MaxVolumes: %d\n", facts->MaxVolumes);
265         printf("        MaxDevHandle: %d\n", facts->MaxDevHandle);
266         printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
267         printf("        MinDevHandle: %d\n", facts->MinDevHandle);
268
269         free(facts);
270         return (0);
271 }
272
273 MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
274
275 static int
276 show_adapters(int ac, char **av)
277 {
278         MPI2_CONFIG_PAGE_MAN_0 *man0;
279         MPI2_IOC_FACTS_REPLY *facts;
280         int unit, fd, error;
281
282         printf("Device Name\t      Chip Name        Board Name        Firmware\n");
283         for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
284                 fd = mps_open(unit);
285                 if (fd < 0)
286                         continue;
287                 facts = mps_get_iocfacts(fd);
288                 if (facts == NULL) {
289                         error = errno;
290                         warn("Faled to get controller iocfacts");
291                         close(fd);
292                         return (error);
293                 }
294                 man0 = mps_read_man_page(fd, 0, NULL);
295                 if (man0 == NULL) {
296                         error = errno;
297                         warn("Failed to get controller info");
298                         close(fd);
299                         free(facts);
300                         return (error);
301                 }
302                 if (man0->Header.PageLength < sizeof(*man0) / 4) {
303                         warnx("Invalid controller info");
304                         close(fd);
305                         free(man0);
306                         free(facts);
307                         return (EINVAL);
308                 }
309                 printf("/dev/mp%s%d\t%16s %16s        %08x\n",
310                     is_mps ? "s": "r", unit,
311                     man0->ChipName, man0->BoardName, facts->FWVersion.Word);
312                 free(man0);
313                 free(facts);
314                 close(fd);
315         }
316         return (0);
317 }
318 MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
319
320 static char *
321 get_device_type(uint32_t di)
322 {
323
324         if (di & 0x4000)
325                 return ("SEP Target    ");
326         if (di & 0x2000)
327                 return ("ATAPI Target  ");
328         if (di & 0x400)
329                 return ("SAS Target    ");
330         if (di & 0x200)
331                 return ("STP Target    ");
332         if (di & 0x100)
333                 return ("SMP Target    ");
334         if (di & 0x80)
335                 return ("SATA Target   ");
336         if (di & 0x70)
337                 return ("SAS Initiator ");
338         if (di & 0x8)
339                 return ("SATA Initiator");
340         if ((di & 0x7) == 0)
341                 return ("No Device     ");
342         return ("Unknown Device");
343 }
344
345 static char *
346 get_enc_type(uint32_t flags, int *issep)
347 {
348         char *type;
349
350         *issep = 0;
351         switch (flags & 0xf) {
352         case 0x01:
353                 type = "Direct Attached SES-2";
354                 *issep = 1;
355                 break;
356         case 0x02:
357                 type = "Direct Attached SGPIO";
358                 break;
359         case 0x03:
360                 type = "Expander SGPIO";
361                 break;
362         case 0x04:
363                 type = "External SES-2";
364                 *issep = 1;
365                 break;
366         case 0x05:
367                 type = "Direct Attached GPIO";
368                 break;
369         case 0x0:
370         default:
371                 return ("Unknown");
372         }
373
374         return (type);
375 }
376
377 static char *
378 mps_device_speed[] = {
379         NULL,
380         NULL,
381         NULL,
382         NULL,
383         NULL,
384         NULL,
385         NULL,
386         NULL,
387         "1.5",
388         "3.0",
389         "6.0",
390         "12 "
391 };
392
393 static char *
394 get_device_speed(uint8_t rate)
395 {
396         char *speed;
397
398         rate &= 0xf;
399         if (rate >= sizeof(mps_device_speed))
400                 return ("Unk");
401
402         if ((speed = mps_device_speed[rate]) == NULL)
403                 return ("???");
404         return (speed);
405 }
406
407 static char *
408 mps_page_name[] = {
409         "IO Unit",
410         "IOC",
411         "BIOS",
412         NULL,
413         NULL,
414         NULL,
415         NULL,
416         NULL,
417         "RAID Volume",
418         "Manufacturing",
419         "RAID Physical Disk",
420         NULL,
421         NULL,
422         NULL,
423         NULL,
424         NULL,
425         "SAS IO Unit",
426         "SAS Expander",
427         "SAS Device",
428         "SAS PHY",
429         "Log",
430         "Enclosure",
431         "RAID Configuration",
432         "Driver Persistent Mapping",
433         "SAS Port",
434         "Ethernet Port",
435         "Extended Manufacturing"
436 };
437
438 static char *
439 get_page_name(u_int page)
440 {
441         char *name;
442
443         if (page >= sizeof(mps_page_name))
444                 return ("Unknown");
445         if ((name = mps_page_name[page]) == NULL)
446                 return ("Unknown");
447         return (name);
448 }
449
450 static int
451 show_all(int ac, char **av)
452 {
453         int error;
454
455         printf("Adapter:\n");
456         error = show_adapter(ac, av);
457         printf("Devices:\n");
458         error = show_devices(ac, av);
459         printf("Enclosures:\n");
460         error = show_enclosures(ac, av);
461         printf("Expanders:\n");
462         error = show_expanders(ac, av);
463         return (error);
464 }
465 MPS_COMMAND(show, all, show_all, "", "Show all devices");
466
467 static int
468 show_devices(int ac, char **av)
469 {
470         MPI2_CONFIG_PAGE_SASIOUNIT_0    *sas0;
471         MPI2_SAS_IO_UNIT0_PHY_DATA      *phydata;
472         MPI2_CONFIG_PAGE_SAS_DEV_0      *device;
473         MPI2_CONFIG_PAGE_EXPANDER_1     *exp1;
474         uint16_t IOCStatus, handle, bus, target;
475         char *type, *speed, enchandle[5], slot[3], bt[8];
476         char buf[256];
477         int fd, error, nphys;
478
479         fd = mps_open(mps_unit);
480         if (fd < 0) {
481                 error = errno;
482                 warn("mps_open");
483                 return (error);
484         }
485
486         sas0 = mps_read_extended_config_page(fd,
487             MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
488             MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
489         if (sas0 == NULL) {
490                 error = errno;
491                 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
492                 return (error);
493         }
494         nphys = sas0->NumPhys;
495
496         printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
497             "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
498             "Enc", "Slot", "Wdt");
499         handle = 0xffff;
500         while (1) {
501                 device = mps_read_extended_config_page(fd,
502                     MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
503                     MPI2_SASDEVICE0_PAGEVERSION, 0,
504                     MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
505                     &IOCStatus);
506                 if (device == NULL) {
507                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
508                                 break;
509                         error = errno;
510                         warn("Error retrieving device page");
511                         close(fd);
512                         return (error);
513                 }
514                 handle = device->DevHandle;
515
516                 if (device->ParentDevHandle == 0x0) {
517                         free(device);
518                         continue;
519                 }
520
521                 bus = 0xffff;
522                 target = 0xffff;
523                 error = mps_map_btdh(fd, &handle, &bus, &target);
524                 if (error) {
525                         free(device);
526                         continue;
527                 }
528                 if ((bus == 0xffff) || (target == 0xffff))
529                         snprintf(bt, sizeof(bt), "       ");
530                 else
531                         snprintf(bt, sizeof(bt), "%02d   %02d", bus, target);
532
533                 type = get_device_type(device->DeviceInfo);
534
535                 if (device->PhyNum < nphys) {
536                         phydata = &sas0->PhyData[device->PhyNum];
537                         speed = get_device_speed(phydata->NegotiatedLinkRate);
538                 } else if (device->ParentDevHandle > 0) {
539                         exp1 = mps_read_extended_config_page(fd,
540                             MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
541                             MPI2_SASEXPANDER1_PAGEVERSION, 1,
542                             MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
543                             (device->PhyNum <<
544                             MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
545                             device->ParentDevHandle, &IOCStatus);
546                         if (exp1 == NULL) {
547                                 if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
548                                         error = errno;
549                                         warn("Error retrieving expander page 1: 0x%x",
550                                             IOCStatus);
551                                         close(fd);
552                                         free(device);
553                                         return (error);
554                                 }
555                                 speed = " ";
556                         } else {
557                                 speed = get_device_speed(exp1->NegotiatedLinkRate);
558                                 free(exp1);
559                         }
560                 } else
561                         speed = " ";
562
563                 if (device->EnclosureHandle != 0) {
564                         snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
565                         snprintf(slot, 3, "%02d", device->Slot);
566                 } else {
567                         snprintf(enchandle, 5, "    ");
568                         snprintf(slot, 3, "  ");
569                 }
570                 printf("%-10s", bt);
571                 snprintf(buf, sizeof(buf), "%08x%08x", device->SASAddress.High,
572                     device->SASAddress.Low);
573                 printf("%-17s", buf);
574                 snprintf(buf, sizeof(buf), "%04x", device->DevHandle);
575                 printf("%-8s", buf);
576                 snprintf(buf, sizeof(buf), "%04x", device->ParentDevHandle);
577                 printf("%-10s", buf);
578                 printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
579                     enchandle, slot, device->MaxPortConnections);
580                 free(device);
581         }
582         printf("\n");
583         free(sas0);
584         close(fd);
585         return (0);
586 }
587 MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
588
589 static int
590 show_enclosures(int ac, char **av)
591 {
592         MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
593         char *type, sepstr[5];
594         uint16_t IOCStatus, handle;
595         int fd, error, issep;
596
597         fd = mps_open(mps_unit);
598         if (fd < 0) {
599                 error = errno;
600                 warn("mps_open");
601                 return (error);
602         }
603
604         printf("Slots      Logical ID     SEPHandle  EncHandle    Type\n");
605         handle = 0xffff;
606         while (1) {
607                 enc = mps_read_extended_config_page(fd,
608                     MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
609                     MPI2_SASENCLOSURE0_PAGEVERSION, 0,
610                     MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
611                     &IOCStatus);
612                 if (enc == NULL) {
613                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
614                                 break;
615                         error = errno;
616                         warn("Error retrieving enclosure page");
617                         close(fd);
618                         return (error);
619                 }
620                 type = get_enc_type(enc->Flags, &issep);
621                 if (issep == 0)
622                         snprintf(sepstr, 5, "    ");
623                 else
624                         snprintf(sepstr, 5, "%04x", enc->SEPDevHandle);
625                 printf("  %.2d    %08x%08x    %s       %04x     %s\n",
626                     enc->NumSlots, enc->EnclosureLogicalID.High,
627                     enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle,
628                     type);
629                 handle = enc->EnclosureHandle;
630                 free(enc);
631         }
632         printf("\n");
633         close(fd);
634         return (0);
635 }
636 MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
637
638 static int
639 show_expanders(int ac, char **av)
640 {
641         MPI2_CONFIG_PAGE_EXPANDER_0     *exp0;
642         MPI2_CONFIG_PAGE_EXPANDER_1     *exp1;
643         uint16_t IOCStatus, handle;
644         char enchandle[5], parent[5], rphy[3], rhandle[5];
645         char *speed, *min, *max, *type;
646         int fd, error, nphys, i;
647
648         fd = mps_open(mps_unit);
649         if (fd < 0) {
650                 error = errno;
651                 warn("mps_open");
652                 return (error);
653         }
654
655         printf("NumPhys   SAS Address     DevHandle   Parent  EncHandle  SAS Level\n");
656         handle = 0xffff;
657         while (1) {
658                 exp0 = mps_read_extended_config_page(fd,
659                     MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
660                     MPI2_SASEXPANDER0_PAGEVERSION, 0,
661                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
662                     &IOCStatus);
663                 if (exp0 == NULL) {
664                         if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
665                                 break;
666                         error = errno;
667                         warn("Error retrieving expander page 0");
668                         close(fd);
669                         return (error);
670                 }
671
672                 nphys = exp0->NumPhys;
673                 handle = exp0->DevHandle;
674
675                 if (exp0->EnclosureHandle == 0x00)
676                         snprintf(enchandle, 5, "    ");
677                 else
678                         snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
679                 if (exp0->ParentDevHandle == 0x0)
680                         snprintf(parent, 5, "    ");
681                 else
682                         snprintf(parent, 5, "%04x", exp0->ParentDevHandle);
683                 printf("  %02d    %08x%08x    %04x       %s     %s       %d\n",
684                     exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low,
685                     exp0->DevHandle, parent, enchandle, exp0->SASLevel);
686
687                 printf("\n");
688                 printf("     Phy  RemotePhy  DevHandle  Speed   Min    Max    Device\n");
689                 for (i = 0; i < nphys; i++) {
690                         exp1 = mps_read_extended_config_page(fd,
691                             MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
692                             MPI2_SASEXPANDER1_PAGEVERSION, 1,
693                             MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
694                             (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
695                             exp0->DevHandle, &IOCStatus);
696                         if (exp1 == NULL) {
697                                 if (IOCStatus !=
698                                     MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
699                                         warn("Error retrieving expander pg 1");
700                                 continue;
701                         }
702                         type = get_device_type(exp1->AttachedDeviceInfo);
703                         if ((exp1->AttachedDeviceInfo &0x7) == 0) {
704                                 speed = "     ";
705                                 snprintf(rphy, 3, "  ");
706                                 snprintf(rhandle, 5, "     ");
707                         } else {
708                                 speed = get_device_speed(
709                                     exp1->NegotiatedLinkRate);
710                                 snprintf(rphy, 3, "%02d",
711                                     exp1->AttachedPhyIdentifier);
712                                 snprintf(rhandle, 5, "%04x",
713                                     exp1->AttachedDevHandle);
714                         }
715                         min = get_device_speed(exp1->HwLinkRate);
716                         max = get_device_speed(exp1->HwLinkRate >> 4);
717                         printf("     %02d     %s         %s     %s  %s  %s  %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
718
719                         free(exp1);
720                 }
721                 free(exp0);
722         }
723
724         printf("\n");
725         close(fd);
726         return (0);
727 }
728
729 MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
730
731 static int
732 show_cfgpage(int ac, char **av)
733 {
734         MPI2_CONFIG_PAGE_HEADER *hdr;
735         MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
736         void *data;
737         uint32_t addr;
738         uint16_t IOCStatus;
739         uint8_t page, num;
740         int fd, error, len, attrs;
741         char *pgname, *pgattr;
742
743         fd = mps_open(mps_unit);
744         if (fd < 0) {
745                 error = errno;
746                 warn("mps_open");
747                 return (error);
748         }
749
750         addr = 0;
751         num = 0;
752         page = 0;
753
754         switch (ac) {
755         case 4:
756                 addr = (uint32_t)strtoul(av[3], NULL, 0);
757         case 3:
758                 num = (uint8_t)strtoul(av[2], NULL, 0);
759         case 2:
760                 page = (uint8_t)strtoul(av[1], NULL, 0);
761                 break;
762         default:
763                 errno = EINVAL;
764                 warn("cfgpage: not enough arguments");
765                 return (EINVAL);
766         }
767
768         if (page >= 0x10)
769                 data = mps_read_extended_config_page(fd, page, 0, num, addr,
770                     &IOCStatus);
771          else 
772                 data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
773
774         if (data == NULL) {
775                 error = errno;
776                 warn("Error retrieving cfg page: %s\n",
777                     mps_ioc_status(IOCStatus));
778                 return (error);
779         }
780
781         if (page >= 0x10) {
782                 ehdr = data;
783                 len = ehdr->ExtPageLength * 4;
784                 page = ehdr->ExtPageType;
785                 attrs = ehdr->PageType >> 4;
786         } else {
787                 hdr = data;
788                 len = hdr->PageLength * 4;
789                 page = hdr->PageType & 0xf;
790                 attrs = hdr->PageType >> 4;
791         }
792
793         pgname = get_page_name(page);
794         if (attrs == 0)
795                 pgattr = "Read-only";
796         else if (attrs == 1)
797                 pgattr = "Read-Write";
798         else if (attrs == 2)
799                 pgattr = "Read-Write Persistent";
800         else
801                 pgattr = "Unknown Page Attribute";
802
803         printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
804         hexdump(data, len, NULL, HD_REVERSED | 4);
805         free(data);
806         close(fd);
807         return (0);
808 }
809
810 MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");