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