1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 #include <sys/types.h> 26 #include <sys/scsi/generic/smp_frames.h> 27 #include <sys/scsi/generic/commands.h> 28 #include <sys/scsi/impl/commands.h> 29 #include <sys/ccompile.h> 30 #include <sys/byteorder.h> 31 32 #include <stdarg.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <errno.h> 38 #include <strings.h> 39 #include <ctype.h> 40 41 #include <scsi/libsmp.h> 42 #include <scsi/libsmp_plugin.h> 43 44 static char *yes = "Yes"; 45 static char *no = "No"; 46 47 static void fatal(int, const char *, ...) __NORETURN; 48 49 static smp_target_t *tp = NULL; 50 static smp_action_t *ap = NULL; 51 static smp_function_t func; 52 static smp_result_t result; 53 static smp_target_def_t tdef; 54 static uint8_t *smp_resp; 55 static size_t smp_resp_len; 56 57 static void 58 fatal(int err, const char *fmt, ...) 59 { 60 va_list ap; 61 62 va_start(ap, fmt); 63 (void) vfprintf(stderr, fmt, ap); 64 va_end(ap); 65 66 (void) fprintf(stderr, "\n"); 67 (void) fflush(stderr); 68 69 _exit(err); 70 } 71 72 static char * 73 smp_get_result(smp_result_t result) 74 { 75 switch (result) { 76 case SMP_RES_FUNCTION_ACCEPTED: 77 return ("Function accepted"); 78 break; 79 case SMP_RES_UNKNOWN_FUNCTION: 80 return ("Unknown function"); 81 break; 82 case SMP_RES_FUNCTION_FAILED: 83 return ("Function failed"); 84 break; 85 case SMP_RES_INVALID_REQUEST_FRAME_LENGTH: 86 return ("Invalid request frame length"); 87 break; 88 case SMP_RES_INVALID_EXPANDER_CHANGE_COUNT: 89 return ("Invalid expander change count"); 90 break; 91 case SMP_RES_BUSY: 92 return ("Busy"); 93 break; 94 case SMP_RES_INCOMPLETE_DESCRIPTOR_LIST: 95 return ("Incomplete descriptor list"); 96 break; 97 case SMP_RES_PHY_DOES_NOT_EXIST: 98 return ("PHY does not exist"); 99 break; 100 case SMP_RES_INDEX_DOES_NOT_EXIST: 101 return ("Index does not exist"); 102 break; 103 case SMP_RES_PHY_DOES_NOT_SUPPORT_SATA: 104 return ("PHY does not support SATA"); 105 break; 106 case SMP_RES_UNKNOWN_PHY_OPERATION: 107 return ("Unknown PHY operation"); 108 break; 109 case SMP_RES_UNKNOWN_PHY_TEST_FUNCTION: 110 return ("Unknown PHY test function"); 111 break; 112 case SMP_RES_PHY_TEST_IN_PROGRESS: 113 return ("PHY test in progress"); 114 break; 115 case SMP_RES_PHY_VACANT: 116 return ("PHY vacant"); 117 break; 118 case SMP_RES_UNKNOWN_PHY_EVENT_SOURCE: 119 return ("Unknown PHY event source"); 120 break; 121 case SMP_RES_UNKNOWN_DESCRIPTOR_TYPE: 122 return ("Unknown descriptor type"); 123 break; 124 case SMP_RES_UNKNOWN_PHY_FILTER: 125 return ("Unknown PHY filter"); 126 break; 127 case SMP_RES_AFFILIATION_VIOLATION: 128 return ("Affiliation violation"); 129 break; 130 case SMP_RES_ZONE_VIOLATION: 131 return ("Zone violation"); 132 break; 133 case SMP_RES_NO_MANAGEMENT_ACCESS_RIGHTS: 134 return ("No management access rights"); 135 break; 136 case SMP_RES_UNKNOWN_ENABLE_DISABLE_ZONING: 137 return ("Unknown enable/disable zoning value"); 138 break; 139 case SMP_RES_ZONE_LOCK_VIOLATION: 140 return ("Zone lock violation"); 141 break; 142 case SMP_RES_NOT_ACTIVATED: 143 return ("Not activated"); 144 break; 145 case SMP_RES_ZONE_GROUP_OUT_OF_RANGE: 146 return ("Zone group out of range"); 147 break; 148 case SMP_RES_NO_PHYSICAL_PRESENCE: 149 return ("No physical presence"); 150 break; 151 case SMP_RES_SAVING_NOT_SUPPORTED: 152 return ("Saving not supported"); 153 break; 154 case SMP_RES_SOURCE_ZONE_GROUP_DNE: 155 return ("Source zone group does not exist"); 156 break; 157 case SMP_RES_DISABLED_PW_NOT_SUPPORTED: 158 return ("Disabled password not supported"); 159 break; 160 default: 161 break; 162 } 163 164 return (NULL); 165 } 166 167 static void 168 smp_execute() 169 { 170 if (smp_exec(ap, tp) != 0) { 171 smp_close(tp); 172 smp_action_free(ap); 173 smp_fini(); 174 fatal(-4, "exec failed: %s", smp_errmsg()); 175 } 176 } 177 178 static void 179 smp_cmd_failed(smp_result_t result) 180 { 181 char *smp_result_str = smp_get_result(result); 182 183 if (result == NULL) { 184 fatal(-5, "Command failed: Unknown result (0x%x)", 185 result); 186 } else { 187 fatal(-5, "Command failed: %s", smp_result_str); 188 } 189 } 190 191 static void 192 smp_get_response(boolean_t close_on_fail) 193 { 194 smp_action_get_response(ap, &result, (void **)&smp_resp, &smp_resp_len); 195 196 if (close_on_fail && (result != SMP_RES_FUNCTION_ACCEPTED)) { 197 smp_close(tp); 198 smp_action_free(ap); 199 smp_fini(); 200 smp_cmd_failed(result); 201 } 202 } 203 204 static void 205 smp_cleanup() 206 { 207 if (tp) { 208 smp_close(tp); 209 tp = NULL; 210 } 211 smp_action_free(ap); 212 smp_fini(); 213 } 214 215 static void 216 smp_handle_report_route_info(int argc, char *argv[]) 217 { 218 smp_report_route_info_req_t *rp; 219 smp_report_route_info_resp_t *rirp; 220 uint16_t route_indexes = smp_target_get_exp_route_indexes(tp); 221 uint8_t num_phys = smp_target_get_number_of_phys(tp); 222 uint16_t rt_idx_req, ri_idx, ri_end; 223 uint8_t phy_id_req, pi_idx, pi_end; 224 boolean_t enabled_entries = B_FALSE; 225 226 /* 227 * Verify the expander supports the PHY-based expander route table 228 */ 229 if (route_indexes == 0) { 230 smp_cleanup(); 231 fatal(-6, "Expander does not support PHY-based route table\n"); 232 } 233 234 rt_idx_req = strtol(argv[3], NULL, 0); 235 phy_id_req = strtol(argv[4], NULL, 0); 236 237 if (((int16_t)rt_idx_req == -1) && ((int8_t)phy_id_req == -1)) { 238 ri_idx = 0; 239 ri_end = route_indexes - 1; 240 pi_idx = 0; 241 pi_end = num_phys - 1; 242 } else if (((int16_t)rt_idx_req < 0) || (rt_idx_req >= route_indexes) || 243 ((int8_t)phy_id_req < 0) || (phy_id_req >= num_phys)) { 244 smp_cleanup(); 245 fatal(-1, "Invalid route index (%d) or PHY ID (%d)\n", 246 rt_idx_req, phy_id_req); 247 } else { 248 ri_end = ri_idx = rt_idx_req; 249 pi_end = pi_idx = phy_id_req; 250 } 251 252 (void) printf("%6s %6s %3s %14s\n", 253 "RT Idx", "PHY ID", "DIS", "Routed SASAddr"); 254 255 smp_action_get_request(ap, (void **)&rp, NULL); 256 257 while (ri_idx <= ri_end) { 258 while (pi_idx <= pi_end) { 259 rp->srrir_phy_identifier = pi_idx; 260 rp->srrir_exp_route_index = ri_idx; 261 262 smp_execute(); 263 smp_get_response(B_FALSE); 264 265 if (result != SMP_RES_FUNCTION_ACCEPTED) { 266 pi_idx++; 267 continue; 268 } 269 270 rirp = (smp_report_route_info_resp_t *)smp_resp; 271 272 if (rirp->srrir_exp_route_entry_disabled == 0) { 273 enabled_entries = B_TRUE; 274 (void) printf("%6d %6d %3d %016llx\n", 275 rirp->srrir_exp_route_index, 276 rirp->srrir_phy_identifier, 277 rirp->srrir_exp_route_entry_disabled, 278 BE_64(rirp->srrir_routed_sas_addr)); 279 } 280 281 pi_idx++; 282 } 283 284 ri_idx++; 285 pi_idx = 0; 286 } 287 288 if (!enabled_entries) { 289 (void) printf("No enabled entries in the table.\n"); 290 } 291 292 smp_cleanup(); 293 exit(0); 294 } 295 296 static char * 297 smp_phy_event_src_str(smp_phy_event_source_t src, boolean_t *peak_detector) 298 { 299 char *src_str; 300 301 *peak_detector = B_FALSE; 302 303 switch (src) { 304 case SMP_PHY_EVENT_NO_EVENT: 305 src_str = "No event"; 306 break; 307 case SMP_PHY_EVENT_INVALID_DWORD_COUNT: 308 src_str = "Invalid DWORD count"; 309 break; 310 case SMP_PHY_EVENT_RUNNING_DISPARITY_ERROR_COUNT: 311 src_str = "Running disparity error count"; 312 break; 313 case SMP_PHY_EVENT_LOSS_OF_DWORD_SYNC_COUNT: 314 src_str = "Loss of DWORD sync count"; 315 break; 316 case SMP_PHY_EVENT_PHY_RESET_PROBLEM_COUNT: 317 src_str = "PHY reset problem count"; 318 break; 319 case SMP_PHY_EVENT_ELASTICITY_BUFFER_OVERFLOW_COUNT: 320 src_str = "Elasticity buffer overflow count"; 321 break; 322 case SMP_PHY_EVENT_RX_ERROR_COUNT: 323 src_str = "Received ERROR count"; 324 break; 325 case SMP_PHY_EVENT_RX_ADDR_FRAME_ERROR_COUNT: 326 src_str = "Received address frame error count"; 327 break; 328 case SMP_PHY_EVENT_TX_ABANDON_CLASS_OPEN_REJ_COUNT: 329 src_str = "Transmitted abandon-class OPEN_REJECT count"; 330 break; 331 case SMP_PHY_EVENT_RX_ABANDON_CLASS_OPEN_REJ_COUNT: 332 src_str = "Received abandon-class OPEN_REJECT count"; 333 break; 334 case SMP_PHY_EVENT_TX_RETRY_CLASS_OPEN_REJ_COUNT: 335 src_str = "Transmitted retry-class OPEN_REJECT count"; 336 break; 337 case SMP_PHY_EVENT_RX_RETRY_CLASS_OPEN_REJ_COUNT: 338 src_str = "Received retry-class OPEN_REJECT count"; 339 break; 340 case SMP_PHY_EVENT_RX_AIP_W_O_PARTIAL_COUNT: 341 src_str = "Received AIP (WAITING ON PARTIAL) count"; 342 break; 343 case SMP_PHY_EVENT_RX_AIP_W_O_CONN_COUNT: 344 src_str = "Received AIP (WAITING ON CONNECTION) count"; 345 break; 346 case SMP_PHY_EVENT_TX_BREAK_COUNT: 347 src_str = "Transmitted BREAK count"; 348 break; 349 case SMP_PHY_EVENT_RX_BREAK_COUNT: 350 src_str = "Received BREAK count"; 351 break; 352 case SMP_PHY_EVENT_BREAK_TIMEOUT_COUNT: 353 src_str = "BREAK timeout count"; 354 break; 355 case SMP_PHY_EVENT_CONNECTION_COUNT: 356 src_str = "Connection count"; 357 break; 358 case SMP_PHY_EVENT_PEAK_TX_PATHWAY_BLOCKED_COUNT: 359 src_str = "Peak transmitted pathway blocked count"; 360 *peak_detector = B_TRUE; 361 break; 362 case SMP_PHY_EVENT_PEAK_TX_ARB_WAIT_TIME: 363 src_str = "Peak transmitted arbitration wait time"; 364 *peak_detector = B_TRUE; 365 break; 366 case SMP_PHY_EVENT_PEAK_ARB_TIME: 367 src_str = "Peak arbitration time"; 368 *peak_detector = B_TRUE; 369 break; 370 case SMP_PHY_EVENT_PEAK_CONNECTION_TIME: 371 src_str = "Peak connection time"; 372 *peak_detector = B_TRUE; 373 break; 374 case SMP_PHY_EVENT_TX_SSP_FRAME_COUNT: 375 src_str = "Transmitted SSP frame count"; 376 break; 377 case SMP_PHY_EVENT_RX_SSP_FRAME_COUNT: 378 src_str = "Received SSP frame count"; 379 break; 380 case SMP_PHY_EVENT_TX_SSP_FRAME_ERROR_COUNT: 381 src_str = "Transmitted SSP frame error count"; 382 break; 383 case SMP_PHY_EVENT_RX_SSP_FRAME_ERROR_COUNT: 384 src_str = "Received SSP frame error count"; 385 break; 386 case SMP_PHY_EVENT_TX_CREDIT_BLOCKED_COUNT: 387 src_str = "Transmitted CREDIT_BLOCKED count"; 388 break; 389 case SMP_PHY_EVENT_RX_CREDIT_BLOCKED_COUNT: 390 src_str = "Received CREDIT_BLOCKED count"; 391 break; 392 case SMP_PHY_EVENT_TX_SATA_FRAME_COUNT: 393 src_str = "Transmitted SATA frame count"; 394 break; 395 case SMP_PHY_EVENT_RX_SATA_FRAME_COUNT: 396 src_str = "Received SATA frame count"; 397 break; 398 case SMP_PHY_EVENT_SATA_FLOW_CTRL_BUF_OVERFLOW_COUNT: 399 src_str = "SATA flow control buffer overflow count"; 400 break; 401 case SMP_PHY_EVENT_TX_SMP_FRAME_COUNT: 402 src_str = "Transmitted SMP frame count"; 403 break; 404 case SMP_PHY_EVENT_RX_SMP_FRAME_COUNT: 405 src_str = "Received SMP frame count"; 406 break; 407 case SMP_PHY_EVENT_RX_SMP_FRAME_ERROR_COUNT: 408 src_str = "Received SMP frame error count"; 409 break; 410 default: 411 src_str = "<Unknown>"; 412 break; 413 } 414 415 return (src_str); 416 } 417 418 static void 419 smp_validate_args(int argc, char *argv[]) 420 { 421 errno = 0; 422 423 if (argc < 3) 424 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 425 426 func = strtoul(argv[2], NULL, 0); 427 428 if (errno != 0) 429 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 430 431 switch (func) { 432 case SMP_FUNC_DISCOVER: 433 case SMP_FUNC_REPORT_PHY_EVENT: 434 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 435 if (argc != 4) { 436 fatal(-1, 437 "Usage: %s <device> 0x%x <phy identifier>\n", 438 argv[0], func); 439 } 440 break; 441 } 442 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 443 if (argc < 4) { 444 fatal(-1, 445 "Usage: %s <device> 0x%x <SAS Address Index>\n", 446 argv[0], func); 447 } 448 break; 449 } 450 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 451 if (argc < 4) { 452 fatal(-1, 453 "Usage: %s <device> 0x%x <report type>\n", 454 argv[0], func); 455 } 456 break; 457 } 458 case SMP_FUNC_ENABLE_DISABLE_ZONING: { 459 if (argc != 4) { 460 fatal(-1, 461 "Usage: %s <device> 0x%x " 462 "[0(no change) | 1(enable)| 2(disable)]\n", 463 argv[0], func); 464 } 465 break; 466 } 467 case SMP_FUNC_REPORT_BROADCAST: { 468 if (argc != 4) { 469 fatal(-1, "Usage: %s <device> 0x%x <bcast type>\n", 470 argv[0], func); 471 } 472 break; 473 } 474 case SMP_FUNC_REPORT_ROUTE_INFO: { 475 if (argc != 5) { 476 fatal(-1, 477 "Usage: %s <device> 0x%x <exp_route_idx> " 478 "<phy_identifier>\n", argv[0], func); 479 } 480 break; 481 } 482 case SMP_FUNC_PHY_CONTROL: { 483 if (argc != 5) { 484 fatal(-1, 485 "Usage: %s <device> 0x%x <phy identifier> " 486 " <phy operation>\n", 487 argv[0], func); 488 } 489 break; 490 } 491 default: { 492 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 493 break; 494 } 495 } 496 } 497 498 int 499 main(int argc, char *argv[]) 500 { 501 uint_t i, j; 502 char *yesorno; 503 uint16_t exp_change_count; 504 505 /* 506 * If the arguments are invalid, this function will not return. 507 */ 508 smp_validate_args(argc, argv); 509 510 if (smp_init(LIBSMP_VERSION) != 0) 511 fatal(-1, "libsmp initialization failed: %s", smp_errmsg()); 512 513 bzero(&tdef, sizeof (smp_target_def_t)); 514 tdef.std_def = argv[1]; 515 516 if ((tp = smp_open(&tdef)) == NULL) { 517 smp_fini(); 518 fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg()); 519 } 520 521 exp_change_count = smp_target_get_change_count(tp); 522 523 (void) printf("%s\n", argv[0]); 524 (void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp)); 525 (void) printf("\tVendor/Product/Revision: %s/%s/%s\n", 526 smp_target_vendor(tp), smp_target_product(tp), 527 smp_target_revision(tp)); 528 (void) printf("\tExp Vendor/ID/Rev: %s/%04x/%02x\n", 529 smp_target_component_vendor(tp), smp_target_component_id(tp), 530 smp_target_component_revision(tp)); 531 (void) printf("\tExpander change count: 0x%04x\n", exp_change_count); 532 533 ap = smp_action_alloc(func, tp, 0); 534 if (ap == NULL) { 535 smp_close(tp); 536 smp_fini(); 537 fatal(-3, "failed to allocate action: %s", smp_errmsg()); 538 } 539 540 switch (func) { 541 case SMP_FUNC_DISCOVER: { 542 smp_discover_req_t *dp; 543 544 smp_action_get_request(ap, (void **)&dp, NULL); 545 dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0); 546 break; 547 } 548 case SMP_FUNC_REPORT_ROUTE_INFO: { 549 smp_handle_report_route_info(argc, argv); 550 break; 551 } 552 case SMP_FUNC_ENABLE_DISABLE_ZONING: { 553 smp_enable_disable_zoning_req_t *rp; 554 555 smp_action_get_request(ap, (void **)&rp, NULL); 556 rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0); 557 break; 558 } 559 case SMP_FUNC_PHY_CONTROL: { 560 smp_phy_control_req_t *rp; 561 562 smp_action_get_request(ap, (void **)&rp, NULL); 563 rp->spcr_phy_identifier = strtoul(argv[3], NULL, 0); 564 rp->spcr_phy_operation = strtoul(argv[4], NULL, 0); 565 break; 566 } 567 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 568 smp_report_exp_route_table_list_req_t *rp; 569 570 smp_action_get_request(ap, (void **)&rp, NULL); 571 SCSI_WRITE16(&rp->srertlr_max_descrs, 64); 572 SCSI_WRITE16(&rp->srertlr_starting_routed_sas_addr_index, 573 strtoull(argv[3], NULL, 0)); 574 rp->srertlr_starting_phy_identifier = 0; 575 break; 576 } 577 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 578 smp_report_phy_error_log_req_t *pelp; 579 580 smp_action_get_request(ap, (void **)&pelp, NULL); 581 pelp->srpelr_phy_identifier = strtoul(argv[3], NULL, 0); 582 break; 583 } 584 case SMP_FUNC_REPORT_PHY_EVENT: { 585 smp_report_phy_event_req_t *rpep; 586 587 smp_action_get_request(ap, (void **)&rpep, NULL); 588 rpep->srper_phy_identifier = strtoul(argv[3], NULL, 0); 589 break; 590 } 591 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 592 smp_report_zone_mgr_password_req_t *rzmprp; 593 594 smp_action_get_request(ap, (void **)&rzmprp, NULL); 595 rzmprp->srzmpr_rpt_type = strtoul(argv[3], NULL, 0); 596 break; 597 } 598 case SMP_FUNC_REPORT_BROADCAST: { 599 smp_report_broadcast_req_t *rbrp; 600 601 smp_action_get_request(ap, (void **)&rbrp, NULL); 602 rbrp->srbr_broadcast_type = strtoul(argv[3], NULL, 0); 603 break; 604 } 605 default: 606 smp_close(tp); 607 smp_action_free(ap); 608 smp_fini(); 609 smp_cmd_failed(result); 610 } 611 612 smp_execute(); 613 smp_get_response(B_TRUE); 614 615 switch (func) { 616 case SMP_FUNC_DISCOVER: { 617 smp_discover_resp_t *rp = (smp_discover_resp_t *)smp_resp; 618 (void) printf("Addr: %016llx Phy: %02x\n", 619 SCSI_READ64(&rp->sdr_sas_addr), rp->sdr_phy_identifier); 620 (void) printf("Peer: %016llx Phy: %02x\n", 621 SCSI_READ64(&rp->sdr_attached_sas_addr), 622 rp->sdr_attached_phy_identifier); 623 (void) printf("Device type: %01x\n", 624 rp->sdr_attached_device_type); 625 break; 626 } 627 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 628 smp_report_zone_mgr_password_resp_t *rp = 629 (smp_report_zone_mgr_password_resp_t *)smp_resp; 630 char *rpt_type = NULL; 631 int idx; 632 switch (rp->srzmpr_rpt_type) { 633 case SMP_ZMP_TYPE_CURRENT: 634 rpt_type = "Current"; 635 break; 636 case SMP_ZMP_TYPE_SAVED: 637 rpt_type = "Saved"; 638 break; 639 case SMP_ZMP_TYPE_DEFAULT: 640 rpt_type = "Default"; 641 break; 642 default: 643 rpt_type = "(Unknown Type)"; 644 break; 645 } 646 (void) printf("%s zone manager password: 0x", rpt_type); 647 for (idx = 0; idx < 32; idx++) { 648 (void) printf("%02x", 649 rp->srzmpr_zone_mgr_password[idx]); 650 } 651 (void) printf("\n"); 652 break; 653 } 654 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 655 smp_report_exp_route_table_list_resp_t *rtlr = 656 (smp_report_exp_route_table_list_resp_t *)smp_resp; 657 smp_route_table_descr_t *descp = &rtlr->srertlr_descrs[0]; 658 int idx, idxx, ndescrs, zoning, startnum; 659 660 (void) printf("Expander change count: 0x%04x\n", 661 BE_16(rtlr->srertlr_exp_change_count)); 662 (void) printf("Expander route table change count: 0x%04x\n", 663 BE_16(rtlr->srertlr_route_table_change_count)); 664 665 if (rtlr->srertlr_zoning_enabled) { 666 yesorno = yes; 667 zoning = 1; 668 } else { 669 yesorno = no; 670 zoning = 0; 671 } 672 (void) printf("Zoning enabled: %s\n", yesorno); 673 674 if (rtlr->srertlr_configuring) { 675 yesorno = yes; 676 } else { 677 yesorno = no; 678 } 679 (void) printf("Configuring: %s\n", yesorno); 680 681 ndescrs = rtlr->srertlr_n_descrs; 682 (void) printf("Number of descriptors: %d\n", ndescrs); 683 startnum = BE_16(rtlr->srertlr_first_routed_sas_addr_index); 684 (void) printf("First/Last routed SAS address index: %d/%d\n", 685 startnum, BE_16(rtlr->srertlr_last_routed_sas_addr_index)); 686 (void) printf("Starting PHY identifier: %d\n", 687 rtlr->srertlr_starting_phy_identifier); 688 689 for (idx = 0; idx < ndescrs; idx++, descp++) { 690 (void) printf("#%03d: Routed SAS addr: %016llx ", 691 idx + startnum, BE_64(descp->srtd_routed_sas_addr)); 692 (void) printf("PHY bitmap: 0x"); 693 for (idxx = 0; idxx < 6; idxx++) { 694 (void) printf("%02x", 695 descp->srtd_phy_bitmap[idxx]); 696 } 697 (void) printf("\n"); 698 if (zoning) { 699 (void) printf("\tZone group: %d\n", 700 descp->srtd_zone_group); 701 } 702 } 703 704 (void) printf("\n"); 705 break; 706 } 707 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 708 smp_report_phy_error_log_resp_t *pelr = 709 (smp_report_phy_error_log_resp_t *)smp_resp; 710 (void) printf("PHY error log for PHY %d:\n", 711 pelr->srpelr_phy_identifier); 712 (void) printf("\tInvalid DWORD count: %d\n", 713 BE_32(pelr->srpelr_invalid_dword_count)); 714 (void) printf("\tRunning disparity error count: %d\n", 715 BE_32(pelr->srpelr_running_disparity_error_count)); 716 (void) printf("\tLoss of DWORD sync count: %d\n", 717 BE_32(pelr->srpelr_loss_dword_sync_count)); 718 (void) printf("\tPHY reset problem count: %d\n", 719 BE_32(pelr->srpelr_phy_reset_problem_count)); 720 break; 721 } 722 case SMP_FUNC_REPORT_PHY_EVENT: { 723 smp_report_phy_event_resp_t *rper = 724 (smp_report_phy_event_resp_t *)smp_resp; 725 smp_phy_event_report_descr_t *perd = 726 &rper->srper_phy_event_descrs[0]; 727 boolean_t peak; 728 int idx; 729 730 (void) printf("PHY event for PHY %d:\n", 731 rper->srper_phy_identifier); 732 (void) printf("Number of PHY event descriptors: %d\n", 733 rper->srper_n_phy_event_descrs); 734 735 for (idx = 0; idx < rper->srper_n_phy_event_descrs; idx++) { 736 (void) printf("%50s : %d\n", 737 smp_phy_event_src_str(perd->sped_phy_event_source, 738 &peak), BE_32(perd->sped_phy_event)); 739 if (peak) { 740 (void) printf("\tPeak value detector " 741 "threshold: %d\n", 742 BE_32(perd->sped_peak_detector_threshold)); 743 } 744 perd++; 745 } 746 747 break; 748 } 749 case SMP_FUNC_REPORT_BROADCAST: { 750 smp_report_broadcast_resp_t *brp = 751 (smp_report_broadcast_resp_t *)smp_resp; 752 smp_broadcast_descr_t *bdp = &brp->srbr_descrs[0]; 753 uint16_t bcount, idx; 754 uint8_t bctype; 755 756 bcount = brp->srbr_number_broadcast_descrs; 757 758 (void) printf("\tNumber of broadcast descriptors: %d\n", 759 bcount); 760 (void) printf("\t%7s %5s %5s %8s\n", 761 "BCType", "PhyID", "BCRsn", "BC Count"); 762 for (idx = 0; idx < bcount; idx++) { 763 (void) printf("\t%7s %5s %5s %8s\n", 764 bdp->sbd_broadcast_type, bdp->sbd_phy_identifier, 765 bdp->sbd_broadcast_reason, 766 bdp->sbd_broadcast_count); 767 bdp++; 768 } 769 770 break; 771 } 772 default: 773 (void) printf("Response: (len %d)\n", smp_resp_len); 774 for (i = 0; i < smp_resp_len; i += 8) { 775 (void) printf("%02x: ", i); 776 for (j = i; j < i + 8; j++) 777 if (j < smp_resp_len) 778 (void) printf("%02x ", smp_resp[j]); 779 else 780 (void) printf(" "); 781 for (j = i; j < i + 8; j++) 782 (void) printf("%c", 783 j < smp_resp_len && isprint(smp_resp[j]) ? 784 smp_resp[j] : j < smp_resp_len ? '.' : 785 '\0'); 786 (void) printf("\n"); 787 } 788 break; 789 } 790 791 smp_cleanup(); 792 return (0); 793 } 794