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