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