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