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 * Copyright 2019, Joyent, Inc. 26 */ 27 #include <sys/types.h> 28 #include <sys/scsi/generic/smp_frames.h> 29 #include <sys/scsi/generic/commands.h> 30 #include <sys/scsi/impl/commands.h> 31 #include <sys/ccompile.h> 32 #include <sys/byteorder.h> 33 34 #include <stdarg.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <errno.h> 40 #include <strings.h> 41 #include <ctype.h> 42 43 #include <scsi/libsmp.h> 44 #include <scsi/libsmp_plugin.h> 45 46 static char *yes = "Yes"; 47 static char *no = "No"; 48 49 static void fatal(int, const char *, ...) __NORETURN; 50 51 static smp_target_t *tp = NULL; 52 static smp_action_t *ap = NULL; 53 static smp_function_t func; 54 static smp_result_t result; 55 static smp_target_def_t tdef; 56 static uint8_t *smp_resp; 57 static size_t smp_resp_len; 58 59 static void 60 fatal(int err, const char *fmt, ...) 61 { 62 va_list ap; 63 64 va_start(ap, fmt); 65 (void) vfprintf(stderr, fmt, ap); 66 va_end(ap); 67 68 (void) fprintf(stderr, "\n"); 69 (void) fflush(stderr); 70 71 _exit(err); 72 } 73 74 /* 75 * Print out a buffer of SMP character array data. The data in str is guaranteed 76 * to be at most len bytes long. While it is supposed to be ascii, we should not 77 * assume as such. 78 */ 79 static void 80 smp_print_ascii(const char *header, const char *str, size_t len) 81 { 82 size_t i, last = len; 83 84 while (last > 0 && str[last - 1] == ' ') 85 last--; 86 87 (void) printf("%s: ", header); 88 for (i = 0; i < last; i++) { 89 if (isascii(str[i]) != 0 && isalnum(str[i]) != 0) { 90 (void) putchar(str[i]); 91 } else { 92 (void) printf("\\x%x", str[i]); 93 } 94 } 95 96 (void) putchar('\n'); 97 } 98 99 static char * 100 smp_get_result(smp_result_t result) 101 { 102 switch (result) { 103 case SMP_RES_FUNCTION_ACCEPTED: 104 return ("Function accepted"); 105 break; 106 case SMP_RES_UNKNOWN_FUNCTION: 107 return ("Unknown function"); 108 break; 109 case SMP_RES_FUNCTION_FAILED: 110 return ("Function failed"); 111 break; 112 case SMP_RES_INVALID_REQUEST_FRAME_LENGTH: 113 return ("Invalid request frame length"); 114 break; 115 case SMP_RES_INVALID_EXPANDER_CHANGE_COUNT: 116 return ("Invalid expander change count"); 117 break; 118 case SMP_RES_BUSY: 119 return ("Busy"); 120 break; 121 case SMP_RES_INCOMPLETE_DESCRIPTOR_LIST: 122 return ("Incomplete descriptor list"); 123 break; 124 case SMP_RES_PHY_DOES_NOT_EXIST: 125 return ("PHY does not exist"); 126 break; 127 case SMP_RES_INDEX_DOES_NOT_EXIST: 128 return ("Index does not exist"); 129 break; 130 case SMP_RES_PHY_DOES_NOT_SUPPORT_SATA: 131 return ("PHY does not support SATA"); 132 break; 133 case SMP_RES_UNKNOWN_PHY_OPERATION: 134 return ("Unknown PHY operation"); 135 break; 136 case SMP_RES_UNKNOWN_PHY_TEST_FUNCTION: 137 return ("Unknown PHY test function"); 138 break; 139 case SMP_RES_PHY_TEST_IN_PROGRESS: 140 return ("PHY test in progress"); 141 break; 142 case SMP_RES_PHY_VACANT: 143 return ("PHY vacant"); 144 break; 145 case SMP_RES_UNKNOWN_PHY_EVENT_SOURCE: 146 return ("Unknown PHY event source"); 147 break; 148 case SMP_RES_UNKNOWN_DESCRIPTOR_TYPE: 149 return ("Unknown descriptor type"); 150 break; 151 case SMP_RES_UNKNOWN_PHY_FILTER: 152 return ("Unknown PHY filter"); 153 break; 154 case SMP_RES_AFFILIATION_VIOLATION: 155 return ("Affiliation violation"); 156 break; 157 case SMP_RES_ZONE_VIOLATION: 158 return ("Zone violation"); 159 break; 160 case SMP_RES_NO_MANAGEMENT_ACCESS_RIGHTS: 161 return ("No management access rights"); 162 break; 163 case SMP_RES_UNKNOWN_ENABLE_DISABLE_ZONING: 164 return ("Unknown enable/disable zoning value"); 165 break; 166 case SMP_RES_ZONE_LOCK_VIOLATION: 167 return ("Zone lock violation"); 168 break; 169 case SMP_RES_NOT_ACTIVATED: 170 return ("Not activated"); 171 break; 172 case SMP_RES_ZONE_GROUP_OUT_OF_RANGE: 173 return ("Zone group out of range"); 174 break; 175 case SMP_RES_NO_PHYSICAL_PRESENCE: 176 return ("No physical presence"); 177 break; 178 case SMP_RES_SAVING_NOT_SUPPORTED: 179 return ("Saving not supported"); 180 break; 181 case SMP_RES_SOURCE_ZONE_GROUP_DNE: 182 return ("Source zone group does not exist"); 183 break; 184 case SMP_RES_DISABLED_PW_NOT_SUPPORTED: 185 return ("Disabled password not supported"); 186 break; 187 default: 188 break; 189 } 190 191 return (NULL); 192 } 193 194 static void 195 smp_execute() 196 { 197 if (smp_exec(ap, tp) != 0) { 198 smp_close(tp); 199 smp_action_free(ap); 200 smp_fini(); 201 fatal(-4, "exec failed: %s", smp_errmsg()); 202 } 203 } 204 205 static void 206 smp_cmd_failed(smp_result_t result) 207 { 208 char *smp_result_str = smp_get_result(result); 209 210 if (smp_result_str == NULL) { 211 fatal(-5, "Command failed: Unknown result (0x%x)", 212 result); 213 } else { 214 fatal(-5, "Command failed: %s", smp_result_str); 215 } 216 } 217 218 static void 219 smp_get_response(boolean_t close_on_fail) 220 { 221 smp_action_get_response(ap, &result, (void **)&smp_resp, &smp_resp_len); 222 223 if (close_on_fail && (result != SMP_RES_FUNCTION_ACCEPTED)) { 224 smp_close(tp); 225 smp_action_free(ap); 226 smp_fini(); 227 smp_cmd_failed(result); 228 } 229 } 230 231 static void 232 smp_cleanup() 233 { 234 if (tp) { 235 smp_close(tp); 236 tp = NULL; 237 } 238 smp_action_free(ap); 239 smp_fini(); 240 } 241 242 /* ARGSUSED */ 243 static void 244 smp_handle_report_route_info(int argc, char *argv[]) 245 { 246 smp_report_route_info_req_t *rp; 247 smp_report_route_info_resp_t *rirp; 248 uint16_t route_indexes = smp_target_get_exp_route_indexes(tp); 249 uint8_t num_phys = smp_target_get_number_of_phys(tp); 250 uint16_t rt_idx_req, ri_idx, ri_end; 251 uint8_t phy_id_req, pi_idx, pi_end; 252 boolean_t enabled_entries = B_FALSE; 253 254 /* 255 * Verify the expander supports the PHY-based expander route table 256 */ 257 if (route_indexes == 0) { 258 smp_cleanup(); 259 fatal(-6, "Expander does not support PHY-based route table\n"); 260 } 261 262 rt_idx_req = strtol(argv[3], NULL, 0); 263 phy_id_req = strtol(argv[4], NULL, 0); 264 265 if (((int16_t)rt_idx_req == -1) && ((int8_t)phy_id_req == -1)) { 266 ri_idx = 0; 267 ri_end = route_indexes - 1; 268 pi_idx = 0; 269 pi_end = num_phys - 1; 270 } else if (((int16_t)rt_idx_req < 0) || (rt_idx_req >= route_indexes) || 271 ((int8_t)phy_id_req < 0) || (phy_id_req >= num_phys)) { 272 smp_cleanup(); 273 fatal(-1, "Invalid route index (%d) or PHY ID (%d)\n", 274 rt_idx_req, phy_id_req); 275 } else { 276 ri_end = ri_idx = rt_idx_req; 277 pi_end = pi_idx = phy_id_req; 278 } 279 280 (void) printf("%6s %6s %3s %14s\n", 281 "RT Idx", "PHY ID", "DIS", "Routed SASAddr"); 282 283 smp_action_get_request(ap, (void **)&rp, NULL); 284 285 while (ri_idx <= ri_end) { 286 while (pi_idx <= pi_end) { 287 rp->srrir_phy_identifier = pi_idx; 288 rp->srrir_exp_route_index = ri_idx; 289 290 smp_execute(); 291 smp_get_response(B_FALSE); 292 293 if (result != SMP_RES_FUNCTION_ACCEPTED) { 294 pi_idx++; 295 continue; 296 } 297 298 rirp = (smp_report_route_info_resp_t *)smp_resp; 299 300 if (rirp->srrir_exp_route_entry_disabled == 0) { 301 enabled_entries = B_TRUE; 302 (void) printf("%6d %6d %3d %016llx\n", 303 rirp->srrir_exp_route_index, 304 rirp->srrir_phy_identifier, 305 rirp->srrir_exp_route_entry_disabled, 306 BE_64(rirp->srrir_routed_sas_addr)); 307 } 308 309 pi_idx++; 310 } 311 312 ri_idx++; 313 pi_idx = 0; 314 } 315 316 if (!enabled_entries) { 317 (void) printf("No enabled entries in the table.\n"); 318 } 319 320 smp_cleanup(); 321 exit(0); 322 } 323 324 static char * 325 smp_phy_event_src_str(smp_phy_event_source_t src, boolean_t *peak_detector) 326 { 327 char *src_str; 328 329 *peak_detector = B_FALSE; 330 331 switch (src) { 332 case SMP_PHY_EVENT_NO_EVENT: 333 src_str = "No event"; 334 break; 335 case SMP_PHY_EVENT_INVALID_DWORD_COUNT: 336 src_str = "Invalid DWORD count"; 337 break; 338 case SMP_PHY_EVENT_RUNNING_DISPARITY_ERROR_COUNT: 339 src_str = "Running disparity error count"; 340 break; 341 case SMP_PHY_EVENT_LOSS_OF_DWORD_SYNC_COUNT: 342 src_str = "Loss of DWORD sync count"; 343 break; 344 case SMP_PHY_EVENT_PHY_RESET_PROBLEM_COUNT: 345 src_str = "PHY reset problem count"; 346 break; 347 case SMP_PHY_EVENT_ELASTICITY_BUFFER_OVERFLOW_COUNT: 348 src_str = "Elasticity buffer overflow count"; 349 break; 350 case SMP_PHY_EVENT_RX_ERROR_COUNT: 351 src_str = "Received ERROR count"; 352 break; 353 case SMP_PHY_EVENT_RX_ADDR_FRAME_ERROR_COUNT: 354 src_str = "Received address frame error count"; 355 break; 356 case SMP_PHY_EVENT_TX_ABANDON_CLASS_OPEN_REJ_COUNT: 357 src_str = "Transmitted abandon-class OPEN_REJECT count"; 358 break; 359 case SMP_PHY_EVENT_RX_ABANDON_CLASS_OPEN_REJ_COUNT: 360 src_str = "Received abandon-class OPEN_REJECT count"; 361 break; 362 case SMP_PHY_EVENT_TX_RETRY_CLASS_OPEN_REJ_COUNT: 363 src_str = "Transmitted retry-class OPEN_REJECT count"; 364 break; 365 case SMP_PHY_EVENT_RX_RETRY_CLASS_OPEN_REJ_COUNT: 366 src_str = "Received retry-class OPEN_REJECT count"; 367 break; 368 case SMP_PHY_EVENT_RX_AIP_W_O_PARTIAL_COUNT: 369 src_str = "Received AIP (WAITING ON PARTIAL) count"; 370 break; 371 case SMP_PHY_EVENT_RX_AIP_W_O_CONN_COUNT: 372 src_str = "Received AIP (WAITING ON CONNECTION) count"; 373 break; 374 case SMP_PHY_EVENT_TX_BREAK_COUNT: 375 src_str = "Transmitted BREAK count"; 376 break; 377 case SMP_PHY_EVENT_RX_BREAK_COUNT: 378 src_str = "Received BREAK count"; 379 break; 380 case SMP_PHY_EVENT_BREAK_TIMEOUT_COUNT: 381 src_str = "BREAK timeout count"; 382 break; 383 case SMP_PHY_EVENT_CONNECTION_COUNT: 384 src_str = "Connection count"; 385 break; 386 case SMP_PHY_EVENT_PEAK_TX_PATHWAY_BLOCKED_COUNT: 387 src_str = "Peak transmitted pathway blocked count"; 388 *peak_detector = B_TRUE; 389 break; 390 case SMP_PHY_EVENT_PEAK_TX_ARB_WAIT_TIME: 391 src_str = "Peak transmitted arbitration wait time"; 392 *peak_detector = B_TRUE; 393 break; 394 case SMP_PHY_EVENT_PEAK_ARB_TIME: 395 src_str = "Peak arbitration time"; 396 *peak_detector = B_TRUE; 397 break; 398 case SMP_PHY_EVENT_PEAK_CONNECTION_TIME: 399 src_str = "Peak connection time"; 400 *peak_detector = B_TRUE; 401 break; 402 case SMP_PHY_EVENT_TX_SSP_FRAME_COUNT: 403 src_str = "Transmitted SSP frame count"; 404 break; 405 case SMP_PHY_EVENT_RX_SSP_FRAME_COUNT: 406 src_str = "Received SSP frame count"; 407 break; 408 case SMP_PHY_EVENT_TX_SSP_FRAME_ERROR_COUNT: 409 src_str = "Transmitted SSP frame error count"; 410 break; 411 case SMP_PHY_EVENT_RX_SSP_FRAME_ERROR_COUNT: 412 src_str = "Received SSP frame error count"; 413 break; 414 case SMP_PHY_EVENT_TX_CREDIT_BLOCKED_COUNT: 415 src_str = "Transmitted CREDIT_BLOCKED count"; 416 break; 417 case SMP_PHY_EVENT_RX_CREDIT_BLOCKED_COUNT: 418 src_str = "Received CREDIT_BLOCKED count"; 419 break; 420 case SMP_PHY_EVENT_TX_SATA_FRAME_COUNT: 421 src_str = "Transmitted SATA frame count"; 422 break; 423 case SMP_PHY_EVENT_RX_SATA_FRAME_COUNT: 424 src_str = "Received SATA frame count"; 425 break; 426 case SMP_PHY_EVENT_SATA_FLOW_CTRL_BUF_OVERFLOW_COUNT: 427 src_str = "SATA flow control buffer overflow count"; 428 break; 429 case SMP_PHY_EVENT_TX_SMP_FRAME_COUNT: 430 src_str = "Transmitted SMP frame count"; 431 break; 432 case SMP_PHY_EVENT_RX_SMP_FRAME_COUNT: 433 src_str = "Received SMP frame count"; 434 break; 435 case SMP_PHY_EVENT_RX_SMP_FRAME_ERROR_COUNT: 436 src_str = "Received SMP frame error count"; 437 break; 438 default: 439 src_str = "<Unknown>"; 440 break; 441 } 442 443 return (src_str); 444 } 445 446 static void 447 smp_validate_args(int argc, char *argv[]) 448 { 449 errno = 0; 450 451 if (argc < 3) 452 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 453 454 func = strtoul(argv[2], NULL, 0); 455 456 if (errno != 0) 457 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 458 459 switch (func) { 460 case SMP_FUNC_REPORT_GENERAL: 461 case SMP_FUNC_REPORT_MANUFACTURER_INFO: 462 if (argc != 3) { 463 fatal(-1, "Usage: %s <device> 0x%x\n", argv[0], func); 464 } 465 break; 466 case SMP_FUNC_DISCOVER: 467 case SMP_FUNC_REPORT_PHY_EVENT: 468 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 469 if (argc != 4) { 470 fatal(-1, 471 "Usage: %s <device> 0x%x <phy identifier>\n", 472 argv[0], func); 473 } 474 break; 475 } 476 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 477 if (argc < 4) { 478 fatal(-1, 479 "Usage: %s <device> 0x%x <SAS Address Index>\n", 480 argv[0], func); 481 } 482 break; 483 } 484 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 485 if (argc < 4) { 486 fatal(-1, 487 "Usage: %s <device> 0x%x <report type>\n", 488 argv[0], func); 489 } 490 break; 491 } 492 case SMP_FUNC_ENABLE_DISABLE_ZONING: { 493 if (argc != 4) { 494 fatal(-1, 495 "Usage: %s <device> 0x%x " 496 "[0(no change) | 1(enable)| 2(disable)]\n", 497 argv[0], func); 498 } 499 break; 500 } 501 case SMP_FUNC_REPORT_BROADCAST: { 502 if (argc != 4) { 503 fatal(-1, "Usage: %s <device> 0x%x <bcast type>\n", 504 argv[0], func); 505 } 506 break; 507 } 508 case SMP_FUNC_REPORT_ROUTE_INFO: { 509 if (argc != 5) { 510 fatal(-1, 511 "Usage: %s <device> 0x%x <exp_route_idx> " 512 "<phy_identifier>\n", argv[0], func); 513 } 514 break; 515 } 516 case SMP_FUNC_PHY_CONTROL: { 517 if (argc != 5) { 518 fatal(-1, 519 "Usage: %s <device> 0x%x <phy identifier> " 520 " <phy operation>\n", 521 argv[0], func); 522 } 523 break; 524 } 525 default: { 526 fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]); 527 break; 528 } 529 } 530 } 531 532 int 533 main(int argc, char *argv[]) 534 { 535 uint_t i, j; 536 char *yesorno; 537 uint16_t exp_change_count; 538 539 /* 540 * If the arguments are invalid, this function will not return. 541 */ 542 smp_validate_args(argc, argv); 543 544 if (smp_init(LIBSMP_VERSION) != 0) 545 fatal(-1, "libsmp initialization failed: %s", smp_errmsg()); 546 547 bzero(&tdef, sizeof (smp_target_def_t)); 548 tdef.std_def = argv[1]; 549 550 if ((tp = smp_open(&tdef)) == NULL) { 551 smp_fini(); 552 fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg()); 553 } 554 555 exp_change_count = smp_target_get_change_count(tp); 556 557 (void) printf("%s\n", argv[0]); 558 (void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp)); 559 (void) printf("\tVendor/Product/Revision: %s/%s/%s\n", 560 smp_target_vendor(tp), smp_target_product(tp), 561 smp_target_revision(tp)); 562 (void) printf("\tExp Vendor/ID/Rev: %s/%04x/%02x\n", 563 smp_target_component_vendor(tp), smp_target_component_id(tp), 564 smp_target_component_revision(tp)); 565 (void) printf("\tExpander change count: 0x%04x\n", exp_change_count); 566 567 ap = smp_action_alloc(func, tp, 0); 568 if (ap == NULL) { 569 smp_close(tp); 570 smp_fini(); 571 fatal(-3, "failed to allocate action: %s", smp_errmsg()); 572 } 573 574 switch (func) { 575 case SMP_FUNC_REPORT_GENERAL: 576 case SMP_FUNC_REPORT_MANUFACTURER_INFO: 577 /* 578 * These functions have no additional request bytes. therefore 579 * there is nothing for us to get and fill in here. 580 */ 581 break; 582 case SMP_FUNC_DISCOVER: { 583 smp_discover_req_t *dp; 584 585 smp_action_get_request(ap, (void **)&dp, NULL); 586 dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0); 587 break; 588 } 589 case SMP_FUNC_REPORT_ROUTE_INFO: { 590 smp_handle_report_route_info(argc, argv); 591 break; 592 } 593 case SMP_FUNC_ENABLE_DISABLE_ZONING: { 594 smp_enable_disable_zoning_req_t *rp; 595 596 smp_action_get_request(ap, (void **)&rp, NULL); 597 rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0); 598 break; 599 } 600 case SMP_FUNC_PHY_CONTROL: { 601 smp_phy_control_req_t *rp; 602 603 smp_action_get_request(ap, (void **)&rp, NULL); 604 rp->spcr_phy_identifier = strtoul(argv[3], NULL, 0); 605 rp->spcr_phy_operation = strtoul(argv[4], NULL, 0); 606 break; 607 } 608 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 609 smp_report_exp_route_table_list_req_t *rp; 610 611 smp_action_get_request(ap, (void **)&rp, NULL); 612 SCSI_WRITE16(&rp->srertlr_max_descrs, 64); 613 SCSI_WRITE16(&rp->srertlr_starting_routed_sas_addr_index, 614 strtoull(argv[3], NULL, 0)); 615 rp->srertlr_starting_phy_identifier = 0; 616 break; 617 } 618 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 619 smp_report_phy_error_log_req_t *pelp; 620 621 smp_action_get_request(ap, (void **)&pelp, NULL); 622 pelp->srpelr_phy_identifier = strtoul(argv[3], NULL, 0); 623 break; 624 } 625 case SMP_FUNC_REPORT_PHY_EVENT: { 626 smp_report_phy_event_req_t *rpep; 627 628 smp_action_get_request(ap, (void **)&rpep, NULL); 629 rpep->srper_phy_identifier = strtoul(argv[3], NULL, 0); 630 break; 631 } 632 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 633 smp_report_zone_mgr_password_req_t *rzmprp; 634 635 smp_action_get_request(ap, (void **)&rzmprp, NULL); 636 rzmprp->srzmpr_rpt_type = strtoul(argv[3], NULL, 0); 637 break; 638 } 639 case SMP_FUNC_REPORT_BROADCAST: { 640 smp_report_broadcast_req_t *rbrp; 641 642 smp_action_get_request(ap, (void **)&rbrp, NULL); 643 rbrp->srbr_broadcast_type = strtoul(argv[3], NULL, 0); 644 break; 645 } 646 default: 647 smp_close(tp); 648 smp_action_free(ap); 649 smp_fini(); 650 smp_cmd_failed(result); 651 } 652 653 smp_execute(); 654 smp_get_response(B_TRUE); 655 656 switch (func) { 657 case SMP_FUNC_REPORT_GENERAL: { 658 smp_report_general_resp_t *gr = 659 (smp_report_general_resp_t *)smp_resp; 660 661 (void) printf("Expander Route Indexes: %u\n", 662 SCSI_READ16(&gr->srgr_exp_route_indexes)); 663 (void) printf("Long Responses: %s\n", 664 gr->srgr_long_response != 0 ? "Supported" : "Unsupported"); 665 (void) printf("Phys: %d\n", gr->srgr_number_of_phys); 666 (void) printf("Features:\n"); 667 if (gr->srgr_externally_configurable_route_table != 0) { 668 (void) printf("\tExternally Configurable Route " 669 "Table\n"); 670 } 671 if (gr->srgr_configuring != 0) { 672 (void) printf("\tConfiguring\n"); 673 } 674 if (gr->srgr_configures_others != 0) { 675 (void) printf("\tConfigures Others\n"); 676 } 677 if (gr->srgr_open_reject_retry_supported != 0) { 678 (void) printf("\tOpen Reject Retry\n"); 679 } 680 if (gr->srgr_stp_continue_awt != 0) { 681 (void) printf("\tSTP Continue AWT\n"); 682 } 683 if (gr->srgr_table_to_table_supported != 0) { 684 (void) printf("\tTable to Table\n"); 685 } 686 687 (void) printf("Logical Identify: %016llx\n", 688 SCSI_READ64(&gr->srgr_enclosure_logical_identifier)); 689 690 (void) printf("STP Bus Inactivity Time Limit: %u us\n", 691 SCSI_READ16(&gr->srgr_stp_bus_inactivity_time_limit) * 100); 692 (void) printf("STP Maximum Connect Time Limit: %u us\n", 693 SCSI_READ16(&gr->srgr_stp_maximum_connect_time_limit) * 694 100); 695 (void) printf("STP SMP I_T Nexus Loss Time: "); 696 if (gr->srgr_stp_smp_nexus_loss_time == 0) { 697 (void) printf("Vendor Specific\n"); 698 } else if (gr->srgr_stp_smp_nexus_loss_time == UINT16_MAX) { 699 (void) printf("Retries Forever\n"); 700 } else { 701 (void) printf("%u ms\n", 702 SCSI_READ16(&gr->srgr_stp_smp_nexus_loss_time)); 703 } 704 705 (void) printf("Physical Presence: %s, %s\n", 706 gr->srgr_physical_presence_supported ? "Supported" : 707 "Unsupported", 708 gr->srgr_physical_presence_asserted ? "Enabled" : 709 "Disabled"); 710 711 (void) printf("Zoning:\n"); 712 if (gr->srgr_zoning_supported != 0) { 713 (void) printf("\tSupported\n"); 714 } else { 715 (void) printf("\tUnsupported\n"); 716 } 717 if (gr->srgr_zoning_enabled != 0) { 718 (void) printf("\tEnabled\n"); 719 } else { 720 (void) printf("\tDisabled\n"); 721 } 722 if (gr->srgr_zone_locked != 0) { 723 (void) printf("\tLocked\n"); 724 } else { 725 (void) printf("\tUnlocked\n"); 726 } 727 if (gr->srgr_saving_zoning_enabled_supported != 0) { 728 (void) printf("\tSaving Zoning Enabled Supported\n"); 729 } 730 if (gr->srgr_saving_zone_perm_table_supported != 0) { 731 (void) printf("\tSaving Zone Perm Table Supported\n"); 732 } 733 if (gr->srgr_saving_zone_phy_info_supported != 0) { 734 (void) printf("\tSaving Zone Phy Info Supported\n"); 735 } 736 if (gr->srgr_saving != 0) { 737 (void) printf("\tSaving\n"); 738 } 739 (void) printf("\tActive Zone Manager SAS Address: %016llx\n", 740 SCSI_READ64(&gr->srgr_active_zm_sas_addr)); 741 (void) printf("\tZone Lock Inactivity Limit: %u ms\n", 742 SCSI_READ16(&gr->srgr_zone_lock_inactivity_limit) * 100); 743 744 (void) printf("Maximum Routed SAS Addresses: %u\n", 745 SCSI_READ16(&gr->srgr_max_routed_sas_addrs)); 746 747 (void) printf("First Enclosure Connector Element Index: %u\n", 748 gr->srgr_first_encl_conn_elem_idx); 749 (void) printf("Number of Enclosure Connector Elements: %u\n", 750 gr->srgr_number_encl_conn_elem_idxs); 751 752 if (gr->srgr_reduced_functionality != 0) { 753 (void) printf("Time to Reduced Functionality: %u ms\n", 754 gr->srgr_time_to_reduced_functionality * 100); 755 } 756 (void) printf("Initial Time to Reduced Functionality: %u ms\n", 757 gr->srgr_initial_time_to_reduced_functionality * 100); 758 (void) printf("Maximum Time to Reduced Functionality: %u ms\n", 759 gr->srgr_max_reduced_functionality_time * 100); 760 (void) printf("Last Self-configuration Status Index: %u\n", 761 SCSI_READ16(&gr->srgr_last_self_conf_status_descr_idx)); 762 (void) printf("Maximum Stored Self-configuration Statuses: " 763 "%u\n", SCSI_READ16( 764 &gr->srgr_max_stored_self_config_status_descrs)); 765 (void) printf("Last Phy Event List Descriptor Index: %u\n", 766 SCSI_READ16(&gr->srgr_last_phy_event_list_descr_idx)); 767 (void) printf("Maximum Stored Phy Event List Descriptors: " 768 "%u\n", SCSI_READ16( 769 &gr->srgr_max_stored_phy_event_list_descrs)); 770 (void) printf("STP Reject to Open Limit: %u us\n", 771 SCSI_READ16(&gr->srgr_stp_reject_to_open_limit) * 10); 772 break; 773 } 774 case SMP_FUNC_REPORT_MANUFACTURER_INFO: { 775 smp_report_manufacturer_info_resp_t *mir = 776 (smp_report_manufacturer_info_resp_t *)smp_resp; 777 778 smp_print_ascii("Vendor", mir->srmir_vendor_identification, 779 sizeof (mir->srmir_vendor_identification)); 780 smp_print_ascii("Product", mir->srmir_product_identification, 781 sizeof (mir->srmir_product_identification)); 782 smp_print_ascii("Revision", mir->srmir_product_revision_level, 783 sizeof (mir->srmir_product_revision_level)); 784 /* 785 * The format of the following section was changed in the SAS 786 * 1.1 specification. If this bit is not present, it is vendor 787 * specific and therefore we don't print them. 788 */ 789 if (mir->srmir_sas_1_1_format == 0) { 790 break; 791 } 792 smp_print_ascii("Component Vendor", 793 mir->srmir_component_vendor_identification, 794 sizeof (mir->srmir_component_vendor_identification)); 795 (void) printf("Component ID: 0x%x\n", 796 SCSI_READ16(&mir->srmir_component_id)); 797 (void) printf("Component Revision: 0x%x\n", 798 mir->srmir_component_revision_level); 799 break; 800 } 801 case SMP_FUNC_DISCOVER: { 802 smp_discover_resp_t *rp = (smp_discover_resp_t *)smp_resp; 803 (void) printf("Addr: %016llx Phy: %02x\n", 804 SCSI_READ64(&rp->sdr_sas_addr), rp->sdr_phy_identifier); 805 (void) printf("Peer: %016llx Phy: %02x\n", 806 SCSI_READ64(&rp->sdr_attached_sas_addr), 807 rp->sdr_attached_phy_identifier); 808 (void) printf("Device type: %01x\n", 809 rp->sdr_attached_device_type); 810 break; 811 } 812 case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { 813 smp_report_zone_mgr_password_resp_t *rp = 814 (smp_report_zone_mgr_password_resp_t *)smp_resp; 815 char *rpt_type = NULL; 816 int idx; 817 switch (rp->srzmpr_rpt_type) { 818 case SMP_ZMP_TYPE_CURRENT: 819 rpt_type = "Current"; 820 break; 821 case SMP_ZMP_TYPE_SAVED: 822 rpt_type = "Saved"; 823 break; 824 case SMP_ZMP_TYPE_DEFAULT: 825 rpt_type = "Default"; 826 break; 827 default: 828 rpt_type = "(Unknown Type)"; 829 break; 830 } 831 (void) printf("%s zone manager password: 0x", rpt_type); 832 for (idx = 0; idx < 32; idx++) { 833 (void) printf("%02x", 834 rp->srzmpr_zone_mgr_password[idx]); 835 } 836 (void) printf("\n"); 837 break; 838 } 839 case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { 840 smp_report_exp_route_table_list_resp_t *rtlr = 841 (smp_report_exp_route_table_list_resp_t *)smp_resp; 842 smp_route_table_descr_t *descp = &rtlr->srertlr_descrs[0]; 843 int idx, idxx, ndescrs, zoning, startnum; 844 845 (void) printf("Expander change count: 0x%04x\n", 846 BE_16(rtlr->srertlr_exp_change_count)); 847 (void) printf("Expander route table change count: 0x%04x\n", 848 BE_16(rtlr->srertlr_route_table_change_count)); 849 850 if (rtlr->srertlr_zoning_enabled) { 851 yesorno = yes; 852 zoning = 1; 853 } else { 854 yesorno = no; 855 zoning = 0; 856 } 857 (void) printf("Zoning enabled: %s\n", yesorno); 858 859 if (rtlr->srertlr_configuring) { 860 yesorno = yes; 861 } else { 862 yesorno = no; 863 } 864 (void) printf("Configuring: %s\n", yesorno); 865 866 ndescrs = rtlr->srertlr_n_descrs; 867 (void) printf("Number of descriptors: %d\n", ndescrs); 868 startnum = BE_16(rtlr->srertlr_first_routed_sas_addr_index); 869 (void) printf("First/Last routed SAS address index: %d/%d\n", 870 startnum, BE_16(rtlr->srertlr_last_routed_sas_addr_index)); 871 (void) printf("Starting PHY identifier: %d\n", 872 rtlr->srertlr_starting_phy_identifier); 873 874 for (idx = 0; idx < ndescrs; idx++, descp++) { 875 (void) printf("#%03d: Routed SAS addr: %016llx ", 876 idx + startnum, BE_64(descp->srtd_routed_sas_addr)); 877 (void) printf("PHY bitmap: 0x"); 878 for (idxx = 0; idxx < 6; idxx++) { 879 (void) printf("%02x", 880 descp->srtd_phy_bitmap[idxx]); 881 } 882 (void) printf("\n"); 883 if (zoning) { 884 (void) printf("\tZone group: %d\n", 885 descp->srtd_zone_group); 886 } 887 } 888 889 (void) printf("\n"); 890 break; 891 } 892 case SMP_FUNC_REPORT_PHY_ERROR_LOG: { 893 smp_report_phy_error_log_resp_t *pelr = 894 (smp_report_phy_error_log_resp_t *)smp_resp; 895 (void) printf("PHY error log for PHY %d:\n", 896 pelr->srpelr_phy_identifier); 897 (void) printf("\tInvalid DWORD count: %d\n", 898 BE_32(pelr->srpelr_invalid_dword_count)); 899 (void) printf("\tRunning disparity error count: %d\n", 900 BE_32(pelr->srpelr_running_disparity_error_count)); 901 (void) printf("\tLoss of DWORD sync count: %d\n", 902 BE_32(pelr->srpelr_loss_dword_sync_count)); 903 (void) printf("\tPHY reset problem count: %d\n", 904 BE_32(pelr->srpelr_phy_reset_problem_count)); 905 break; 906 } 907 case SMP_FUNC_REPORT_PHY_EVENT: { 908 smp_report_phy_event_resp_t *rper = 909 (smp_report_phy_event_resp_t *)smp_resp; 910 smp_phy_event_report_descr_t *perd = 911 &rper->srper_phy_event_descrs[0]; 912 boolean_t peak; 913 int idx; 914 915 (void) printf("PHY event for PHY %d:\n", 916 rper->srper_phy_identifier); 917 (void) printf("Number of PHY event descriptors: %d\n", 918 rper->srper_n_phy_event_descrs); 919 920 for (idx = 0; idx < rper->srper_n_phy_event_descrs; idx++) { 921 (void) printf("%50s : %d\n", 922 smp_phy_event_src_str(perd->sped_phy_event_source, 923 &peak), BE_32(perd->sped_phy_event)); 924 if (peak) { 925 (void) printf("\tPeak value detector " 926 "threshold: %d\n", 927 BE_32(perd->sped_peak_detector_threshold)); 928 } 929 perd++; 930 } 931 932 break; 933 } 934 case SMP_FUNC_REPORT_BROADCAST: { 935 smp_report_broadcast_resp_t *brp = 936 (smp_report_broadcast_resp_t *)smp_resp; 937 smp_broadcast_descr_t *bdp = &brp->srbr_descrs[0]; 938 uint16_t bcount, idx; 939 940 bcount = brp->srbr_number_broadcast_descrs; 941 942 (void) printf("\tNumber of broadcast descriptors: %d\n", 943 bcount); 944 (void) printf("\t%7s %5s %5s %8s\n", 945 "BCType", "PhyID", "BCRsn", "BC Count"); 946 for (idx = 0; idx < bcount; idx++) { 947 (void) printf("\t%7s %5s %5s %8s\n", 948 bdp->sbd_broadcast_type, bdp->sbd_phy_identifier, 949 bdp->sbd_broadcast_reason, 950 bdp->sbd_broadcast_count); 951 bdp++; 952 } 953 954 break; 955 } 956 default: 957 (void) printf("Response: (len %d)\n", smp_resp_len); 958 for (i = 0; i < smp_resp_len; i += 8) { 959 (void) printf("%02x: ", i); 960 for (j = i; j < i + 8; j++) 961 if (j < smp_resp_len) 962 (void) printf("%02x ", smp_resp[j]); 963 else 964 (void) printf(" "); 965 for (j = i; j < i + 8; j++) 966 (void) printf("%c", 967 j < smp_resp_len && isprint(smp_resp[j]) ? 968 smp_resp[j] : j < smp_resp_len ? '.' : 969 '\0'); 970 (void) printf("\n"); 971 } 972 break; 973 } 974 975 smp_cleanup(); 976 return (0); 977 } 978