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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <printAttrs.h>
31 #include <smhbaapi.h>
32
33 #define TABLEN 2
34 typedef struct inputArgs {
35 int wwnCount;
36 char **wwn_argv;
37 uint64_t portWWN;
38 char *hbaName;
39 int pflag;
40 int *wwn_flag;
41 } inputArg_t;
42
43 typedef struct tgt_mapping {
44 SMHBA_SCSIENTRY tgtentry;
45 uchar_t inq_vid[8];
46 uchar_t inq_pid[16];
47 uchar_t inq_dtype;
48 struct tgt_mapping *next;
49 }tgt_mapping;
50
51 /*
52 * Remote port tree node structure.
53 */
54 typedef struct smhba_rp_tree {
55 SMHBA_PORTATTRIBUTES portattr;
56 SMHBA_SAS_PORT sasattr;
57 tgt_mapping *first_entry;
58 int printed;
59 struct smhba_rp_tree *parent;
60 struct smhba_rp_tree *child;
61 struct smhba_rp_tree *sibling;
62 }rp_tree_t;
63
64 /*
65 * Report LUN data structure.
66 */
67 struct lun {
68 uchar_t val[8];
69 };
70
71 typedef struct rep_luns_rsp {
72 uint32_t length;
73 uint32_t rsrvd;
74 struct lun lun[1];
75 } rep_luns_rsp_t;
76
77 /*
78 * The following flag is used for printing HBA header on-demand.
79 */
80 static int g_printHBA = 0;
81
82 /*
83 * The following structure is for sorted output of HBA and HBA Port.
84 */
85 typedef struct _sas_elem {
86 char name[256];
87 int index;
88 }sas_elem_t;
89
90 /*
91 * The following two functions are for generating hierachy of expander
92 * subcommand.
93 */
94 static int
95 sas_rp_tree_insert(rp_tree_t **rproot, rp_tree_t *rpnode);
96 static int
97 sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
98 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
99 rp_tree_t *rpnode, inputArg_t *input, int gident,
100 int *printPort);
101 static int
102 sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
103 SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
104 inputArg_t *input, int lident, int gident);
105 static int
106 sas_print_rpnode(inputArg_t *input,
107 rp_tree_t *rpnode, int lident, int gident);
108 static void sas_rp_tree_free(rp_tree_t *rproot);
109
110 typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
111 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
112 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
113
114 static int processHBA(inputArg_t *input,
115 processPortFunc processPort);
116
117 static int isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN);
118 static int isStringInArgv(inputArg_t *input, const char *adapterName);
119 static boolean_t compareLUName(char *cmdArg, char *osName);
120 static discoveredDevice *LUList = NULL;
121 static targetPortList_t *gTargetPortList = NULL;
122
123 /* processes for hanlding local HBA info */
124 static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
125 int numberOfPorts, const char *adapterName);
126 static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
127 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
128 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
129 static int processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
130 SMHBA_PORTATTRIBUTES *port, int pflag);
131 static int processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex,
132 int phyIndex, PSMHBA_SAS_PHY phyattrs, int pflag);
133
134 /* process for handling expander info */
135 static int handleExpander(HBA_HANDLE handle, char *adapterName,
136 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
137 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
138
139 /* process for handling target port info */
140 static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
141 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
142 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
143
144 /* process for handling logical unit info */
145 static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
146 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
147 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
148
149 /* process for target port SCSI processing */
150 static int
151 searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
152 SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
153 struct targetPortConfig *configData);
154
155 /* process for target port config processing */
156 static int searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
157 SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
158 SMHBA_SAS_PORT *sasattr, int pflag);
159
160 /* process for logical-unit config processing */
161 static int
162 searchDevice(PSMHBA_SCSIENTRY entryP, HBA_HANDLE handle, HBA_WWN hbaPortWWN,
163 HBA_WWN domainPortWWN, char *portName, int pflag);
164
165 /* get domain port out of hba-port phy attr. */
166 HBA_STATUS get_domainPort(HBA_HANDLE handle,
167 int portindex, PSMHBA_PORTATTRIBUTES port,
168 HBA_WWN *pdomainPort);
169
170 static int
171 sas_name_comp(const char *name1, const char *name2);
172 static void
173 sas_elem_sort(sas_elem_t *array, int nelem);
174
175 /*
176 * function for hba subcommand
177 *
178 * Arguments:
179 * wwnCount - count of the number of WWNs in wwn_argv
180 * if wwnCount > 0, then we will only print information for
181 * the hba ports listed in wwn_argv
182 * if wwnCount == 0, then we will print information on all hba ports
183 * wwn_argv - argument array of hba port WWNs
184 * options - any options specified by the caller
185 *
186 * returns:
187 * 0 if successful
188 * >0 otherwise
189 */
190 int
sas_util_list_hba(int hbaCount,char ** hba_argv,cmdOptions_t * options)191 sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
192 {
193 HBA_STATUS status;
194 int processHBA_flags = 0;
195 inputArg_t input;
196 int err_cnt = 0;
197
198 /* process each of the options */
199 for (; options->optval; options++) {
200 switch (options->optval) {
201 case 'v':
202 processHBA_flags |= PRINT_VERBOSE;
203 break;
204 default:
205 break;
206 }
207 }
208
209 if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
210 (void) fprintf(stderr, "%s %s\n",
211 gettext("Failed to load SM-HBA libraries."
212 "Reason:"), getHBAStatus(status));
213 err_cnt++;
214 return (err_cnt);
215 }
216
217 (void) memset(&input, 0, sizeof (input));
218 /* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
219 input.wwnCount = hbaCount;
220 input.wwn_argv = hba_argv;
221 input.pflag = processHBA_flags;
222
223 /*
224 * Process and filter for every local hba,
225 * when the hba is not specificed, print all hba(s).
226 */
227 err_cnt += processHBA(&input, NULL);
228
229 (void) HBA_FreeLibrary();
230
231 return (err_cnt);
232 }
233
234 /*
235 * function for hba-port subcommand
236 *
237 * Arguments:
238 * wwnCount - count of the number of WWNs in wwn_argv
239 * if wwnCount > 0, then we will only print information for
240 * the hba ports listed in wwn_argv
241 * if wwnCount == 0, then we will print information on all hba ports
242 * wwn_argv - argument array of hba port WWNs
243 * options - any options specified by the caller
244 *
245 * returns:
246 * 0 if successful
247 * >0 otherwise
248 */
249 int
sas_util_list_hbaport(int wwnCount,char ** wwn_argv,cmdOptions_t * options)250 sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
251 {
252 HBA_STATUS status;
253 int processHBA_flags = 0;
254 inputArg_t input;
255 int err_cnt = 0;
256 char hbaName[256] = {'\0'};
257
258 /* process each of the options */
259 for (; options->optval; options++) {
260 switch (options->optval) {
261 case 'a':
262 (void) strlcpy(hbaName,
263 options->optarg, sizeof (hbaName));
264 break;
265 case 'y':
266 processHBA_flags |= PRINT_PHY;
267 break;
268 case 'l':
269 processHBA_flags |= PRINT_PHY_LINKSTAT;
270 break;
271 case 'v':
272 processHBA_flags |= PRINT_VERBOSE;
273 break;
274 default:
275 break;
276 }
277 }
278
279 if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
280 (void) fprintf(stderr, "%s %s\n",
281 gettext("Failed to load SM-HBA libraries."
282 "Reason:"), getHBAStatus(status));
283 err_cnt++;
284 return (err_cnt);
285 }
286
287 (void) memset(&input, 0, sizeof (input));
288 input.wwnCount = wwnCount;
289 input.wwn_argv = wwn_argv;
290 input.hbaName = hbaName;
291 input.pflag = processHBA_flags;
292
293 /*
294 * Process and filter for every local hba-port,
295 * when the hba-port is not specificed, print all hba-port(s).
296 */
297 err_cnt += processHBA(&input, handleHBAPort);
298
299 (void) HBA_FreeLibrary();
300
301 return (err_cnt);
302 }
303
304 /*
305 * function for expander subcommand
306 *
307 * Arguments:
308 * wwnCount - the number of Remote Port SAS Address in wwn_argv
309 * if wwnCount == 0, then print information on all
310 * expander devices.
311 * if wwnCount > 0, then print information for the exapnders
312 * given in wwn_argv.
313 * wwn_argv - array of WWNs
314 * options - options specified by the caller
315 *
316 * returns:
317 * 0 if successful
318 * >0 otherwise
319 */
320 int
sas_util_list_expander(int wwnCount,char ** wwn_argv,cmdOptions_t * options)321 sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
322 {
323 HBA_STATUS status;
324 int processHBA_flags = 0;
325 char hbaPort[MAXPATHLEN + 1] = {0};
326 inputArg_t input;
327 int err_cnt = 0;
328
329 /* process each of the options */
330 for (; options->optval; options++) {
331 switch (options->optval) {
332 case 'p':
333 (void) strlcpy(hbaPort, options->optarg,
334 sizeof (hbaPort));
335 break;
336 case 't':
337 processHBA_flags |= PRINT_TARGET_PORT;
338 break;
339 case 'v':
340 processHBA_flags |= PRINT_VERBOSE;
341 break;
342 default:
343 break;
344 }
345 }
346
347 if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
348 (void) fprintf(stderr, "%s %s\n",
349 gettext("Failed to load SM-HBA libraries."
350 "Reason:"), getHBAStatus(status));
351 err_cnt++;
352 return (err_cnt);
353 }
354
355 (void) memset(&input, 0, sizeof (input));
356 input.wwnCount = wwnCount;
357 input.wwn_argv = wwn_argv;
358 input.pflag = processHBA_flags;
359 input.hbaName = hbaPort;
360
361 /*
362 * Process and filter for every hba-port,
363 * when the hba-port is not specificed, print all hba-port(s).
364 */
365 err_cnt += processHBA(&input, handleExpander);
366
367 (void) HBA_FreeLibrary();
368
369 return (err_cnt);
370 }
371
372 /*
373 * function for target-port subcommand
374 *
375 * Arguments:
376 * wwnCount - the number of Remote Port SAS Address in wwn_argv
377 * if wwnCount == 0, then print information on all
378 * target ports.
379 * if wwnCount > 0, then print information for the target ports
380 * given in wwn_argv.
381 * wwn_argv - array of WWNs
382 * options - options specified by the caller
383 *
384 * returns:
385 * 0 if successful
386 * >0 otherwise
387 */
388 int
sas_util_list_targetport(int tpCount,char ** tpArgv,cmdOptions_t * options)389 sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
390 {
391 HBA_STATUS status;
392 int processHBA_flags = 0;
393 int tp, tpFound;
394 inputArg_t input;
395 targetPortList_t *tpListWalk;
396 int err_cnt = 0;
397 uint64_t tmpAddr;
398
399 /* process each of the options */
400 for (; options->optval; options++) {
401 switch (options->optval) {
402 case 's':
403 processHBA_flags |= PRINT_TARGET_SCSI;
404 break;
405 case 'v':
406 processHBA_flags |= PRINT_VERBOSE;
407 break;
408 default:
409 break;
410 }
411 }
412
413 if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
414 (void) fprintf(stderr, "%s %s\n",
415 gettext("Failed to load SM-HBA libraries."
416 "Reason:"), getHBAStatus(status));
417 err_cnt++;
418 return (err_cnt);
419 }
420
421 (void) memset(&input, 0, sizeof (input));
422 input.wwnCount = tpCount;
423 input.wwn_argv = tpArgv;
424 input.pflag = processHBA_flags;
425
426 /*
427 * Process and filter for every hba-port,
428 * when the hba-port is not specificed, print all hba-port(s).
429 */
430 err_cnt += processHBA(&input, handleTargetPort);
431
432 if (tpCount == 0) {
433 /* list all target port */
434 for (tpListWalk = gTargetPortList; tpListWalk != NULL;
435 tpListWalk = tpListWalk->next) {
436 err_cnt += printTargetPortInfo(tpListWalk, input.pflag);
437 }
438 } else {
439 /*
440 * When operands provided, we should set the error code
441 * only if there are issues related with the operands.
442 */
443 err_cnt = 0;
444 /*
445 * list any paths not found first
446 * this gives the user cleaner output
447 */
448 for (tp = 0; tp < tpCount; tp++) {
449 errno = 0;
450 tmpAddr = strtoull(tpArgv[tp], NULL, 16);
451 if ((tmpAddr == 0) && (errno != 0)) {
452 err_cnt++;
453 continue;
454 }
455 for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
456 tpListWalk != NULL;
457 tpListWalk = tpListWalk->next) {
458 if (wwnConversion(tpListWalk->sasattr.
459 LocalSASAddress.wwn) == tmpAddr) {
460 tpFound = B_TRUE;
461 break;
462 }
463 }
464 if (tpFound == B_FALSE) {
465 (void) fprintf(stderr,
466 "Error: Target Port %s Not Found \n",
467 tpArgv[tp]);
468 err_cnt++;
469 }
470 }
471 /* list all paths requested in order requested */
472 for (tp = 0; tp < tpCount; tp++) {
473 errno = 0;
474 tmpAddr = strtoull(tpArgv[tp], NULL, 16);
475 if ((tmpAddr == 0) && (errno != 0)) {
476 continue;
477 }
478 for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
479 tpListWalk != NULL;
480 tpListWalk = tpListWalk->next) {
481 if (wwnConversion(tpListWalk->sasattr.
482 LocalSASAddress.wwn) == tmpAddr) {
483 err_cnt += printTargetPortInfo(
484 tpListWalk,
485 processHBA_flags);
486 }
487 }
488 }
489 }
490 (void) HBA_FreeLibrary();
491 return (err_cnt);
492 }
493 /*
494 * This function will enumerate all the hba and hba ports,
495 * call the callback function to proceed with futher process.
496 *
497 * Arguments:
498 * input - contains all the input parameters.
499 * processPort - a callback function when handling each port.
500 *
501 * Return Value:
502 * 0 sucessfully processed handle
503 * >0 error has occured
504 */
505 static int
processHBA(inputArg_t * input,processPortFunc processPort)506 processHBA(inputArg_t *input, processPortFunc processPort)
507 {
508 int numAdapters = 0;
509 int matchedHBAs = 0;
510 int matchedHBAPorts = 0;
511 int hbaPortExist = 0;
512 HBA_STATUS status;
513 HBA_HANDLE handle;
514 HBA_UINT32 numberOfPorts = 0;
515 int portIndex = 0;
516 HBA_PORTTYPE porttype;
517 SMHBA_LIBRARYATTRIBUTES libattrs;
518 SMHBA_ADAPTERATTRIBUTES attrs;
519 SMHBA_PORTATTRIBUTES port;
520 SMHBA_SAS_PORT sasattrs;
521 int i, sum, ret = 0;
522 int remote_avail = 0;
523 int local_avail = 0;
524 sas_elem_t *adpt_array = NULL;
525 sas_elem_t *port_array = NULL;
526
527 numAdapters = HBA_GetNumberOfAdapters();
528 if (numAdapters == 0) {
529 (void) fprintf(stderr, "%s\n",
530 gettext("Error: No Adapters Found."));
531 return (++ret);
532 }
533
534 /*
535 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
536 * array of flags for each operands.
537 */
538 if (input->wwnCount && (processPort != handleTargetPort) &&
539 (processPort != handleLogicalUnit)) {
540 input->wwn_flag = calloc(input->wwnCount, sizeof (int));
541 if (input->wwn_flag == NULL) {
542 (void) fprintf(stderr, "%s\n",
543 gettext("No enough memory on heap"));
544 return (++ret);
545 }
546 }
547
548 adpt_array = calloc(numAdapters, sizeof (sas_elem_t));
549 if (adpt_array == NULL) {
550 (void) fprintf(stderr, "%s\n",
551 gettext("No enough memory on heap"));
552 if (input->wwn_flag) {
553 free(input->wwn_flag);
554 input->wwn_flag = NULL;
555 }
556 return (++ret);
557 }
558 for (i = 0; i < numAdapters; i++) {
559 status =
560 SMHBA_GetVendorLibraryAttributes(i, &libattrs);
561 /*
562 * If we get SAS incompatible library warning here,
563 * just skip the following steps.
564 */
565 if (status != 1) {
566 continue;
567 }
568 status = HBA_GetAdapterName(i, adpt_array[i].name);
569 if (status != HBA_STATUS_OK) {
570 (void) fprintf(stderr, "%s %d %s %s\n",
571 gettext("Error: Failed to get the name for"
572 " HBA index"),
573 i, gettext("Reason:"),
574 getHBAStatus(status));
575 ret++;
576 continue;
577 }
578 adpt_array[i].index = i;
579 }
580 /* Sort the HBA Name in place. */
581 sas_elem_sort(adpt_array, numAdapters);
582
583 for (i = 0; i < numAdapters; i++) {
584 int times = 0;
585 if (adpt_array[i].name[0] != '\0') {
586 if ((handle = HBA_OpenAdapter(adpt_array[i].name))
587 == 0) {
588 (void) fprintf(stderr, "%s %s.\n",
589 gettext("Error: Failed to open adapter"),
590 adpt_array[i].name);
591 ret++;
592 continue;
593 }
594 } else {
595 continue;
596 }
597
598 /*
599 * We need to support an adapter without hba port.
600 * So get attributes anyway.
601 */
602 (void) memset(&attrs, 0, sizeof (attrs));
603 status = SMHBA_GetAdapterAttributes(handle, &attrs);
604 while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
605 status == HBA_STATUS_ERROR_BUSY) &&
606 times++ < HBA_MAX_RETRIES) {
607 (void) sleep(1);
608 status = SMHBA_GetAdapterAttributes(handle,
609 &attrs);
610 }
611 if (status != HBA_STATUS_OK) {
612 (void) fprintf(stderr, "%s %s %s %s\n",
613 gettext("Error: Failed to get attributes"
614 " for HBA "), adpt_array[i].name,
615 gettext("Reason:"),
616 getHBAStatus(status));
617
618 HBA_CloseAdapter(handle);
619 ret++;
620 continue;
621 }
622
623 status = SMHBA_GetNumberOfPorts(handle, &numberOfPorts);
624 if (status != HBA_STATUS_OK) {
625 (void) fprintf(stderr, "%s %s %s %s\n",
626 gettext("Error: Failed to get number of ports "
627 "for HBA"), adpt_array[i].name,
628 gettext("Reason:"),
629 getHBAStatus(status));
630 HBA_CloseAdapter(handle);
631 ret++;
632 continue;
633 }
634
635 /*
636 * Deal with each subcommand for hba filter here,
637 * processPort is NULL for hba subcommand.
638 */
639 if (processPort == NULL) {
640 matchedHBAs += handleHBA(&attrs, input,
641 numberOfPorts, adpt_array[i].name);
642 HBA_CloseAdapter(handle);
643 continue;
644 } else if (processPort == handleHBAPort) {
645 if (input->hbaName[0] != '\0') {
646 if (strcmp(input->hbaName,
647 adpt_array[i].name) == 0) {
648 matchedHBAs++;
649 } else {
650 continue;
651 }
652 } else {
653 matchedHBAs++;
654 }
655 } else {
656 matchedHBAs++;
657 }
658
659 /*
660 * In order to have a sorted output for HBA Port, we should
661 * do the sorting before moving on.
662 */
663 if (numberOfPorts) {
664 port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
665 }
666 for (portIndex = 0; portIndex < numberOfPorts; portIndex++) {
667 if ((status = SMHBA_GetPortType(handle,
668 portIndex, &porttype)) != HBA_STATUS_OK) {
669 (void) fprintf(stderr, "%s %s %s %s\n",
670 gettext("Failed to get adapter port type "
671 "for HBA"), adpt_array[i].name,
672 gettext("Reason:"),
673 getHBAStatus(status));
674 ret++;
675 continue;
676 }
677 if (porttype != HBA_PORTTYPE_SASDEVICE) {
678 /* skip any non-sas hba port */
679 continue;
680 }
681 (void) memset(&port, 0, sizeof (port));
682 (void) memset(&sasattrs, 0, sizeof (sasattrs));
683 port.PortSpecificAttribute.SASPort = &sasattrs;
684 if ((status = SMHBA_GetAdapterPortAttributes(
685 handle, portIndex, &port)) != HBA_STATUS_OK) {
686 /*
687 * Not able to get port attributes.
688 * print out error message and
689 * move on to the next port
690 */
691 (void) fprintf(stderr, "%s %s %s %d %s %s\n",
692 gettext("Error: Failed to get port "
693 "attributes for HBA"), adpt_array[i].name,
694 gettext("port index"), portIndex,
695 gettext("Reason:"),
696 getHBAStatus(status));
697 ret++;
698 continue;
699 }
700 (void) strlcpy(port_array[portIndex].name,
701 port.OSDeviceName,
702 sizeof (port_array[portIndex].name));
703 port_array[portIndex].index = portIndex;
704 }
705 /* Sort the HBA Port Name here. */
706 if (port_array) {
707 sas_elem_sort(port_array, numberOfPorts);
708 }
709 /*
710 * Sum up the local hba ports available.
711 */
712 local_avail += numberOfPorts;
713
714 /*
715 * Clear g_printHBA flag for expander subcommand.
716 */
717 g_printHBA = 0;
718
719 /* process each port on the given adapter */
720 for (portIndex = 0;
721 portIndex < numberOfPorts;
722 portIndex++) {
723 /*
724 * We only handle the port which is valid.
725 */
726 if (port_array[portIndex].name[0] == '\0') {
727 continue;
728 }
729 (void) memset(&port, 0, sizeof (port));
730 (void) memset(&sasattrs, 0, sizeof (sasattrs));
731 port.PortSpecificAttribute.SASPort = &sasattrs;
732
733 (void) SMHBA_GetAdapterPortAttributes(handle,
734 port_array[portIndex].index, &port);
735
736 /*
737 * We have different things to do for the three
738 * sub-commands here.
739 */
740 if (processPort == handleHBAPort) {
741 /*
742 * For hba-port, we will check whether the
743 * specified hba port exist first.
744 * But if no hba port specified, we should
745 * by pass this check(just let hbaPortExist
746 * be 1).
747 */
748 if (input->wwnCount > 0) {
749 if (isStringInArgv(input,
750 port.OSDeviceName)) {
751 hbaPortExist = 1;
752 if (g_printHBA == 0) {
753 (void) fprintf(stdout,
754 "%s %s\n",
755 "HBA Name:",
756 adpt_array[i].name);
757 g_printHBA = 1;
758 }
759 }
760 } else {
761 hbaPortExist = 1;
762 if (g_printHBA == 0) {
763 (void) fprintf(stdout,
764 "%s %s\n",
765 "HBA Name:",
766 adpt_array[i].name);
767 g_printHBA = 1;
768 }
769 }
770 }
771
772 if (processPort == handleExpander) {
773 /*
774 * For expander device, input->hbaName is
775 * the hba port name specified on the
776 * command line(with -p option).
777 */
778 if (input->hbaName[0] != '\0') {
779 if (strcmp(input->hbaName,
780 port.OSDeviceName) == 0)
781 hbaPortExist = 1;
782 } else
783 hbaPortExist = 1;
784 }
785
786 if (processPort == handleTargetPort) {
787 /*
788 * For target port, we don't need to check the
789 * hba port address, so let it go here.
790 */
791 hbaPortExist = 1;
792 }
793
794 if (processPort == handleLogicalUnit) {
795 /*
796 * For lu, we don't need to check the hba
797 * port address, so let it go here.
798 */
799 hbaPortExist = 1;
800 }
801
802 if (hbaPortExist) {
803 if (port.PortSpecificAttribute.SASPort->
804 NumberofDiscoveredPorts) {
805 remote_avail++;
806 }
807 ret += (*processPort)(handle,
808 adpt_array[i].name,
809 port_array[portIndex].index, &port,
810 &attrs, input);
811 /*
812 * We should reset the hbaPortExist flag
813 * here for next round of check and count
814 * for the machedHBAPorts.
815 */
816 hbaPortExist = 0;
817 matchedHBAPorts++;
818 }
819 }
820 if (port_array) {
821 free(port_array);
822 port_array = NULL;
823 }
824 HBA_CloseAdapter(handle);
825 }
826 if (adpt_array) {
827 free(adpt_array);
828 adpt_array = NULL;
829 }
830
831 /*
832 * When we are here, we have traversed all the hba and hba ports.
833 */
834 if (matchedHBAs == 0) {
835 (void) fprintf(stderr, "%s\n",
836 gettext("Error: Matching HBA not found."));
837 if (input->wwn_flag) {
838 free(input->wwn_flag);
839 input->wwn_flag = NULL;
840 }
841 return (++ret);
842 } else if (processPort == NULL) {
843 /*
844 * processPort == NULL signifies hba subcommand.
845 * If enter here, it means we have at least one matching
846 * hba, we need to check if there are mismatching ones.
847 */
848 for (i = 0; i < input->wwnCount; i++) {
849 if (input->wwn_flag[i] == 0) {
850 (void) fprintf(stderr, "%s %s %s\n",
851 gettext("Error: HBA"),
852 input->wwn_argv[i],
853 gettext("not found."));
854 ret++;
855 }
856 }
857 } else {
858 if (local_avail > 0 && matchedHBAPorts == 0) {
859 (void) fprintf(stderr, "%s\n",
860 gettext("Error: Matching HBA Port "
861 "not found."));
862 if (input->wwn_flag) {
863 free(input->wwn_flag);
864 input->wwn_flag = NULL;
865 }
866 return (++ret);
867 } else if (local_avail == 0) {
868 (void) fprintf(stderr, "%s\n",
869 gettext("Error: No HBA Port Configured."));
870 if (input->wwn_flag) {
871 free(input->wwn_flag);
872 input->wwn_flag = NULL;
873 }
874 return (++ret);
875 } else if (processPort == handleHBAPort) {
876 /*
877 * If enter here, we have at least one HBA port
878 * matched. For hba-port subcommand, we shall check
879 * whether there are operands mismatching.
880 */
881 for (i = 0; i < input->wwnCount; i++) {
882 if (input->wwn_flag[i] == 0) {
883 (void) fprintf(stderr, "%s %s %s\n",
884 gettext("Error: HBA Port"),
885 input->wwn_argv[i],
886 gettext("not found."));
887 ret++;
888 }
889 }
890 }
891 }
892
893 /*
894 * For expander subcommand, we need to check if the
895 * specified sas address(ese) exist (none/partial/all).
896 */
897 if (processPort == handleExpander) {
898 if (input->wwnCount > 0) {
899 sum = 0;
900 for (i = 0; i < input->wwnCount; i++) {
901 sum += input->wwn_flag[i];
902 }
903 /*
904 * If sum is zero, it means that for all the given
905 * operands matching count is zero. So none of the
906 * specified SAS address exist actually.
907 */
908 if (sum == 0) {
909 (void) fprintf(stderr, gettext("Error: "
910 "Matching SAS Address not found.\n"));
911 free(input->wwn_flag);
912 input->wwn_flag = NULL;
913 return (++ret);
914 }
915
916 /*
917 * If we get here, it means that some of the specified
918 * sas address exist, we will know through looping the
919 * wwn_flag array.
920 */
921 for (i = 0; i < input->wwnCount; i++) {
922 if (input->wwn_flag[i] == 0) {
923 (void) fprintf(stderr, "%s %s %s\n",
924 gettext("Error: SAS Address"),
925 input->wwn_argv[i],
926 gettext("not found."));
927 ret++;
928 }
929 }
930 }
931 /* even if no remote port is found it is not an error. */
932 }
933 if (input->wwn_flag) {
934 free(input->wwn_flag);
935 input->wwn_flag = NULL;
936 }
937 return (ret);
938 }
939
940 /*
941 * This function will handle the phy stuff for hba-port subcommand.
942 *
943 * Arguments:
944 * handle - handle to hba port.
945 * portIndex - the index of hba port currently being processed.
946 * port - pointer to hba port attributes.
947 * pflag - options user specified.
948 *
949 * Return Value:
950 * 0 sucessfully processed handle
951 * >0 error has occured
952 */
953 static int
processHBAPortPhyInfo(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,int pflag)954 processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
955 SMHBA_PORTATTRIBUTES *port, int pflag)
956 {
957 int phyIndex = 0, err_cnt = 0;
958 HBA_UINT32 numphys = 0;
959 HBA_STATUS status = 0;
960 SMHBA_SAS_PHY phyattrs;
961
962 if (port == NULL)
963 return (++err_cnt);
964
965 numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
966 if (numphys == 0)
967 return (0);
968
969 if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
970 (void) fprintf(stdout, "%s\n", " Phy Information:");
971 else
972 return (0);
973
974
975 for (phyIndex = 0; phyIndex < numphys; phyIndex++) {
976 (void) memset(&phyattrs, 0, sizeof (phyattrs));
977 status = SMHBA_GetSASPhyAttributes(
978 handle, portIndex, phyIndex, &phyattrs);
979 if (status != HBA_STATUS_OK) {
980 (void) fprintf(stderr, "%s %d %s %s\n",
981 gettext("Failed to get SAS Phy attributes"
982 "phyIndex"), phyIndex,
983 gettext("Reason:"),
984 getHBAStatus(status));
985 err_cnt++;
986 continue;
987 }
988 if (pflag & PRINT_PHY)
989 printHBAPortPhyInfo(&phyattrs);
990 if (pflag & PRINT_PHY_LINKSTAT)
991 err_cnt += processHBAPortPhyStat(handle,
992 portIndex, phyIndex, &phyattrs, pflag);
993 }
994 return (err_cnt);
995 }
996
997 /*
998 * This function will handle the phy stuff for hba-port subcommand.
999 *
1000 * Arguments:
1001 * handle - handle to hba port.
1002 * portIndex - the index of hba port currently being processed.
1003 * port - pointer to hba port attributes.
1004 * pflag - options user specified.
1005 *
1006 * Return Value:
1007 * 0 sucessfully processed handle
1008 * >0 error has occured
1009 */
1010 static int
processHBAPortPhyStat(HBA_HANDLE handle,HBA_UINT32 portIndex,int phyIndex,PSMHBA_SAS_PHY phyattrs,int pflag)1011 processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
1012 PSMHBA_SAS_PHY phyattrs, int pflag)
1013 {
1014 HBA_STATUS status = 0;
1015 SMHBA_PHYSTATISTICS phystat;
1016 SMHBA_SASPHYSTATISTICS sasphystat;
1017
1018 if ((pflag & PRINT_PHY) == 0) {
1019 (void) fprintf(stdout, "%s %d\n",
1020 " Identifier:", phyattrs->PhyIdentifier);
1021 }
1022
1023 (void) memset(&phystat, 0, sizeof (phystat));
1024 (void) memset(&sasphystat, 0, sizeof (sasphystat));
1025 phystat.SASPhyStatistics = &sasphystat;
1026 status = SMHBA_GetPhyStatistics(handle, portIndex, phyIndex, &phystat);
1027 if (status != HBA_STATUS_OK) {
1028 (void) fprintf(stdout, "%s\n",
1029 " Link Error Statistics:");
1030 (void) fprintf(stderr, "%s\n",
1031 gettext(" Failed to retrieve Link "
1032 "Error Statistics!"));
1033 return (1);
1034 }
1035 printHBAPortPhyStatistics(phystat.SASPhyStatistics);
1036 return (0);
1037 }
1038
1039 /*
1040 * Check whether the pWWN exist in the WWNs list which specified by user.
1041 *
1042 * Arguments:
1043 * input - contains all the input parameters.
1044 * pWWN - pointer to the hba port sas address.
1045 *
1046 * Return Value:
1047 * 1 true, the pWWN exist in the sas address list specified.
1048 * 0 false.
1049 */
1050 static int
isPortWWNInArgv(inputArg_t * input,PHBA_WWN pWWN)1051 isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
1052 {
1053 int port_wwn_counter = 0;
1054 int portfound = 0;
1055 uint64_t hbaWWN;
1056
1057 /* list only ports given in wwn_argv */
1058 for (port_wwn_counter = 0;
1059 port_wwn_counter < input->wwnCount;
1060 port_wwn_counter++) {
1061 hbaWWN = strtoull(input->wwn_argv[port_wwn_counter], NULL,
1062 16);
1063 if (hbaWWN == 0 && errno != 0)
1064 continue;
1065 if (wwnConversion(pWWN->wwn) == hbaWWN) {
1066 if (input->wwn_flag) {
1067 input->wwn_flag[port_wwn_counter]++;
1068 }
1069 portfound = 1;
1070 }
1071 }
1072 return (portfound);
1073 }
1074
1075 /*
1076 * Check whether the string value exists in the input list,
1077 * which specified by user.
1078 *
1079 * Arguments:
1080 * input - contains all the input parameters.
1081 * stringName - could be hba adapter name
1082 * hba-port name.
1083 *
1084 * Return Value:
1085 * 1 true, the HBA exists in the list specified.
1086 * 0 false.
1087 */
1088 static int
isStringInArgv(inputArg_t * input,const char * stringName)1089 isStringInArgv(inputArg_t *input, const char *stringName)
1090 {
1091 int counter = 0;
1092 int found = 0;
1093
1094 /* list only hba(s) given in wwn_argv */
1095 for (counter = 0;
1096 counter < input->wwnCount;
1097 counter++) {
1098 if (strcmp(input->wwn_argv[counter],
1099 stringName) == 0) {
1100 if (input->wwn_flag)
1101 input->wwn_flag[counter]++;
1102 found = 1;
1103 }
1104 }
1105 return (found);
1106 }
1107
1108 /*
1109 * Callback function for hba subcommand.
1110 *
1111 * Arguments:
1112 * attrs - pointer to adapter attributes currently being processed.
1113 * input - contains all the input parameters.
1114 * numberOfPorts - number of ports of this HBA.
1115 *
1116 * Return Value:
1117 * matching number
1118 */
handleHBA(SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input,int numberOfPorts,const char * adapterName)1119 static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
1120 int numberOfPorts, const char *adapterName)
1121 {
1122 int matchingHBA = 1;
1123
1124 if (input->wwnCount == 0) {
1125 printHBAInfo(attrs, input->pflag, numberOfPorts, adapterName);
1126 } else {
1127 if (isStringInArgv(input, adapterName)) {
1128 printHBAInfo(attrs,
1129 input->pflag, numberOfPorts, adapterName);
1130 } else {
1131 matchingHBA = 0;
1132 }
1133 }
1134
1135 return (matchingHBA);
1136 }
1137
1138 /*
1139 * Callback function for hba-port subcommand.
1140 *
1141 * Arguments:
1142 * handle - handle to hba port.
1143 * portIndex - the index of hba port currently being processed.
1144 * port - pointer to hba port attributes.
1145 * attrs - pointer to adapter attributes currently being processed.
1146 * input - contains all the input parameters.
1147 *
1148 * Return Value:
1149 * 0 sucessfully processed handle
1150 * >0 error has occured
1151 */
1152 /*ARGSUSED*/
handleHBAPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1153 static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
1154 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1155 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1156 {
1157 int ret = 0;
1158 printHBAPortInfo(port, attrs, input->pflag);
1159 ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
1160 return (ret);
1161 }
1162
1163 /*
1164 * Callback function for expander subcommand.
1165 *
1166 * Arguments:
1167 * handle - handle to hba port.
1168 * portIndex - the index of hba port currently being processed.
1169 * port - pointer to hba port attributes.
1170 * attrs - pointer to adapter attributes currently being processed.
1171 * input - contains all the input parameters.
1172 *
1173 * Return Value:
1174 * 0 sucessfully processed handle
1175 * >0 error has occured
1176 */
1177 /*ARGSUSED*/
handleExpander(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1178 static int handleExpander(HBA_HANDLE handle, char *adapterName,
1179 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1180 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1181 {
1182 SMHBA_PORTATTRIBUTES attr;
1183 SMHBA_SAS_PORT sasport;
1184 HBA_STATUS status;
1185 int ret = 0;
1186 int i, numberOfRP;
1187 rp_tree_t *rpnode;
1188 rp_tree_t *rproot = NULL;
1189 rp_tree_t *unsolved_head = NULL;
1190 rp_tree_t *unsolved_tail = NULL;
1191 rp_tree_t *unsolved_sentinel = NULL;
1192 int printPort = 0;
1193 int numberOfEXP = 0;
1194 int unsolved_inserted = 0;
1195 int unsolved_left = 0;
1196 int disco_port_fail = 0;
1197 boolean_t firstPrinted = B_FALSE;
1198
1199 (void) memset(&attr, 0, sizeof (attr));
1200 (void) memset(&sasport, 0, sizeof (sasport));
1201 attr.PortSpecificAttribute.SASPort = &sasport;
1202
1203 /*
1204 * Retrive all expander device from this hba port first.
1205 */
1206 if ((numberOfRP = port->PortSpecificAttribute.SASPort->
1207 NumberofDiscoveredPorts) == 0) {
1208 /* no remote port. just return 0. */
1209 return (ret);
1210 }
1211
1212 for (i = 0; i < numberOfRP; i++) {
1213 rpnode = calloc(1, sizeof (rp_tree_t));
1214 rpnode->portattr.PortSpecificAttribute.SASPort =
1215 &rpnode->sasattr;
1216 status = SMHBA_GetDiscoveredPortAttributes(handle,
1217 portIndex, i, &rpnode->portattr);
1218 if (status != HBA_STATUS_OK) {
1219 disco_port_fail++;
1220 free(rpnode);
1221 ret++;
1222 continue;
1223 }
1224
1225 if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
1226 numberOfEXP++;
1227 }
1228 /*
1229 * We will try to insert this expander device and target
1230 * ports into the topology tree. If we failed, we can chain
1231 * them together and try again when we have all the
1232 * discovered port information in hands.
1233 */
1234 if (rproot == NULL && memcmp(port->
1235 PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
1236 rpnode->sasattr.AttachedSASAddress.wwn,
1237 sizeof (HBA_WWN)) == 0) {
1238 /*
1239 * The root node of tree should
1240 * be set up first.
1241 */
1242 rproot = rpnode;
1243 } else {
1244 /*
1245 * If we can not set up the root node of
1246 * the tree or we failed to insert
1247 * the disocvered port node, queue it up then.
1248 */
1249 if (rproot == NULL ||
1250 sas_rp_tree_insert(&rproot, rpnode) != 0) {
1251 if (unsolved_head == NULL) {
1252 unsolved_head = rpnode;
1253 unsolved_tail = rpnode;
1254 } else {
1255 rpnode->sibling = unsolved_head;
1256 unsolved_head = rpnode;
1257 }
1258 }
1259 }
1260 }
1261
1262 if (disco_port_fail) {
1263 (void) fprintf(stderr, "%s %d %s %s\n",
1264 gettext("Error: Failed to get attributes for"),
1265 disco_port_fail,
1266 gettext("connected ports of HBA port"),
1267 port->OSDeviceName);
1268 }
1269
1270 /* no expander found. No need further processing. */
1271 if (numberOfEXP == 0) {
1272 while (unsolved_head) {
1273 unsolved_tail =
1274 unsolved_head->sibling;
1275 free(unsolved_head);
1276 unsolved_head = unsolved_tail;
1277 }
1278 if (rproot) sas_rp_tree_free(rproot);
1279 return (ret);
1280 }
1281
1282 /*
1283 * When we're here, we should already have all information,
1284 * now we try again to insert them into the topology tree.
1285 * unsolved_head is the pointer which point to the head of
1286 * unsolved rpnode linked list.
1287 * unsolved_tail is the pointer which point to the tail of
1288 * unsolved rpnode linked list.
1289 * unsolved_sentinel is for insertion failure detection.
1290 * When we're trying to insert the rpnodes from unsolved
1291 * linked list, it may happen that some of the rpnodes can
1292 * not be inserted no matter how many times we loop through
1293 * this linked list. So we use unsolved_sentinel to identify
1294 * the tail of last round of scanning, and unsolved_inserted
1295 * which is a counter will be used to count how many rpnodes
1296 * have been inserted from last round, if it is zero, which
1297 * means that we can not insert rpnodes into rptree any more,
1298 * and we should stop and deallocate the memory they occupied.
1299 */
1300 unsolved_sentinel = unsolved_tail;
1301 while (unsolved_head) {
1302 rpnode = unsolved_head;
1303 unsolved_head = unsolved_head->sibling;
1304 if (unsolved_head == NULL)
1305 unsolved_tail = NULL;
1306 rpnode->sibling = NULL;
1307 if (sas_rp_tree_insert(&rproot, rpnode) != 0) {
1308 unsolved_tail->sibling = rpnode;
1309 unsolved_tail = rpnode;
1310 if (rpnode == unsolved_sentinel) {
1311 /*
1312 * We just scanned one round for the
1313 * unsolved list. Check to see whether we
1314 * have nodes inserted, if none, we should
1315 * break in case of an indefinite loop.
1316 */
1317 if (unsolved_inserted == 0) {
1318 /*
1319 * Indicate there is unhandled node.
1320 * Chain free the whole unsolved
1321 * list here.
1322 */
1323 unsolved_left++;
1324 break;
1325 } else {
1326 unsolved_inserted = 0;
1327 unsolved_sentinel = unsolved_tail;
1328 }
1329 }
1330 } else {
1331 /*
1332 * We just inserted one rpnode, increment the
1333 * unsolved_inserted counter. We will utilize this
1334 * counter to detect an indefinite insertion loop.
1335 */
1336 unsolved_inserted++;
1337 }
1338 }
1339
1340 /* check if there is left out discovered ports. */
1341 if (unsolved_left) {
1342 ret++;
1343 (void) fprintf(stderr, "%s %s\n",
1344 gettext("Error: Failed to establish expander topology on"),
1345 port->OSDeviceName);
1346 (void) fprintf(stderr, "%s\n",
1347 gettext(" Folowing port(s) are unresolved."));
1348 while (unsolved_head) {
1349 unsolved_tail =
1350 unsolved_head->sibling;
1351 (void) fprintf(stderr, "%s%016llx ",
1352 firstPrinted ? "" : "\t",
1353 wwnConversion(unsolved_head->sasattr.
1354 LocalSASAddress.wwn));
1355 if (firstPrinted == B_FALSE) firstPrinted = B_TRUE;
1356 free(unsolved_head);
1357 unsolved_head = unsolved_tail;
1358 }
1359 (void) fprintf(stderr, "\n");
1360 /* still print what we have */
1361 ret += sas_rp_tree_print(handle, adapterName, portIndex,
1362 port, rproot, input, 2 * TABLEN, &printPort);
1363 } else {
1364 ret += sas_rp_tree_print(handle, adapterName, portIndex,
1365 port, rproot, input, 2 * TABLEN, &printPort);
1366 }
1367
1368 if (rproot) sas_rp_tree_free(rproot);
1369
1370 return (ret);
1371 }
1372
1373 /*
1374 * Callback function for target-port subcommand.
1375 *
1376 * Arguments:
1377 * handle - handle to hba port.
1378 * portIndex - the index of hba port currently being processed.
1379 * port - pointer to hba port attributes.
1380 * attrs - pointer to adapter attributes currently being processed.
1381 * input - contains all the input parameters.
1382 *
1383 * Return Value:
1384 * 0 sucessfully processed handle
1385 * >0 error has occured
1386 */
1387 /*ARGSUSED*/
handleTargetPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1388 static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
1389 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1390 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1391 {
1392 HBA_STATUS status;
1393 SMHBA_PORTATTRIBUTES targetattr;
1394 SMHBA_SAS_PORT sasattr;
1395 int i;
1396 int ret = 0;
1397 int disco_port_fail = 0;
1398
1399 targetattr.PortSpecificAttribute.SASPort = &sasattr;
1400
1401 for (i = 0; i < port->PortSpecificAttribute.SASPort->
1402 NumberofDiscoveredPorts; i++) {
1403 status = SMHBA_GetDiscoveredPortAttributes(handle,
1404 portIndex, i, &targetattr);
1405 if (status != HBA_STATUS_OK) {
1406 disco_port_fail++;
1407 } else {
1408 /* skip expander device */
1409 if (targetattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
1410 ret += searchTargetPort(handle, portIndex, port,
1411 &targetattr, &sasattr, input->pflag);
1412 }
1413 }
1414 }
1415
1416 if (disco_port_fail) {
1417 ret++;
1418 (void) fprintf(stderr, "%s %d %s %s\n",
1419 gettext("Error: Failed to get attributes for"),
1420 disco_port_fail,
1421 gettext("connected ports of HBA port"),
1422 port->OSDeviceName);
1423 }
1424 return (ret);
1425 }
1426
1427 /*
1428 * ****************************************************************************
1429 *
1430 * compareLUName -
1431 * compare names directly and also check if disk namees match with
1432 * different slice number or /devices path are speicified and matches.
1433 *
1434 * cmdArg - first string to compare
1435 * osName - os name from attributes
1436 *
1437 * returns B_TRUE if the strings match either directly or via devid
1438 * B_FALSE otherwise
1439 *
1440 * ****************************************************************************
1441 */
1442 static boolean_t
compareLUName(char * cmdArg,char * osName)1443 compareLUName(char *cmdArg, char *osName)
1444 {
1445
1446 boolean_t isSame = B_FALSE;
1447 char dev1[MAXPATHLEN], dev2[MAXPATHLEN];
1448 char *ch1, *ch2;
1449
1450 if (strcmp(cmdArg, osName) == 0) {
1451 isSame = B_TRUE;
1452 } else {
1453 /* user input didn't match, try to match the core of args. */
1454 (void) strlcpy(dev1, cmdArg, MAXPATHLEN);
1455 (void) strlcpy(dev2, osName, MAXPATHLEN);
1456 /* is this /devices path */
1457 if (((ch1 = strrchr(dev1, ',')) != NULL) &&
1458 ((ch2 = strrchr(dev2, ',')) != NULL)) {
1459 *ch1 = *ch2 = '\0';
1460 if (strcmp(dev1, dev2) == 0) {
1461 isSame = B_TRUE;
1462 }
1463 /* is this a /dev link */
1464 } else if ((strncmp(dev1, "/dev/", 5) == 0) &&
1465 (strncmp(dev2, "/dev/", 5) == 0)) {
1466 if ((strstr(dev1, "dsk") != NULL) &&
1467 ((strstr(dev2, "dsk") != NULL))) {
1468 /* if it is disk link */
1469 if (((ch1 = strrchr(dev1, 's')) != NULL) &&
1470 ((ch2 = strrchr(dev2, 's')) != NULL)) {
1471 *ch1 = *ch2 = '\0';
1472 if (strcmp(dev1, dev2) == 0) {
1473 isSame = B_TRUE;
1474 }
1475 }
1476 } else {
1477 /* other dev links */
1478 if (strcmp(dev1, dev2) == 0) {
1479 isSame = B_TRUE;
1480 }
1481 }
1482 }
1483 } /* compare */
1484
1485 return (isSame);
1486 }
1487
1488 /*
1489 * Process logical-unit(lu) subcommand.
1490 *
1491 * Arguments:
1492 * luCount - number of OS device name(s) specified by user.
1493 * luArgv - array of OS device name(s) specified by user.
1494 * options - all the options specified by user.
1495 *
1496 * Return Value:
1497 * 0 sucessfully processed handle
1498 * >0 error has occured
1499 */
1500 int
sas_util_list_logicalunit(int luCount,char ** luArgv,cmdOptions_t * options)1501 sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
1502 {
1503 HBA_STATUS status;
1504 int processHBA_flags = 0;
1505 int lu;
1506 boolean_t pathFound;
1507 boolean_t verbose;
1508 inputArg_t input;
1509 discoveredDevice *LUListWalk = NULL;
1510 int err_cnt = 0;
1511
1512 for (; options->optval; options++) {
1513 if (options->optval == 'v') {
1514 processHBA_flags |= PRINT_VERBOSE;
1515 }
1516 }
1517
1518 /* HBA_LoadLibrary() */
1519 if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1520 (void) fprintf(stderr, "%s %s\n",
1521 gettext("Failed to load SM-HBA libraries."
1522 "Reason:"), getHBAStatus(status));
1523 err_cnt++;
1524 return (err_cnt);
1525 }
1526
1527 (void) memset(&input, 0, sizeof (input));
1528 input.pflag = processHBA_flags;
1529 input.wwnCount = luCount;
1530 input.wwn_argv = luArgv;
1531
1532 err_cnt += processHBA(&input, handleLogicalUnit);
1533 verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
1534
1535 if (luCount == 0) {
1536 /* list all paths */
1537 for (LUListWalk = LUList; LUListWalk != NULL;
1538 LUListWalk = LUListWalk->next) {
1539 err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
1540 }
1541 } else {
1542 /*
1543 * When operands provided, we should set the error code
1544 * only if there are issues related with the operands.
1545 */
1546 err_cnt = 0;
1547 /*
1548 * list any paths not found first
1549 * this gives the user cleaner output
1550 */
1551 for (lu = 0; lu < luCount; lu++) {
1552 for (LUListWalk = LUList, pathFound = B_FALSE;
1553 LUListWalk != NULL;
1554 LUListWalk = LUListWalk->next) {
1555 if (compareLUName(luArgv[lu],
1556 LUListWalk->OSDeviceName)) {
1557 pathFound = B_TRUE;
1558 break;
1559 }
1560 }
1561 if (pathFound == B_FALSE) {
1562 (void) fprintf(stderr,
1563 "Error: Logical Unit %s Not Found \n",
1564 luArgv[lu]);
1565 err_cnt++;
1566 }
1567 }
1568 /* list all paths requested in order requested */
1569 for (lu = 0; lu < luCount; lu++) {
1570 for (LUListWalk = LUList; LUListWalk != NULL;
1571 LUListWalk = LUListWalk->next) {
1572 if (compareLUName(luArgv[lu],
1573 LUListWalk->OSDeviceName)) {
1574 err_cnt += printOSDeviceNameInfo(
1575 LUListWalk,
1576 verbose);
1577 }
1578 }
1579 }
1580 }
1581 (void) HBA_FreeLibrary();
1582 return (err_cnt);
1583 }
1584
1585 /*
1586 * Callback function for logical-unit(lu) subcommand.
1587 *
1588 * Arguments:
1589 * handle - handle to hba port.
1590 * portIndex - the index of hba port currently being processed.
1591 * port - pointer to hba port attributes.
1592 * attrs - pointer to adapter attributes currently being processed.
1593 * input - contains all the input parameters.
1594 *
1595 * Return Value:
1596 * 0 sucessfully processed handle
1597 * >0 error has occured
1598 */
1599 /*ARGSUSED*/
handleLogicalUnit(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1600 static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
1601 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1602 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1603 {
1604 HBA_STATUS status;
1605 SMHBA_TARGETMAPPING *map;
1606 HBA_WWN hbaPortWWN, domainPortWWN;
1607 char *portName = NULL;
1608 int numentries;
1609 int count = 0;
1610 int ret = 0;
1611
1612 hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
1613 portName = port->OSDeviceName;
1614
1615 status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1616 switch (status) {
1617 case HBA_STATUS_OK:
1618 break;
1619 case HBA_STATUS_ERROR_NOT_SUPPORTED:
1620 /* don't increase error flag for no phy configuration */
1621 return (ret);
1622 case HBA_STATUS_ERROR:
1623 default:
1624 return (++ret);
1625 }
1626
1627 if ((map = calloc(1, sizeof (*map))) == NULL) {
1628 (void) fprintf(stderr, "%s\n",
1629 gettext("No enough memory on heap."));
1630 return (++ret);
1631 }
1632 map->NumberOfEntries = 1;
1633
1634 /*
1635 * First, we need to get the target mapping data from this hba
1636 * port.
1637 */
1638 status = SMHBA_GetTargetMapping(handle,
1639 hbaPortWWN, domainPortWWN, map);
1640
1641 if (status == HBA_STATUS_ERROR_MORE_DATA) {
1642 numentries = map->NumberOfEntries;
1643 free(map);
1644 map = calloc(1, sizeof (HBA_UINT32) +
1645 (numentries * sizeof (SMHBA_SCSIENTRY)));
1646 if (map == NULL) {
1647 (void) fprintf(stderr, "%s\n",
1648 gettext("No enough memory on heap."));
1649 return (++ret);
1650 }
1651 map->NumberOfEntries = numentries;
1652 status = SMHBA_GetTargetMapping(handle,
1653 hbaPortWWN, domainPortWWN, map);
1654 }
1655
1656 if (status != HBA_STATUS_OK) {
1657 (void) fprintf(stderr, "%s %016llx %s %s\n",
1658 gettext("Error: Failed to get SCSI mapping data for "
1659 "the HBA port"), wwnConversion(hbaPortWWN.wwn),
1660 gettext("Reason:"),
1661 getHBAStatus(status));
1662 free(map);
1663 return (++ret);
1664 }
1665
1666 /*
1667 * By iterating each entry of the targetmapping data, we will
1668 * construct a global list of logical unit.
1669 */
1670 for (count = 0; count < map->NumberOfEntries; count++) {
1671 ret += searchDevice(
1672 &(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
1673 portName, input->pflag);
1674 }
1675 free(map);
1676 return (ret);
1677 }
1678
1679 /*
1680 * Search the matching targetmapping data for given target port and SAM LUN
1681 * and return target mapping data if found.
1682 *
1683 * Arguments:
1684 * handle - handle to hba port.
1685 * portIndex - hba port index
1686 * port - hba port attributes.
1687 * targetportWWN - target port SAS address.
1688 * domainportWWN - domain port SAS address.
1689 * domainportttr - target port SAS attributes.
1690 * samLUN - samLUN from report LUNs data.
1691 * data - matching target mapping data.
1692 *
1693 * Return Value:
1694 * 0 sucessfully processed handle
1695 * >0 error has occured
1696 */
1697 static int
searchTargetPortMappingData(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_SAS_PORT * sasattr,struct targetPortConfig * configData)1698 searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
1699 SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
1700 struct targetPortConfig *configData)
1701 {
1702 int ret = 0;
1703 HBA_STATUS status;
1704 SMHBA_TARGETMAPPING *map = NULL;
1705 HBA_WWN hbaPortWWN, domainPortWWN;
1706 int numentries, count;
1707 targetPortMappingData_t *TPMapData;
1708 struct scsi_inquiry inq;
1709 struct scsi_extended_sense sense;
1710 HBA_UINT32 responseSize, senseSize = 0;
1711 uchar_t rawLUNs[DEFAULT_LUN_LENGTH], *lun_string;
1712 HBA_UINT8 scsiStatus;
1713 rep_luns_rsp_t *lun_resp;
1714 int lunNum, numberOfLun, lunCount;
1715 uint32_t lunlength, tmp_lunlength;
1716 uint64_t sasLUN;
1717 SMHBA_SCSILUN smhbaLUN;
1718
1719 hbaPortWWN = port->PortSpecificAttribute.SASPort->
1720 LocalSASAddress;
1721
1722 status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1723 if (status == HBA_STATUS_OK) {
1724 if ((map = calloc(1, sizeof (*map))) == NULL) {
1725 (void) fprintf(stderr, "%s\n",
1726 gettext("No enough memory on heap."));
1727 return (++ret);
1728 }
1729 map->NumberOfEntries = 1;
1730
1731 status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
1732 domainPortWWN, map);
1733
1734 if (status == HBA_STATUS_ERROR_MORE_DATA) {
1735 numentries = map->NumberOfEntries;
1736 free(map);
1737 map = calloc(1, sizeof (HBA_UINT32) +
1738 (numentries * sizeof (SMHBA_SCSIENTRY)));
1739 if (map == NULL) {
1740 (void) fprintf(stderr, "%s\n",
1741 gettext("No enough memory on heap."));
1742 return (++ret);
1743 }
1744 map->NumberOfEntries = numentries;
1745 status = SMHBA_GetTargetMapping(handle,
1746 hbaPortWWN, domainPortWWN, map);
1747 }
1748
1749 if (status != HBA_STATUS_OK) {
1750 /* continue to build mapping data based SCSI info */
1751 ret++;
1752 free(map);
1753 map = NULL;
1754 }
1755 }
1756
1757 /*
1758 * Get report lun data.
1759 */
1760 responseSize = DEFAULT_LUN_LENGTH;
1761 senseSize = sizeof (struct scsi_extended_sense);
1762 (void) memset(&sense, 0, sizeof (sense));
1763 status = SMHBA_ScsiReportLUNs(
1764 handle,
1765 hbaPortWWN,
1766 sasattr->LocalSASAddress,
1767 domainPortWWN,
1768 (void *)rawLUNs,
1769 &responseSize,
1770 &scsiStatus,
1771 (void *) &sense, &senseSize);
1772
1773 /*
1774 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
1775 * a remote HBA and move on
1776 */
1777 if (status != HBA_STATUS_OK) {
1778 configData->reportLUNsFailed = B_TRUE;
1779 if (map != NULL) {
1780 /*
1781 * Let's search mapping data and indicate that Report
1782 * LUNs failed.
1783 */
1784 for (count = 0; count < map->NumberOfEntries; count++) {
1785 if (memcmp(map->entry[count].PortLun.
1786 PortWWN.wwn, sasattr->LocalSASAddress.wwn,
1787 sizeof (HBA_WWN)) == 0) {
1788 /* allocate mapping data for each LUN */
1789 TPMapData = calloc(1,
1790 sizeof (targetPortMappingData_t));
1791 if (TPMapData == NULL) {
1792 (void) fprintf(stderr, "%s\n",
1793 gettext("No enough "
1794 "memory."));
1795 free(map);
1796 return (++ret);
1797 }
1798 TPMapData->mappingExist = B_TRUE;
1799 TPMapData->osLUN =
1800 map->entry[count].ScsiId.ScsiOSLun;
1801 (void) strlcpy(TPMapData->osDeviceName,
1802 map->entry[count].ScsiId.
1803 OSDeviceName,
1804 sizeof (TPMapData->osDeviceName));
1805 TPMapData->inq_vid[0] = '\0';
1806 TPMapData->inq_pid[0] = '\0';
1807 TPMapData->inq_dtype = DTYPE_UNKNOWN;
1808 if (configData->map == NULL) {
1809 configData->map = TPMapData;
1810 } else {
1811 TPMapData->next =
1812 configData->map->next;
1813 configData->map = TPMapData;
1814 }
1815 }
1816 }
1817 }
1818 (void) free(map);
1819 return (++ret);
1820 }
1821 lun_resp = (rep_luns_rsp_t *)((void *)rawLUNs);
1822 (void) memcpy(&tmp_lunlength, &(lun_resp->length),
1823 sizeof (tmp_lunlength));
1824 lunlength = ntohl(tmp_lunlength);
1825 (void) memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
1826 for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
1827 /* allocate mapping data for each LUN */
1828 TPMapData = calloc(1,
1829 sizeof (targetPortMappingData_t));
1830 if (TPMapData == NULL) {
1831 (void) fprintf(stderr, "%s\n",
1832 gettext("No enough memory."));
1833 free(map);
1834 return (++ret);
1835 }
1836
1837 (void) memcpy(&TPMapData->reportLUN, lun_resp->
1838 lun[lunCount].val, sizeof (SMHBA_SCSILUN));
1839
1840 /*
1841 * now issue standard inquiry to get Vendor
1842 * and product information
1843 */
1844 responseSize = sizeof (struct scsi_inquiry);
1845 senseSize = sizeof (struct scsi_extended_sense);
1846 (void) memset(&inq, 0, sizeof (struct scsi_inquiry));
1847 (void) memset(&sense, 0, sizeof (sense));
1848 sasLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
1849 (void) memcpy(&smhbaLUN, &sasLUN, sizeof (SMHBA_SCSILUN));
1850 status = SMHBA_ScsiInquiry(
1851 handle,
1852 hbaPortWWN,
1853 sasattr->LocalSASAddress,
1854 domainPortWWN,
1855 smhbaLUN,
1856 0,
1857 0,
1858 (void *) &inq, &responseSize,
1859 &scsiStatus,
1860 (void *) &sense, &senseSize);
1861 if (status != HBA_STATUS_OK) {
1862 TPMapData->inq_vid[0] = '\0';
1863 TPMapData->inq_pid[0] = '\0';
1864 TPMapData->inq_dtype = DTYPE_UNKNOWN;
1865 /* indicate that inquiry for this lun is failed */
1866 TPMapData->inquiryFailed = B_TRUE;
1867 } else {
1868 (void) memcpy(TPMapData->inq_vid, inq.inq_vid,
1869 sizeof (TPMapData->inq_vid));
1870 (void) memcpy(TPMapData->inq_pid, inq.inq_pid,
1871 sizeof (TPMapData->inq_pid));
1872 TPMapData->inq_dtype = inq.inq_dtype;
1873 }
1874
1875 if (map != NULL) {
1876 for (count = 0; count < map->NumberOfEntries; count++) {
1877 if ((memcmp(map->entry[count].PortLun.
1878 PortWWN.wwn, sasattr->LocalSASAddress.wwn,
1879 sizeof (HBA_WWN)) == 0) &&
1880 (memcmp(&(map->entry[count].PortLun.
1881 TargetLun), &smhbaLUN,
1882 sizeof (SMHBA_SCSILUN))
1883 == 0)) {
1884 TPMapData->mappingExist = B_TRUE;
1885 TPMapData->osLUN =
1886 map->entry[count].ScsiId.ScsiOSLun;
1887 (void) strlcpy(TPMapData->osDeviceName,
1888 map->entry[count].ScsiId.
1889 OSDeviceName,
1890 sizeof (TPMapData->osDeviceName));
1891 break;
1892 }
1893 }
1894 if (count == map->NumberOfEntries) {
1895 TPMapData->osDeviceName[0] = '\0';
1896 lun_string = lun_resp->lun[lunCount].val;
1897 lunNum = ((lun_string[0] & 0x3F) << 8) |
1898 lun_string[1];
1899 TPMapData->osLUN = lunNum;
1900 }
1901 } else {
1902 /* Not able to get any target mapping information */
1903 TPMapData->osDeviceName[0] = '\0';
1904 lun_string = lun_resp->lun[lunCount].val;
1905 lunNum = ((lun_string[0] & 0x3F) << 8) |
1906 lun_string[1];
1907 TPMapData->osLUN = lunNum;
1908 }
1909
1910 if (configData->map == NULL) {
1911 configData->map = TPMapData;
1912 } else {
1913 TPMapData->next = configData->map->next;
1914 configData->map = TPMapData;
1915 }
1916 }
1917 free(map);
1918 return (ret);
1919 }
1920
1921 /*
1922 * Search the discovered LUs and construct the global LU list.
1923 *
1924 * Arguments:
1925 * handle - handle to hba port.
1926 * portIndex - hba port index
1927 * port - hba port attributes.
1928 * targetattr - target port attributes.
1929 * sasattr - target port SAS attributes.
1930 * pflag - options the user specified.
1931 *
1932 * Return Value:
1933 * 0 sucessfully processed handle
1934 * >0 error has occured
1935 */
1936 static int
searchTargetPort(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_PORTATTRIBUTES * targetattr,SMHBA_SAS_PORT * sasattr,int pflag)1937 searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
1938 SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
1939 SMHBA_SAS_PORT *sasattr, int pflag)
1940 {
1941 int ret = 0;
1942 HBA_WWN expander;
1943 HBA_WWN domainPortWWN;
1944 targetPortList_t *discoveredTP, *newTP;
1945 targetPortConfig_t *TPConfig, *newConfig, *prevConfig;
1946 boolean_t foundTP = B_FALSE;
1947 boolean_t foundConfig = B_FALSE;
1948 int status;
1949 SMHBA_PORTATTRIBUTES tgtattr;
1950 SMHBA_SAS_PORT tgtsasport;
1951 int expanderValid = 0;
1952
1953 status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1954 switch (status) {
1955 case HBA_STATUS_OK:
1956 break;
1957 case HBA_STATUS_ERROR_NOT_SUPPORTED:
1958 /* don't increase error flag for no phy configuration */
1959 return (ret);
1960 case HBA_STATUS_ERROR:
1961 default:
1962 return (++ret);
1963 }
1964
1965 /*
1966 * First, we will iterate the already constructed target port
1967 * list to see whether there is a target port already exist with
1968 * matching target port SAS address.
1969 */
1970 for (discoveredTP = gTargetPortList; discoveredTP != NULL;
1971 discoveredTP = discoveredTP->next) {
1972 if (memcmp((void *)sasattr->LocalSASAddress.wwn,
1973 (void *)discoveredTP->sasattr.LocalSASAddress.wwn,
1974 sizeof (HBA_WWN)) == 0) {
1975 /*
1976 * if the target port exist and
1977 * verbose is not set, just return
1978 */
1979 if (((pflag & PRINT_VERBOSE) == 0) &&
1980 ((pflag & PRINT_TARGET_SCSI) == 0)) {
1981 return (ret);
1982 }
1983 foundTP = B_TRUE;
1984 break;
1985 }
1986 }
1987
1988 if (foundTP == B_TRUE) {
1989 /*
1990 * If there is a target port already exist, we should
1991 * add more information on the target port to construct the
1992 * whole topology.
1993 * Here we will check whether the current hba port name
1994 * has already been added.
1995 */
1996 /* first get the expander SAS address compare */
1997 if (memcmp((void *)port->PortSpecificAttribute.SASPort->
1998 LocalSASAddress.wwn, (void *)sasattr->
1999 AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
2000 /* NO expander */
2001 (void) memset((void *)expander.wwn, 0,
2002 sizeof (HBA_WWN));
2003 expanderValid = 1;
2004 } else {
2005 if (wwnConversion(sasattr->AttachedSASAddress.wwn)
2006 != 0) {
2007 /* expander exist. We should verify it. */
2008 (void) memcpy((void *)expander.wwn,
2009 (void *)sasattr->AttachedSASAddress.wwn,
2010 sizeof (HBA_WWN));
2011
2012 (void) memset(&tgtattr, 0, sizeof (tgtattr));
2013 (void) memset(&tgtsasport, 0,
2014 sizeof (tgtsasport));
2015 tgtattr.PortSpecificAttribute.SASPort
2016 = &tgtsasport;
2017 status = SMHBA_GetPortAttributesByWWN(handle,
2018 sasattr->AttachedSASAddress, domainPortWWN,
2019 &tgtattr);
2020 if (status == HBA_STATUS_OK && tgtattr.PortType
2021 == HBA_PORTTYPE_SASEXPANDER) {
2022 expanderValid = 1;
2023 }
2024 }
2025 }
2026
2027 for (TPConfig = discoveredTP->configEntry,
2028 foundConfig = B_FALSE; TPConfig != NULL;
2029 TPConfig = TPConfig->next) {
2030 if ((strcmp(TPConfig->hbaPortName,
2031 port->OSDeviceName) == 0) &&
2032 (memcmp((void *)expander.wwn, (void *)TPConfig->
2033 expanderSASAddr.wwn,
2034 sizeof (HBA_WWN)) == 0)) {
2035 foundConfig = B_TRUE;
2036 break;
2037 }
2038 }
2039
2040 /*
2041 * If we get here, it means that it is a new hba port/exapnder
2042 * sas address for this discovered target port.
2043 */
2044 if (foundConfig == B_FALSE) {
2045 newConfig = (targetPortConfig_t *)calloc(1,
2046 sizeof (targetPortConfig_t));
2047 if (newConfig == NULL) {
2048 (void) fprintf(stderr,
2049 "%s\n", strerror(errno));
2050 return (++ret);
2051 }
2052
2053 (void) strlcpy(newConfig->hbaPortName, port->
2054 OSDeviceName, sizeof (newConfig->hbaPortName));
2055 (void) memcpy((void *)newConfig->expanderSASAddr.wwn,
2056 (void *)expander.wwn, sizeof (HBA_WWN));
2057 newConfig->expanderValid = expanderValid;
2058 if (discoveredTP->configEntry == NULL) {
2059 discoveredTP->configEntry = newConfig;
2060 } else {
2061 TPConfig = discoveredTP->configEntry;
2062 prevConfig = TPConfig;
2063 while (TPConfig != NULL &&
2064 sas_name_comp(newConfig->hbaPortName,
2065 TPConfig->hbaPortName) > 0) {
2066 prevConfig = TPConfig;
2067 TPConfig = TPConfig->next;
2068 }
2069 if (TPConfig == prevConfig) {
2070 /* Should be inserted in the head. */
2071 newConfig->next = TPConfig;
2072 discoveredTP->configEntry = newConfig;
2073 } else {
2074 newConfig->next = TPConfig;
2075 prevConfig->next = newConfig;
2076 }
2077 }
2078 /* if scsi option is not set return */
2079 if ((pflag & PRINT_TARGET_SCSI) == 0) {
2080 return (0);
2081 } else {
2082 return (searchTargetPortMappingData(
2083 handle, portIndex, port,
2084 sasattr, newConfig));
2085 }
2086 }
2087 } else {
2088 /*
2089 * Here we got a new target port which has not ever exist
2090 * in our global target port list. So add it to the list.
2091 * list.
2092 */
2093 newTP = (targetPortList_t *)calloc(1,
2094 sizeof (targetPortList_t));
2095
2096 if (newTP == NULL) {
2097 (void) fprintf(stderr, "%s\n", strerror(errno));
2098 return (++ret);
2099 }
2100
2101 (void) memcpy((void *)&newTP->targetattr, (void *)targetattr,
2102 sizeof (SMHBA_PORTATTRIBUTES));
2103 (void) memcpy((void *)&newTP->sasattr, (void *)sasattr,
2104 sizeof (SMHBA_SAS_PORT));
2105
2106 newConfig = (targetPortConfig_t *)calloc(1,
2107 sizeof (targetPortConfig_t));
2108
2109 if (newConfig == NULL) {
2110 (void) fprintf(stderr, "%s\n", strerror(errno));
2111 free(newTP);
2112 return (++ret);
2113 }
2114
2115 (void) strlcpy(newConfig->hbaPortName, port->OSDeviceName,
2116 sizeof (newConfig->hbaPortName));
2117 if (memcmp((void *)port->PortSpecificAttribute.SASPort->
2118 LocalSASAddress.wwn, (void *)sasattr->
2119 AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
2120 /* NO expander */
2121 (void) memset((void *)newConfig->expanderSASAddr.wwn,
2122 0, sizeof (HBA_WWN));
2123 } else {
2124 /* expander exist. We should verify it. */
2125 (void) memcpy((void *)newConfig->expanderSASAddr.wwn,
2126 (void *)sasattr->AttachedSASAddress.wwn,
2127 sizeof (HBA_WWN));
2128
2129 (void) memset(&tgtattr, 0, sizeof (tgtattr));
2130 (void) memset(&tgtsasport, 0, sizeof (tgtsasport));
2131 tgtattr.PortSpecificAttribute.SASPort = &tgtsasport;
2132 status = SMHBA_GetPortAttributesByWWN(handle,
2133 sasattr->AttachedSASAddress, domainPortWWN,
2134 &tgtattr);
2135 if (status == HBA_STATUS_OK && tgtattr.PortType ==
2136 HBA_PORTTYPE_SASEXPANDER) {
2137 expanderValid = 1;
2138 }
2139 newConfig->expanderValid = expanderValid;
2140 }
2141
2142 newTP->configEntry = newConfig;
2143
2144 newTP->next = gTargetPortList; /* insert at head */
2145 gTargetPortList = newTP; /* set new head */
2146
2147 /* if scsi option is not set return */
2148 if ((pflag & PRINT_TARGET_SCSI) == 0) {
2149 return (0);
2150 } else {
2151 return (searchTargetPortMappingData(
2152 handle, portIndex, port, sasattr, newConfig));
2153 }
2154 }
2155 return (ret);
2156 }
2157
2158 /*
2159 * Search the discovered LUs and construct the global LU list.
2160 *
2161 * Arguments:
2162 * entryP - one of the target mapping data.
2163 * handle - handle to hba port.
2164 * hbaPortWWN - hba port sas address.
2165 * domainPortWWN - domain port WWN for this sas domain.
2166 * portName - HBA port OS Device Name.
2167 * pflag - options the user specified.
2168 *
2169 * Return Value:
2170 * 0 sucessfully processed handle
2171 * >0 error has occured
2172 */
2173 static int
searchDevice(PSMHBA_SCSIENTRY entryP,HBA_HANDLE handle,HBA_WWN hbaPortWWN,HBA_WWN domainPortWWN,char * portName,int pflag)2174 searchDevice(PSMHBA_SCSIENTRY entryP,
2175 HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
2176 char *portName, int pflag)
2177 {
2178 HBA_STATUS status;
2179 int ret = 0;
2180 discoveredDevice *discoveredLU, *newDevice;
2181 portList *portElem, *newPort, *prevElem;
2182 tgtPortWWNList *newTgtWWN, *TgtWWNList;
2183 boolean_t foundDevice = B_FALSE;
2184 boolean_t foundPort = B_FALSE;
2185 struct scsi_inquiry inq;
2186 HBA_UINT32 responseSize, senseSize = 0;
2187 HBA_UINT8 inq_status;
2188 SMHBA_SCSILUN smhbaLUN;
2189 struct scsi_extended_sense sense;
2190
2191 /* if OSDeviceName is not set, we don't need to search */
2192 if (entryP->ScsiId.OSDeviceName[0] == '\0') {
2193 return (ret);
2194 }
2195
2196 /*
2197 * First, we will iterate the already constructed discovered LU
2198 * list to see whether there is a LU already exist with the same OS
2199 * device name as current target mapping data entry.
2200 */
2201 for (discoveredLU = LUList; discoveredLU != NULL;
2202 discoveredLU = discoveredLU->next) {
2203 if (strcmp(entryP->ScsiId.OSDeviceName,
2204 discoveredLU->OSDeviceName) == 0) {
2205 /*
2206 * if there is existing OS Device Name and
2207 * verbose is not set, just return
2208 */
2209 if ((pflag & PRINT_VERBOSE) == 0) {
2210 return (ret);
2211 }
2212 foundDevice = B_TRUE;
2213 break;
2214 }
2215 }
2216
2217 if (foundDevice == B_TRUE) {
2218 /*
2219 * If there is a discovered LU already exist, we should
2220 * add more information on this LU to construct the whole
2221 * topology.
2222 * Here we will check whether the current hba port has
2223 * already been added.
2224 */
2225 for (portElem = discoveredLU->HBAPortList,
2226 foundPort = B_FALSE; portElem != NULL;
2227 portElem = portElem->next) {
2228 if (strcmp(portElem->portName,
2229 portName) == 0) {
2230 foundPort = B_TRUE;
2231 break;
2232 }
2233 }
2234
2235 /*
2236 * If we get here, it means that it is a new hba port name
2237 * for this discovered LU.
2238 */
2239 if (foundPort == B_FALSE) {
2240 newPort = (portList *)calloc(1, sizeof (portList));
2241 if (newPort == NULL) {
2242 (void) fprintf(stderr, "%s\n", strerror(errno));
2243 return (++ret);
2244 }
2245 (void) strlcpy(newPort->portName, portName,
2246 sizeof (newPort->portName));
2247
2248 portElem = discoveredLU->HBAPortList;
2249 prevElem = portElem;
2250 while (portElem != NULL &&
2251 sas_name_comp(newPort->portName, portElem->portName)
2252 > 0) {
2253 prevElem = portElem;
2254 portElem = portElem->next;
2255 }
2256 if (portElem == prevElem) {
2257 /* Insert in the head of list. */
2258 newPort->next = portElem;
2259 discoveredLU->HBAPortList = newPort;
2260 } else {
2261 newPort->next = portElem;
2262 prevElem->next = newPort;
2263 }
2264 /* add Target Port */
2265 newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
2266 sizeof (tgtPortWWNList));
2267 if (newPort->tgtPortWWN == NULL) {
2268 (void) fprintf(stderr, "%s\n", strerror(errno));
2269 return (++ret);
2270 }
2271 (void) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
2272 (void *)&(entryP->PortLun.PortWWN),
2273 sizeof (HBA_WWN));
2274 /* Set LUN data */
2275 newPort->tgtPortWWN->scsiOSLun =
2276 entryP->ScsiId.ScsiOSLun;
2277 } else {
2278 /*
2279 * Otherwise, we just need to add the target port
2280 * sas address information.
2281 */
2282 for (TgtWWNList = portElem->tgtPortWWN;
2283 TgtWWNList != NULL;
2284 TgtWWNList = TgtWWNList->next) {
2285 if (memcmp(&TgtWWNList->portWWN,
2286 &entryP->PortLun.PortWWN,
2287 sizeof (HBA_WWN)) == 0)
2288 return (0);
2289 }
2290 /* add it to existing */
2291 newTgtWWN = (tgtPortWWNList *)calloc(1,
2292 sizeof (tgtPortWWNList));
2293 if (newTgtWWN == NULL) {
2294 (void) fprintf(stderr, "%s\n", strerror(errno));
2295 return (++ret);
2296 }
2297 /* insert at head */
2298 newTgtWWN->next = portElem->tgtPortWWN;
2299 portElem->tgtPortWWN = newTgtWWN;
2300 (void) memcpy((void *)&(newTgtWWN->portWWN),
2301 (void *)&(entryP->PortLun.PortWWN),
2302 sizeof (HBA_WWN));
2303 /* Set LUN data */
2304 newTgtWWN->scsiOSLun =
2305 entryP->ScsiId.ScsiOSLun;
2306 }
2307 } else {
2308 /*
2309 * Here we got a new discovered LU which has not ever exist
2310 * in our global LU list. So add it into our global LU
2311 * list.
2312 */
2313 newDevice = (discoveredDevice *)calloc(1,
2314 sizeof (discoveredDevice));
2315
2316 if (newDevice == NULL) {
2317 (void) fprintf(stderr, "%s\n", strerror(errno));
2318 return (++ret);
2319 }
2320 newDevice->next = LUList; /* insert at head */
2321 LUList = newDevice; /* set new head */
2322
2323 /* copy device name */
2324 (void) strlcpy(newDevice->OSDeviceName,
2325 entryP->ScsiId.OSDeviceName,
2326 sizeof (newDevice->OSDeviceName));
2327
2328 /* if verbose is not set return */
2329 if ((pflag & PRINT_VERBOSE) == 0) {
2330 return (0);
2331 }
2332
2333 /* copy WWN data */
2334 newDevice->HBAPortList = (portList *)calloc(1,
2335 sizeof (portList));
2336 if (newDevice->HBAPortList == NULL) {
2337 (void) fprintf(stderr, "%s\n", strerror(errno));
2338 return (++ret);
2339 }
2340 (void) strlcpy(newDevice->HBAPortList->portName,
2341 portName, sizeof (newDevice->HBAPortList->portName));
2342
2343 newDevice->HBAPortList->tgtPortWWN =
2344 (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
2345 if (newDevice->HBAPortList->tgtPortWWN == NULL) {
2346 (void) fprintf(stderr, "%s\n", strerror(errno));
2347 return (++ret);
2348 }
2349
2350 (void) memcpy((void *)&(newDevice->HBAPortList->\
2351 tgtPortWWN->portWWN),
2352 (void *)&(entryP->PortLun.PortWWN),
2353 sizeof (HBA_WWN));
2354 newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
2355 entryP->ScsiId.ScsiOSLun;
2356
2357 responseSize = sizeof (struct scsi_inquiry);
2358 senseSize = sizeof (struct scsi_extended_sense);
2359 (void) memset(&inq, 0, sizeof (struct scsi_inquiry));
2360 (void) memset(&sense, 0, sizeof (sense));
2361 (void) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
2362 sizeof (smhbaLUN));
2363
2364 /*
2365 * Retrieve the VPD data for the newly found discovered LU.
2366 */
2367 status = SMHBA_ScsiInquiry(
2368 handle,
2369 hbaPortWWN,
2370 entryP->PortLun.PortWWN,
2371 domainPortWWN,
2372 smhbaLUN,
2373 0,
2374 0,
2375 (void *) &inq, &responseSize,
2376 &inq_status,
2377 (void *) &sense, &senseSize);
2378
2379 if (status != HBA_STATUS_OK) {
2380 /* init VID/PID/dType as '\0' */
2381 newDevice->VID[0] = '\0';
2382 newDevice->PID[0] = '\0';
2383 newDevice->dType = DTYPE_UNKNOWN;
2384 /* initialize inq status */
2385 newDevice->inquiryFailed = B_TRUE;
2386 ret++;
2387 } else {
2388 (void) memcpy(newDevice->VID, inq.inq_vid,
2389 sizeof (newDevice->VID));
2390 (void) memcpy(newDevice->PID, inq.inq_pid,
2391 sizeof (newDevice->PID));
2392 newDevice->dType = inq.inq_dtype;
2393 /* initialize inq status */
2394 newDevice->inquiryFailed = B_FALSE;
2395 }
2396 }
2397 return (ret);
2398 }
2399
2400 /*
2401 * Function we use to insert a newly discovered port.
2402 * Return:
2403 * 0 - success
2404 * >0 - failed
2405 */
2406 static int
sas_rp_tree_insert(rp_tree_t ** rproot,rp_tree_t * rpnode)2407 sas_rp_tree_insert(rp_tree_t **rproot,
2408 rp_tree_t *rpnode)
2409 {
2410 HBA_UINT8 *wwn1, *wwn2, *wwn3;
2411 rp_tree_t *node_ptr;
2412 int ret = 0;
2413
2414 if (rproot == NULL) {
2415 (void) fprintf(stderr, "%s\n",
2416 gettext("Error: NULL rproot"));
2417 return (1);
2418 }
2419
2420 if (rpnode == NULL) {
2421 (void) fprintf(stderr, "%s\n",
2422 gettext("Error: NULL rpnode"));
2423 return (1);
2424 }
2425
2426 if (*rproot == NULL) {
2427 *rproot = rpnode;
2428 return (0);
2429 }
2430
2431 wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
2432 wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
2433 wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
2434
2435 /*
2436 * If the attched sas address is equal to the local sas address,
2437 * then this should be a child node of current root node.
2438 */
2439 if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
2440 (void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
2441 rpnode->parent = *rproot;
2442 } else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
2443 /*
2444 * If the attached sas address is equal to the attached sas
2445 * address of current root node, then this should be a
2446 * sibling node.
2447 * Insert the SAS/SATA Device at the head of sibling list.
2448 */
2449 if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2450 rpnode->sibling = *rproot;
2451 *rproot = rpnode;
2452 } else {
2453 /*
2454 * Insert the SAS Expander at the tail of sibling
2455 * list.
2456 */
2457 node_ptr = *rproot;
2458 while (node_ptr->sibling != NULL)
2459 node_ptr = node_ptr->sibling;
2460 node_ptr->sibling = rpnode;
2461 }
2462 rpnode->parent = (*rproot)->parent;
2463 } else {
2464 /*
2465 * If enter here, we should first try to insert the discovered
2466 * port node into the child sub-tree, then try to insert to the
2467 * sibling sub-trees. If we failed to insert the discovered
2468 * port node, return 1. The caller will queue this node
2469 * up and retry insertion later.
2470 */
2471 if ((*rproot)->child) {
2472 ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
2473 }
2474 if ((*rproot)->child == NULL || ret != 0) {
2475 if ((*rproot)->sibling) {
2476 ret = sas_rp_tree_insert(&(*rproot)->sibling,
2477 rpnode);
2478 } else
2479 ret = 1;
2480 }
2481 return (ret);
2482 }
2483 return (0);
2484 }
2485
2486 /*
2487 * Function which will print out the whole disocvered port topology.
2488 * Here we use the Preorder Traversal algorithm.
2489 * The indentation rules are:
2490 * 1 * TABLEN - for attributes
2491 * 2 * TABLEN - for next tier target port/expander
2492 */
2493 static int
sas_rp_tree_print(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,rp_tree_t * rpnode,inputArg_t * input,int gident,int * printPort)2494 sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
2495 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
2496 rp_tree_t *rpnode, inputArg_t *input,
2497 int gident, int *printPort)
2498 {
2499 int ret = 0, lident;
2500
2501 if (rpnode == NULL)
2502 return (ret);
2503 lident = gident;
2504
2505 /*
2506 * We assume that all the nodes are disocvered ports(sas device or
2507 * expander).
2508 */
2509 if (input->wwnCount > 0) {
2510 /* Adjust local indentation if a discovered port specified. */
2511 lident = 2 * TABLEN;
2512 /*
2513 * Check whether current node match one of the specified
2514 * SAS addresses.
2515 */
2516 if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
2517 !isPortWWNInArgv(input,
2518 &rpnode->sasattr.LocalSASAddress)) {
2519 /*
2520 * Step down to child tree first.
2521 */
2522 ret += sas_rp_tree_print(handle, adapterName,
2523 portIndex, port, rpnode->child, input,
2524 gident + 2 * TABLEN, printPort);
2525 /*
2526 * Then check the sibling tree.
2527 */
2528 ret += sas_rp_tree_print(handle, adapterName,
2529 portIndex, port, rpnode->sibling, input,
2530 gident, printPort);
2531 return (ret);
2532 }
2533 }
2534
2535 if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
2536 (input->pflag & PRINT_TARGET_PORT)) {
2537 /*
2538 * We should print the header(HBA Name + HBA Port Name)
2539 * on-demand. It means that, if we have expander device
2540 * address specified on the command line, we should print
2541 * the header once we find a matching one. Or we will
2542 * print the header from the beginning of the output.
2543 */
2544 if (g_printHBA == 0) {
2545 (void) fprintf(stdout, "%s %s\n",
2546 "HBA Name:", adapterName);
2547 g_printHBA = 1;
2548 }
2549
2550 if (*printPort == 0) {
2551 (void) fprintf(stdout, "%s%s %s\n",
2552 getIndentSpaces(TABLEN),
2553 "HBA Port Name:", port->OSDeviceName);
2554 *printPort = 1;
2555 }
2556 ret += sas_print_rpnode(input, rpnode, lident, gident);
2557 }
2558
2559 /*
2560 * If operands provided with "-t" option specified, we will print
2561 * the immediate child nodes information under the expander.
2562 */
2563 if (input->pflag & PRINT_TARGET_PORT) {
2564 /* no operand. ignore the option. */
2565 if (input->wwnCount > 0) {
2566 if (rpnode->portattr.PortType ==
2567 HBA_PORTTYPE_SASEXPANDER) {
2568 ret += sas_rp_tree_print_desc(handle,
2569 portIndex, port, rpnode->child,
2570 input,
2571 lident + 2 * TABLEN,
2572 gident + 2 * TABLEN);
2573 }
2574 }
2575 }
2576
2577 /*
2578 * Here we use DFS(Depth First Search) algorithm to traverse the
2579 * whole tree.
2580 */
2581 ret += sas_rp_tree_print(handle, adapterName,
2582 portIndex, port, rpnode->child, input,
2583 gident + 2 * TABLEN, printPort);
2584 ret += sas_rp_tree_print(handle, adapterName,
2585 portIndex, port, rpnode->sibling, input,
2586 gident, printPort);
2587 return (ret);
2588 }
2589
2590 /*
2591 * Function which will destroy the whole discovered port tree.
2592 * Here we use the Postorder Traversal algorithm.
2593 */
sas_rp_tree_free(rp_tree_t * rproot)2594 static void sas_rp_tree_free(rp_tree_t *rproot)
2595 {
2596 tgt_mapping *cur, *next;
2597
2598 if (rproot == NULL)
2599 return;
2600
2601 /*
2602 * Free child tree first.
2603 */
2604 if (rproot->child) {
2605 sas_rp_tree_free(rproot->child);
2606 }
2607
2608 /*
2609 * Free sibling trees then.
2610 */
2611 if (rproot->sibling) {
2612 sas_rp_tree_free(rproot->sibling);
2613 }
2614
2615 /*
2616 * Free root node at last.
2617 */
2618 cur = rproot->first_entry;
2619 while (cur != NULL) {
2620 next = cur->next;
2621 free(cur);
2622 cur = next;
2623 }
2624 free(rproot);
2625 }
2626
2627 /*
2628 * Function used to print out all the descendant nodes.
2629 * handle - handle to HBA.
2630 * port - port attributes of current HBA port.
2631 * desc - the root node of a subtree which will be processed.
2632 * input - input argument.
2633 * lident - local indentation for shifting indentation.
2634 * gident - global indentation, can also be used to obtain Tier number.
2635 */
2636 /*ARGSUSED*/
2637 static int
sas_rp_tree_print_desc(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,rp_tree_t * desc,inputArg_t * input,int lident,int gident)2638 sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
2639 SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
2640 inputArg_t *input, int lident, int gident)
2641 {
2642 int ret = 0;
2643 rp_tree_t *rp_node;
2644
2645 if (desc == NULL)
2646 return (ret);
2647 /*
2648 * Walk through the subtree of desc by Pre-Order Traversal Algo.
2649 */
2650 for (rp_node = desc; rp_node != NULL; rp_node = rp_node->sibling) {
2651 ret += sas_print_rpnode(input, rp_node, lident, gident);
2652 }
2653
2654 return (ret);
2655 }
2656
2657 /*
2658 * Function used to print the information of specified SAS address.
2659 * handle - handle to a HBA.
2660 * port - port attributes of a HBA port.
2661 * rpnode - discovered port which will be processed.
2662 * lident - local indentation used for shifting indentation.
2663 * gident - global indentation used for calculating "Tier" number.
2664 */
2665 static int
sas_print_rpnode(inputArg_t * input,rp_tree_t * rpnode,int lident,int gident)2666 sas_print_rpnode(inputArg_t *input,
2667 rp_tree_t *rpnode, int lident, int gident)
2668 {
2669 int ret = 0;
2670
2671 if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
2672 (void) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
2673 getIndentSpaces(lident),
2674 "Expander SAS Address",
2675 gident / (2 * TABLEN),
2676 wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2677 } else {
2678 (void) fprintf(stdout, "%s%s %016llx\n",
2679 getIndentSpaces(lident),
2680 "Target Port SAS Address:",
2681 wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2682 }
2683 if (input->pflag & PRINT_VERBOSE) {
2684 if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2685 (void) fprintf(stdout, "%s%s %s\n",
2686 getIndentSpaces(TABLEN + lident),
2687 "Type:",
2688 getStateString(rpnode->portattr.PortType,
2689 porttype_string));
2690 } else {
2691 (void) fprintf(stdout, "%s%s %s\n",
2692 getIndentSpaces(TABLEN + lident),
2693 "OS Device Name:",
2694 rpnode->portattr.OSDeviceName);
2695 (void) fprintf(stdout, "%s%s %s\n",
2696 getIndentSpaces(TABLEN + lident),
2697 "State: ",
2698 getStateString(rpnode->portattr.PortState,
2699 portstate_string));
2700 }
2701 }
2702 rpnode->printed = 1;
2703 return (ret);
2704 }
2705
2706 /*
2707 * Function used to get the correct domainPortWWN as needed by some of the
2708 * SMHBA APIs.
2709 * handle - handle to a HBA.
2710 * portIndex - index to locate the port.
2711 * port - pointer to the structure holding port attributes.
2712 * pdomainPort - pointer to the buffer holding domainPortWWN.
2713 */
2714 HBA_STATUS
get_domainPort(HBA_HANDLE handle,int portIndex,PSMHBA_PORTATTRIBUTES port,HBA_WWN * pdomainPort)2715 get_domainPort(HBA_HANDLE handle,
2716 int portIndex, PSMHBA_PORTATTRIBUTES port,
2717 HBA_WWN *pdomainPort)
2718 {
2719 HBA_STATUS status;
2720 PSMHBA_SAS_PORT sasport;
2721 SMHBA_SAS_PHY phyattr;
2722
2723 sasport = port->PortSpecificAttribute.SASPort;
2724 (void) memset(pdomainPort, 0, sizeof (HBA_WWN));
2725 /*
2726 * Since iport can exist without any phys,
2727 * sasinfo hba-port -v has indicated numberOfPhys;
2728 * if there is no phys within the hba, just return OK.
2729 */
2730 if (sasport->NumberofPhys > 0) {
2731 status = SMHBA_GetSASPhyAttributes(handle, portIndex,
2732 0, &phyattr);
2733 if (status != HBA_STATUS_OK)
2734 return (status);
2735 (void) memcpy(pdomainPort, &phyattr.domainPortWWN,
2736 sizeof (HBA_WWN));
2737 } else {
2738 /* return not supported for no phy configured */
2739 return (HBA_STATUS_ERROR_NOT_SUPPORTED);
2740 }
2741 return (HBA_STATUS_OK);
2742 }
2743
2744 /*
2745 * Comparison function for comparing names possibly ending with digits.
2746 * Return:
2747 * <0 - name1 is less than name2.
2748 * 0 - name1 is equal with name2.
2749 * >0 - name1 is more than name2.
2750 */
2751 static int
sas_name_comp(const char * name1,const char * name2)2752 sas_name_comp(const char *name1, const char *name2)
2753 {
2754 int i = 0;
2755
2756 if (name1 == name2)
2757 return (0);
2758
2759 while ((name1[i] == name2[i]) && (name1[i] != '\0'))
2760 i++;
2761
2762 /* If neither of name1[i] and name2[i] is '\0'. */
2763 if (isdigit(name1[i]) && isdigit(name2[i]))
2764 return (atoi(&name1[i]) - atoi(&name2[i]));
2765
2766 /* One of name1[i] and name2[i] is not digit. */
2767 return (name1[i] - name2[i]);
2768 }
2769 /*
2770 * Comparison function for sorting HBA/HBA Port.
2771 * arg1 - first argument of type sas_elem_t.
2772 * arg2 - second argument of type sas_elem_t.
2773 * Return:
2774 * <0 - arg1 is less than arg2.
2775 * 0 - arg1 is equal with arg2.
2776 * >0 - arg1 is more than arg2.
2777 */
2778 static int
sas_elem_compare(const void * arg1,const void * arg2)2779 sas_elem_compare(const void *arg1, const void *arg2)
2780 {
2781 sas_elem_t *p1, *p2;
2782 p1 = (sas_elem_t *)arg1;
2783 p2 = (sas_elem_t *)arg2;
2784 return (sas_name_comp(p1->name, p2->name));
2785 }
2786
2787 /*
2788 * Sorting function for HBA/HBA Port output.
2789 * array - elements array of type sas_elem_t.
2790 * nelem - number of elements in array of type sas_elem_t.
2791 */
2792 static void
sas_elem_sort(sas_elem_t * array,int nelem)2793 sas_elem_sort(sas_elem_t *array, int nelem)
2794 {
2795 qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);
2796 }
2797