2 * Copyright (c) 2015 Netflix, Inc.
3 * Written by: Scott Long <scottl@freebsd.org>
5 * Copyright (c) 2008 Yahoo!, Inc.
7 * Written by: John Baldwin <jhb@FreeBSD.org>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
34 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/errno.h>
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);
56 #define STANDALONE_STATE "ONLINE"
59 show_adapter(int ac, char **av)
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;
69 char *speed, *minspeed, *maxspeed, *isdisabled, *type;
70 char devhandle[5], ctrlhandle[5];
74 warnx("show adapter: extra arguments");
78 fd = mps_open(mps_unit);
85 man0 = mps_read_man_page(fd, 0, NULL);
88 warn("Failed to get controller info");
91 if (man0->Header.PageLength < sizeof(*man0) / 4) {
92 warnx("Invalid controller info");
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);
102 bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
105 warn("Failed to get BIOS page 3 info");
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));
114 if ((facts = mps_get_iocfacts(fd)) == NULL) {
115 printf("could not get controller IOCFacts\n");
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)
128 fd = mps_open(mps_unit);
135 sas0 = mps_read_extended_config_page(fd,
136 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
137 MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
140 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
146 sas1 = mps_read_extended_config_page(fd,
147 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
148 MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
151 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
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");
168 if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
173 minspeed = get_device_speed(phy1->MaxMinLinkRate);
174 maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
175 type = get_device_type(phy0->ControllerPhyDeviceInfo);
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);
183 snprintf(devhandle, 5, " ");
184 snprintf(ctrlhandle, 5, " ");
187 printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
188 i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
198 MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
201 show_iocfacts(int ac, char **av)
203 MPI2_IOC_FACTS_REPLY *facts;
208 fd = mps_open(mps_unit);
215 if ((facts = mps_get_iocfacts(fd)) == NULL) {
216 printf("could not get controller IOCFacts\n");
221 fb = (uint8_t *)facts;
223 #define IOCCAP "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" \
224 "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" \
225 "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc" \
226 "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV"
228 bzero(tmpbuf, sizeof(tmpbuf));
229 mps_parse_flags(facts->IOCCapabilities, IOCCAP, tmpbuf, sizeof(tmpbuf));
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,
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);
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);
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);
276 printf(" CurrentHostPageSize: %d\n", (uint8_t)(fb[0x3e]));
282 MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
285 show_adapters(int ac, char **av)
287 MPI2_CONFIG_PAGE_MAN_0 *man0;
288 MPI2_IOC_FACTS_REPLY *facts;
291 printf("Device Name\t Chip Name Board Name Firmware\n");
292 for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
296 facts = mps_get_iocfacts(fd);
299 warn("Faled to get controller iocfacts");
303 man0 = mps_read_man_page(fd, 0, NULL);
306 warn("Failed to get controller info");
311 if (man0->Header.PageLength < sizeof(*man0) / 4) {
312 warnx("Invalid controller info");
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);
327 MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
330 get_device_type(uint32_t di)
334 return ("SEP Target ");
336 return ("ATAPI Target ");
338 return ("SAS Target ");
340 return ("STP Target ");
342 return ("SMP Target ");
344 return ("SATA Target ");
346 return ("SAS Initiator ");
348 return ("SATA Initiator");
350 return ("No Device ");
351 return ("Unknown Device");
355 get_enc_type(uint32_t flags, int *issep)
360 switch (flags & 0xf) {
362 type = "Direct Attached SES-2";
366 type = "Direct Attached SGPIO";
369 type = "Expander SGPIO";
372 type = "External SES-2";
376 type = "Direct Attached GPIO";
387 mps_device_speed[] = {
403 get_device_speed(uint8_t rate)
408 if (rate >= sizeof(mps_device_speed))
411 if ((speed = mps_device_speed[rate]) == NULL)
428 "RAID Physical Disk",
440 "RAID Configuration",
441 "Driver Persistent Mapping",
444 "Extended Manufacturing"
448 get_page_name(u_int page)
452 if (page >= sizeof(mps_page_name))
454 if ((name = mps_page_name[page]) == NULL)
460 show_all(int ac, char **av)
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);
474 MPS_COMMAND(show, all, show_all, "", "Show all devices");
477 show_devices(int ac, char **av)
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];
486 int fd, error, nphys;
488 fd = mps_open(mps_unit);
495 sas0 = mps_read_extended_config_page(fd,
496 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
497 MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
500 warn("Error retrieving SAS IO Unit page %d", IOCStatus);
503 nphys = sas0->NumPhys;
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");
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,
515 if (device == NULL) {
516 if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
519 warn("Error retrieving device page");
523 handle = device->DevHandle;
525 if (device->ParentDevHandle == 0x0) {
532 error = mps_map_btdh(fd, &handle, &bus, &target);
537 if ((bus == 0xffff) || (target == 0xffff))
538 snprintf(bt, sizeof(bt), " ");
540 snprintf(bt, sizeof(bt), "%02d %02d", bus, target);
542 type = get_device_type(device->DeviceInfo);
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 |
553 MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
554 device->ParentDevHandle, &IOCStatus);
556 if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
558 warn("Error retrieving expander page 1: 0x%x",
566 speed = get_device_speed(exp1->NegotiatedLinkRate);
572 if (device->EnclosureHandle != 0) {
573 snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
574 snprintf(slot, 3, "%02d", device->Slot);
576 snprintf(enchandle, 5, " ");
577 snprintf(slot, 3, " ");
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);
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);
596 MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
599 show_enclosures(int ac, char **av)
601 MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
602 char *type, sepstr[5];
603 uint16_t IOCStatus, handle;
604 int fd, error, issep;
606 fd = mps_open(mps_unit);
613 printf("Slots Logical ID SEPHandle EncHandle Type\n");
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,
622 if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
625 warn("Error retrieving enclosure page");
629 type = get_enc_type(enc->Flags, &issep);
631 snprintf(sepstr, 5, " ");
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,
638 handle = enc->EnclosureHandle;
645 MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
648 show_expanders(int ac, char **av)
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;
657 fd = mps_open(mps_unit);
664 printf("NumPhys SAS Address DevHandle Parent EncHandle SAS Level\n");
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,
673 if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
676 warn("Error retrieving expander page 0");
681 nphys = exp0->NumPhys;
682 handle = exp0->DevHandle;
684 if (exp0->EnclosureHandle == 0x00)
685 snprintf(enchandle, 5, " ");
687 snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
688 if (exp0->ParentDevHandle == 0x0)
689 snprintf(parent, 5, " ");
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);
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);
707 MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
708 warn("Error retrieving expander pg 1");
711 type = get_device_type(exp1->AttachedDeviceInfo);
712 if ((exp1->AttachedDeviceInfo &0x7) == 0) {
714 snprintf(rphy, 3, " ");
715 snprintf(rhandle, 5, " ");
717 speed = get_device_speed(
718 exp1->NegotiatedLinkRate);
719 snprintf(rphy, 3, "%02d",
720 exp1->AttachedPhyIdentifier);
721 snprintf(rhandle, 5, "%04x",
722 exp1->AttachedDevHandle);
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);
738 MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
741 show_cfgpage(int ac, char **av)
743 MPI2_CONFIG_PAGE_HEADER *hdr;
744 MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
749 int fd, error, len, attrs;
750 char *pgname, *pgattr;
752 fd = mps_open(mps_unit);
765 addr = (uint32_t)strtoul(av[3], NULL, 0);
767 num = (uint8_t)strtoul(av[2], NULL, 0);
769 page = (uint8_t)strtoul(av[1], NULL, 0);
773 warn("cfgpage: not enough arguments");
778 data = mps_read_extended_config_page(fd, page, 0, num, addr,
781 data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
785 warn("Error retrieving cfg page: %s\n",
786 mps_ioc_status(IOCStatus));
792 len = ehdr->ExtPageLength * 4;
793 page = ehdr->ExtPageType;
794 attrs = ehdr->PageType >> 4;
797 len = hdr->PageLength * 4;
798 page = hdr->PageType & 0xf;
799 attrs = hdr->PageType >> 4;
802 pgname = get_page_name(page);
804 pgattr = "Read-only";
806 pgattr = "Read-Write";
808 pgattr = "Read-Write Persistent";
810 pgattr = "Unknown Page Attribute";
812 printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
813 hexdump(data, len, NULL, HD_REVERSED | 4);
819 MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");