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