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