3252 Need a proper flock() implementation
[unleashed.git] / usr / src / cmd / sasinfo / sasinfo-list.c
blob57b39b82472802f26cb82f24f03e9734a72aae41
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <printAttrs.h>
31 #include <smhbaapi.h>
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;
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;
52 * Remote port tree node structure.
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;
65 * Report LUN data structure.
67 struct lun {
68 uchar_t val[8];
71 typedef struct rep_luns_rsp {
72 uint32_t length;
73 uint32_t rsrvd;
74 struct lun lun[1];
75 } rep_luns_rsp_t;
78 * The following flag is used for printing HBA header on-demand.
80 static int g_printHBA = 0;
83 * The following structure is for sorted output of HBA and HBA Port.
85 typedef struct _sas_elem {
86 char name[256];
87 int index;
88 }sas_elem_t;
91 * The following two functions are for generating hierachy of expander
92 * subcommand.
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);
110 typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
111 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
112 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
114 static int processHBA(inputArg_t *input,
115 processPortFunc processPort);
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;
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);
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);
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);
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);
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);
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);
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);
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);
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);
176 * function for hba subcommand
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
186 * returns:
187 * 0 if successful
188 * >0 otherwise
191 sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
193 HBA_STATUS status;
194 int processHBA_flags = 0;
195 inputArg_t input;
196 int err_cnt = 0;
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;
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);
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;
224 * Process and filter for every local hba,
225 * when the hba is not specificed, print all hba(s).
227 err_cnt += processHBA(&input, NULL);
229 (void) HBA_FreeLibrary();
231 return (err_cnt);
235 * function for hba-port subcommand
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
245 * returns:
246 * 0 if successful
247 * >0 otherwise
250 sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
252 HBA_STATUS status;
253 int processHBA_flags = 0;
254 inputArg_t input;
255 int err_cnt = 0;
256 char hbaName[256] = {'\0'};
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;
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);
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;
294 * Process and filter for every local hba-port,
295 * when the hba-port is not specificed, print all hba-port(s).
297 err_cnt += processHBA(&input, handleHBAPort);
299 (void) HBA_FreeLibrary();
301 return (err_cnt);
305 * function for expander subcommand
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
316 * returns:
317 * 0 if successful
318 * >0 otherwise
321 sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
323 HBA_STATUS status;
324 int processHBA_flags = 0;
325 char hbaPort[MAXPATHLEN + 1] = {0};
326 inputArg_t input;
327 int err_cnt = 0;
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;
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);
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;
362 * Process and filter for every hba-port,
363 * when the hba-port is not specificed, print all hba-port(s).
365 err_cnt += processHBA(&input, handleExpander);
367 (void) HBA_FreeLibrary();
369 return (err_cnt);
373 * function for target-port subcommand
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
384 * returns:
385 * 0 if successful
386 * >0 otherwise
389 sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
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;
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;
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);
421 (void *) memset(&input, 0, sizeof (input));
422 input.wwnCount = tpCount;
423 input.wwn_argv = tpArgv;
424 input.pflag = processHBA_flags;
427 * Process and filter for every hba-port,
428 * when the hba-port is not specificed, print all hba-port(s).
430 err_cnt += processHBA(&input, handleTargetPort);
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);
438 } else {
440 * When operands provided, we should set the error code
441 * only if there are issues related with the operands.
443 err_cnt = 0;
445 * list any paths not found first
446 * this gives the user cleaner output
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;
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;
464 if (tpFound == B_FALSE) {
465 (void *) fprintf(stderr,
466 "Error: Target Port %s Not Found \n",
467 tpArgv[tp]);
468 err_cnt++;
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;
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);
490 (void) HBA_FreeLibrary();
491 return (err_cnt);
494 * This function will enumerate all the hba and hba ports,
495 * call the callback function to proceed with futher process.
497 * Arguments:
498 * input - contains all the input parameters.
499 * processPort - a callback function when handling each port.
501 * Return Value:
502 * 0 sucessfully processed handle
503 * >0 error has occured
505 static int
506 processHBA(inputArg_t *input, processPortFunc processPort)
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;
527 numAdapters = HBA_GetNumberOfAdapters();
528 if (numAdapters == 0) {
529 (void *) fprintf(stderr, "%s\n",
530 gettext("Error: No Adapters Found."));
531 return (++ret);
535 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
536 * array of flags for each operands.
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);
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;
556 return (++ret);
558 for (i = 0; i < numAdapters; i++) {
559 status =
560 SMHBA_GetVendorLibraryAttributes(i, &libattrs);
562 * If we get SAS incompatible library warning here,
563 * just skip the following steps.
565 if (status != 1) {
566 continue;
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;
578 adpt_array[i].index = i;
580 /* Sort the HBA Name in place. */
581 sas_elem_sort(adpt_array, numAdapters);
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;
594 } else {
595 continue;
599 * We need to support an adapter without hba port.
600 * So get attributes anyway.
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);
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));
618 HBA_CloseAdapter(handle);
619 ret++;
620 continue;
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;
636 * Deal with each subcommand for hba filter here,
637 * processPort is NULL for hba subcommand.
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;
652 } else {
653 matchedHBAs++;
655 } else {
656 matchedHBAs++;
660 * In order to have a sorted output for HBA Port, we should
661 * do the sorting before moving on.
663 if (numberOfPorts) {
664 port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
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;
677 if (porttype != HBA_PORTTYPE_SASDEVICE) {
678 /* skip any non-sas hba port */
679 continue;
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) {
687 * Not able to get port attributes.
688 * print out error message and
689 * move on to the next port
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;
700 (void) strlcpy(port_array[portIndex].name,
701 port.OSDeviceName,
702 sizeof (port_array[portIndex].name));
703 port_array[portIndex].index = portIndex;
705 /* Sort the HBA Port Name here. */
706 if (port_array) {
707 sas_elem_sort(port_array, numberOfPorts);
710 * Sum up the local hba ports available.
712 local_avail += numberOfPorts;
715 * Clear g_printHBA flag for expander subcommand.
717 g_printHBA = 0;
719 /* process each port on the given adapter */
720 for (portIndex = 0;
721 portIndex < numberOfPorts;
722 portIndex++) {
724 * We only handle the port which is valid.
726 if (port_array[portIndex].name[0] == '\0') {
727 continue;
729 (void *) memset(&port, 0, sizeof (port));
730 (void *) memset(&sasattrs, 0, sizeof (sasattrs));
731 port.PortSpecificAttribute.SASPort = &sasattrs;
733 (void) SMHBA_GetAdapterPortAttributes(handle,
734 port_array[portIndex].index, &port);
737 * We have different things to do for the three
738 * sub-commands here.
740 if (processPort == handleHBAPort) {
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).
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;
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;
772 if (processPort == handleExpander) {
774 * For expander device, input->hbaName is
775 * the hba port name specified on the
776 * command line(with -p option).
778 if (input->hbaName[0] != '\0') {
779 if (strcmp(input->hbaName,
780 port.OSDeviceName) == 0)
781 hbaPortExist = 1;
782 } else
783 hbaPortExist = 1;
786 if (processPort == handleTargetPort) {
788 * For target port, we don't need to check the
789 * hba port address, so let it go here.
791 hbaPortExist = 1;
794 if (processPort == handleLogicalUnit) {
796 * For lu, we don't need to check the hba
797 * port address, so let it go here.
799 hbaPortExist = 1;
802 if (hbaPortExist) {
803 if (port.PortSpecificAttribute.SASPort->
804 NumberofDiscoveredPorts) {
805 remote_avail++;
807 ret += (*processPort)(handle,
808 adpt_array[i].name,
809 port_array[portIndex].index, &port,
810 &attrs, input);
812 * We should reset the hbaPortExist flag
813 * here for next round of check and count
814 * for the machedHBAPorts.
816 hbaPortExist = 0;
817 matchedHBAPorts++;
820 if (port_array) {
821 free(port_array);
822 port_array = NULL;
824 HBA_CloseAdapter(handle);
826 if (adpt_array) {
827 free(adpt_array);
828 adpt_array = NULL;
832 * When we are here, we have traversed all the hba and hba ports.
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;
841 return (++ret);
842 } else if (processPort == NULL) {
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.
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++;
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;
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;
874 return (++ret);
875 } else if (processPort == handleHBAPort) {
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.
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++;
894 * For expander subcommand, we need to check if the
895 * specified sas address(ese) exist (none/partial/all).
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];
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.
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);
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.
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++;
931 /* even if no remote port is found it is not an error. */
933 if (input->wwn_flag) {
934 free(input->wwn_flag);
935 input->wwn_flag = NULL;
937 return (ret);
941 * This function will handle the phy stuff for hba-port subcommand.
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.
949 * Return Value:
950 * 0 sucessfully processed handle
951 * >0 error has occured
953 static int
954 processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
955 SMHBA_PORTATTRIBUTES *port, int pflag)
957 int phyIndex = 0, err_cnt = 0;
958 HBA_UINT32 numphys = 0;
959 HBA_STATUS status = 0;
960 SMHBA_SAS_PHY phyattrs;
962 if (port == NULL)
963 return (++err_cnt);
965 numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
966 if (numphys == 0)
967 return (0);
969 if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
970 (void *) fprintf(stdout, "%s\n", " Phy Information:");
971 else
972 return (0);
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;
988 if (pflag & PRINT_PHY)
989 printHBAPortPhyInfo(&phyattrs);
990 if (pflag & PRINT_PHY_LINKSTAT)
991 err_cnt += processHBAPortPhyStat(handle,
992 portIndex, phyIndex, &phyattrs, pflag);
994 return (err_cnt);
998 * This function will handle the phy stuff for hba-port subcommand.
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.
1006 * Return Value:
1007 * 0 sucessfully processed handle
1008 * >0 error has occured
1010 static int
1011 processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
1012 PSMHBA_SAS_PHY phyattrs, int pflag)
1014 HBA_STATUS status = 0;
1015 SMHBA_PHYSTATISTICS phystat;
1016 SMHBA_SASPHYSTATISTICS sasphystat;
1018 if ((pflag & PRINT_PHY) == 0) {
1019 (void *) fprintf(stdout, "%s %d\n",
1020 " Identifier:", phyattrs->PhyIdentifier);
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);
1035 printHBAPortPhyStatistics(phystat.SASPhyStatistics);
1036 return (0);
1040 * Check whether the pWWN exist in the WWNs list which specified by user.
1042 * Arguments:
1043 * input - contains all the input parameters.
1044 * pWWN - pointer to the hba port sas address.
1046 * Return Value:
1047 * 1 true, the pWWN exist in the sas address list specified.
1048 * 0 false.
1050 static int
1051 isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
1053 int port_wwn_counter = 0;
1054 int portfound = 0;
1055 uint64_t hbaWWN;
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]++;
1069 portfound = 1;
1072 return (portfound);
1076 * Check whether the string value exists in the input list,
1077 * which specified by user.
1079 * Arguments:
1080 * input - contains all the input parameters.
1081 * stringName - could be hba adapter name
1082 * hba-port name.
1084 * Return Value:
1085 * 1 true, the HBA exists in the list specified.
1086 * 0 false.
1088 static int
1089 isStringInArgv(inputArg_t *input, const char *stringName)
1091 int counter = 0;
1092 int found = 0;
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;
1105 return (found);
1109 * Callback function for hba subcommand.
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.
1116 * Return Value:
1117 * matching number
1119 static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
1120 int numberOfPorts, const char *adapterName)
1122 int matchingHBA = 1;
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;
1135 return (matchingHBA);
1139 * Callback function for hba-port subcommand.
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.
1148 * Return Value:
1149 * 0 sucessfully processed handle
1150 * >0 error has occured
1152 /*ARGSUSED*/
1153 static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
1154 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1155 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1157 int ret = 0;
1158 printHBAPortInfo(port, attrs, input->pflag);
1159 ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
1160 return (ret);
1164 * Callback function for expander subcommand.
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.
1173 * Return Value:
1174 * 0 sucessfully processed handle
1175 * >0 error has occured
1177 /*ARGSUSED*/
1178 static int handleExpander(HBA_HANDLE handle, char *adapterName,
1179 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1180 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
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;
1199 (void *) memset(&attr, 0, sizeof (attr));
1200 (void *) memset(&sasport, 0, sizeof (sasport));
1201 attr.PortSpecificAttribute.SASPort = &sasport;
1204 * Retrive all expander device from this hba port first.
1206 if ((numberOfRP = port->PortSpecificAttribute.SASPort->
1207 NumberofDiscoveredPorts) == 0) {
1208 /* no remote port. just return 0. */
1209 return (ret);
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;
1225 if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
1226 numberOfEXP++;
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.
1234 if (rproot == NULL && memcmp(port->
1235 PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
1236 rpnode->sasattr.AttachedSASAddress.wwn,
1237 sizeof (HBA_WWN)) == 0) {
1239 * The root node of tree should
1240 * be set up first.
1242 rproot = rpnode;
1243 } else {
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.
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;
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);
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;
1278 if (rproot) sas_rp_tree_free(rproot);
1279 return (ret);
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.
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) {
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.
1317 if (unsolved_inserted == 0) {
1319 * Indicate there is unhandled node.
1320 * Chain free the whole unsolved
1321 * list here.
1323 unsolved_left++;
1324 break;
1325 } else {
1326 unsolved_inserted = 0;
1327 unsolved_sentinel = unsolved_tail;
1330 } else {
1332 * We just inserted one rpnode, increment the
1333 * unsolved_inserted counter. We will utilize this
1334 * counter to detect an indefinite insertion loop.
1336 unsolved_inserted++;
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;
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);
1368 if (rproot) sas_rp_tree_free(rproot);
1370 return (ret);
1374 * Callback function for target-port subcommand.
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.
1383 * Return Value:
1384 * 0 sucessfully processed handle
1385 * >0 error has occured
1387 /*ARGSUSED*/
1388 static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
1389 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1390 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
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;
1399 targetattr.PortSpecificAttribute.SASPort = &sasattr;
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);
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);
1424 return (ret);
1428 * ****************************************************************************
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.
1434 * cmdArg - first string to compare
1435 * osName - os name from attributes
1437 * returns B_TRUE if the strings match either directly or via devid
1438 * B_FALSE otherwise
1440 * ****************************************************************************
1442 static boolean_t
1443 compareLUName(char *cmdArg, char *osName)
1446 boolean_t isSame = B_FALSE;
1447 char dev1[MAXPATHLEN], dev2[MAXPATHLEN];
1448 char *ch1, *ch2;
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;
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;
1476 } else {
1477 /* other dev links */
1478 if (strcmp(dev1, dev2) == 0) {
1479 isSame = B_TRUE;
1483 } /* compare */
1485 return (isSame);
1489 * Process logical-unit(lu) subcommand.
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.
1496 * Return Value:
1497 * 0 sucessfully processed handle
1498 * >0 error has occured
1501 sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
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;
1512 for (; options->optval; options++) {
1513 if (options->optval == 'v') {
1514 processHBA_flags |= PRINT_VERBOSE;
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);
1527 (void *) memset(&input, 0, sizeof (input));
1528 input.pflag = processHBA_flags;
1529 input.wwnCount = luCount;
1530 input.wwn_argv = luArgv;
1532 err_cnt += processHBA(&input, handleLogicalUnit);
1533 verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
1535 if (luCount == 0) {
1536 /* list all paths */
1537 for (LUListWalk = LUList; LUListWalk != NULL;
1538 LUListWalk = LUListWalk->next) {
1539 err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
1541 } else {
1543 * When operands provided, we should set the error code
1544 * only if there are issues related with the operands.
1546 err_cnt = 0;
1548 * list any paths not found first
1549 * this gives the user cleaner output
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;
1561 if (pathFound == B_FALSE) {
1562 (void *) fprintf(stderr,
1563 "Error: Logical Unit %s Not Found \n",
1564 luArgv[lu]);
1565 err_cnt++;
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);
1581 (void) HBA_FreeLibrary();
1582 return (err_cnt);
1586 * Callback function for logical-unit(lu) subcommand.
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.
1595 * Return Value:
1596 * 0 sucessfully processed handle
1597 * >0 error has occured
1599 /*ARGSUSED*/
1600 static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
1601 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1602 SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
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;
1612 hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
1613 portName = port->OSDeviceName;
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);
1627 if ((map = calloc(1, sizeof (*map))) == NULL) {
1628 (void *) fprintf(stderr, "%s\n",
1629 gettext("No enough memory on heap."));
1630 return (++ret);
1632 map->NumberOfEntries = 1;
1635 * First, we need to get the target mapping data from this hba
1636 * port.
1638 status = SMHBA_GetTargetMapping(handle,
1639 hbaPortWWN, domainPortWWN, map);
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);
1651 map->NumberOfEntries = numentries;
1652 status = SMHBA_GetTargetMapping(handle,
1653 hbaPortWWN, domainPortWWN, map);
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);
1667 * By iterating each entry of the targetmapping data, we will
1668 * construct a global list of logical unit.
1670 for (count = 0; count < map->NumberOfEntries; count++) {
1671 ret += searchDevice(
1672 &(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
1673 portName, input->pflag);
1675 free(map);
1676 return (ret);
1680 * Search the matching targetmapping data for given target port and SAM LUN
1681 * and return target mapping data if found.
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.
1693 * Return Value:
1694 * 0 sucessfully processed handle
1695 * >0 error has occured
1697 static int
1698 searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
1699 SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
1700 struct targetPortConfig *configData)
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;
1719 hbaPortWWN = port->PortSpecificAttribute.SASPort->
1720 LocalSASAddress;
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);
1729 map->NumberOfEntries = 1;
1731 status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
1732 domainPortWWN, map);
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);
1744 map->NumberOfEntries = numentries;
1745 status = SMHBA_GetTargetMapping(handle,
1746 hbaPortWWN, domainPortWWN, map);
1749 if (status != HBA_STATUS_OK) {
1750 /* continue to build mapping data based SCSI info */
1751 ret++;
1752 free(map);
1753 map = NULL;
1758 * Get report lun data.
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);
1774 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
1775 * a remote HBA and move on
1777 if (status != HBA_STATUS_OK) {
1778 configData->reportLUNsFailed = B_TRUE;
1779 if (map != NULL) {
1781 * Let's search mapping data and indicate that Report
1782 * LUNs failed.
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);
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;
1818 (void) free(map);
1819 return (++ret);
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);
1837 (void) memcpy(&TPMapData->reportLUN, lun_resp->
1838 lun[lunCount].val, sizeof (SMHBA_SCSILUN));
1841 * now issue standard inquiry to get Vendor
1842 * and product information
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,
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;
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;
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;
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;
1910 if (configData->map == NULL) {
1911 configData->map = TPMapData;
1912 } else {
1913 TPMapData->next = configData->map->next;
1914 configData->map = TPMapData;
1917 free(map);
1918 return (ret);
1922 * Search the discovered LUs and construct the global LU list.
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.
1932 * Return Value:
1933 * 0 sucessfully processed handle
1934 * >0 error has occured
1936 static int
1937 searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
1938 SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
1939 SMHBA_SAS_PORT *sasattr, int pflag)
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;
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);
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.
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) {
1976 * if the target port exist and
1977 * verbose is not set, just return
1979 if (((pflag & PRINT_VERBOSE) == 0) &&
1980 ((pflag & PRINT_TARGET_SCSI) == 0)) {
1981 return (ret);
1983 foundTP = B_TRUE;
1984 break;
1988 if (foundTP == B_TRUE) {
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.
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));
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;
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;
2041 * If we get here, it means that it is a new hba port/exapnder
2042 * sas address for this discovered target port.
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);
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;
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;
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));
2087 } else {
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.
2093 newTP = (targetPortList_t *)calloc(1,
2094 sizeof (targetPortList_t));
2096 if (newTP == NULL) {
2097 (void *) fprintf(stderr, "%s\n", strerror(errno));
2098 return (++ret);
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));
2106 newConfig = (targetPortConfig_t *)calloc(1,
2107 sizeof (targetPortConfig_t));
2109 if (newConfig == NULL) {
2110 (void *) fprintf(stderr, "%s\n", strerror(errno));
2111 free(newTP);
2112 return (++ret);
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));
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;
2139 newConfig->expanderValid = expanderValid;
2142 newTP->configEntry = newConfig;
2144 newTP->next = gTargetPortList; /* insert at head */
2145 gTargetPortList = newTP; /* set new head */
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));
2155 return (ret);
2159 * Search the discovered LUs and construct the global LU list.
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.
2169 * Return Value:
2170 * 0 sucessfully processed handle
2171 * >0 error has occured
2173 static int
2174 searchDevice(PSMHBA_SCSIENTRY entryP,
2175 HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
2176 char *portName, int pflag)
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;
2191 /* if OSDeviceName is not set, we don't need to search */
2192 if (entryP->ScsiId.OSDeviceName[0] == '\0') {
2193 return (ret);
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.
2201 for (discoveredLU = LUList; discoveredLU != NULL;
2202 discoveredLU = discoveredLU->next) {
2203 if (strcmp(entryP->ScsiId.OSDeviceName,
2204 discoveredLU->OSDeviceName) == 0) {
2206 * if there is existing OS Device Name and
2207 * verbose is not set, just return
2209 if ((pflag & PRINT_VERBOSE) == 0) {
2210 return (ret);
2212 foundDevice = B_TRUE;
2213 break;
2217 if (foundDevice == B_TRUE) {
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.
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;
2236 * If we get here, it means that it is a new hba port name
2237 * for this discovered LU.
2239 if (foundPort == B_FALSE) {
2240 newPort = (portList *)calloc(1, sizeof (portList));
2241 if (newPort == NULL) {
2242 (void *) fprintf(stderr,
2243 "%s\n", strerror(errno));
2244 return (++ret);
2246 (void) strlcpy(newPort->portName, portName,
2247 sizeof (newPort->portName));
2249 portElem = discoveredLU->HBAPortList;
2250 prevElem = portElem;
2251 while (portElem != NULL &&
2252 sas_name_comp(newPort->portName, portElem->portName)
2253 > 0) {
2254 prevElem = portElem;
2255 portElem = portElem->next;
2257 if (portElem == prevElem) {
2258 /* Insert in the head of list. */
2259 newPort->next = portElem;
2260 discoveredLU->HBAPortList = newPort;
2261 } else {
2262 newPort->next = portElem;
2263 prevElem->next = newPort;
2265 /* add Target Port */
2266 newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
2267 sizeof (tgtPortWWNList));
2268 if (newPort->tgtPortWWN == NULL) {
2269 (void *) fprintf(stderr,
2270 "%s\n", strerror(errno));
2271 return (++ret);
2273 (void *) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
2274 (void *)&(entryP->PortLun.PortWWN),
2275 sizeof (HBA_WWN));
2276 /* Set LUN data */
2277 newPort->tgtPortWWN->scsiOSLun =
2278 entryP->ScsiId.ScsiOSLun;
2279 } else {
2281 * Otherwise, we just need to add the target port
2282 * sas address information.
2284 for (TgtWWNList = portElem->tgtPortWWN;
2285 TgtWWNList != NULL;
2286 TgtWWNList = TgtWWNList->next) {
2287 if (memcmp(&TgtWWNList->portWWN,
2288 &entryP->PortLun.PortWWN,
2289 sizeof (HBA_WWN)) == 0)
2290 return (0);
2292 /* add it to existing */
2293 newTgtWWN = (tgtPortWWNList *)calloc(1,
2294 sizeof (tgtPortWWNList));
2295 if (newTgtWWN == NULL) {
2296 (void *) fprintf(stderr,
2297 "%s\n", strerror(errno));
2298 return (++ret);
2300 /* insert at head */
2301 newTgtWWN->next = portElem->tgtPortWWN;
2302 portElem->tgtPortWWN = newTgtWWN;
2303 (void *) memcpy((void *)&(newTgtWWN->portWWN),
2304 (void *)&(entryP->PortLun.PortWWN),
2305 sizeof (HBA_WWN));
2306 /* Set LUN data */
2307 newTgtWWN->scsiOSLun =
2308 entryP->ScsiId.ScsiOSLun;
2310 } else {
2312 * Here we got a new discovered LU which has not ever exist
2313 * in our global LU list. So add it into our global LU
2314 * list.
2316 newDevice = (discoveredDevice *)calloc(1,
2317 sizeof (discoveredDevice));
2319 if (newDevice == NULL) {
2320 (void *) fprintf(stderr, "%s\n", strerror(errno));
2321 return (++ret);
2323 newDevice->next = LUList; /* insert at head */
2324 LUList = newDevice; /* set new head */
2326 /* copy device name */
2327 (void *) strlcpy(newDevice->OSDeviceName,
2328 entryP->ScsiId.OSDeviceName,
2329 sizeof (newDevice->OSDeviceName));
2331 /* if verbose is not set return */
2332 if ((pflag & PRINT_VERBOSE) == 0) {
2333 return (0);
2336 /* copy WWN data */
2337 newDevice->HBAPortList = (portList *)calloc(1,
2338 sizeof (portList));
2339 if (newDevice->HBAPortList == NULL) {
2340 (void *) fprintf(stderr, "%s\n", strerror(errno));
2341 return (++ret);
2343 (void) strlcpy(newDevice->HBAPortList->portName,
2344 portName, sizeof (newDevice->HBAPortList->portName));
2346 newDevice->HBAPortList->tgtPortWWN =
2347 (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
2348 if (newDevice->HBAPortList->tgtPortWWN == NULL) {
2349 (void *) fprintf(stderr, "%s\n", strerror(errno));
2350 return (++ret);
2353 (void *) memcpy((void *)&(newDevice->HBAPortList->\
2354 tgtPortWWN->portWWN),
2355 (void *)&(entryP->PortLun.PortWWN),
2356 sizeof (HBA_WWN));
2357 newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
2358 entryP->ScsiId.ScsiOSLun;
2360 responseSize = sizeof (struct scsi_inquiry);
2361 senseSize = sizeof (struct scsi_extended_sense);
2362 (void *) memset(&inq, 0, sizeof (struct scsi_inquiry));
2363 (void *) memset(&sense, 0, sizeof (sense));
2364 (void *) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
2365 sizeof (smhbaLUN));
2368 * Retrieve the VPD data for the newly found discovered LU.
2370 status = SMHBA_ScsiInquiry(
2371 handle,
2372 hbaPortWWN,
2373 entryP->PortLun.PortWWN,
2374 domainPortWWN,
2375 smhbaLUN,
2378 (void *) &inq, &responseSize,
2379 &inq_status,
2380 (void *) &sense, &senseSize);
2382 if (status != HBA_STATUS_OK) {
2383 /* init VID/PID/dType as '\0' */
2384 newDevice->VID[0] = '\0';
2385 newDevice->PID[0] = '\0';
2386 newDevice->dType = DTYPE_UNKNOWN;
2387 /* initialize inq status */
2388 newDevice->inquiryFailed = B_TRUE;
2389 ret++;
2390 } else {
2391 (void *) memcpy(newDevice->VID, inq.inq_vid,
2392 sizeof (newDevice->VID));
2393 (void *) memcpy(newDevice->PID, inq.inq_pid,
2394 sizeof (newDevice->PID));
2395 newDevice->dType = inq.inq_dtype;
2396 /* initialize inq status */
2397 newDevice->inquiryFailed = B_FALSE;
2400 return (ret);
2404 * Function we use to insert a newly discovered port.
2405 * Return:
2406 * 0 - success
2407 * >0 - failed
2409 static int
2410 sas_rp_tree_insert(rp_tree_t **rproot,
2411 rp_tree_t *rpnode)
2413 HBA_UINT8 *wwn1, *wwn2, *wwn3;
2414 rp_tree_t *node_ptr;
2415 int ret = 0;
2417 if (rproot == NULL) {
2418 (void *) fprintf(stderr, "%s\n",
2419 gettext("Error: NULL rproot"));
2420 return (1);
2423 if (rpnode == NULL) {
2424 (void *) fprintf(stderr, "%s\n",
2425 gettext("Error: NULL rpnode"));
2426 return (1);
2429 if (*rproot == NULL) {
2430 *rproot = rpnode;
2431 return (0);
2434 wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
2435 wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
2436 wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
2439 * If the attched sas address is equal to the local sas address,
2440 * then this should be a child node of current root node.
2442 if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
2443 (void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
2444 rpnode->parent = *rproot;
2445 } else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
2447 * If the attached sas address is equal to the attached sas
2448 * address of current root node, then this should be a
2449 * sibling node.
2450 * Insert the SAS/SATA Device at the head of sibling list.
2452 if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2453 rpnode->sibling = *rproot;
2454 *rproot = rpnode;
2455 } else {
2457 * Insert the SAS Expander at the tail of sibling
2458 * list.
2460 node_ptr = *rproot;
2461 while (node_ptr->sibling != NULL)
2462 node_ptr = node_ptr->sibling;
2463 node_ptr->sibling = rpnode;
2465 rpnode->parent = (*rproot)->parent;
2466 } else {
2468 * If enter here, we should first try to insert the discovered
2469 * port node into the child sub-tree, then try to insert to the
2470 * sibling sub-trees. If we failed to insert the discovered
2471 * port node, return 1. The caller will queue this node
2472 * up and retry insertion later.
2474 if ((*rproot)->child) {
2475 ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
2477 if ((*rproot)->child == NULL || ret != 0) {
2478 if ((*rproot)->sibling) {
2479 ret = sas_rp_tree_insert(&(*rproot)->sibling,
2480 rpnode);
2481 } else
2482 ret = 1;
2484 return (ret);
2486 return (0);
2490 * Function which will print out the whole disocvered port topology.
2491 * Here we use the Preorder Traversal algorithm.
2492 * The indentation rules are:
2493 * 1 * TABLEN - for attributes
2494 * 2 * TABLEN - for next tier target port/expander
2496 static int
2497 sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
2498 HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
2499 rp_tree_t *rpnode, inputArg_t *input,
2500 int gident, int *printPort)
2502 int ret = 0, lident;
2504 if (rpnode == NULL)
2505 return (ret);
2506 lident = gident;
2509 * We assume that all the nodes are disocvered ports(sas device or
2510 * expander).
2512 if (input->wwnCount > 0) {
2513 /* Adjust local indentation if a discovered port specified. */
2514 lident = 2 * TABLEN;
2516 * Check whether current node match one of the specified
2517 * SAS addresses.
2519 if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
2520 !isPortWWNInArgv(input,
2521 &rpnode->sasattr.LocalSASAddress)) {
2523 * Step down to child tree first.
2525 ret += sas_rp_tree_print(handle, adapterName,
2526 portIndex, port, rpnode->child, input,
2527 gident + 2 * TABLEN, printPort);
2529 * Then check the sibling tree.
2531 ret += sas_rp_tree_print(handle, adapterName,
2532 portIndex, port, rpnode->sibling, input,
2533 gident, printPort);
2534 return (ret);
2538 if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
2539 (input->pflag & PRINT_TARGET_PORT)) {
2541 * We should print the header(HBA Name + HBA Port Name)
2542 * on-demand. It means that, if we have expander device
2543 * address specified on the command line, we should print
2544 * the header once we find a matching one. Or we will
2545 * print the header from the beginning of the output.
2547 if (g_printHBA == 0) {
2548 (void *) fprintf(stdout, "%s %s\n",
2549 "HBA Name:", adapterName);
2550 g_printHBA = 1;
2553 if (*printPort == 0) {
2554 (void *) fprintf(stdout, "%s%s %s\n",
2555 getIndentSpaces(TABLEN),
2556 "HBA Port Name:", port->OSDeviceName);
2557 *printPort = 1;
2559 ret += sas_print_rpnode(input, rpnode, lident, gident);
2563 * If operands provided with "-t" option specified, we will print
2564 * the immediate child nodes information under the expander.
2566 if (input->pflag & PRINT_TARGET_PORT) {
2567 /* no operand. ignore the option. */
2568 if (input->wwnCount > 0) {
2569 if (rpnode->portattr.PortType ==
2570 HBA_PORTTYPE_SASEXPANDER) {
2571 ret += sas_rp_tree_print_desc(handle,
2572 portIndex, port, rpnode->child,
2573 input,
2574 lident + 2 * TABLEN,
2575 gident + 2 * TABLEN);
2581 * Here we use DFS(Depth First Search) algorithm to traverse the
2582 * whole tree.
2584 ret += sas_rp_tree_print(handle, adapterName,
2585 portIndex, port, rpnode->child, input,
2586 gident + 2 * TABLEN, printPort);
2587 ret += sas_rp_tree_print(handle, adapterName,
2588 portIndex, port, rpnode->sibling, input,
2589 gident, printPort);
2590 return (ret);
2594 * Function which will destroy the whole discovered port tree.
2595 * Here we use the Postorder Traversal algorithm.
2597 static void sas_rp_tree_free(rp_tree_t *rproot)
2599 tgt_mapping *cur, *next;
2601 if (rproot == NULL)
2602 return;
2605 * Free child tree first.
2607 if (rproot->child) {
2608 sas_rp_tree_free(rproot->child);
2612 * Free sibling trees then.
2614 if (rproot->sibling) {
2615 sas_rp_tree_free(rproot->sibling);
2619 * Free root node at last.
2621 cur = rproot->first_entry;
2622 while (cur != NULL) {
2623 next = cur->next;
2624 free(cur);
2625 cur = next;
2627 free(rproot);
2631 * Function used to print out all the descendant nodes.
2632 * handle - handle to HBA.
2633 * port - port attributes of current HBA port.
2634 * desc - the root node of a subtree which will be processed.
2635 * input - input argument.
2636 * lident - local indentation for shifting indentation.
2637 * gident - global indentation, can also be used to obtain Tier number.
2639 /*ARGSUSED*/
2640 static int
2641 sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
2642 SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
2643 inputArg_t *input, int lident, int gident)
2645 int ret = 0;
2646 rp_tree_t *rp_node;
2648 if (desc == NULL)
2649 return (ret);
2651 * Walk through the subtree of desc by Pre-Order Traversal Algo.
2653 for (rp_node = desc; rp_node != NULL; rp_node = rp_node->sibling) {
2654 ret += sas_print_rpnode(input, rp_node, lident, gident);
2657 return (ret);
2661 * Function used to print the information of specified SAS address.
2662 * handle - handle to a HBA.
2663 * port - port attributes of a HBA port.
2664 * rpnode - discovered port which will be processed.
2665 * lident - local indentation used for shifting indentation.
2666 * gident - global indentation used for calculating "Tier" number.
2668 static int
2669 sas_print_rpnode(inputArg_t *input,
2670 rp_tree_t *rpnode, int lident, int gident)
2672 int ret = 0;
2674 if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
2675 (void *) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
2676 getIndentSpaces(lident),
2677 "Expander SAS Address",
2678 gident / (2 * TABLEN),
2679 wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2680 } else {
2681 (void *) fprintf(stdout, "%s%s %016llx\n",
2682 getIndentSpaces(lident),
2683 "Target Port SAS Address:",
2684 wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2686 if (input->pflag & PRINT_VERBOSE) {
2687 if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2688 (void *) fprintf(stdout, "%s%s %s\n",
2689 getIndentSpaces(TABLEN + lident),
2690 "Type:",
2691 getStateString(rpnode->portattr.PortType,
2692 porttype_string));
2693 } else {
2694 (void *) fprintf(stdout, "%s%s %s\n",
2695 getIndentSpaces(TABLEN + lident),
2696 "OS Device Name:",
2697 rpnode->portattr.OSDeviceName);
2698 (void *) fprintf(stdout, "%s%s %s\n",
2699 getIndentSpaces(TABLEN + lident),
2700 "State: ",
2701 getStateString(rpnode->portattr.PortState,
2702 portstate_string));
2705 rpnode->printed = 1;
2706 return (ret);
2710 * Function used to get the correct domainPortWWN as needed by some of the
2711 * SMHBA APIs.
2712 * handle - handle to a HBA.
2713 * portIndex - index to locate the port.
2714 * port - pointer to the structure holding port attributes.
2715 * pdomainPort - pointer to the buffer holding domainPortWWN.
2717 HBA_STATUS
2718 get_domainPort(HBA_HANDLE handle,
2719 int portIndex, PSMHBA_PORTATTRIBUTES port,
2720 HBA_WWN *pdomainPort)
2722 HBA_STATUS status;
2723 PSMHBA_SAS_PORT sasport;
2724 SMHBA_SAS_PHY phyattr;
2726 sasport = port->PortSpecificAttribute.SASPort;
2727 (void *) memset(pdomainPort, 0, sizeof (HBA_WWN));
2729 * Since iport can exist without any phys,
2730 * sasinfo hba-port -v has indicated numberOfPhys;
2731 * if there is no phys within the hba, just return OK.
2733 if (sasport->NumberofPhys > 0) {
2734 status = SMHBA_GetSASPhyAttributes(handle, portIndex,
2735 0, &phyattr);
2736 if (status != HBA_STATUS_OK)
2737 return (status);
2738 (void *) memcpy(pdomainPort, &phyattr.domainPortWWN,
2739 sizeof (HBA_WWN));
2740 } else {
2741 /* return not supported for no phy configured */
2742 return (HBA_STATUS_ERROR_NOT_SUPPORTED);
2744 return (HBA_STATUS_OK);
2748 * Comparison function for comparing names possibly ending with digits.
2749 * Return:
2750 * <0 - name1 is less than name2.
2751 * 0 - name1 is equal with name2.
2752 * >0 - name1 is more than name2.
2754 static int
2755 sas_name_comp(const char *name1, const char *name2)
2757 int i = 0;
2759 if (name1 == name2)
2760 return (0);
2762 while ((name1[i] == name2[i]) && (name1[i] != '\0'))
2763 i++;
2765 /* If neither of name1[i] and name2[i] is '\0'. */
2766 if (isdigit(name1[i]) && isdigit(name2[i]))
2767 return (atoi(&name1[i]) - atoi(&name2[i]));
2769 /* One of name1[i] and name2[i] is not digit. */
2770 return (name1[i] - name2[i]);
2773 * Comparison function for sorting HBA/HBA Port.
2774 * arg1 - first argument of type sas_elem_t.
2775 * arg2 - second argument of type sas_elem_t.
2776 * Return:
2777 * <0 - arg1 is less than arg2.
2778 * 0 - arg1 is equal with arg2.
2779 * >0 - arg1 is more than arg2.
2781 static int
2782 sas_elem_compare(const void *arg1, const void *arg2)
2784 sas_elem_t *p1, *p2;
2785 p1 = (sas_elem_t *)arg1;
2786 p2 = (sas_elem_t *)arg2;
2787 return (sas_name_comp(p1->name, p2->name));
2791 * Sorting function for HBA/HBA Port output.
2792 * array - elements array of type sas_elem_t.
2793 * nelem - number of elements in array of type sas_elem_t.
2795 static void
2796 sas_elem_sort(sas_elem_t *array, int nelem)
2798 qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);