xref: /illumos-gate/usr/src/cmd/scsi/smp/common/smp.c (revision e77c795bcbe51aebd7579fe13cbf2a6d56eca47f)
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 
44 static char *yes = "Yes";
45 static char *no = "No";
46 
47 static void fatal(int, const char *, ...) __NORETURN;
48 
49 static smp_target_t *tp = NULL;
50 static smp_action_t *ap = NULL;
51 static smp_function_t func;
52 static smp_result_t result;
53 static smp_target_def_t tdef;
54 static uint8_t *smp_resp;
55 static size_t smp_resp_len;
56 
57 static void
58 fatal(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 
72 static char *
73 smp_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 
167 static void
168 smp_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 
178 static void
179 smp_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 
191 static void
192 smp_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 
204 static void
205 smp_cleanup()
206 {
207 	if (tp) {
208 		smp_close(tp);
209 		tp = NULL;
210 	}
211 	smp_action_free(ap);
212 	smp_fini();
213 }
214 
215 static void
216 smp_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 
296 static char *
297 smp_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 
418 static void
419 smp_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 
498 int
499 main(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