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