/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2015 PALO, Richard * Copyright 2019, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *yes = "Yes"; static char *no = "No"; static void fatal(int, const char *, ...) __NORETURN; static smp_target_t *tp = NULL; static smp_action_t *ap = NULL; static smp_function_t func; static smp_result_t result; static smp_target_def_t tdef; static uint8_t *smp_resp; static size_t smp_resp_len; static void fatal(int err, const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); (void) fprintf(stderr, "\n"); (void) fflush(stderr); _exit(err); } /* * Print out a buffer of SMP character array data. The data in str is guaranteed * to be at most len bytes long. While it is supposed to be ascii, we should not * assume as such. */ static void smp_print_ascii(const char *header, const char *str, size_t len) { size_t i, last = len; while (last > 0 && str[last - 1] == ' ') last--; (void) printf("%s: ", header); for (i = 0; i < last; i++) { if (isascii(str[i]) != 0 && isalnum(str[i]) != 0) { (void) putchar(str[i]); } else { (void) printf("\\x%x", str[i]); } } (void) putchar('\n'); } static char * smp_get_result(smp_result_t result) { switch (result) { case SMP_RES_FUNCTION_ACCEPTED: return ("Function accepted"); break; case SMP_RES_UNKNOWN_FUNCTION: return ("Unknown function"); break; case SMP_RES_FUNCTION_FAILED: return ("Function failed"); break; case SMP_RES_INVALID_REQUEST_FRAME_LENGTH: return ("Invalid request frame length"); break; case SMP_RES_INVALID_EXPANDER_CHANGE_COUNT: return ("Invalid expander change count"); break; case SMP_RES_BUSY: return ("Busy"); break; case SMP_RES_INCOMPLETE_DESCRIPTOR_LIST: return ("Incomplete descriptor list"); break; case SMP_RES_PHY_DOES_NOT_EXIST: return ("PHY does not exist"); break; case SMP_RES_INDEX_DOES_NOT_EXIST: return ("Index does not exist"); break; case SMP_RES_PHY_DOES_NOT_SUPPORT_SATA: return ("PHY does not support SATA"); break; case SMP_RES_UNKNOWN_PHY_OPERATION: return ("Unknown PHY operation"); break; case SMP_RES_UNKNOWN_PHY_TEST_FUNCTION: return ("Unknown PHY test function"); break; case SMP_RES_PHY_TEST_IN_PROGRESS: return ("PHY test in progress"); break; case SMP_RES_PHY_VACANT: return ("PHY vacant"); break; case SMP_RES_UNKNOWN_PHY_EVENT_SOURCE: return ("Unknown PHY event source"); break; case SMP_RES_UNKNOWN_DESCRIPTOR_TYPE: return ("Unknown descriptor type"); break; case SMP_RES_UNKNOWN_PHY_FILTER: return ("Unknown PHY filter"); break; case SMP_RES_AFFILIATION_VIOLATION: return ("Affiliation violation"); break; case SMP_RES_ZONE_VIOLATION: return ("Zone violation"); break; case SMP_RES_NO_MANAGEMENT_ACCESS_RIGHTS: return ("No management access rights"); break; case SMP_RES_UNKNOWN_ENABLE_DISABLE_ZONING: return ("Unknown enable/disable zoning value"); break; case SMP_RES_ZONE_LOCK_VIOLATION: return ("Zone lock violation"); break; case SMP_RES_NOT_ACTIVATED: return ("Not activated"); break; case SMP_RES_ZONE_GROUP_OUT_OF_RANGE: return ("Zone group out of range"); break; case SMP_RES_NO_PHYSICAL_PRESENCE: return ("No physical presence"); break; case SMP_RES_SAVING_NOT_SUPPORTED: return ("Saving not supported"); break; case SMP_RES_SOURCE_ZONE_GROUP_DNE: return ("Source zone group does not exist"); break; case SMP_RES_DISABLED_PW_NOT_SUPPORTED: return ("Disabled password not supported"); break; default: break; } return (NULL); } static void smp_execute() { if (smp_exec(ap, tp) != 0) { smp_close(tp); smp_action_free(ap); smp_fini(); fatal(-4, "exec failed: %s", smp_errmsg()); } } static void smp_cmd_failed(smp_result_t result) { char *smp_result_str = smp_get_result(result); if (smp_result_str == NULL) { fatal(-5, "Command failed: Unknown result (0x%x)", result); } else { fatal(-5, "Command failed: %s", smp_result_str); } } static void smp_get_response(boolean_t close_on_fail) { smp_action_get_response(ap, &result, (void **)&smp_resp, &smp_resp_len); if (close_on_fail && (result != SMP_RES_FUNCTION_ACCEPTED)) { smp_close(tp); smp_action_free(ap); smp_fini(); smp_cmd_failed(result); } } static void smp_cleanup() { if (tp) { smp_close(tp); tp = NULL; } smp_action_free(ap); smp_fini(); } /* ARGSUSED */ static void smp_handle_report_route_info(int argc, char *argv[]) { smp_report_route_info_req_t *rp; smp_report_route_info_resp_t *rirp; uint16_t route_indexes = smp_target_get_exp_route_indexes(tp); uint8_t num_phys = smp_target_get_number_of_phys(tp); uint16_t rt_idx_req, ri_idx, ri_end; uint8_t phy_id_req, pi_idx, pi_end; boolean_t enabled_entries = B_FALSE; /* * Verify the expander supports the PHY-based expander route table */ if (route_indexes == 0) { smp_cleanup(); fatal(-6, "Expander does not support PHY-based route table\n"); } rt_idx_req = strtol(argv[3], NULL, 0); phy_id_req = strtol(argv[4], NULL, 0); if (((int16_t)rt_idx_req == -1) && ((int8_t)phy_id_req == -1)) { ri_idx = 0; ri_end = route_indexes - 1; pi_idx = 0; pi_end = num_phys - 1; } else if (((int16_t)rt_idx_req < 0) || (rt_idx_req >= route_indexes) || ((int8_t)phy_id_req < 0) || (phy_id_req >= num_phys)) { smp_cleanup(); fatal(-1, "Invalid route index (%d) or PHY ID (%d)\n", rt_idx_req, phy_id_req); } else { ri_end = ri_idx = rt_idx_req; pi_end = pi_idx = phy_id_req; } (void) printf("%6s %6s %3s %14s\n", "RT Idx", "PHY ID", "DIS", "Routed SASAddr"); smp_action_get_request(ap, (void **)&rp, NULL); while (ri_idx <= ri_end) { while (pi_idx <= pi_end) { rp->srrir_phy_identifier = pi_idx; rp->srrir_exp_route_index = ri_idx; smp_execute(); smp_get_response(B_FALSE); if (result != SMP_RES_FUNCTION_ACCEPTED) { pi_idx++; continue; } rirp = (smp_report_route_info_resp_t *)smp_resp; if (rirp->srrir_exp_route_entry_disabled == 0) { enabled_entries = B_TRUE; (void) printf("%6d %6d %3d %016llx\n", rirp->srrir_exp_route_index, rirp->srrir_phy_identifier, rirp->srrir_exp_route_entry_disabled, BE_64(rirp->srrir_routed_sas_addr)); } pi_idx++; } ri_idx++; pi_idx = 0; } if (!enabled_entries) { (void) printf("No enabled entries in the table.\n"); } smp_cleanup(); exit(0); } static char * smp_phy_event_src_str(smp_phy_event_source_t src, boolean_t *peak_detector) { char *src_str; *peak_detector = B_FALSE; switch (src) { case SMP_PHY_EVENT_NO_EVENT: src_str = "No event"; break; case SMP_PHY_EVENT_INVALID_DWORD_COUNT: src_str = "Invalid DWORD count"; break; case SMP_PHY_EVENT_RUNNING_DISPARITY_ERROR_COUNT: src_str = "Running disparity error count"; break; case SMP_PHY_EVENT_LOSS_OF_DWORD_SYNC_COUNT: src_str = "Loss of DWORD sync count"; break; case SMP_PHY_EVENT_PHY_RESET_PROBLEM_COUNT: src_str = "PHY reset problem count"; break; case SMP_PHY_EVENT_ELASTICITY_BUFFER_OVERFLOW_COUNT: src_str = "Elasticity buffer overflow count"; break; case SMP_PHY_EVENT_RX_ERROR_COUNT: src_str = "Received ERROR count"; break; case SMP_PHY_EVENT_RX_ADDR_FRAME_ERROR_COUNT: src_str = "Received address frame error count"; break; case SMP_PHY_EVENT_TX_ABANDON_CLASS_OPEN_REJ_COUNT: src_str = "Transmitted abandon-class OPEN_REJECT count"; break; case SMP_PHY_EVENT_RX_ABANDON_CLASS_OPEN_REJ_COUNT: src_str = "Received abandon-class OPEN_REJECT count"; break; case SMP_PHY_EVENT_TX_RETRY_CLASS_OPEN_REJ_COUNT: src_str = "Transmitted retry-class OPEN_REJECT count"; break; case SMP_PHY_EVENT_RX_RETRY_CLASS_OPEN_REJ_COUNT: src_str = "Received retry-class OPEN_REJECT count"; break; case SMP_PHY_EVENT_RX_AIP_W_O_PARTIAL_COUNT: src_str = "Received AIP (WAITING ON PARTIAL) count"; break; case SMP_PHY_EVENT_RX_AIP_W_O_CONN_COUNT: src_str = "Received AIP (WAITING ON CONNECTION) count"; break; case SMP_PHY_EVENT_TX_BREAK_COUNT: src_str = "Transmitted BREAK count"; break; case SMP_PHY_EVENT_RX_BREAK_COUNT: src_str = "Received BREAK count"; break; case SMP_PHY_EVENT_BREAK_TIMEOUT_COUNT: src_str = "BREAK timeout count"; break; case SMP_PHY_EVENT_CONNECTION_COUNT: src_str = "Connection count"; break; case SMP_PHY_EVENT_PEAK_TX_PATHWAY_BLOCKED_COUNT: src_str = "Peak transmitted pathway blocked count"; *peak_detector = B_TRUE; break; case SMP_PHY_EVENT_PEAK_TX_ARB_WAIT_TIME: src_str = "Peak transmitted arbitration wait time"; *peak_detector = B_TRUE; break; case SMP_PHY_EVENT_PEAK_ARB_TIME: src_str = "Peak arbitration time"; *peak_detector = B_TRUE; break; case SMP_PHY_EVENT_PEAK_CONNECTION_TIME: src_str = "Peak connection time"; *peak_detector = B_TRUE; break; case SMP_PHY_EVENT_TX_SSP_FRAME_COUNT: src_str = "Transmitted SSP frame count"; break; case SMP_PHY_EVENT_RX_SSP_FRAME_COUNT: src_str = "Received SSP frame count"; break; case SMP_PHY_EVENT_TX_SSP_FRAME_ERROR_COUNT: src_str = "Transmitted SSP frame error count"; break; case SMP_PHY_EVENT_RX_SSP_FRAME_ERROR_COUNT: src_str = "Received SSP frame error count"; break; case SMP_PHY_EVENT_TX_CREDIT_BLOCKED_COUNT: src_str = "Transmitted CREDIT_BLOCKED count"; break; case SMP_PHY_EVENT_RX_CREDIT_BLOCKED_COUNT: src_str = "Received CREDIT_BLOCKED count"; break; case SMP_PHY_EVENT_TX_SATA_FRAME_COUNT: src_str = "Transmitted SATA frame count"; break; case SMP_PHY_EVENT_RX_SATA_FRAME_COUNT: src_str = "Received SATA frame count"; break; case SMP_PHY_EVENT_SATA_FLOW_CTRL_BUF_OVERFLOW_COUNT: src_str = "SATA flow control buffer overflow count"; break; case SMP_PHY_EVENT_TX_SMP_FRAME_COUNT: src_str = "Transmitted SMP frame count"; break; case SMP_PHY_EVENT_RX_SMP_FRAME_COUNT: src_str = "Received SMP frame count"; break; case SMP_PHY_EVENT_RX_SMP_FRAME_ERROR_COUNT: src_str = "Received SMP frame error count"; break; default: src_str = ""; break; } return (src_str); } static void smp_validate_args(int argc, char *argv[]) { errno = 0; if (argc < 3) fatal(-1, "Usage: %s ...\n", argv[0]); func = strtoul(argv[2], NULL, 0); if (errno != 0) fatal(-1, "Usage: %s ...\n", argv[0]); switch (func) { case SMP_FUNC_REPORT_GENERAL: case SMP_FUNC_REPORT_MANUFACTURER_INFO: if (argc != 3) { fatal(-1, "Usage: %s 0x%x\n", argv[0], func); } break; case SMP_FUNC_DISCOVER: case SMP_FUNC_REPORT_PHY_EVENT: case SMP_FUNC_REPORT_PHY_ERROR_LOG: { if (argc != 4) { fatal(-1, "Usage: %s 0x%x \n", argv[0], func); } break; } case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { if (argc < 4) { fatal(-1, "Usage: %s 0x%x \n", argv[0], func); } break; } case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { if (argc < 4) { fatal(-1, "Usage: %s 0x%x \n", argv[0], func); } break; } case SMP_FUNC_ENABLE_DISABLE_ZONING: { if (argc != 4) { fatal(-1, "Usage: %s 0x%x " "[0(no change) | 1(enable)| 2(disable)]\n", argv[0], func); } break; } case SMP_FUNC_REPORT_BROADCAST: { if (argc != 4) { fatal(-1, "Usage: %s 0x%x \n", argv[0], func); } break; } case SMP_FUNC_REPORT_ROUTE_INFO: { if (argc != 5) { fatal(-1, "Usage: %s 0x%x " "\n", argv[0], func); } break; } case SMP_FUNC_PHY_CONTROL: { if (argc != 5) { fatal(-1, "Usage: %s 0x%x " " \n", argv[0], func); } break; } default: { fatal(-1, "Usage: %s ...\n", argv[0]); break; } } } int main(int argc, char *argv[]) { uint_t i, j; char *yesorno; uint16_t exp_change_count; /* * If the arguments are invalid, this function will not return. */ smp_validate_args(argc, argv); if (smp_init(LIBSMP_VERSION) != 0) fatal(-1, "libsmp initialization failed: %s", smp_errmsg()); bzero(&tdef, sizeof (smp_target_def_t)); tdef.std_def = argv[1]; if ((tp = smp_open(&tdef)) == NULL) { smp_fini(); fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg()); } exp_change_count = smp_target_get_change_count(tp); (void) printf("%s\n", argv[0]); (void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp)); (void) printf("\tVendor/Product/Revision: %s/%s/%s\n", smp_target_vendor(tp), smp_target_product(tp), smp_target_revision(tp)); (void) printf("\tExp Vendor/ID/Rev: %s/%04x/%02x\n", smp_target_component_vendor(tp), smp_target_component_id(tp), smp_target_component_revision(tp)); (void) printf("\tExpander change count: 0x%04x\n", exp_change_count); ap = smp_action_alloc(func, tp, 0); if (ap == NULL) { smp_close(tp); smp_fini(); fatal(-3, "failed to allocate action: %s", smp_errmsg()); } switch (func) { case SMP_FUNC_REPORT_GENERAL: case SMP_FUNC_REPORT_MANUFACTURER_INFO: /* * These functions have no additional request bytes. therefore * there is nothing for us to get and fill in here. */ break; case SMP_FUNC_DISCOVER: { smp_discover_req_t *dp; smp_action_get_request(ap, (void **)&dp, NULL); dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0); break; } case SMP_FUNC_REPORT_ROUTE_INFO: { smp_handle_report_route_info(argc, argv); break; } case SMP_FUNC_ENABLE_DISABLE_ZONING: { smp_enable_disable_zoning_req_t *rp; smp_action_get_request(ap, (void **)&rp, NULL); rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0); break; } case SMP_FUNC_PHY_CONTROL: { smp_phy_control_req_t *rp; smp_action_get_request(ap, (void **)&rp, NULL); rp->spcr_phy_identifier = strtoul(argv[3], NULL, 0); rp->spcr_phy_operation = strtoul(argv[4], NULL, 0); break; } case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { smp_report_exp_route_table_list_req_t *rp; smp_action_get_request(ap, (void **)&rp, NULL); SCSI_WRITE16(&rp->srertlr_max_descrs, 64); SCSI_WRITE16(&rp->srertlr_starting_routed_sas_addr_index, strtoull(argv[3], NULL, 0)); rp->srertlr_starting_phy_identifier = 0; break; } case SMP_FUNC_REPORT_PHY_ERROR_LOG: { smp_report_phy_error_log_req_t *pelp; smp_action_get_request(ap, (void **)&pelp, NULL); pelp->srpelr_phy_identifier = strtoul(argv[3], NULL, 0); break; } case SMP_FUNC_REPORT_PHY_EVENT: { smp_report_phy_event_req_t *rpep; smp_action_get_request(ap, (void **)&rpep, NULL); rpep->srper_phy_identifier = strtoul(argv[3], NULL, 0); break; } case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { smp_report_zone_mgr_password_req_t *rzmprp; smp_action_get_request(ap, (void **)&rzmprp, NULL); rzmprp->srzmpr_rpt_type = strtoul(argv[3], NULL, 0); break; } case SMP_FUNC_REPORT_BROADCAST: { smp_report_broadcast_req_t *rbrp; smp_action_get_request(ap, (void **)&rbrp, NULL); rbrp->srbr_broadcast_type = strtoul(argv[3], NULL, 0); break; } default: smp_close(tp); smp_action_free(ap); smp_fini(); smp_cmd_failed(result); } smp_execute(); smp_get_response(B_TRUE); switch (func) { case SMP_FUNC_REPORT_GENERAL: { smp_report_general_resp_t *gr = (smp_report_general_resp_t *)smp_resp; (void) printf("Expander Route Indexes: %u\n", SCSI_READ16(&gr->srgr_exp_route_indexes)); (void) printf("Long Responses: %s\n", gr->srgr_long_response != 0 ? "Supported" : "Unsupported"); (void) printf("Phys: %d\n", gr->srgr_number_of_phys); (void) printf("Features:\n"); if (gr->srgr_externally_configurable_route_table != 0) { (void) printf("\tExternally Configurable Route " "Table\n"); } if (gr->srgr_configuring != 0) { (void) printf("\tConfiguring\n"); } if (gr->srgr_configures_others != 0) { (void) printf("\tConfigures Others\n"); } if (gr->srgr_open_reject_retry_supported != 0) { (void) printf("\tOpen Reject Retry\n"); } if (gr->srgr_stp_continue_awt != 0) { (void) printf("\tSTP Continue AWT\n"); } if (gr->srgr_table_to_table_supported != 0) { (void) printf("\tTable to Table\n"); } (void) printf("Logical Identify: %016llx\n", SCSI_READ64(&gr->srgr_enclosure_logical_identifier)); (void) printf("STP Bus Inactivity Time Limit: %u us\n", SCSI_READ16(&gr->srgr_stp_bus_inactivity_time_limit) * 100); (void) printf("STP Maximum Connect Time Limit: %u us\n", SCSI_READ16(&gr->srgr_stp_maximum_connect_time_limit) * 100); (void) printf("STP SMP I_T Nexus Loss Time: "); if (gr->srgr_stp_smp_nexus_loss_time == 0) { (void) printf("Vendor Specific\n"); } else if (gr->srgr_stp_smp_nexus_loss_time == UINT16_MAX) { (void) printf("Retries Forever\n"); } else { (void) printf("%u ms\n", SCSI_READ16(&gr->srgr_stp_smp_nexus_loss_time)); } (void) printf("Physical Presence: %s, %s\n", gr->srgr_physical_presence_supported ? "Supported" : "Unsupported", gr->srgr_physical_presence_asserted ? "Enabled" : "Disabled"); (void) printf("Zoning:\n"); if (gr->srgr_zoning_supported != 0) { (void) printf("\tSupported\n"); } else { (void) printf("\tUnsupported\n"); } if (gr->srgr_zoning_enabled != 0) { (void) printf("\tEnabled\n"); } else { (void) printf("\tDisabled\n"); } if (gr->srgr_zone_locked != 0) { (void) printf("\tLocked\n"); } else { (void) printf("\tUnlocked\n"); } if (gr->srgr_saving_zoning_enabled_supported != 0) { (void) printf("\tSaving Zoning Enabled Supported\n"); } if (gr->srgr_saving_zone_perm_table_supported != 0) { (void) printf("\tSaving Zone Perm Table Supported\n"); } if (gr->srgr_saving_zone_phy_info_supported != 0) { (void) printf("\tSaving Zone Phy Info Supported\n"); } if (gr->srgr_saving != 0) { (void) printf("\tSaving\n"); } (void) printf("\tActive Zone Manager SAS Address: %016llx\n", SCSI_READ64(&gr->srgr_active_zm_sas_addr)); (void) printf("\tZone Lock Inactivity Limit: %u ms\n", SCSI_READ16(&gr->srgr_zone_lock_inactivity_limit) * 100); (void) printf("Maximum Routed SAS Addresses: %u\n", SCSI_READ16(&gr->srgr_max_routed_sas_addrs)); (void) printf("First Enclosure Connector Element Index: %u\n", gr->srgr_first_encl_conn_elem_idx); (void) printf("Number of Enclosure Connector Elements: %u\n", gr->srgr_number_encl_conn_elem_idxs); if (gr->srgr_reduced_functionality != 0) { (void) printf("Time to Reduced Functionality: %u ms\n", gr->srgr_time_to_reduced_functionality * 100); } (void) printf("Initial Time to Reduced Functionality: %u ms\n", gr->srgr_initial_time_to_reduced_functionality * 100); (void) printf("Maximum Time to Reduced Functionality: %u ms\n", gr->srgr_max_reduced_functionality_time * 100); (void) printf("Last Self-configuration Status Index: %u\n", SCSI_READ16(&gr->srgr_last_self_conf_status_descr_idx)); (void) printf("Maximum Stored Self-configuration Statuses: " "%u\n", SCSI_READ16( &gr->srgr_max_stored_self_config_status_descrs)); (void) printf("Last Phy Event List Descriptor Index: %u\n", SCSI_READ16(&gr->srgr_last_phy_event_list_descr_idx)); (void) printf("Maximum Stored Phy Event List Descriptors: " "%u\n", SCSI_READ16( &gr->srgr_max_stored_phy_event_list_descrs)); (void) printf("STP Reject to Open Limit: %u us\n", SCSI_READ16(&gr->srgr_stp_reject_to_open_limit) * 10); break; } case SMP_FUNC_REPORT_MANUFACTURER_INFO: { smp_report_manufacturer_info_resp_t *mir = (smp_report_manufacturer_info_resp_t *)smp_resp; smp_print_ascii("Vendor", mir->srmir_vendor_identification, sizeof (mir->srmir_vendor_identification)); smp_print_ascii("Product", mir->srmir_product_identification, sizeof (mir->srmir_product_identification)); smp_print_ascii("Revision", mir->srmir_product_revision_level, sizeof (mir->srmir_product_revision_level)); /* * The format of the following section was changed in the SAS * 1.1 specification. If this bit is not present, it is vendor * specific and therefore we don't print them. */ if (mir->srmir_sas_1_1_format == 0) { break; } smp_print_ascii("Component Vendor", mir->srmir_component_vendor_identification, sizeof (mir->srmir_component_vendor_identification)); (void) printf("Component ID: 0x%x\n", SCSI_READ16(&mir->srmir_component_id)); (void) printf("Component Revision: 0x%x\n", mir->srmir_component_revision_level); break; } case SMP_FUNC_DISCOVER: { smp_discover_resp_t *rp = (smp_discover_resp_t *)smp_resp; (void) printf("Addr: %016llx Phy: %02x\n", SCSI_READ64(&rp->sdr_sas_addr), rp->sdr_phy_identifier); (void) printf("Peer: %016llx Phy: %02x\n", SCSI_READ64(&rp->sdr_attached_sas_addr), rp->sdr_attached_phy_identifier); (void) printf("Device type: %01x\n", rp->sdr_attached_device_type); break; } case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: { smp_report_zone_mgr_password_resp_t *rp = (smp_report_zone_mgr_password_resp_t *)smp_resp; char *rpt_type = NULL; int idx; switch (rp->srzmpr_rpt_type) { case SMP_ZMP_TYPE_CURRENT: rpt_type = "Current"; break; case SMP_ZMP_TYPE_SAVED: rpt_type = "Saved"; break; case SMP_ZMP_TYPE_DEFAULT: rpt_type = "Default"; break; default: rpt_type = "(Unknown Type)"; break; } (void) printf("%s zone manager password: 0x", rpt_type); for (idx = 0; idx < 32; idx++) { (void) printf("%02x", rp->srzmpr_zone_mgr_password[idx]); } (void) printf("\n"); break; } case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: { smp_report_exp_route_table_list_resp_t *rtlr = (smp_report_exp_route_table_list_resp_t *)smp_resp; smp_route_table_descr_t *descp = &rtlr->srertlr_descrs[0]; int idx, idxx, ndescrs, zoning, startnum; (void) printf("Expander change count: 0x%04x\n", BE_16(rtlr->srertlr_exp_change_count)); (void) printf("Expander route table change count: 0x%04x\n", BE_16(rtlr->srertlr_route_table_change_count)); if (rtlr->srertlr_zoning_enabled) { yesorno = yes; zoning = 1; } else { yesorno = no; zoning = 0; } (void) printf("Zoning enabled: %s\n", yesorno); if (rtlr->srertlr_configuring) { yesorno = yes; } else { yesorno = no; } (void) printf("Configuring: %s\n", yesorno); ndescrs = rtlr->srertlr_n_descrs; (void) printf("Number of descriptors: %d\n", ndescrs); startnum = BE_16(rtlr->srertlr_first_routed_sas_addr_index); (void) printf("First/Last routed SAS address index: %d/%d\n", startnum, BE_16(rtlr->srertlr_last_routed_sas_addr_index)); (void) printf("Starting PHY identifier: %d\n", rtlr->srertlr_starting_phy_identifier); for (idx = 0; idx < ndescrs; idx++, descp++) { (void) printf("#%03d: Routed SAS addr: %016llx ", idx + startnum, BE_64(descp->srtd_routed_sas_addr)); (void) printf("PHY bitmap: 0x"); for (idxx = 0; idxx < 6; idxx++) { (void) printf("%02x", descp->srtd_phy_bitmap[idxx]); } (void) printf("\n"); if (zoning) { (void) printf("\tZone group: %d\n", descp->srtd_zone_group); } } (void) printf("\n"); break; } case SMP_FUNC_REPORT_PHY_ERROR_LOG: { smp_report_phy_error_log_resp_t *pelr = (smp_report_phy_error_log_resp_t *)smp_resp; (void) printf("PHY error log for PHY %d:\n", pelr->srpelr_phy_identifier); (void) printf("\tInvalid DWORD count: %d\n", BE_32(pelr->srpelr_invalid_dword_count)); (void) printf("\tRunning disparity error count: %d\n", BE_32(pelr->srpelr_running_disparity_error_count)); (void) printf("\tLoss of DWORD sync count: %d\n", BE_32(pelr->srpelr_loss_dword_sync_count)); (void) printf("\tPHY reset problem count: %d\n", BE_32(pelr->srpelr_phy_reset_problem_count)); break; } case SMP_FUNC_REPORT_PHY_EVENT: { smp_report_phy_event_resp_t *rper = (smp_report_phy_event_resp_t *)smp_resp; smp_phy_event_report_descr_t *perd = &rper->srper_phy_event_descrs[0]; boolean_t peak; int idx; (void) printf("PHY event for PHY %d:\n", rper->srper_phy_identifier); (void) printf("Number of PHY event descriptors: %d\n", rper->srper_n_phy_event_descrs); for (idx = 0; idx < rper->srper_n_phy_event_descrs; idx++) { (void) printf("%50s : %d\n", smp_phy_event_src_str(perd->sped_phy_event_source, &peak), BE_32(perd->sped_phy_event)); if (peak) { (void) printf("\tPeak value detector " "threshold: %d\n", BE_32(perd->sped_peak_detector_threshold)); } perd++; } break; } case SMP_FUNC_REPORT_BROADCAST: { smp_report_broadcast_resp_t *brp = (smp_report_broadcast_resp_t *)smp_resp; smp_broadcast_descr_t *bdp = &brp->srbr_descrs[0]; uint16_t bcount, idx; bcount = brp->srbr_number_broadcast_descrs; (void) printf("\tNumber of broadcast descriptors: %d\n", bcount); (void) printf("\t%7s %5s %5s %8s\n", "BCType", "PhyID", "BCRsn", "BC Count"); for (idx = 0; idx < bcount; idx++) { (void) printf("\t%7s %5s %5s %8s\n", bdp->sbd_broadcast_type, bdp->sbd_phy_identifier, bdp->sbd_broadcast_reason, bdp->sbd_broadcast_count); bdp++; } break; } default: (void) printf("Response: (len %d)\n", smp_resp_len); for (i = 0; i < smp_resp_len; i += 8) { (void) printf("%02x: ", i); for (j = i; j < i + 8; j++) if (j < smp_resp_len) (void) printf("%02x ", smp_resp[j]); else (void) printf(" "); for (j = i; j < i + 8; j++) (void) printf("%c", j < smp_resp_len && isprint(smp_resp[j]) ? smp_resp[j] : j < smp_resp_len ? '.' : '\0'); (void) printf("\n"); } break; } smp_cleanup(); return (0); }