changeset 13106:efddb0166961

6962613 REPORT GENERAL structure definition includes extra bit 6970613 Updates to smp headers and the smp utility
author David Hollister <david.hollister@oracle.com>
date Thu, 12 Aug 2010 15:59:36 -0600
parents 48f2dbca79a2
children eb7af425d949
files usr/src/cmd/scsi/smp/common/smp.c usr/src/lib/scsi/libsmp/common/libsmp.h usr/src/lib/scsi/libsmp/common/smp_engine.c usr/src/lib/scsi/libsmp/mapfile-vers usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c usr/src/uts/common/sys/scsi/generic/smp_frames.h
diffstat 6 files changed, 768 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/scsi/smp/common/smp.c	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/cmd/scsi/smp/common/smp.c	Thu Aug 12 15:59:36 2010 -0600
@@ -27,6 +27,7 @@
 #include <sys/scsi/generic/commands.h>
 #include <sys/scsi/impl/commands.h>
 #include <sys/ccompile.h>
+#include <sys/byteorder.h>
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -40,8 +41,19 @@
 #include <scsi/libsmp.h>
 #include <scsi/libsmp_plugin.h>
 
+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, ...)
 {
@@ -57,31 +69,444 @@
 	_exit(err);
 }
 
-int
-main(int argc, char *argv[])
+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 (result == 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();
+}
+
+static void
+smp_handle_report_route_info(int argc, char *argv[])
 {
-	smp_target_t *tp;
-	smp_action_t *ap;
-	smp_errno_t err;
-	smp_function_t func;
-	smp_result_t result;
-	smp_target_def_t tdef;
-	smp_discover_resp_t *rp;
-	smp_report_manufacturer_info_resp_t *ip;
-	uint8_t *resp;
-	size_t len;
-	uint_t cap;
-	void *x;
-	uint_t i, j;
+	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 = "<Unknown>";
+		break;
+	}
+
+	return (src_str);
+}
+
+static void
+smp_validate_args(int argc, char *argv[])
+{
+	errno = 0;
 
 	if (argc < 3)
 		fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]);
 
-	errno = 0;
 	func = strtoul(argv[2], NULL, 0);
+
 	if (errno != 0)
 		fatal(-1, "Usage: %s <device> <function> ...\n", argv[0]);
 
+	switch (func) {
+	case SMP_FUNC_DISCOVER:
+	case SMP_FUNC_REPORT_PHY_EVENT:
+	case SMP_FUNC_REPORT_PHY_ERROR_LOG: {
+		if (argc != 4) {
+			fatal(-1,
+			    "Usage: %s <device> 0x%x <phy identifier>\n",
+			    argv[0], func);
+		}
+		break;
+	}
+	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: {
+		if (argc < 4) {
+			fatal(-1,
+			    "Usage: %s <device> 0x%x <SAS Address Index>\n",
+			    argv[0], func);
+		}
+		break;
+	}
+	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD: {
+		if (argc < 4) {
+			fatal(-1,
+			    "Usage: %s <device> 0x%x <report type>\n",
+			    argv[0], func);
+		}
+		break;
+	}
+	case SMP_FUNC_ENABLE_DISABLE_ZONING: {
+		if (argc != 4) {
+			fatal(-1,
+			    "Usage: %s <device> 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 <device> 0x%x <bcast type>\n",
+			    argv[0], func);
+		}
+		break;
+	}
+	case SMP_FUNC_REPORT_ROUTE_INFO: {
+		if (argc != 5) {
+			fatal(-1,
+			    "Usage: %s <device> 0x%x <exp_route_idx> "
+			    "<phy_identifier>\n", argv[0], func);
+		}
+		break;
+	}
+	case SMP_FUNC_PHY_CONTROL: {
+		if (argc != 5) {
+			fatal(-1,
+			    "Usage: %s <device> 0x%x <phy identifier> "
+			    " <phy operation>\n",
+			    argv[0], func);
+		}
+		break;
+	}
+	default: {
+		fatal(-1, "Usage: %s <device> <function> ...\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());
 
@@ -93,7 +518,18 @@
 		fatal(-2, "failed to open %s: %s", argv[1], smp_errmsg());
 	}
 
-	cap = smp_target_getcap(tp);
+	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);
@@ -101,104 +537,84 @@
 		fatal(-3, "failed to allocate action: %s", smp_errmsg());
 	}
 
-	if (func == SMP_FUNC_DISCOVER) {
+	switch (func) {
+	case SMP_FUNC_DISCOVER: {
 		smp_discover_req_t *dp;
-		if (argc < 4)
-			fatal(-1,
-			    "Usage: %s <device> 0x10 <phy identifier>\n",
-			    argv[0]);
 
 		smp_action_get_request(ap, (void **)&dp, NULL);
 		dp->sdr_phy_identifier = strtoul(argv[3], NULL, 0);
-	} else if (func == SMP_FUNC_REPORT_ROUTE_INFO) {
-		smp_report_route_info_req_t *rp;
-		if (argc < 5)
-			fatal(-1, "Usage: %s <device> 0x13 <expander route "
-			    "index> <phy identifier>\n",
-			    argv[0]);
-
-		smp_action_get_request(ap, (void **)&rp, NULL);
-		rp->srrir_exp_route_index = strtoul(argv[3], NULL, 0);
-		rp->srrir_phy_identifier = strtoul(argv[4], NULL, 0);
-	} else if (func == SMP_FUNC_ENABLE_DISABLE_ZONING) {
+		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;
-		if (argc < 4)
-			fatal(-1,
-			    "Usage: %s <device> 0x81 "
-			    "[0(no change) | 1(enable)| 2(disable)]\n",
-			    argv[0]);
 
 		smp_action_get_request(ap, (void **)&rp, NULL);
 		rp->sedzr_enable_disable_zoning = strtoul(argv[3], NULL, 0);
-	} else if (func == SMP_FUNC_PHY_CONTROL) {
+		break;
+	}
+	case SMP_FUNC_PHY_CONTROL: {
 		smp_phy_control_req_t *rp;
-		if (argc < 5)
-			fatal(-1,
-			    "Usage: %s <device> 0x91 <phy identifier> "
-			    " <phy operation>\n",
-			    argv[0]);
-
-		smp_action_get_request(ap, (void **)&rp, NULL);
 
 		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);
-	} else if (func == SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST) {
+		break;
+	}
+	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST: {
 		smp_report_exp_route_table_list_req_t *rp;
-		if (argc < 4)
-			fatal(-1,
-			    "Usage: %s <device> 0x22 <SAS Address Index> \n",
-			    argv[0]);
 
 		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;
 
-	(void) printf("%s\n", argv[0]);
-	(void) printf("\tSAS Address: %016llx\n", smp_target_addr(tp));
-	(void) printf("\tVendor: %s\n", smp_target_vendor(tp));
-	(void) printf("\tProduct: %s\n", smp_target_product(tp));
-	(void) printf("\tRevision: %s\n", smp_target_revision(tp));
-	(void) printf("\tExp Vendor: %s\n", smp_target_component_vendor(tp));
-	(void) printf("\tExp ID: %04x\n", smp_target_component_id(tp));
-	(void) printf("\tExp Rev: %02x\n", smp_target_component_revision(tp));
+		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;
 
-	if (smp_exec(ap, tp) != 0) {
+		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();
-		fatal(-4, "exec failed: %s", smp_errmsg());
-	}
-
-	smp_close(tp);
-	smp_action_get_response(ap, &result, (void **)&resp, &len);
-
-	if (result != SMP_RES_FUNCTION_ACCEPTED) {
-		smp_action_free(ap);
-		smp_fini();
-		fatal(-5, "command failed with status code %d", result);
+		smp_cmd_failed(result);
 	}
 
-	(void) printf("Response: (len %d)\n", len);
-	for (i = 0; i < len; i += 8) {
-		(void) printf("%02x: ", i);
-		for (j = i; j < i + 8; j++)
-			if (j < len)
-				(void) printf("%02x ", resp[j]);
-			else
-				(void) printf("   ");
-		for (j = i; j < i + 8; j++)
-			(void) printf("%c",
-			    j < len && isprint(resp[j]) ? resp[j] :
-			    j < len ? '.' : '\0');
-		(void) printf("\n");
-	}
+	smp_execute();
+	smp_get_response(B_TRUE);
 
-	if (func == SMP_FUNC_DISCOVER) {
-		rp = (smp_discover_resp_t *)resp;
+	switch (func) {
+	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",
@@ -206,10 +622,172 @@
 		    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;
+		uint8_t bctype;
+
+		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_action_free(ap);
-	smp_fini();
-
+	smp_cleanup();
 	return (0);
 }
--- a/usr/src/lib/scsi/libsmp/common/libsmp.h	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/lib/scsi/libsmp/common/libsmp.h	Thu Aug 12 15:59:36 2010 -0600
@@ -86,6 +86,8 @@
 extern uint_t smp_target_getcap(const smp_target_t *);
 extern uint16_t smp_target_get_change_count(const smp_target_t *);
 extern void smp_target_set_change_count(smp_target_t *, uint16_t);
+extern uint8_t smp_target_get_number_of_phys(const smp_target_t *);
+extern uint16_t smp_target_get_exp_route_indexes(const smp_target_t *);
 extern const char *smp_target_vendor(const smp_target_t *);
 extern const char *smp_target_product(const smp_target_t *);
 extern const char *smp_target_revision(const smp_target_t *);
--- a/usr/src/lib/scsi/libsmp/common/smp_engine.c	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/lib/scsi/libsmp/common/smp_engine.c	Thu Aug 12 15:59:36 2010 -0600
@@ -378,6 +378,18 @@
 	return (tp->st_change_count);
 }
 
+uint8_t
+smp_target_get_number_of_phys(const smp_target_t *tp)
+{
+	return (tp->st_repgen.srgr_number_of_phys);
+}
+
+uint16_t
+smp_target_get_exp_route_indexes(const smp_target_t *tp)
+{
+	return (tp->st_repgen.srgr_exp_route_indexes);
+}
+
 void
 smp_close(smp_target_t *tp)
 {
--- a/usr/src/lib/scsi/libsmp/mapfile-vers	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/lib/scsi/libsmp/mapfile-vers	Thu Aug 12 15:59:36 2010 -0600
@@ -78,6 +78,8 @@
 		smp_plugin_register;
 		smp_plugin_setspecific;
 		smp_plugin_getspecific;
+		smp_target_get_number_of_phys;
+		smp_target_get_exp_route_indexes;
 
 		smp_alloc;
 		smp_zalloc;
--- a/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c	Thu Aug 12 15:59:36 2010 -0600
@@ -236,6 +236,18 @@
 
 /*ARGSUSED*/
 static size_t
+sas2_report_zone_mgr_password_rq_len(size_t user, smp_target_t *tp)
+{
+	if (user != 0) {
+		(void) smp_set_errno(ESMP_RANGE);
+		return (0);
+	}
+
+	return (SMP_REQ_MINLEN + sizeof (smp_report_zone_perm_table_req_t));
+}
+
+/*ARGSUSED*/
+static size_t
 sas2_report_broadcast_rq_len(size_t user, smp_target_t *tp)
 {
 	if (user != 0) {
@@ -658,7 +670,7 @@
 {
 	.sfd_function = SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD,
 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
-	.sfd_rq_len = sas2_rq_len,
+	.sfd_rq_len = sas2_report_zone_mgr_password_rq_len,
 	.sfd_rq_dataoff = sas2_rq_dataoff,
 	.sfd_rq_setframe = sas2_rq_setframe,
 	.sfd_rs_datalen = sas2_rs_datalen,
@@ -916,9 +928,10 @@
 	switch (fn) {
 	case SMP_FUNC_REPORT_GENERAL:
 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
+		return (SMP_REQ_MINLEN);
 	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
-		return (SMP_REQ_MINLEN);
-
+		return (SMP_REQ_MINLEN +
+		    sizeof (smp_report_zone_mgr_password_req_t));
 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
 		if (cap & SMP_TARGET_C_LONG_RESP)
 			return (SMP_REQ_MINLEN +
@@ -1023,7 +1036,6 @@
 	switch (fn) {
 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
 	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
-	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
 	case SMP_FUNC_REPORT_BROADCAST:
 	case SMP_FUNC_REPORT_PHY_EVENT:
 	case SMP_FUNC_DISCOVER_LIST:
@@ -1043,7 +1055,9 @@
 	case SMP_FUNC_PHY_TEST_FUNCTION:
 	case SMP_FUNC_CONFIG_PHY_EVENT:
 		return (SMP_RESP_MINLEN);
-
+	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
+		return (SMP_RESP_MINLEN +
+		    sizeof (smp_report_zone_mgr_password_resp_t));
 	case SMP_FUNC_REPORT_GENERAL:
 		return (SMP_RESP_MINLEN + 24);
 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
--- a/usr/src/uts/common/sys/scsi/generic/smp_frames.h	Thu Aug 12 14:55:22 2010 -0700
+++ b/usr/src/uts/common/sys/scsi/generic/smp_frames.h	Thu Aug 12 15:59:36 2010 -0600
@@ -18,10 +18,8 @@
  *
  * CDDL HEADER END
  */
-
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SYS_SCSI_GENERIC_SMP_FRAMES_H
@@ -104,6 +102,7 @@
 	SMP_RES_NO_PHYSICAL_PRESENCE		= 0x26,
 	SMP_RES_SAVING_NOT_SUPPORTED		= 0x27,
 	SMP_RES_SOURCE_ZONE_GROUP_DNE		= 0x28,
+	SMP_RES_DISABLED_PW_NOT_SUPPORTED	= 0x29,
 	SMP_RES_NONE				= -1
 } smp_result_t;
 
@@ -179,7 +178,7 @@
 	    srgr_saving_zone_phy_info_supported		:1,
 	    srgr_saving_zone_mgr_password_supported	:1,
 	    srgr_saving					:1,
-	    _reserved7					:4);
+	    _reserved7					:3);
 	uint16_t srgr_max_routed_sas_addrs;
 	uint64_t srgr_active_zm_sas_addr;
 	uint16_t srgr_zone_lock_inactivity_limit;
@@ -336,11 +335,27 @@
 	((__d)[31 - ((__z) >> 3)] &= ~(1 << ((__z) & 7)))
 
 /*
- * SAS-2 10.4.3.8 REPORT ZONE MANAGER PASSWORD (no additional request bytes)
+ * SAS-2 10.4.3.8 REPORT ZONE MANAGER PASSWORD
  */
+typedef enum smp_report_zmp_report_type {
+	SMP_ZMP_TYPE_CURRENT		= 0x0,
+	SMP_ZMP_TYPE_SAVED		= 0x2,
+	SMP_ZMP_TYPE_DEFAULT		= 0x3
+} smp_report_zmp_report_type_t;
+
+typedef struct smp_report_zone_mgr_password_req {
+	DECL_BITFIELD2(
+	    srzmpr_rpt_type		:2,
+	    _reserved1			:6);
+	uint8_t _reserved2[2];
+} smp_report_zone_mgr_password_req_t;
+
 typedef struct smp_report_zone_mgr_password_resp {
 	uint16_t srzmpr_exp_change_count;
-	uint8_t _reserved1[2];
+	DECL_BITFIELD2(
+	    srzmpr_rpt_type		:2,
+	    _reserved1			:6);
+	uint8_t _reserved2;
 	uint8_t srzmpr_zone_mgr_password[32];
 } smp_report_zone_mgr_password_resp_t;
 
@@ -638,6 +653,43 @@
 /*
  * SAS-2 10.4.3.14 SAS-2 REPORT PHY EVENT
  */
+typedef enum smp_phy_event_source {
+	SMP_PHY_EVENT_NO_EVENT				= 0x00,
+	SMP_PHY_EVENT_INVALID_DWORD_COUNT		= 0x01,
+	SMP_PHY_EVENT_RUNNING_DISPARITY_ERROR_COUNT	= 0x02,
+	SMP_PHY_EVENT_LOSS_OF_DWORD_SYNC_COUNT		= 0x03,
+	SMP_PHY_EVENT_PHY_RESET_PROBLEM_COUNT		= 0x04,
+	SMP_PHY_EVENT_ELASTICITY_BUFFER_OVERFLOW_COUNT	= 0x05,
+	SMP_PHY_EVENT_RX_ERROR_COUNT			= 0x06,
+	SMP_PHY_EVENT_RX_ADDR_FRAME_ERROR_COUNT		= 0x20,
+	SMP_PHY_EVENT_TX_ABANDON_CLASS_OPEN_REJ_COUNT	= 0x21,
+	SMP_PHY_EVENT_RX_ABANDON_CLASS_OPEN_REJ_COUNT	= 0x22,
+	SMP_PHY_EVENT_TX_RETRY_CLASS_OPEN_REJ_COUNT	= 0x23,
+	SMP_PHY_EVENT_RX_RETRY_CLASS_OPEN_REJ_COUNT	= 0x24,
+	SMP_PHY_EVENT_RX_AIP_W_O_PARTIAL_COUNT		= 0x25,
+	SMP_PHY_EVENT_RX_AIP_W_O_CONN_COUNT		= 0x26,
+	SMP_PHY_EVENT_TX_BREAK_COUNT			= 0x27,
+	SMP_PHY_EVENT_RX_BREAK_COUNT			= 0x28,
+	SMP_PHY_EVENT_BREAK_TIMEOUT_COUNT		= 0x29,
+	SMP_PHY_EVENT_CONNECTION_COUNT			= 0x2A,
+	SMP_PHY_EVENT_PEAK_TX_PATHWAY_BLOCKED_COUNT	= 0x2B,
+	SMP_PHY_EVENT_PEAK_TX_ARB_WAIT_TIME		= 0x2C,
+	SMP_PHY_EVENT_PEAK_ARB_TIME			= 0x2D,
+	SMP_PHY_EVENT_PEAK_CONNECTION_TIME		= 0x2E,
+	SMP_PHY_EVENT_TX_SSP_FRAME_COUNT		= 0x40,
+	SMP_PHY_EVENT_RX_SSP_FRAME_COUNT		= 0x41,
+	SMP_PHY_EVENT_TX_SSP_FRAME_ERROR_COUNT		= 0x42,
+	SMP_PHY_EVENT_RX_SSP_FRAME_ERROR_COUNT		= 0x43,
+	SMP_PHY_EVENT_TX_CREDIT_BLOCKED_COUNT		= 0x44,
+	SMP_PHY_EVENT_RX_CREDIT_BLOCKED_COUNT		= 0x45,
+	SMP_PHY_EVENT_TX_SATA_FRAME_COUNT		= 0x50,
+	SMP_PHY_EVENT_RX_SATA_FRAME_COUNT		= 0x51,
+	SMP_PHY_EVENT_SATA_FLOW_CTRL_BUF_OVERFLOW_COUNT	= 0x52,
+	SMP_PHY_EVENT_TX_SMP_FRAME_COUNT		= 0x60,
+	SMP_PHY_EVENT_RX_SMP_FRAME_COUNT		= 0x61,
+	SMP_PHY_EVENT_RX_SMP_FRAME_ERROR_COUNT		= 0x63
+} smp_phy_event_source_t;
+
 typedef struct smp_report_phy_event_req {
 	uint8_t _reserved1;
 	uint8_t _reserved2[4];
@@ -818,12 +870,15 @@
 typedef struct smp_report_exp_route_table_list_resp {
 	uint16_t srertlr_exp_change_count;
 	uint16_t srertlr_route_table_change_count;
-	DECL_BITFIELD3(
-	    _reserved1		:1,
-	    srertlr_configuring	:1,
-	    _reserved2		:6);
+	DECL_BITFIELD5(
+	    srertlr_zoning_enabled	:1,
+	    srertlr_configuring		:1,
+	    srertlr_zone_configuring	:1,
+	    srertlr_self_configuring	:1,
+	    _reserved2			:4);
 	uint8_t _reserved3;
-	uint16_t srertlr_n_descrs;
+	uint8_t srertlr_descr_length;
+	uint8_t srertlr_n_descrs;
 	uint16_t srertlr_first_routed_sas_addr_index;
 	uint16_t srertlr_last_routed_sas_addr_index;
 	uint8_t _reserved4[3];