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