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