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