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