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