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
fatal(int err,const char * fmt,...)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 *
smp_get_result(smp_result_t result)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
smp_execute()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
smp_cmd_failed(smp_result_t result)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
smp_get_response(boolean_t close_on_fail)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
smp_cleanup()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
smp_handle_report_route_info(int argc,char * argv[])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 *
smp_phy_event_src_str(smp_phy_event_source_t src,boolean_t * peak_detector)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
smp_validate_args(int argc,char * argv[])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
main(int argc,char * argv[])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