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