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