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