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