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
46 static char *yes = "Yes";
47 static char *no = "No";
48
49 static void fatal(int, const char *, ...) __NORETURN;
50
51 static smp_target_t *tp = NULL;
52 static smp_action_t *ap = NULL;
53 static smp_function_t func;
54 static smp_result_t result;
55 static smp_target_def_t tdef;
56 static uint8_t *smp_resp;
57 static size_t smp_resp_len;
58
59 static void
fatal(int err,const char * fmt,...)60 fatal(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 */
79 static void
smp_print_ascii(const char * header,const char * str,size_t len)80 smp_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
99 static char *
smp_get_result(smp_result_t result)100 smp_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
194 static void
smp_execute()195 smp_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
205 static void
smp_cmd_failed(smp_result_t result)206 smp_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
218 static void
smp_get_response(boolean_t close_on_fail)219 smp_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
231 static void
smp_cleanup()232 smp_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 */
243 static void
smp_handle_report_route_info(int argc,char * argv[])244 smp_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
324 static char *
smp_phy_event_src_str(smp_phy_event_source_t src,boolean_t * peak_detector)325 smp_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
446 static void
smp_validate_args(int argc,char * argv[])447 smp_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
532 int
main(int argc,char * argv[])533 main(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