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->PhyNum < nphys) { 581 phydata = &sas0->PhyData[device->PhyNum]; 582 speed = get_device_speed(phydata->NegotiatedLinkRate); 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