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