1297590Ssbruno/*- 2297590Ssbruno * Copyright (c) 2015 Netflix, Inc. 3297590Ssbruno * All rights reserved. 4297590Ssbruno * Written by: Scott Long <scottl@freebsd.org> 5297590Ssbruno * 6297590Ssbruno * Copyright (c) 2008 Yahoo!, Inc. 7297590Ssbruno * All rights reserved. 8297590Ssbruno * Written by: John Baldwin <jhb@FreeBSD.org> 9297590Ssbruno * 10297590Ssbruno * Redistribution and use in source and binary forms, with or without 11297590Ssbruno * modification, are permitted provided that the following conditions 12297590Ssbruno * are met: 13297590Ssbruno * 1. Redistributions of source code must retain the above copyright 14297590Ssbruno * notice, this list of conditions and the following disclaimer. 15297590Ssbruno * 2. Redistributions in binary form must reproduce the above copyright 16297590Ssbruno * notice, this list of conditions and the following disclaimer in the 17297590Ssbruno * documentation and/or other materials provided with the distribution. 18297590Ssbruno * 3. Neither the name of the author nor the names of any co-contributors 19297590Ssbruno * may be used to endorse or promote products derived from this software 20297590Ssbruno * without specific prior written permission. 21297590Ssbruno * 22297590Ssbruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23297590Ssbruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24297590Ssbruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25297590Ssbruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26297590Ssbruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27297590Ssbruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28297590Ssbruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29297590Ssbruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30297590Ssbruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31297590Ssbruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32297590Ssbruno * SUCH DAMAGE. 33297590Ssbruno */ 34297590Ssbruno 35297590Ssbruno#include <sys/cdefs.h> 36297590Ssbruno__RCSID("$FreeBSD$"); 37297590Ssbruno 38297590Ssbruno#include <sys/param.h> 39297590Ssbruno#include <sys/errno.h> 40297590Ssbruno#include <err.h> 41297590Ssbruno#include <libutil.h> 42297590Ssbruno#include <stdio.h> 43297590Ssbruno#include <stdlib.h> 44297590Ssbruno#include <string.h> 45297590Ssbruno#include <unistd.h> 46297590Ssbruno#include "mpsutil.h" 47297590Ssbruno 48297590Ssbrunostatic char * get_device_speed(uint8_t rate); 49297590Ssbrunostatic char * get_device_type(uint32_t di); 50297590Ssbrunostatic int show_all(int ac, char **av); 51297590Ssbrunostatic int show_devices(int ac, char **av); 52297590Ssbrunostatic int show_enclosures(int ac, char **av); 53297590Ssbrunostatic int show_expanders(int ac, char **av); 54297590Ssbruno 55297590SsbrunoMPS_TABLE(top, show); 56297590Ssbruno 57297590Ssbruno#define STANDALONE_STATE "ONLINE" 58297590Ssbruno 59297590Ssbrunostatic int 60297590Ssbrunoshow_adapter(int ac, char **av) 61297590Ssbruno{ 62297590Ssbruno MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0; 63297590Ssbruno MPI2_CONFIG_PAGE_SASIOUNIT_1 *sas1; 64297590Ssbruno MPI2_SAS_IO_UNIT0_PHY_DATA *phy0; 65297590Ssbruno MPI2_SAS_IO_UNIT1_PHY_DATA *phy1; 66297590Ssbruno MPI2_CONFIG_PAGE_MAN_0 *man0; 67297590Ssbruno MPI2_CONFIG_PAGE_BIOS_3 *bios3; 68297590Ssbruno MPI2_IOC_FACTS_REPLY *facts; 69297590Ssbruno U16 IOCStatus; 70297590Ssbruno char *speed, *minspeed, *maxspeed, *isdisabled, *type; 71297590Ssbruno char devhandle[5], ctrlhandle[5]; 72297590Ssbruno int error, fd, v, i; 73297590Ssbruno 74297590Ssbruno if (ac != 1) { 75297590Ssbruno warnx("show adapter: extra arguments"); 76297590Ssbruno return (EINVAL); 77297590Ssbruno } 78297590Ssbruno 79297590Ssbruno fd = mps_open(mps_unit); 80297590Ssbruno if (fd < 0) { 81297590Ssbruno error = errno; 82297590Ssbruno warn("mps_open"); 83297590Ssbruno return (error); 84297590Ssbruno } 85297590Ssbruno 86297590Ssbruno man0 = mps_read_man_page(fd, 0, NULL); 87297590Ssbruno if (man0 == NULL) { 88297590Ssbruno error = errno; 89297590Ssbruno warn("Failed to get controller info"); 90297590Ssbruno return (error); 91297590Ssbruno } 92297590Ssbruno if (man0->Header.PageLength < sizeof(*man0) / 4) { 93297590Ssbruno warnx("Invalid controller info"); 94297590Ssbruno return (EINVAL); 95297590Ssbruno } 96297590Ssbruno printf("mp%s%d Adapter:\n", is_mps ? "s": "r", mps_unit); 97297590Ssbruno printf(" Board Name: %.16s\n", man0->BoardName); 98297590Ssbruno printf(" Board Assembly: %.16s\n", man0->BoardAssembly); 99297590Ssbruno printf(" Chip Name: %.16s\n", man0->ChipName); 100297590Ssbruno printf(" Chip Revision: %.16s\n", man0->ChipRevision); 101297590Ssbruno free(man0); 102297590Ssbruno 103297590Ssbruno bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL); 104297590Ssbruno if (bios3 == NULL) { 105297590Ssbruno error = errno; 106297590Ssbruno warn("Failed to get BIOS page 3 info"); 107297590Ssbruno return (error); 108297590Ssbruno } 109297590Ssbruno v = bios3->BiosVersion; 110297590Ssbruno printf(" BIOS Revision: %d.%02d.%02d.%02d\n", 111297590Ssbruno ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16), 112297590Ssbruno ((v & 0xff00) >> 8), (v & 0xff)); 113297590Ssbruno free(bios3); 114297590Ssbruno 115297590Ssbruno if ((facts = mps_get_iocfacts(fd)) == NULL) { 116297590Ssbruno printf("could not get controller IOCFacts\n"); 117297590Ssbruno close(fd); 118297590Ssbruno return (errno); 119297590Ssbruno } 120297590Ssbruno v = facts->FWVersion.Word; 121297590Ssbruno printf("Firmware Revision: %d.%02d.%02d.%02d\n", 122297590Ssbruno ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16), 123297590Ssbruno ((v & 0xff00) >> 8), (v & 0xff)); 124297590Ssbruno printf(" Integrated RAID: %s\n", 125297590Ssbruno (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) 126297590Ssbruno ? "yes" : "no"); 127297590Ssbruno free(facts); 128297590Ssbruno 129297590Ssbruno fd = mps_open(mps_unit); 130297590Ssbruno if (fd < 0) { 131297590Ssbruno error = errno; 132297590Ssbruno warn("mps_open"); 133297590Ssbruno return (error); 134297590Ssbruno } 135297590Ssbruno 136297590Ssbruno sas0 = mps_read_extended_config_page(fd, 137297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 138297590Ssbruno MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus); 139297590Ssbruno if (sas0 == NULL) { 140297590Ssbruno error = errno; 141297590Ssbruno warn("Error retrieving SAS IO Unit page %d", IOCStatus); 142297590Ssbruno return (error); 143297590Ssbruno } 144297590Ssbruno 145297590Ssbruno sas1 = mps_read_extended_config_page(fd, 146297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 147297590Ssbruno MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus); 148297590Ssbruno if (sas0 == NULL) { 149297590Ssbruno error = errno; 150297590Ssbruno warn("Error retrieving SAS IO Unit page %d", IOCStatus); 151297590Ssbruno return (error); 152297590Ssbruno } 153297590Ssbruno printf("\n"); 154297590Ssbruno 155297590Ssbruno printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle", 156297590Ssbruno "DevHandle", "Disabled", "Speed", "Min", "Max", "Device"); 157297590Ssbruno for (i = 0; i < sas0->NumPhys; i++) { 158297590Ssbruno phy0 = &sas0->PhyData[i]; 159297590Ssbruno phy1 = &sas1->PhyData[i]; 160297590Ssbruno if (phy0->PortFlags & 161297590Ssbruno MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { 162297590Ssbruno printf("Discovery still in progress\n"); 163297590Ssbruno continue; 164297590Ssbruno } 165297590Ssbruno if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED) 166297590Ssbruno isdisabled = "Y"; 167297590Ssbruno else 168297590Ssbruno isdisabled = "N"; 169297590Ssbruno 170297590Ssbruno minspeed = get_device_speed(phy1->MaxMinLinkRate); 171297590Ssbruno maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4); 172297590Ssbruno type = get_device_type(phy0->ControllerPhyDeviceInfo); 173297590Ssbruno 174297590Ssbruno if (phy0->AttachedDevHandle != 0) { 175297590Ssbruno snprintf(devhandle, 5, "%04x", phy0->AttachedDevHandle); 176297590Ssbruno snprintf(ctrlhandle, 5, "%04x", 177297590Ssbruno phy0->ControllerDevHandle); 178297590Ssbruno speed = get_device_speed(phy0->NegotiatedLinkRate); 179297590Ssbruno } else { 180297590Ssbruno snprintf(devhandle, 5, " "); 181297590Ssbruno snprintf(ctrlhandle, 5, " "); 182297590Ssbruno speed = " "; 183297590Ssbruno } 184297590Ssbruno printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n", 185297590Ssbruno i, ctrlhandle, devhandle, isdisabled, speed, minspeed, 186297590Ssbruno maxspeed, type); 187297590Ssbruno } 188297590Ssbruno free(sas0); 189297590Ssbruno free(sas1); 190297590Ssbruno printf("\n"); 191297590Ssbruno close(fd); 192297590Ssbruno return (0); 193297590Ssbruno} 194297590Ssbruno 195297590SsbrunoMPS_COMMAND(show, adapter, show_adapter, "", "display controller information") 196297590Ssbruno 197297590Ssbrunostatic int 198297590Ssbrunoshow_iocfacts(int ac, char **av) 199297590Ssbruno{ 200297590Ssbruno MPI2_IOC_FACTS_REPLY *facts; 201297590Ssbruno int error, fd; 202297590Ssbruno 203297590Ssbruno fd = mps_open(mps_unit); 204297590Ssbruno if (fd < 0) { 205297590Ssbruno error = errno; 206297590Ssbruno warn("mps_open"); 207297590Ssbruno return (error); 208297590Ssbruno } 209297590Ssbruno 210297590Ssbruno if ((facts = mps_get_iocfacts(fd)) == NULL) { 211297590Ssbruno printf("could not get controller IOCFacts\n"); 212297590Ssbruno close(fd); 213297590Ssbruno return (errno); 214297590Ssbruno } 215297590Ssbruno 216297590Ssbruno printf(" MaxChainDepth: %d\n", facts->MaxChainDepth); 217297590Ssbruno printf(" WhoInit: 0x%x\n", facts->WhoInit); 218297590Ssbruno printf(" NumberOfPorts: %d\n", facts->NumberOfPorts); 219297590Ssbruno printf(" MaxMSIxVectors: %d\n", facts->MaxMSIxVectors); 220297590Ssbruno printf(" RequestCredit: %d\n", facts->RequestCredit); 221297590Ssbruno printf(" ProductID: 0x%x\n", facts->ProductID); 222297590Ssbruno printf(" IOCCapabilities: 0x%x\n", facts->IOCCapabilities); 223297590Ssbruno printf(" FWVersion: 0x%08x\n", facts->FWVersion.Word); 224297590Ssbruno printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize); 225297590Ssbruno printf(" MaxInitiators: %d\n", facts->MaxInitiators); 226297590Ssbruno printf(" MaxTargets: %d\n", facts->MaxTargets); 227297590Ssbruno printf(" MaxSasExpanders: %d\n", facts->MaxSasExpanders); 228297590Ssbruno printf(" MaxEnclosures: %d\n", facts->MaxEnclosures); 229297590Ssbruno printf(" ProtocolFlags: 0x%x\n", facts->ProtocolFlags); 230297590Ssbruno printf(" HighPriorityCredit: %d\n", facts->HighPriorityCredit); 231297590Ssbruno printf("MaxRepDescPostQDepth: %d\n", 232297590Ssbruno facts->MaxReplyDescriptorPostQueueDepth); 233297590Ssbruno printf(" ReplyFrameSize: %d\n", facts->ReplyFrameSize); 234297590Ssbruno printf(" MaxVolumes: %d\n", facts->MaxVolumes); 235297590Ssbruno printf(" MaxDevHandle: %d\n", facts->MaxDevHandle); 236297590Ssbruno printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries); 237297590Ssbruno printf(" MinDevHandle: %d\n", facts->MinDevHandle); 238297590Ssbruno 239297590Ssbruno free(facts); 240297590Ssbruno return (0); 241297590Ssbruno} 242297590Ssbruno 243297590SsbrunoMPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message"); 244297590Ssbruno 245297590Ssbrunostatic int 246297590Ssbrunoshow_adapters(int ac, char **av) 247297590Ssbruno{ 248297590Ssbruno MPI2_CONFIG_PAGE_MAN_0 *man0; 249297590Ssbruno MPI2_IOC_FACTS_REPLY *facts; 250297590Ssbruno int unit, fd, error; 251297590Ssbruno 252297590Ssbruno printf("Device Name\t Chip Name Board Name Firmware\n"); 253297590Ssbruno for (unit = 0; unit < MPS_MAX_UNIT; unit++) { 254297590Ssbruno fd = mps_open(unit); 255297590Ssbruno if (fd < 0) 256297590Ssbruno continue; 257297590Ssbruno facts = mps_get_iocfacts(fd); 258297590Ssbruno if (facts == NULL) { 259297590Ssbruno error = errno; 260297590Ssbruno warn("Faled to get controller iocfacts"); 261297590Ssbruno close(fd); 262297590Ssbruno return (error); 263297590Ssbruno } 264297590Ssbruno man0 = mps_read_man_page(fd, 0, NULL); 265297590Ssbruno if (man0 == NULL) { 266297590Ssbruno error = errno; 267297590Ssbruno warn("Failed to get controller info"); 268297590Ssbruno close(fd); 269297590Ssbruno return (error); 270297590Ssbruno } 271297590Ssbruno if (man0->Header.PageLength < sizeof(*man0) / 4) { 272297590Ssbruno warnx("Invalid controller info"); 273297590Ssbruno close(fd); 274297590Ssbruno free(man0); 275297590Ssbruno return (EINVAL); 276297590Ssbruno } 277297590Ssbruno printf("/dev/mp%s%d\t%16s %16s %08x\n", 278297590Ssbruno is_mps ? "s": "r", unit, 279297590Ssbruno man0->ChipName, man0->BoardName, facts->FWVersion.Word); 280297590Ssbruno free(man0); 281297590Ssbruno free(facts); 282297590Ssbruno close(fd); 283297590Ssbruno } 284297590Ssbruno return (0); 285297590Ssbruno} 286297590SsbrunoMPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters"); 287297590Ssbruno 288297590Ssbrunostatic char * 289297590Ssbrunoget_device_type(uint32_t di) 290297590Ssbruno{ 291297590Ssbruno 292297590Ssbruno if (di & 0x4000) 293297590Ssbruno return ("SEP Target "); 294297590Ssbruno if (di & 0x2000) 295297590Ssbruno return ("ATAPI Target "); 296297590Ssbruno if (di & 0x400) 297297590Ssbruno return ("SAS Target "); 298297590Ssbruno if (di & 0x200) 299297590Ssbruno return ("STP Target "); 300297590Ssbruno if (di & 0x100) 301297590Ssbruno return ("SMP Target "); 302297590Ssbruno if (di & 0x80) 303297590Ssbruno return ("SATA Target "); 304297590Ssbruno if (di & 0x70) 305297590Ssbruno return ("SAS Initiator "); 306297590Ssbruno if (di & 0x8) 307297590Ssbruno return ("SATA Initiator"); 308297590Ssbruno if ((di & 0x7) == 0) 309297590Ssbruno return ("No Device "); 310297590Ssbruno return ("Unknown Device"); 311297590Ssbruno} 312297590Ssbruno 313297590Ssbrunostatic char * 314297590Ssbrunoget_enc_type(uint32_t flags, int *issep) 315297590Ssbruno{ 316297590Ssbruno char *type; 317297590Ssbruno 318297590Ssbruno *issep = 0; 319297590Ssbruno switch (flags & 0xf) { 320297590Ssbruno case 0x01: 321297590Ssbruno type = "Direct Attached SES-2"; 322297590Ssbruno *issep = 1; 323297590Ssbruno break; 324297590Ssbruno case 0x02: 325297590Ssbruno type = "Direct Attached SGPIO"; 326297590Ssbruno break; 327297590Ssbruno case 0x03: 328297590Ssbruno type = "Expander SGPIO"; 329297590Ssbruno break; 330297590Ssbruno case 0x04: 331297590Ssbruno type = "External SES-2"; 332297590Ssbruno *issep = 1; 333297590Ssbruno break; 334297590Ssbruno case 0x05: 335297590Ssbruno type = "Direct Attached GPIO"; 336297590Ssbruno break; 337297590Ssbruno case 0x0: 338297590Ssbruno default: 339297590Ssbruno return ("Unknown"); 340297590Ssbruno } 341297590Ssbruno 342297590Ssbruno return (type); 343297590Ssbruno} 344297590Ssbruno 345297590Ssbrunostatic char * 346297590Ssbrunomps_device_speed[] = { 347297590Ssbruno NULL, 348297590Ssbruno NULL, 349297590Ssbruno NULL, 350297590Ssbruno NULL, 351297590Ssbruno NULL, 352297590Ssbruno NULL, 353297590Ssbruno NULL, 354297590Ssbruno NULL, 355297590Ssbruno "1.5", 356297590Ssbruno "3.0", 357297590Ssbruno "6.0", 358297590Ssbruno "12 " 359297590Ssbruno}; 360297590Ssbruno 361297590Ssbrunostatic char * 362297590Ssbrunoget_device_speed(uint8_t rate) 363297590Ssbruno{ 364297590Ssbruno char *speed; 365297590Ssbruno 366297590Ssbruno rate &= 0xf; 367297590Ssbruno if (rate >= sizeof(mps_device_speed)) 368297590Ssbruno return ("Unk"); 369297590Ssbruno 370297590Ssbruno if ((speed = mps_device_speed[rate]) == NULL) 371297590Ssbruno return ("???"); 372297590Ssbruno return (speed); 373297590Ssbruno} 374297590Ssbruno 375297590Ssbrunostatic char * 376297590Ssbrunomps_page_name[] = { 377297590Ssbruno "IO Unit", 378297590Ssbruno "IOC", 379297590Ssbruno "BIOS", 380297590Ssbruno NULL, 381297590Ssbruno NULL, 382297590Ssbruno NULL, 383297590Ssbruno NULL, 384297590Ssbruno NULL, 385297590Ssbruno "RAID Volume", 386297590Ssbruno "Manufacturing", 387297590Ssbruno "RAID Physical Disk", 388297590Ssbruno NULL, 389297590Ssbruno NULL, 390297590Ssbruno NULL, 391297590Ssbruno NULL, 392297590Ssbruno NULL, 393297590Ssbruno "SAS IO Unit", 394297590Ssbruno "SAS Expander", 395297590Ssbruno "SAS Device", 396297590Ssbruno "SAS PHY", 397297590Ssbruno "Log", 398297590Ssbruno "Enclosure", 399297590Ssbruno "RAID Configuration", 400297590Ssbruno "Driver Persistent Mapping", 401297590Ssbruno "SAS Port", 402297590Ssbruno "Ethernet Port", 403297590Ssbruno "Extended Manufacturing" 404297590Ssbruno}; 405297590Ssbruno 406297590Ssbrunostatic char * 407297590Ssbrunoget_page_name(u_int page) 408297590Ssbruno{ 409297590Ssbruno char *name; 410297590Ssbruno 411297590Ssbruno if (page >= sizeof(mps_page_name)) 412297590Ssbruno return ("Unknown"); 413297590Ssbruno if ((name = mps_page_name[page]) == NULL) 414297590Ssbruno return ("Unknown"); 415297590Ssbruno return (name); 416297590Ssbruno} 417297590Ssbruno 418297590Ssbrunostatic int 419297590Ssbrunoshow_all(int ac, char **av) 420297590Ssbruno{ 421297590Ssbruno int error; 422297590Ssbruno 423297590Ssbruno printf("Adapter:\n"); 424297590Ssbruno error = show_adapter(ac, av); 425297590Ssbruno printf("Devices:\n"); 426297590Ssbruno error = show_devices(ac, av); 427297590Ssbruno printf("Enclosures:\n"); 428297590Ssbruno error = show_enclosures(ac, av); 429297590Ssbruno printf("Expanders:\n"); 430297590Ssbruno error = show_expanders(ac, av); 431297590Ssbruno return (error); 432297590Ssbruno} 433297590SsbrunoMPS_COMMAND(show, all, show_all, "", "Show all devices"); 434297590Ssbruno 435297590Ssbrunostatic int 436297590Ssbrunoshow_devices(int ac, char **av) 437297590Ssbruno{ 438297590Ssbruno MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0; 439297590Ssbruno MPI2_SAS_IO_UNIT0_PHY_DATA *phydata; 440297590Ssbruno MPI2_CONFIG_PAGE_SAS_DEV_0 *device; 441297590Ssbruno MPI2_CONFIG_PAGE_EXPANDER_1 *exp1; 442297590Ssbruno uint16_t IOCStatus, handle, bus, target; 443297590Ssbruno char *type, *speed, enchandle[5], slot[3], bt[8]; 444297590Ssbruno char buf[256]; 445297590Ssbruno int fd, error, nphys; 446297590Ssbruno 447297590Ssbruno fd = mps_open(mps_unit); 448297590Ssbruno if (fd < 0) { 449297590Ssbruno error = errno; 450297590Ssbruno warn("mps_open"); 451297590Ssbruno return (error); 452297590Ssbruno } 453297590Ssbruno 454297590Ssbruno sas0 = mps_read_extended_config_page(fd, 455297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 456297590Ssbruno MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus); 457297590Ssbruno if (sas0 == NULL) { 458297590Ssbruno error = errno; 459297590Ssbruno warn("Error retrieving SAS IO Unit page %d", IOCStatus); 460297590Ssbruno return (error); 461297590Ssbruno } 462297590Ssbruno nphys = sas0->NumPhys; 463297590Ssbruno 464297590Ssbruno printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n", 465297590Ssbruno "T", "SAS Address", "Handle", "Parent", "Device", "Speed", 466297590Ssbruno "Enc", "Slot", "Wdt"); 467297590Ssbruno handle = 0xffff; 468297590Ssbruno while (1) { 469297590Ssbruno device = mps_read_extended_config_page(fd, 470297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 471297590Ssbruno MPI2_SASDEVICE0_PAGEVERSION, 0, 472297590Ssbruno MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle, 473297590Ssbruno &IOCStatus); 474297590Ssbruno if (device == NULL) { 475297590Ssbruno if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 476297590Ssbruno break; 477297590Ssbruno error = errno; 478297590Ssbruno warn("Error retrieving device page"); 479297590Ssbruno return (error); 480297590Ssbruno } 481297590Ssbruno handle = device->DevHandle; 482297590Ssbruno 483297590Ssbruno if (device->ParentDevHandle == 0x0) { 484297590Ssbruno free(device); 485297590Ssbruno continue; 486297590Ssbruno } 487297590Ssbruno 488297590Ssbruno bus = 0xffff; 489297590Ssbruno target = 0xffff; 490297590Ssbruno error = mps_map_btdh(fd, &handle, &bus, &target); 491297590Ssbruno if (error) { 492297590Ssbruno free(device); 493297590Ssbruno continue; 494297590Ssbruno } 495297590Ssbruno if ((bus == 0xffff) || (target == 0xffff)) 496297590Ssbruno snprintf(bt, sizeof(bt), " "); 497297590Ssbruno else 498297590Ssbruno snprintf(bt, sizeof(bt), "%02d %02d", bus, target); 499297590Ssbruno 500297590Ssbruno type = get_device_type(device->DeviceInfo); 501297590Ssbruno 502297590Ssbruno if (device->PhyNum < nphys) { 503297590Ssbruno phydata = &sas0->PhyData[device->PhyNum]; 504297590Ssbruno speed = get_device_speed(phydata->NegotiatedLinkRate); 505297590Ssbruno } else if (device->ParentDevHandle > 0) { 506297590Ssbruno exp1 = mps_read_extended_config_page(fd, 507297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 508297590Ssbruno MPI2_SASEXPANDER1_PAGEVERSION, 1, 509297590Ssbruno MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | 510297590Ssbruno (device->PhyNum << 511297590Ssbruno MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | 512297590Ssbruno device->ParentDevHandle, &IOCStatus); 513297590Ssbruno if (exp1 == NULL) { 514297590Ssbruno if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) { 515297590Ssbruno error = errno; 516297590Ssbruno warn("Error retrieving expander page 1: 0x%x", 517297590Ssbruno IOCStatus); 518297590Ssbruno return (error); 519297590Ssbruno } 520297590Ssbruno speed = " "; 521297590Ssbruno } else { 522297590Ssbruno speed = get_device_speed(exp1->NegotiatedLinkRate); 523297590Ssbruno free(exp1); 524297590Ssbruno } 525297590Ssbruno } else 526297590Ssbruno speed = " "; 527297590Ssbruno 528297590Ssbruno if (device->EnclosureHandle != 0) { 529297590Ssbruno snprintf(enchandle, 5, "%04x", device->EnclosureHandle); 530297590Ssbruno snprintf(slot, 3, "%02d", device->Slot); 531297590Ssbruno } else { 532297590Ssbruno snprintf(enchandle, 5, " "); 533297590Ssbruno snprintf(slot, 3, " "); 534297590Ssbruno } 535297590Ssbruno printf("%-10s", bt); 536297590Ssbruno snprintf(buf, sizeof(buf), "%08x%08x", device->SASAddress.High, 537297590Ssbruno device->SASAddress.Low); 538297590Ssbruno printf("%-17s", buf); 539297590Ssbruno snprintf(buf, sizeof(buf), "%04x", device->DevHandle); 540297590Ssbruno printf("%-8s", buf); 541297590Ssbruno snprintf(buf, sizeof(buf), "%04x", device->ParentDevHandle); 542297590Ssbruno printf("%-10s", buf); 543297590Ssbruno printf("%-14s%-6s%-5s%-6s%d\n", type, speed, 544297590Ssbruno enchandle, slot, device->MaxPortConnections); 545297590Ssbruno free(device); 546297590Ssbruno } 547297590Ssbruno printf("\n"); 548297590Ssbruno free(sas0); 549297590Ssbruno close(fd); 550297590Ssbruno return (0); 551297590Ssbruno} 552297590SsbrunoMPS_COMMAND(show, devices, show_devices, "", "Show attached devices"); 553297590Ssbruno 554297590Ssbrunostatic int 555297590Ssbrunoshow_enclosures(int ac, char **av) 556297590Ssbruno{ 557297590Ssbruno MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc; 558297590Ssbruno char *type, sepstr[5]; 559297590Ssbruno uint16_t IOCStatus, handle; 560297590Ssbruno int fd, error, issep; 561297590Ssbruno 562297590Ssbruno fd = mps_open(mps_unit); 563297590Ssbruno if (fd < 0) { 564297590Ssbruno error = errno; 565297590Ssbruno warn("mps_open"); 566297590Ssbruno return (error); 567297590Ssbruno } 568297590Ssbruno 569297590Ssbruno printf("Slots Logical ID SEPHandle EncHandle Type\n"); 570297590Ssbruno handle = 0xffff; 571297590Ssbruno while (1) { 572297590Ssbruno enc = mps_read_extended_config_page(fd, 573297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 574297590Ssbruno MPI2_SASENCLOSURE0_PAGEVERSION, 0, 575297590Ssbruno MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle, 576297590Ssbruno &IOCStatus); 577297590Ssbruno if (enc == NULL) { 578297590Ssbruno if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 579297590Ssbruno break; 580297590Ssbruno error = errno; 581297590Ssbruno warn("Error retrieving enclosure page"); 582297590Ssbruno return (error); 583297590Ssbruno } 584297590Ssbruno type = get_enc_type(enc->Flags, &issep); 585297590Ssbruno if (issep == 0) 586297590Ssbruno snprintf(sepstr, 5, " "); 587297590Ssbruno else 588297590Ssbruno snprintf(sepstr, 5, "%04x", enc->SEPDevHandle); 589297590Ssbruno printf(" %.2d %08x%08x %s %04x %s\n", 590297590Ssbruno enc->NumSlots, enc->EnclosureLogicalID.High, 591297590Ssbruno enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle, 592297590Ssbruno type); 593297590Ssbruno handle = enc->EnclosureHandle; 594297590Ssbruno free(enc); 595297590Ssbruno } 596297590Ssbruno printf("\n"); 597297590Ssbruno close(fd); 598297590Ssbruno return (0); 599297590Ssbruno} 600297590SsbrunoMPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures"); 601297590Ssbruno 602297590Ssbrunostatic int 603297590Ssbrunoshow_expanders(int ac, char **av) 604297590Ssbruno{ 605297590Ssbruno MPI2_CONFIG_PAGE_EXPANDER_0 *exp0; 606297590Ssbruno MPI2_CONFIG_PAGE_EXPANDER_1 *exp1; 607297590Ssbruno uint16_t IOCStatus, handle; 608297590Ssbruno char enchandle[5], parent[5], rphy[3], rhandle[5]; 609297590Ssbruno char *speed, *min, *max, *type; 610297590Ssbruno int fd, error, nphys, i; 611297590Ssbruno 612297590Ssbruno fd = mps_open(mps_unit); 613297590Ssbruno if (fd < 0) { 614297590Ssbruno error = errno; 615297590Ssbruno warn("mps_open"); 616297590Ssbruno return (error); 617297590Ssbruno } 618297590Ssbruno 619297590Ssbruno printf("NumPhys SAS Address DevHandle Parent EncHandle SAS Level\n"); 620297590Ssbruno handle = 0xffff; 621297590Ssbruno while (1) { 622297590Ssbruno exp0 = mps_read_extended_config_page(fd, 623297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 624297590Ssbruno MPI2_SASEXPANDER0_PAGEVERSION, 0, 625297590Ssbruno MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle, 626297590Ssbruno &IOCStatus); 627297590Ssbruno if (exp0 == NULL) { 628297590Ssbruno if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 629297590Ssbruno break; 630297590Ssbruno error = errno; 631297590Ssbruno warn("Error retrieving expander page 0"); 632297590Ssbruno return (error); 633297590Ssbruno } 634297590Ssbruno 635297590Ssbruno nphys = exp0->NumPhys; 636297590Ssbruno handle = exp0->DevHandle; 637297590Ssbruno 638297590Ssbruno if (exp0->EnclosureHandle == 0x00) 639297590Ssbruno snprintf(enchandle, 5, " "); 640297590Ssbruno else 641297590Ssbruno snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle); 642297590Ssbruno if (exp0->ParentDevHandle == 0x0) 643297590Ssbruno snprintf(parent, 5, " "); 644297590Ssbruno else 645297590Ssbruno snprintf(parent, 5, "%04x", exp0->ParentDevHandle); 646297590Ssbruno printf(" %02d %08x%08x %04x %s %s %d\n", 647297590Ssbruno exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low, 648297590Ssbruno exp0->DevHandle, parent, enchandle, exp0->SASLevel); 649297590Ssbruno 650297590Ssbruno printf("\n"); 651297590Ssbruno printf(" Phy RemotePhy DevHandle Speed Min Max Device\n"); 652297590Ssbruno for (i = 0; i < nphys; i++) { 653297590Ssbruno exp1 = mps_read_extended_config_page(fd, 654297590Ssbruno MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 655297590Ssbruno MPI2_SASEXPANDER1_PAGEVERSION, 1, 656297590Ssbruno MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | 657297590Ssbruno (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | 658297590Ssbruno exp0->DevHandle, &IOCStatus); 659297590Ssbruno if (exp1 == NULL) { 660297590Ssbruno if (IOCStatus != 661297590Ssbruno MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 662297590Ssbruno warn("Error retrieving expander pg 1"); 663297590Ssbruno continue; 664297590Ssbruno } 665297590Ssbruno type = get_device_type(exp1->AttachedDeviceInfo); 666297590Ssbruno if ((exp1->AttachedDeviceInfo &0x7) == 0) { 667297590Ssbruno speed = " "; 668297590Ssbruno snprintf(rphy, 3, " "); 669297590Ssbruno snprintf(rhandle, 5, " "); 670297590Ssbruno } else { 671297590Ssbruno speed = get_device_speed( 672297590Ssbruno exp1->NegotiatedLinkRate); 673297590Ssbruno snprintf(rphy, 3, "%02d", 674297590Ssbruno exp1->AttachedPhyIdentifier); 675297590Ssbruno snprintf(rhandle, 5, "%04x", 676297590Ssbruno exp1->AttachedDevHandle); 677297590Ssbruno } 678297590Ssbruno min = get_device_speed(exp1->HwLinkRate); 679297590Ssbruno max = get_device_speed(exp1->HwLinkRate >> 4); 680297590Ssbruno printf(" %02d %s %s %s %s %s %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type); 681297590Ssbruno 682297590Ssbruno free(exp1); 683297590Ssbruno } 684297590Ssbruno free(exp0); 685297590Ssbruno } 686297590Ssbruno 687297590Ssbruno printf("\n"); 688297590Ssbruno close(fd); 689297590Ssbruno return (0); 690297590Ssbruno} 691297590Ssbruno 692297590SsbrunoMPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders"); 693297590Ssbruno 694297590Ssbrunostatic int 695297590Ssbrunoshow_cfgpage(int ac, char **av) 696297590Ssbruno{ 697297590Ssbruno MPI2_CONFIG_PAGE_HEADER *hdr; 698297590Ssbruno MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr; 699297590Ssbruno void *data; 700297590Ssbruno uint32_t addr; 701297590Ssbruno uint16_t IOCStatus; 702297590Ssbruno uint8_t page, num; 703297590Ssbruno int fd, error, len, attrs; 704297590Ssbruno char *pgname, *pgattr; 705297590Ssbruno 706297590Ssbruno fd = mps_open(mps_unit); 707297590Ssbruno if (fd < 0) { 708297590Ssbruno error = errno; 709297590Ssbruno warn("mps_open"); 710297590Ssbruno return (error); 711297590Ssbruno } 712297590Ssbruno 713297590Ssbruno addr = 0; 714297590Ssbruno num = 0; 715297590Ssbruno page = 0; 716297590Ssbruno 717297590Ssbruno switch (ac) { 718297590Ssbruno case 4: 719297590Ssbruno addr = (uint32_t)strtoul(av[3], NULL, 0); 720297590Ssbruno case 3: 721297590Ssbruno num = (uint8_t)strtoul(av[2], NULL, 0); 722297590Ssbruno case 2: 723297590Ssbruno page = (uint8_t)strtoul(av[1], NULL, 0); 724297590Ssbruno break; 725297590Ssbruno default: 726297590Ssbruno errno = EINVAL; 727297590Ssbruno warn("cfgpage: not enough arguments"); 728297590Ssbruno return (EINVAL); 729297590Ssbruno } 730297590Ssbruno 731297590Ssbruno if (page >= 0x10) 732297590Ssbruno data = mps_read_extended_config_page(fd, page, 0, num, addr, 733297590Ssbruno &IOCStatus); 734297590Ssbruno else 735297590Ssbruno data = mps_read_config_page(fd, page, num, addr, &IOCStatus); 736297590Ssbruno 737297590Ssbruno if (data == NULL) { 738297590Ssbruno error = errno; 739297590Ssbruno warn("Error retrieving cfg page: %s\n", 740297590Ssbruno mps_ioc_status(IOCStatus)); 741297590Ssbruno return (error); 742297590Ssbruno } 743297590Ssbruno 744297590Ssbruno if (page >= 0x10) { 745297590Ssbruno ehdr = data; 746297590Ssbruno len = ehdr->ExtPageLength * 4; 747297590Ssbruno page = ehdr->ExtPageType; 748297590Ssbruno attrs = ehdr->PageType >> 4; 749297590Ssbruno } else { 750297590Ssbruno hdr = data; 751297590Ssbruno len = hdr->PageLength * 4; 752297590Ssbruno page = hdr->PageType & 0xf; 753297590Ssbruno attrs = hdr->PageType >> 4; 754297590Ssbruno } 755297590Ssbruno 756297590Ssbruno pgname = get_page_name(page); 757297590Ssbruno if (attrs == 0) 758297590Ssbruno pgattr = "Read-only"; 759297590Ssbruno else if (attrs == 1) 760297590Ssbruno pgattr = "Read-Write"; 761297590Ssbruno else if (attrs == 2) 762297590Ssbruno pgattr = "Read-Write Persistent"; 763297590Ssbruno else 764297590Ssbruno pgattr = "Unknown Page Attribute"; 765297590Ssbruno 766297590Ssbruno printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr); 767297590Ssbruno hexdump(data, len, NULL, HD_REVERSED | 4); 768297590Ssbruno free(data); 769297590Ssbruno return (0); 770297590Ssbruno} 771297590Ssbruno 772297590SsbrunoMPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page"); 773