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