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