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 <libscf.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <syslog.h>
31#include <strings.h>
32#include <ctype.h>
33#include <fcinfo.h>
34
35
36#define	FCADM_RETRY_TIMES	10
37#define	FCADM_SLEEP_TIME	1
38
39static char *
40WWN2str(char *buf, HBA_WWN *wwn) {
41	int j;
42	unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
43	buf[0] = '\0';
44	for (j = 0; j < 16; j += 2) {
45		sprintf(&buf[j], "%02X", (int)*pc++);
46	}
47	return (buf);
48}
49
50static int
51isValidWWN(char *wwn)
52{
53	int index;
54
55	if (wwn == NULL) {
56		return (0);
57	}
58
59	if (strlen(wwn) != 16) {
60		return (0);
61	}
62
63	for (index = 0; index < 16; index++) {
64		if (isxdigit(wwn[index])) {
65			continue;
66		}
67		return (0);
68	}
69	return (1);
70}
71
72
73/*
74 * Initialize scf stmf service access
75 * handle - returned handle
76 * service - returned service handle
77 */
78static int
79cfgInit(scf_handle_t **handle, scf_service_t **service)
80{
81	scf_scope_t	*scope = NULL;
82	int		ret;
83
84	if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
85		/* log error */
86		ret = NPIV_ERROR;
87		goto err;
88	}
89
90	if (scf_handle_bind(*handle) == -1) {
91		/* log error */
92		ret = NPIV_ERROR;
93		goto err;
94	}
95
96	if ((*service = scf_service_create(*handle)) == NULL) {
97		/* log error */
98		ret = NPIV_ERROR;
99		goto err;
100	}
101
102	if ((scope = scf_scope_create(*handle)) == NULL) {
103		/* log error */
104		ret = NPIV_ERROR;
105		goto err;
106	}
107
108	if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
109		/* log error */
110		ret = NPIV_ERROR;
111		goto err;
112	}
113
114	if (scf_scope_get_service(scope, NPIV_SERVICE, *service) == -1) {
115		/* log error */
116		ret = NPIV_ERROR_SERVICE_NOT_FOUND;
117		goto err;
118	}
119
120	scf_scope_destroy(scope);
121
122	return (NPIV_SUCCESS);
123
124err:
125	if (*handle != NULL) {
126		scf_handle_destroy(*handle);
127	}
128	if (*service != NULL) {
129		scf_service_destroy(*service);
130		*service = NULL;
131	}
132	if (scope != NULL) {
133		scf_scope_destroy(scope);
134	}
135	return (ret);
136}
137
138static int
139npivAddRemoveNPIVEntry(char *ppwwn, char *vnwwn,
140    char *vpwwn, int vindex, int addRemoveFlag) {
141	scf_handle_t	*handle = NULL;
142	scf_service_t	*svc = NULL;
143	scf_propertygroup_t	*pg = NULL;
144	scf_transaction_t	*tran = NULL;
145	scf_transaction_entry_t	*entry = NULL;
146	scf_property_t	*prop = NULL;
147	scf_value_t	*valueLookup = NULL;
148	scf_iter_t	*valueIter = NULL;
149	scf_value_t	**valueSet = NULL;
150	int	ret = NPIV_SUCCESS;
151	boolean_t	createProp = B_FALSE;
152	int	lastAlloc = 0;
153	char	buf[NPIV_PORT_LIST_LENGTH] = {0};
154	char	memberName[NPIV_PORT_LIST_LENGTH] = {0};
155	boolean_t	found = B_FALSE;
156	int	i = 0;
157	int	valueArraySize = 0;
158	int	commitRet;
159
160	if (vnwwn) {
161		sprintf(memberName, "%s:%s:%s:%d", ppwwn, vpwwn, vnwwn, vindex);
162	} else {
163		sprintf(memberName, "%s:%s", ppwwn, vpwwn);
164	}
165
166	ret = cfgInit(&handle, &svc);
167	if (ret != NPIV_SUCCESS) {
168		goto out;
169	}
170
171	if (((pg = scf_pg_create(handle)) == NULL) ||
172	    ((tran = scf_transaction_create(handle)) == NULL) ||
173	    ((entry = scf_entry_create(handle)) == NULL) ||
174	    ((prop = scf_property_create(handle)) == NULL) ||
175	    ((valueIter = scf_iter_create(handle)) == NULL)) {
176		ret = NPIV_ERROR;
177		goto out;
178	}
179
180	/* get property group or create it */
181	if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) {
182		if ((scf_error() == SCF_ERROR_NOT_FOUND) &&
183		    (addRemoveFlag == NPIV_ADD)) {
184			if (scf_service_add_pg(svc, NPIV_PG_NAME,
185			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
186				syslog(LOG_ERR, "add pg failed - %s",
187				    scf_strerror(scf_error()));
188				ret = NPIV_ERROR;
189			} else {
190				createProp = B_TRUE;
191			}
192		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
193			ret = NPIV_ERROR_NOT_FOUND;
194		} else {
195			syslog(LOG_ERR, "get pg failed - %s",
196			    scf_strerror(scf_error()));
197			ret = NPIV_ERROR;
198		}
199		if (ret != NPIV_SUCCESS) {
200			goto out;
201		}
202	}
203
204	/* Begin the transaction */
205	if (scf_transaction_start(tran, pg) == -1) {
206		syslog(LOG_ERR, "start transaction failed - %s",
207		    scf_strerror(scf_error()));
208		ret = NPIV_ERROR;
209		goto out;
210	}
211
212	valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
213	    * (lastAlloc = PORT_LIST_ALLOC));
214	if (valueSet == NULL) {
215		ret = NPIV_ERROR_NOMEM;
216		goto out;
217	}
218
219	if (createProp) {
220		if (scf_transaction_property_new(tran, entry, NPIV_PORT_LIST,
221		    SCF_TYPE_USTRING) == -1) {
222			if (scf_error() == SCF_ERROR_EXISTS) {
223				ret = NPIV_ERROR_EXISTS;
224			} else {
225				syslog(LOG_ERR,
226				    "transaction property new failed - %s",
227				    scf_strerror(scf_error()));
228				ret = NPIV_ERROR;
229			}
230			goto out;
231		}
232	} else {
233		if (scf_transaction_property_change(tran, entry,
234		    NPIV_PORT_LIST, SCF_TYPE_USTRING) == -1) {
235			syslog(LOG_ERR,
236			    "transaction property change failed - %s",
237			    scf_strerror(scf_error()));
238			ret = NPIV_ERROR;
239			goto out;
240		}
241
242		if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) {
243			syslog(LOG_ERR, "get property failed - %s",
244			    scf_strerror(scf_error()));
245			ret = NPIV_ERROR;
246			goto out;
247		}
248
249		valueLookup = scf_value_create(handle);
250		if (valueLookup == NULL) {
251			syslog(LOG_ERR, "scf value alloc failed - %s",
252			    scf_strerror(scf_error()));
253			ret = NPIV_ERROR;
254			goto out;
255		}
256
257		if (scf_iter_property_values(valueIter, prop) == -1) {
258			syslog(LOG_ERR, "iter value failed - %s",
259			    scf_strerror(scf_error()));
260			ret = NPIV_ERROR;
261			goto out;
262		}
263
264		while (scf_iter_next_value(valueIter, valueLookup) == 1) {
265			bzero(buf, sizeof (buf));
266			if (scf_value_get_ustring(valueLookup,
267			    buf, MAXNAMELEN) == -1) {
268				syslog(LOG_ERR, "iter value failed - %s",
269				    scf_strerror(scf_error()));
270				ret = NPIV_ERROR;
271				break;
272			}
273
274			if ((strlen(buf) >= strlen(memberName)) &&
275			    bcmp(buf, memberName, strlen(memberName)) == 0) {
276				if (addRemoveFlag == NPIV_ADD) {
277					ret = NPIV_ERROR_EXISTS;
278					break;
279				} else {
280					found = B_TRUE;
281					continue;
282				}
283			}
284
285			valueSet[i] = scf_value_create(handle);
286			if (valueSet[i] == NULL) {
287				syslog(LOG_ERR, "scf value alloc failed - %s",
288				    scf_strerror(scf_error()));
289				ret = NPIV_ERROR;
290				break;
291			}
292
293			if (scf_value_set_ustring(valueSet[i], buf) == -1) {
294				syslog(LOG_ERR, "set value failed - %s",
295				    scf_strerror(scf_error()));
296				ret = NPIV_ERROR;
297				break;
298			}
299
300			if (scf_entry_add_value(entry, valueSet[i]) == -1) {
301				syslog(LOG_ERR, "add value failed - %s",
302				    scf_strerror(scf_error()));
303				ret = NPIV_ERROR;
304				break;
305			}
306
307			i++;
308
309			if (i >= lastAlloc) {
310				lastAlloc += PORT_LIST_ALLOC;
311				valueSet = realloc(valueSet,
312				    sizeof (*valueSet) * lastAlloc);
313				if (valueSet == NULL) {
314					ret = NPIV_ERROR;
315					break;
316				}
317			}
318		}
319	}
320
321	valueArraySize = i;
322	if (!found && (addRemoveFlag == NPIV_REMOVE)) {
323		ret = NPIV_ERROR_MEMBER_NOT_FOUND;
324	}
325	if (ret != NPIV_SUCCESS) {
326		goto out;
327	}
328
329	if (addRemoveFlag == NPIV_ADD) {
330		/*
331		 * Now create the new entry
332		 */
333		valueSet[i] = scf_value_create(handle);
334		if (valueSet[i] == NULL) {
335			syslog(LOG_ERR, "scf value alloc failed - %s",
336			    scf_strerror(scf_error()));
337			ret = NPIV_ERROR;
338			goto out;
339		} else {
340			valueArraySize++;
341		}
342
343		/*
344		 * Set the new member name
345		 */
346		if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
347			syslog(LOG_ERR, "set value failed - %s",
348			    scf_strerror(scf_error()));
349			ret = NPIV_ERROR;
350			goto out;
351		}
352
353		/*
354		 * Add the new member
355		 */
356		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
357			syslog(LOG_ERR, "add value failed - %s",
358			    scf_strerror(scf_error()));
359			ret = NPIV_ERROR;
360			goto out;
361		}
362	}
363
364	if ((commitRet = scf_transaction_commit(tran)) != 1) {
365		syslog(LOG_ERR, "transaction commit failed - %s",
366		    scf_strerror(scf_error()));
367		if (commitRet == 0) {
368			ret = NPIV_ERROR_BUSY;
369		} else {
370			ret = NPIV_ERROR;
371		}
372		goto out;
373	}
374
375out:
376	/*
377	 * Free resources
378	 */
379	if (handle != NULL) {
380		scf_handle_destroy(handle);
381	}
382	if (svc != NULL) {
383		scf_service_destroy(svc);
384	}
385	if (pg != NULL) {
386		scf_pg_destroy(pg);
387	}
388	if (tran != NULL) {
389		scf_transaction_destroy(tran);
390	}
391	if (entry != NULL) {
392		scf_entry_destroy(entry);
393	}
394	if (prop != NULL) {
395		scf_property_destroy(prop);
396	}
397	if (valueIter != NULL) {
398		scf_iter_destroy(valueIter);
399	}
400	if (valueLookup != NULL) {
401		scf_value_destroy(valueLookup);
402	}
403
404	/*
405	 * Free valueSet scf resources
406	 */
407	if (valueArraySize > 0) {
408		for (i = 0; i < valueArraySize; i++) {
409			scf_value_destroy(valueSet[i]);
410		}
411	}
412	/*
413	 * Now free the pointer array to the resources
414	 */
415	if (valueSet != NULL) {
416		free(valueSet);
417	}
418
419	return (ret);
420}
421
422static int
423retrieveNPIVAttrs(HBA_HANDLE handle, HBA_WWN portWWN,
424    HBA_PORTNPIVATTRIBUTES *npivattrs, HBA_UINT32 *portIndex) {
425	HBA_STATUS		status;
426	HBA_ADAPTERATTRIBUTES	attrs;
427	HBA_PORTATTRIBUTES	portattrs;
428	int			portCtr;
429	int			times = 0;
430
431	/* argument checking */
432	if (npivattrs == NULL || portIndex == NULL) {
433		return (1);
434	}
435
436	memset(&attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES));
437	status = HBA_GetAdapterAttributes(handle, &attrs);
438	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
439	    status == HBA_STATUS_ERROR_BUSY) &&
440	    times++ < 130) {
441		status = HBA_GetAdapterAttributes(handle, &attrs);
442		if (status == HBA_STATUS_OK) {
443			break;
444		}
445		(void) sleep(1);
446	}
447	if (status != HBA_STATUS_OK) {
448		return (1);
449	}
450
451	memset(&portattrs, 0, sizeof (HBA_PORTATTRIBUTES));
452	for (portCtr = 0; portCtr < attrs.NumberOfPorts; portCtr++) {
453		status = HBA_GetAdapterPortAttributes(handle,
454		    portCtr, &portattrs);
455		times = 0;
456		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
457		    status == HBA_STATUS_ERROR_BUSY) &&
458		    times++ < HBA_MAX_RETRIES) {
459			status = HBA_GetAdapterPortAttributes(handle,
460			    portCtr, &portattrs);
461			if (status == HBA_STATUS_OK) {
462				break;
463			}
464			(void) sleep(1);
465		}
466
467		if (status != HBA_STATUS_OK) {
468			return (1);
469		}
470
471		if (memcmp(portWWN.wwn, portattrs.PortWWN.wwn,
472		    sizeof (portattrs.PortWWN.wwn)) == 0) {
473			break;
474		}
475	}
476	if (portCtr >= attrs.NumberOfPorts) {
477		*portIndex = 0;
478		return (1);
479	}
480	*portIndex = portCtr;
481
482	status = Sun_HBA_GetPortNPIVAttributes(handle, portCtr, npivattrs);
483	times = 0;
484	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
485	    status == HBA_STATUS_ERROR_BUSY) &&
486	    times++ < HBA_MAX_RETRIES) {
487		status = Sun_HBA_GetPortNPIVAttributes(handle,
488		    portCtr, npivattrs);
489		if (status == HBA_STATUS_OK) {
490			break;
491		}
492		(void) sleep(1);
493	}
494	if (status != HBA_STATUS_OK) {
495		return (1);
496	}
497
498	return (0);
499}
500
501
502int
503fc_util_delete_npivport(int wwnCount, char **wwn_argv,
504    cmdOptions_t *options)
505{
506	uint64_t	physicalportWWN, virtualportWWN;
507	HBA_WWN		portWWN, vportWWN;
508	HBA_STATUS	status;
509	HBA_HANDLE	handle;
510	HBA_PORTNPIVATTRIBUTES	npivattrs;
511	HBA_UINT32	portIndex;
512	char		pwwn[17];
513	int		times;
514
515	if (wwnCount != 1) {
516		fprintf(stderr,
517		    gettext("Invalid Parameter\n"));
518		return (1);
519	}
520
521	for (; options->optval; options++) {
522		switch (options->optval) {
523		case 'p':
524			if (!isValidWWN(options->optarg)) {
525				fprintf(stderr,
526				    gettext("Invalid Port WWN\n"));
527				return (1);
528			}
529			sscanf(options->optarg, "%016llx", &virtualportWWN);
530			break;
531		default:
532			return (1);
533		}
534	}
535
536	if (!isValidWWN(wwn_argv[0])) {
537		fprintf(stderr,
538		    gettext("Invalid Physical Port WWN\n"));
539		return (1);
540	}
541
542	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
543		fprintf(stderr,
544		    gettext("Failed to load FC-HBA common library\n"));
545		printStatus(status);
546		fprintf(stderr, "\n");
547		return (1);
548	}
549	sscanf(wwn_argv[0], "%016llx", &physicalportWWN);
550	physicalportWWN = htonll(physicalportWWN);
551	memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));
552
553	virtualportWWN = htonll(virtualportWWN);
554	memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));
555
556	status = HBA_OpenAdapterByWWN(&handle, portWWN);
557	if (status != HBA_STATUS_OK) {
558		fprintf(stderr,
559		    gettext("Error: HBA port %s: not found\n"),
560		    wwn_argv[0]);
561		HBA_FreeLibrary();
562		return (1);
563	}
564
565	/* Get physical port NPIV attributes */
566	if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) {
567		/* Check port NPIV attributes */
568		if (npivattrs.MaxNumberOfNPIVPorts == 0) {
569			fprintf(stderr,
570			    gettext("Error: NPIV not Supported\n"));
571			HBA_CloseAdapter(handle);
572			HBA_FreeLibrary();
573			return (1);
574		}
575
576		/* Delete a virtual port */
577		status = Sun_HBA_DeleteNPIVPort(handle, portIndex,
578		    vportWWN);
579		times = 0;
580		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
581		    status == HBA_STATUS_ERROR_BUSY) &&
582		    times++ < HBA_MAX_RETRIES) {
583			(void) sleep(1);
584			status = Sun_HBA_DeleteNPIVPort(handle, portIndex,
585			    vportWWN);
586			if (status == HBA_STATUS_OK) {
587				break;
588			}
589		}
590		if (status != HBA_STATUS_OK) {
591			fprintf(stderr,
592			    gettext("Error: failed to delete a npiv port\n"));
593			HBA_CloseAdapter(handle);
594			HBA_FreeLibrary();
595			return (1);
596		}
597	} else {
598		fprintf(stderr,
599		    gettext("Error: failed to get port NPIV attributes\n"));
600		HBA_CloseAdapter(handle);
601		HBA_FreeLibrary();
602		return (1);
603	}
604
605	HBA_CloseAdapter(handle);
606	HBA_FreeLibrary();
607
608	WWN2str(pwwn, &vportWWN);
609	npivAddRemoveNPIVEntry(wwn_argv[0],
610	    NULL, pwwn, 0, NPIV_REMOVE);
611
612	return (0);
613}
614
615int
616fc_util_create_npivport(int wwnCount,
617    char **wwn_argv, cmdOptions_t *options)
618{
619	uint64_t	physicalportWWN, virtualnodeWWN, virtualportWWN;
620	HBA_WWN		portWWN, vnodeWWN, vportWWN;
621	HBA_STATUS	status;
622	HBA_HANDLE	handle;
623	HBA_PORTNPIVATTRIBUTES	npivattrs;
624	HBA_UINT32	portIndex;
625	HBA_UINT32	npivportIndex = 0;
626	char		nwwn[17], pwwn[17];
627	int		randomflag = 0;
628	int		times;
629
630	if (wwnCount != 1) {
631		fprintf(stderr,
632		    gettext("Invalid Parameter\n"));
633		return (1);
634	}
635
636	for (; options->optval; options++) {
637		switch (options->optval) {
638		case 'p':
639			if (!isValidWWN(options->optarg)) {
640				fprintf(stderr,
641				    gettext("Invalid Port WWN\n"));
642				return (1);
643			}
644			sscanf(options->optarg, "%016llx", &virtualportWWN);
645			randomflag++;
646			break;
647		case 'n':
648			if (!isValidWWN(options->optarg)) {
649				fprintf(stderr,
650				    gettext("Invalid Node WWN\n"));
651				return (1);
652			}
653			sscanf(options->optarg, "%016llx", &virtualnodeWWN);
654			randomflag++;
655			break;
656		default:
657			return (1);
658		}
659	}
660
661	if (!isValidWWN(wwn_argv[0])) {
662		fprintf(stderr,
663		    gettext("Invalid Physical Port WWN\n"));
664		wwnCount = 0;
665		return (1);
666	}
667
668	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
669		fprintf(stderr,
670		    gettext("Failed to load FC-HBA common library\n"));
671		printStatus(status);
672		fprintf(stderr, "\n");
673		return (1);
674	}
675
676	sscanf(wwn_argv[0], "%016llx", &physicalportWWN);
677	physicalportWWN = htonll(physicalportWWN);
678	memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));
679
680	status = HBA_OpenAdapterByWWN(&handle, portWWN);
681	if (status != HBA_STATUS_OK) {
682		fprintf(stderr,
683		    gettext("Error: HBA port %s: not found\n"),
684		    wwn_argv[0]);
685		HBA_FreeLibrary();
686		return (1);
687	}
688
689	if (randomflag != 2) {
690		status = Sun_HBA_AdapterCreateWWN(handle, 0,
691		    &vnodeWWN, &vportWWN, NULL, HBA_CREATE_WWN_RANDOM);
692		if (status != HBA_STATUS_OK) {
693			fprintf(stderr,
694			    gettext("Error: Fail to get Random WWN\n"));
695			HBA_CloseAdapter(handle);
696			HBA_FreeLibrary();
697			return (1);
698		}
699	} else {
700		virtualnodeWWN = htonll(virtualnodeWWN);
701		memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN));
702		virtualportWWN = htonll(virtualportWWN);
703		memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));
704	}
705
706	if (memcmp(vnodeWWN.wwn, vportWWN.wwn, 8) == 0) {
707		fprintf(stderr,
708		    gettext("Error: Port WWN is same as Node WWN\n"));
709		HBA_CloseAdapter(handle);
710		HBA_FreeLibrary();
711		return (1);
712	}
713
714	/* Get physical port NPIV attributes */
715	if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) {
716		/* Check port NPIV attributes */
717		if (npivattrs.MaxNumberOfNPIVPorts == 0) {
718			fprintf(stderr,
719			    gettext("Error: NPIV not Supported\n"));
720			HBA_CloseAdapter(handle);
721			HBA_FreeLibrary();
722			return (1);
723		}
724		if (npivattrs.MaxNumberOfNPIVPorts ==
725		    npivattrs.NumberOfNPIVPorts) {
726			fprintf(stderr,
727			    gettext("Error: Can not create more NPIV port\n"));
728			HBA_CloseAdapter(handle);
729			HBA_FreeLibrary();
730			return (1);
731		}
732
733		/* Create a virtual port */
734		status = Sun_HBA_CreateNPIVPort(handle, portIndex,
735		    vnodeWWN, vportWWN, &npivportIndex);
736		times = 0;
737		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
738		    status == HBA_STATUS_ERROR_BUSY) &&
739		    times++ < HBA_MAX_RETRIES) {
740			(void) sleep(1);
741			status = Sun_HBA_CreateNPIVPort(handle, portIndex,
742			    vnodeWWN, vportWWN, &npivportIndex);
743			if (status == HBA_STATUS_OK) {
744				break;
745			}
746		}
747
748		if (status != HBA_STATUS_OK) {
749			fprintf(stderr,
750			    gettext("Error: failed to create a npiv port\n"));
751			HBA_CloseAdapter(handle);
752			HBA_FreeLibrary();
753			return (1);
754		}
755	} else {
756		fprintf(stderr,
757		    gettext("Error: failed to get port NPIV attributes\n"));
758		HBA_CloseAdapter(handle);
759		HBA_FreeLibrary();
760		return (1);
761	}
762
763	HBA_CloseAdapter(handle);
764	HBA_FreeLibrary();
765
766	WWN2str(nwwn, &vnodeWWN);
767	WWN2str(pwwn, &vportWWN);
768	npivAddRemoveNPIVEntry(wwn_argv[0],
769	    nwwn, pwwn, npivportIndex, NPIV_ADD);
770
771	return (0);
772}
773
774int
775create_npivport(char *ppwwn_str, char *vnwwn_str,
776    char *vpwwn_str, int vindex)
777{
778	uint64_t	physicalportWWN, virtualnodeWWN, virtualportWWN;
779	HBA_WWN		portWWN, vnodeWWN, vportWWN;
780	HBA_STATUS	status;
781	HBA_HANDLE	handle;
782	HBA_PORTNPIVATTRIBUTES	npivattrs;
783	HBA_UINT32	portIndex;
784	HBA_UINT32	npivportIndex;
785	int		times = 0;
786
787	sscanf(ppwwn_str, "%016llx", &physicalportWWN);
788	physicalportWWN = htonll(physicalportWWN);
789	memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));
790	sscanf(vnwwn_str, "%016llx", &virtualnodeWWN);
791	virtualnodeWWN = htonll(virtualnodeWWN);
792	memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN));
793	sscanf(vpwwn_str, "%016llx", &virtualportWWN);
794	virtualportWWN = htonll(virtualportWWN);
795	memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));
796	npivportIndex = vindex;
797
798	status = HBA_OpenAdapterByWWN(&handle, portWWN);
799	while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
800	    status == HBA_STATUS_ERROR_BUSY) {
801		(void) sleep(FCADM_SLEEP_TIME);
802		status = HBA_OpenAdapterByWWN(&handle, portWWN);
803		if (times++ > FCADM_RETRY_TIMES) {
804			return (1);
805		}
806	}
807
808	/* Get physical port NPIV attributes */
809	if (retrieveNPIVAttrs(handle, portWWN,
810	    &npivattrs, &portIndex) == 0) {
811		/* Check port NPIV attributes */
812		if (npivattrs.MaxNumberOfNPIVPorts == 0) {
813			goto failed;
814		}
815		if (npivattrs.MaxNumberOfNPIVPorts ==
816		    npivattrs.NumberOfNPIVPorts) {
817			goto failed;
818		}
819
820		/* Create a virtual port */
821		status = Sun_HBA_CreateNPIVPort(handle, portIndex,
822		    vnodeWWN, vportWWN, &npivportIndex);
823		times = 0;
824		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
825		    status == HBA_STATUS_ERROR_BUSY) {
826			(void) sleep(FCADM_SLEEP_TIME);
827			status = Sun_HBA_CreateNPIVPort(handle, portIndex,
828			    vnodeWWN, vportWWN, &npivportIndex);
829			if (times++ > FCADM_RETRY_TIMES) {
830				goto failed;
831			}
832		}
833	}
834
835failed:
836	HBA_CloseAdapter(handle);
837
838	return (0);
839}
840
841int
842fc_util_create_portlist()
843{
844	scf_handle_t	*handle = NULL;
845	scf_service_t	*svc = NULL;
846	scf_propertygroup_t	*pg = NULL;
847	scf_transaction_t	*tran = NULL;
848	scf_transaction_entry_t	*entry = NULL;
849	scf_property_t		*prop = NULL;
850	scf_value_t	*valueLookup = NULL;
851	scf_iter_t	*valueIter = NULL;
852	char		buf[NPIV_PORT_LIST_LENGTH] = {0};
853	int		commitRet;
854
855	commitRet = cfgInit(&handle, &svc);
856	if (commitRet != NPIV_SUCCESS) {
857		goto out;
858	}
859
860	if (((pg = scf_pg_create(handle)) == NULL) ||
861	    ((tran = scf_transaction_create(handle)) == NULL) ||
862	    ((entry = scf_entry_create(handle)) == NULL) ||
863	    ((prop = scf_property_create(handle)) == NULL) ||
864	    ((valueIter = scf_iter_create(handle)) == NULL)) {
865		goto out;
866	}
867
868	/* get property group or create it */
869	if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) {
870		goto out;
871	}
872
873	if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) {
874		syslog(LOG_ERR, "get property failed - %s",
875		    scf_strerror(scf_error()));
876		goto out;
877	}
878
879	valueLookup = scf_value_create(handle);
880	if (valueLookup == NULL) {
881		syslog(LOG_ERR, "scf value alloc failed - %s",
882		    scf_strerror(scf_error()));
883		goto out;
884	}
885
886	if (scf_iter_property_values(valueIter, prop) == -1) {
887		syslog(LOG_ERR, "iter value failed - %s",
888		    scf_strerror(scf_error()));
889		goto out;
890	}
891
892	if (HBA_LoadLibrary() != HBA_STATUS_OK) {
893		goto out;
894	}
895	HBA_GetNumberOfAdapters();
896
897	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
898		char ppwwn[17] = {0};
899		char vnwwn[17] = {0};
900		char vpwwn[17] = {0};
901		int vindex = 0;
902
903		bzero(buf, sizeof (buf));
904		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
905			syslog(LOG_ERR, "iter value failed - %s",
906			    scf_strerror(scf_error()));
907			break;
908		}
909
910		sscanf(buf, "%16s:%16s:%16s:%d", ppwwn, vpwwn, vnwwn, &vindex);
911		create_npivport(ppwwn, vnwwn, vpwwn, vindex);
912	}
913
914	HBA_FreeLibrary();
915out:
916	/*
917	 * Free resources
918	 */
919	if (handle != NULL) {
920		scf_handle_destroy(handle);
921	}
922	if (svc != NULL) {
923		scf_service_destroy(svc);
924	}
925	if (pg != NULL) {
926		scf_pg_destroy(pg);
927	}
928	if (tran != NULL) {
929		scf_transaction_destroy(tran);
930	}
931	if (entry != NULL) {
932		scf_entry_destroy(entry);
933	}
934	if (prop != NULL) {
935		scf_property_destroy(prop);
936	}
937	if (valueIter != NULL) {
938		scf_iter_destroy(valueIter);
939	}
940	if (valueLookup != NULL) {
941		scf_value_destroy(valueLookup);
942	}
943
944	return (0);
945}
946
947/* ARGSUSED */
948int
949fc_util_force_lip(int objects, char *argv[])
950{
951	uint64_t	hbaWWN;
952	HBA_WWN		myWWN;
953	HBA_HANDLE	handle;
954	HBA_STATUS	status;
955	int		rval = 0;
956
957	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
958		fprintf(stderr, gettext("Failed to load FC-HBA library\n"));
959		printStatus(status);
960		fprintf(stderr, "\n");
961		return (1);
962	}
963
964	sscanf(argv[0], "%016llx", &hbaWWN);
965	hbaWWN = htonll(hbaWWN);
966	memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN));
967
968	/*
969	 * Try target mode first
970	 */
971	if ((status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN)) !=
972	    HBA_STATUS_OK) {
973		/*
974		 * Continue to try initiator mode
975		 */
976		if ((status = HBA_OpenAdapterByWWN(&handle, myWWN)) !=
977		    HBA_STATUS_OK) {
978			fprintf(stderr, gettext("Error: HBA %s not found\n"),
979			    argv[0]);
980			return (0);
981		}
982	}
983
984	status = Sun_HBA_ForceLip(handle, &rval);
985	if ((status != HBA_STATUS_OK) || (rval != 0)) {
986		fprintf(stderr, gettext("Error: Failed to reinitialize the "
987		    "link of HBA %s\n"), argv[0]);
988	}
989
990	return (0);
991}
992