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