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