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