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