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[5], ctrlhandle[5]; 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, 5, "%04x", le16toh(phy0->AttachedDevHandle)); 214 snprintf(ctrlhandle, 5, "%04x", 215 le16toh(phy0->ControllerDevHandle)); 216 speed = get_device_speed(phy0->NegotiatedLinkRate); 217 } else { 218 snprintf(devhandle, 5, " "); 219 snprintf(ctrlhandle, 5, " "); 220 speed = " "; 221 } 222 printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n", 223 i, ctrlhandle, devhandle, isdisabled, speed, minspeed, 224 maxspeed, type); 225 } 226 free(sas0); 227 free(sas1); 228 printf("\n"); 229 close(fd); 230 return (0); 231 } 232 233 MPS_COMMAND(show, adapter, show_adapter, "", "display controller information") 234 235 static int 236 show_iocfacts(int ac, char **av) 237 { 238 MPI2_IOC_FACTS_REPLY *facts; 239 uint8_t *fb; 240 char tmpbuf[128]; 241 int error, fd; 242 243 fd = mps_open(mps_unit); 244 if (fd < 0) { 245 error = errno; 246 warn("mps_open"); 247 return (error); 248 } 249 250 if ((facts = mps_get_iocfacts(fd)) == NULL) { 251 printf("could not get controller IOCFacts\n"); 252 close(fd); 253 return (errno); 254 } 255 256 fb = (uint8_t *)facts; 257 258 #define IOCCAP "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" \ 259 "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" \ 260 "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc" \ 261 "\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV" 262 263 bzero(tmpbuf, sizeof(tmpbuf)); 264 mps_parse_flags(facts->IOCCapabilities, IOCCAP, tmpbuf, sizeof(tmpbuf)); 265 266 printf(" MsgVersion: %d.%d\n", 267 facts->MsgVersion >> 8, facts->MsgVersion & 0xff); 268 printf(" MsgLength: %d\n", facts->MsgLength); 269 printf(" Function: 0x%x\n", facts->Function); 270 printf(" HeaderVersion: %02d,%02d\n", 271 facts->HeaderVersion >> 8, facts->HeaderVersion & 0xff); 272 printf(" IOCNumber: %d\n", facts->IOCNumber); 273 printf(" MsgFlags: 0x%x\n", facts->MsgFlags); 274 printf(" VP_ID: %d\n", facts->VP_ID); 275 printf(" VF_ID: %d\n", facts->VF_ID); 276 printf(" IOCExceptions: %d\n", facts->IOCExceptions); 277 printf(" IOCStatus: %d\n", facts->IOCStatus); 278 printf(" IOCLogInfo: 0x%x\n", facts->IOCLogInfo); 279 printf(" MaxChainDepth: %d\n", facts->MaxChainDepth); 280 printf(" WhoInit: 0x%x\n", facts->WhoInit); 281 printf(" NumberOfPorts: %d\n", facts->NumberOfPorts); 282 printf(" MaxMSIxVectors: %d\n", facts->MaxMSIxVectors); 283 printf(" RequestCredit: %d\n", facts->RequestCredit); 284 printf(" ProductID: 0x%x\n", facts->ProductID); 285 printf(" IOCCapabilities: 0x%x %s\n", facts->IOCCapabilities, 286 tmpbuf); 287 printf(" FWVersion: %02d.%02d.%02d.%02d\n", 288 facts->FWVersion.Struct.Major, facts->FWVersion.Struct.Minor, 289 facts->FWVersion.Struct.Unit, facts->FWVersion.Struct.Dev); 290 printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize); 291 if (is_mps == 0) 292 printf(" MaxChainSegmentSize: %d\n", (uint16_t)(fb[0x26])); 293 printf(" MaxInitiators: %d\n", facts->MaxInitiators); 294 printf(" MaxTargets: %d\n", facts->MaxTargets); 295 printf(" MaxSasExpanders: %d\n", facts->MaxSasExpanders); 296 printf(" MaxEnclosures: %d\n", facts->MaxEnclosures); 297 298 bzero(tmpbuf, sizeof(tmpbuf)); 299 mps_parse_flags(facts->ProtocolFlags, 300 "\4NvmeDevices\2ScsiTarget\1ScsiInitiator", tmpbuf, sizeof(tmpbuf)); 301 printf(" ProtocolFlags: 0x%x %s\n", facts->ProtocolFlags, tmpbuf); 302 printf(" HighPriorityCredit: %d\n", facts->HighPriorityCredit); 303 printf("MaxRepDescPostQDepth: %d\n", 304 facts->MaxReplyDescriptorPostQueueDepth); 305 printf(" ReplyFrameSize: %d\n", facts->ReplyFrameSize); 306 printf(" MaxVolumes: %d\n", facts->MaxVolumes); 307 printf(" MaxDevHandle: %d\n", facts->MaxDevHandle); 308 printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries); 309 printf(" MinDevHandle: %d\n", facts->MinDevHandle); 310 if (is_mps == 0) 311 printf(" CurrentHostPageSize: %d\n", (uint8_t)(fb[0x3e])); 312 313 free(facts); 314 return (0); 315 } 316 317 MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message"); 318 319 static int 320 show_adapters(int ac, char **av) 321 { 322 MPI2_CONFIG_PAGE_MAN_0 *man0; 323 MPI2_IOC_FACTS_REPLY *facts; 324 int unit, fd, error; 325 326 printf("Device Name\t Chip Name Board Name Firmware\n"); 327 for (unit = 0; unit < MPS_MAX_UNIT; unit++) { 328 fd = mps_open(unit); 329 if (fd < 0) 330 continue; 331 facts = mps_get_iocfacts(fd); 332 if (facts == NULL) { 333 error = errno; 334 warn("Faled to get controller iocfacts"); 335 close(fd); 336 return (error); 337 } 338 man0 = mps_read_man_page(fd, 0, NULL); 339 if (man0 == NULL) { 340 error = errno; 341 warn("Failed to get controller info"); 342 close(fd); 343 free(facts); 344 return (error); 345 } 346 if (man0->Header.PageLength < sizeof(*man0) / 4) { 347 warnx("Invalid controller info"); 348 close(fd); 349 free(man0); 350 free(facts); 351 return (EINVAL); 352 } 353 printf("/dev/mp%s%d\t%16s %16s %08x\n", 354 is_mps ? "s": "r", unit, 355 man0->ChipName, man0->BoardName, facts->FWVersion.Word); 356 free(man0); 357 free(facts); 358 close(fd); 359 } 360 return (0); 361 } 362 MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters"); 363 364 static char * 365 get_device_type(uint32_t di) 366 { 367 368 if (di & 0x4000) 369 return ("SEP Target "); 370 if (di & 0x2000) 371 return ("ATAPI Target "); 372 if (di & 0x400) 373 return ("SAS Target "); 374 if (di & 0x200) 375 return ("STP Target "); 376 if (di & 0x100) 377 return ("SMP Target "); 378 if (di & 0x80) 379 return ("SATA Target "); 380 if (di & 0x70) 381 return ("SAS Initiator "); 382 if (di & 0x8) 383 return ("SATA Initiator"); 384 if ((di & 0x7) == 0) 385 return ("No Device "); 386 return ("Unknown Device"); 387 } 388 389 static char * 390 get_enc_type(uint32_t flags, int *issep) 391 { 392 char *type; 393 394 *issep = 0; 395 switch (flags & 0xf) { 396 case 0x01: 397 type = "Direct Attached SES-2"; 398 *issep = 1; 399 break; 400 case 0x02: 401 type = "Direct Attached SGPIO"; 402 break; 403 case 0x03: 404 type = "Expander SGPIO"; 405 break; 406 case 0x04: 407 type = "External SES-2"; 408 *issep = 1; 409 break; 410 case 0x05: 411 type = "Direct Attached GPIO"; 412 break; 413 case 0x0: 414 default: 415 return ("Unknown"); 416 } 417 418 return (type); 419 } 420 421 static char * 422 mps_device_speed[] = { 423 NULL, 424 NULL, 425 NULL, 426 NULL, 427 NULL, 428 NULL, 429 NULL, 430 NULL, 431 "1.5", 432 "3.0", 433 "6.0", 434 "12 " 435 }; 436 437 static char * 438 get_device_speed(uint8_t rate) 439 { 440 char *speed; 441 442 rate &= 0xf; 443 if (rate >= sizeof(mps_device_speed)) 444 return ("Unk"); 445 446 if ((speed = mps_device_speed[rate]) == NULL) 447 return ("???"); 448 return (speed); 449 } 450 451 static char * 452 mps_page_name[] = { 453 "IO Unit", 454 "IOC", 455 "BIOS", 456 NULL, 457 NULL, 458 NULL, 459 NULL, 460 NULL, 461 "RAID Volume", 462 "Manufacturing", 463 "RAID Physical Disk", 464 NULL, 465 NULL, 466 NULL, 467 NULL, 468 NULL, 469 "SAS IO Unit", 470 "SAS Expander", 471 "SAS Device", 472 "SAS PHY", 473 "Log", 474 "Enclosure", 475 "RAID Configuration", 476 "Driver Persistent Mapping", 477 "SAS Port", 478 "Ethernet Port", 479 "Extended Manufacturing" 480 }; 481 482 static char * 483 get_page_name(u_int page) 484 { 485 char *name; 486 487 if (page >= sizeof(mps_page_name)) 488 return ("Unknown"); 489 if ((name = mps_page_name[page]) == NULL) 490 return ("Unknown"); 491 return (name); 492 } 493 494 static int 495 show_all(int ac, char **av) 496 { 497 int error; 498 499 printf("Adapter:\n"); 500 error = show_adapter(ac, av); 501 printf("Devices:\n"); 502 error = show_devices(ac, av); 503 printf("Enclosures:\n"); 504 error = show_enclosures(ac, av); 505 printf("Expanders:\n"); 506 error = show_expanders(ac, av); 507 return (error); 508 } 509 MPS_COMMAND(show, all, show_all, "", "Show all devices"); 510 511 static int 512 show_devices(int ac, char **av) 513 { 514 MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0; 515 MPI2_SAS_IO_UNIT0_PHY_DATA *phydata; 516 MPI2_CONFIG_PAGE_SAS_DEV_0 *device; 517 MPI2_CONFIG_PAGE_EXPANDER_1 *exp1; 518 uint16_t IOCStatus, handle, bus, target; 519 char *type, *speed, enchandle[5], slot[3], bt[8]; 520 char buf[256]; 521 int fd, error, nphys; 522 523 fd = mps_open(mps_unit); 524 if (fd < 0) { 525 error = errno; 526 warn("mps_open"); 527 return (error); 528 } 529 530 sas0 = mps_read_extended_config_page(fd, 531 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 532 MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus); 533 if (sas0 == NULL) { 534 error = errno; 535 warn("Error retrieving SAS IO Unit page %d", IOCStatus); 536 return (error); 537 } 538 nphys = sas0->NumPhys; 539 540 printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n", 541 "T", "SAS Address", "Handle", "Parent", "Device", "Speed", 542 "Enc", "Slot", "Wdt"); 543 handle = 0xffff; 544 while (1) { 545 device = mps_read_extended_config_page(fd, 546 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 547 MPI2_SASDEVICE0_PAGEVERSION, 0, 548 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle, 549 &IOCStatus); 550 if (device == NULL) { 551 if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 552 break; 553 error = errno; 554 warn("Error retrieving device page"); 555 close(fd); 556 return (error); 557 } 558 handle = le16toh(device->DevHandle); 559 560 if (device->ParentDevHandle == 0x0) { 561 free(device); 562 continue; 563 } 564 565 bus = 0xffff; 566 target = 0xffff; 567 error = mps_map_btdh(fd, &handle, &bus, &target); 568 if (error) { 569 free(device); 570 continue; 571 } 572 if ((bus == 0xffff) || (target == 0xffff)) 573 snprintf(bt, sizeof(bt), " "); 574 else 575 snprintf(bt, sizeof(bt), "%02d %02d", bus, target); 576 577 type = get_device_type(le32toh(device->DeviceInfo)); 578 579 if (device->PhyNum < nphys) { 580 phydata = &sas0->PhyData[device->PhyNum]; 581 speed = get_device_speed(phydata->NegotiatedLinkRate); 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, 5, "%04x", le16toh(device->EnclosureHandle)); 609 snprintf(slot, 3, "%02d", le16toh(device->Slot)); 610 } else { 611 snprintf(enchandle, 5, " "); 612 snprintf(slot, 3, " "); 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[5]; 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, 5, " "); 667 else 668 snprintf(sepstr, 5, "%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[5], parent[5], rphy[3], rhandle[5]; 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, 5, " "); 721 else 722 snprintf(enchandle, 5, "%04d", le16toh(exp0->EnclosureHandle)); 723 if (exp0->ParentDevHandle == 0x0) 724 snprintf(parent, 5, " "); 725 else 726 snprintf(parent, 5, "%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, 3, " "); 750 snprintf(rhandle, 5, " "); 751 } else { 752 speed = get_device_speed( 753 exp1->NegotiatedLinkRate); 754 snprintf(rphy, 3, "%02d", 755 exp1->AttachedPhyIdentifier); 756 snprintf(rhandle, 5, "%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