xref: /illumos-gate/usr/src/cmd/fcinfo/fcoeadm.c (revision 179c3dac)
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 "fcinfo.h"
27 #include <libintl.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <sys/list.h>
33 #include <stddef.h>
34 #include <strings.h>
35 #include <libfcoe.h>
36 #include <libscf.h>
37 #include <syslog.h>
38 
39 static const char *FCOE_DRIVER_PATH	= "/devices/fcoe:admin";
40 
41 static char *
42 WWN2str(char *buf, FCOE_PORT_WWN *wwn) {
43 	int j;
44 	unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
45 	buf[0] = '\0';
46 	for (j = 0; j < 16; j += 2) {
47 		sprintf(&buf[j], "%02X", (int)*pc++);
48 	}
49 	return (buf);
50 }
51 
52 static int
53 isValidWWN(char *wwn)
54 {
55 	int index;
56 
57 	if (wwn == NULL) {
58 		return (0);
59 	}
60 
61 	if (strlen(wwn) != 16) {
62 		return (0);
63 	}
64 
65 	for (index = 0; index < 16; index++) {
66 		if (isxdigit(wwn[index])) {
67 			continue;
68 		}
69 		return (0);
70 	}
71 	return (1);
72 }
73 
74 static uint64_t wwnconvert(uchar_t *wwn)
75 {
76 	uint64_t tmp;
77 	memcpy(&tmp, wwn, sizeof (uint64_t));
78 	return (ntohll(tmp));
79 }
80 
81 /*
82  * prints out all the HBA port information
83  */
84 void
85 printFCOEPortInfo(FCOE_PORT_ATTRIBUTE *attr)
86 {
87 	int i;
88 	if (attr == NULL) {
89 		return;
90 	}
91 	fprintf(stdout, gettext("HBA Port WWN: %016llx\n"),
92 	    wwnconvert((unsigned char *)&attr->port_wwn));
93 
94 	fprintf(stdout, gettext("\tPort Type: %s\n"),
95 	    (attr->port_type == 0) ? "Initiator" : "Target");
96 
97 	fprintf(stdout, gettext("\tMAC Name: %s\n"), attr->mac_link_name);
98 
99 	fprintf(stdout, gettext("\tMTU Size: %d\n"), attr->mtu_size);
100 
101 	fprintf(stdout, gettext("\tMAC Factory Address: "));
102 	for (i = 0; i < 6; i++) {
103 		fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]);
104 	}
105 	fprintf(stdout, gettext("\n\tMAC Current Address: "));
106 	for (i = 0; i < 6; i++) {
107 		fprintf(stdout, gettext("%02x"), attr->mac_current_addr[i]);
108 	}
109 	fprintf(stdout, gettext("\n\tPromiscuous Mode: %s\n"),
110 	    attr->mac_promisc == 1 ? "On" : "Off");
111 }
112 
113 /*
114  * Initialize scf fcoe service access
115  * handle - returned handle
116  * service - returned service handle
117  */
118 static int
119 fcoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service)
120 {
121 	scf_scope_t	*scope = NULL;
122 	int		ret;
123 
124 	if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
125 		syslog(LOG_ERR, "scf_handle_create failed - %s",
126 		    scf_strerror(scf_error()));
127 		ret = FCOE_ERROR;
128 		goto err;
129 	}
130 
131 	if (scf_handle_bind(*handle) == -1) {
132 		syslog(LOG_ERR, "scf_handle_bind failed - %s",
133 		    scf_strerror(scf_error()));
134 		ret = FCOE_ERROR;
135 		goto err;
136 	}
137 
138 	if ((*service = scf_service_create(*handle)) == NULL) {
139 		syslog(LOG_ERR, "scf_service_create failed - %s",
140 		    scf_strerror(scf_error()));
141 		ret = FCOE_ERROR;
142 		goto err;
143 	}
144 
145 	if ((scope = scf_scope_create(*handle)) == NULL) {
146 		syslog(LOG_ERR, "scf_scope_create failed - %s",
147 		    scf_strerror(scf_error()));
148 		ret = FCOE_ERROR;
149 		goto err;
150 	}
151 
152 	if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
153 		syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
154 		    scf_strerror(scf_error()));
155 		ret = FCOE_ERROR;
156 		goto err;
157 	}
158 
159 	if (scf_scope_get_service(scope, FCOE_SERVICE, *service) == -1) {
160 		syslog(LOG_ERR, "scf_scope_get_service failed - %s",
161 		    scf_strerror(scf_error()));
162 		ret = FCOE_ERROR_SERVICE_NOT_FOUND;
163 		goto err;
164 	}
165 
166 	scf_scope_destroy(scope);
167 
168 	return (FCOE_SUCCESS);
169 
170 err:
171 	if (*handle != NULL) {
172 		scf_handle_destroy(*handle);
173 	}
174 	if (*service != NULL) {
175 		scf_service_destroy(*service);
176 		*service = NULL;
177 	}
178 	if (scope != NULL) {
179 		scf_scope_destroy(scope);
180 	}
181 	return (ret);
182 }
183 
184 
185 static int
186 fcoe_adm_add_remove_scf_entry(char *mac_name,
187     char *pwwn, char *nwwn,
188     int is_target, int is_promiscuous, int addRemoveFlag)
189 {
190 	scf_handle_t	*handle = NULL;
191 	scf_service_t	*svc = NULL;
192 	scf_propertygroup_t	*pg = NULL;
193 	scf_transaction_t	*tran = NULL;
194 	scf_transaction_entry_t	*entry = NULL;
195 	scf_property_t	*prop = NULL;
196 	scf_value_t	*valueLookup = NULL;
197 	scf_iter_t	*valueIter = NULL;
198 	scf_value_t	**valueSet = NULL;
199 	int	ret = FCOE_SUCCESS;
200 	boolean_t	createProp = B_FALSE;
201 	int	lastAlloc = 0;
202 	char	buf[FCOE_PORT_LIST_LENGTH] = {0};
203 	char	memberName[FCOE_PORT_LIST_LENGTH] = {0};
204 	boolean_t	found = B_FALSE;
205 	int	i = 0;
206 	int	valueArraySize = 0;
207 	int	commitRet;
208 
209 	sprintf(memberName, "%s:%s:%s:%d:%d", mac_name, pwwn, nwwn,
210 	    is_target, is_promiscuous);
211 
212 	ret = fcoe_cfg_scf_init(&handle, &svc);
213 	if (ret != FCOE_SUCCESS) {
214 		goto out;
215 	}
216 
217 	if (((pg = scf_pg_create(handle)) == NULL) ||
218 	    ((tran = scf_transaction_create(handle)) == NULL) ||
219 	    ((entry = scf_entry_create(handle)) == NULL) ||
220 	    ((prop = scf_property_create(handle)) == NULL) ||
221 	    ((valueIter = scf_iter_create(handle)) == NULL)) {
222 		ret = FCOE_ERROR;
223 		goto out;
224 	}
225 
226 	/* get property group or create it */
227 	if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
228 		if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
229 			if (scf_service_add_pg(svc, FCOE_PG_NAME,
230 			    SCF_GROUP_APPLICATION, 0, pg) == -1) {
231 				syslog(LOG_ERR, "add pg failed - %s",
232 				    scf_strerror(scf_error()));
233 				ret = FCOE_ERROR;
234 			} else {
235 				createProp = B_TRUE;
236 			}
237 		} else {
238 			syslog(LOG_ERR, "get pg failed - %s",
239 			    scf_strerror(scf_error()));
240 			ret = FCOE_ERROR;
241 		}
242 		if (ret != FCOE_SUCCESS) {
243 			goto out;
244 		}
245 	}
246 
247 	/* to make sure property exists */
248 	if (createProp == B_FALSE) {
249 		if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
250 			if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
251 				createProp = B_TRUE;
252 			} else {
253 				syslog(LOG_ERR, "get property failed - %s",
254 				    scf_strerror(scf_error()));
255 				ret = FCOE_ERROR;
256 				goto out;
257 			}
258 		}
259 	}
260 
261 	/* Begin the transaction */
262 	if (scf_transaction_start(tran, pg) == -1) {
263 		syslog(LOG_ERR, "start transaction failed - %s",
264 		    scf_strerror(scf_error()));
265 		ret = FCOE_ERROR;
266 		goto out;
267 	}
268 
269 	valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
270 	    * (lastAlloc = PORT_LIST_ALLOC));
271 	if (valueSet == NULL) {
272 		ret = FCOE_ERROR_NOMEM;
273 		goto out;
274 	}
275 
276 	if (createProp) {
277 		if (scf_transaction_property_new(tran, entry, FCOE_PORT_LIST,
278 		    SCF_TYPE_USTRING) == -1) {
279 			if (scf_error() == SCF_ERROR_EXISTS) {
280 				ret = FCOE_ERROR_EXISTS;
281 			} else {
282 				syslog(LOG_ERR,
283 				    "transaction property new failed - %s",
284 				    scf_strerror(scf_error()));
285 				ret = FCOE_ERROR;
286 			}
287 			goto out;
288 		}
289 	} else {
290 		if (scf_transaction_property_change(tran, entry,
291 		    FCOE_PORT_LIST, SCF_TYPE_USTRING) == -1) {
292 			syslog(LOG_ERR,
293 			    "transaction property change failed - %s",
294 			    scf_strerror(scf_error()));
295 			ret = FCOE_ERROR;
296 			goto out;
297 		}
298 
299 		if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
300 			syslog(LOG_ERR, "get property failed - %s",
301 			    scf_strerror(scf_error()));
302 			ret = FCOE_ERROR;
303 			goto out;
304 		}
305 
306 		valueLookup = scf_value_create(handle);
307 		if (valueLookup == NULL) {
308 			syslog(LOG_ERR, "scf value alloc failed - %s",
309 			    scf_strerror(scf_error()));
310 			ret = FCOE_ERROR;
311 			goto out;
312 		}
313 
314 		if (scf_iter_property_values(valueIter, prop) == -1) {
315 			syslog(LOG_ERR, "iter value failed - %s",
316 			    scf_strerror(scf_error()));
317 			ret = FCOE_ERROR;
318 			goto out;
319 		}
320 
321 		while (scf_iter_next_value(valueIter, valueLookup) == 1) {
322 			char *macnameIter = NULL;
323 			char buftmp[FCOE_PORT_LIST_LENGTH] = {0};
324 
325 			bzero(buf, sizeof (buf));
326 			if (scf_value_get_ustring(valueLookup,
327 			    buf, MAXNAMELEN) == -1) {
328 				syslog(LOG_ERR, "iter value failed- %s",
329 				    scf_strerror(scf_error()));
330 				ret = FCOE_ERROR;
331 				break;
332 			}
333 			strcpy(buftmp, buf);
334 			macnameIter = strtok(buftmp, ":");
335 			if (bcmp(macnameIter, mac_name,
336 			    strlen(mac_name)) == 0) {
337 				if (addRemoveFlag == FCOE_SCF_ADD) {
338 					ret = FCOE_ERROR_EXISTS;
339 					break;
340 				} else {
341 					found = B_TRUE;
342 					continue;
343 				}
344 			}
345 
346 			valueSet[i] = scf_value_create(handle);
347 			if (valueSet[i] == NULL) {
348 				syslog(LOG_ERR, "scf value alloc failed - %s",
349 				    scf_strerror(scf_error()));
350 				ret = FCOE_ERROR;
351 				break;
352 			}
353 
354 			if (scf_value_set_ustring(valueSet[i], buf) == -1) {
355 				syslog(LOG_ERR, "set value failed 1- %s",
356 				    scf_strerror(scf_error()));
357 				ret = FCOE_ERROR;
358 				break;
359 			}
360 
361 			if (scf_entry_add_value(entry, valueSet[i]) == -1) {
362 				syslog(LOG_ERR, "add value failed - %s",
363 				    scf_strerror(scf_error()));
364 				ret = FCOE_ERROR;
365 				break;
366 			}
367 
368 			i++;
369 
370 			if (i >= lastAlloc) {
371 				lastAlloc += PORT_LIST_ALLOC;
372 				valueSet = realloc(valueSet,
373 				    sizeof (*valueSet) * lastAlloc);
374 				if (valueSet == NULL) {
375 					ret = FCOE_ERROR;
376 					break;
377 				}
378 			}
379 		}
380 	}
381 
382 	valueArraySize = i;
383 	if (!found && (addRemoveFlag == FCOE_SCF_REMOVE)) {
384 		ret = FCOE_ERROR_MEMBER_NOT_FOUND;
385 	}
386 	if (ret != FCOE_SUCCESS) {
387 		goto out;
388 	}
389 
390 	if (addRemoveFlag == FCOE_SCF_ADD) {
391 		/*
392 		 * Now create the new entry
393 		 */
394 		valueSet[i] = scf_value_create(handle);
395 		if (valueSet[i] == NULL) {
396 			syslog(LOG_ERR, "scf value alloc failed - %s",
397 			    scf_strerror(scf_error()));
398 			ret = FCOE_ERROR;
399 			goto out;
400 		} else {
401 			valueArraySize++;
402 		}
403 
404 		/*
405 		 * Set the new member name
406 		 */
407 		if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
408 			syslog(LOG_ERR, "set value failed 2- %s",
409 			    scf_strerror(scf_error()));
410 			ret = FCOE_ERROR;
411 			goto out;
412 		}
413 
414 		/*
415 		 * Add the new member
416 		 */
417 		if (scf_entry_add_value(entry, valueSet[i]) == -1) {
418 			syslog(LOG_ERR, "add value failed - %s",
419 			    scf_strerror(scf_error()));
420 			ret = FCOE_ERROR;
421 			goto out;
422 		}
423 	}
424 
425 	if ((commitRet = scf_transaction_commit(tran)) != 1) {
426 		syslog(LOG_ERR, "transaction commit failed - %s",
427 		    scf_strerror(scf_error()));
428 		if (commitRet == 0) {
429 			ret = FCOE_ERROR_BUSY;
430 		} else {
431 			ret = FCOE_ERROR;
432 		}
433 		goto out;
434 	}
435 
436 out:
437 	/*
438 	 * Free resources
439 	 */
440 	if (handle != NULL) {
441 		scf_handle_destroy(handle);
442 	}
443 	if (svc != NULL) {
444 		scf_service_destroy(svc);
445 	}
446 	if (pg != NULL) {
447 		scf_pg_destroy(pg);
448 	}
449 	if (tran != NULL) {
450 		scf_transaction_destroy(tran);
451 	}
452 	if (entry != NULL) {
453 		scf_entry_destroy(entry);
454 	}
455 	if (prop != NULL) {
456 		scf_property_destroy(prop);
457 	}
458 	if (valueIter != NULL) {
459 		scf_iter_destroy(valueIter);
460 	}
461 	if (valueLookup != NULL) {
462 		scf_value_destroy(valueLookup);
463 	}
464 
465 	/*
466 	 * Free valueSet scf resources
467 	 */
468 	if (valueArraySize > 0) {
469 		for (i = 0; i < valueArraySize; i++) {
470 			scf_value_destroy(valueSet[i]);
471 		}
472 	}
473 	/*
474 	 * Now free the pointer array to the resources
475 	 */
476 	if (valueSet != NULL) {
477 		free(valueSet);
478 	}
479 
480 	return (ret);
481 }
482 
483 int
484 fcoe_adm_create_port(int objects, char *argv[],
485     cmdOptions_t *options)
486 {
487 	FCOE_STATUS status = FCOE_STATUS_OK;
488 	uint64_t	nodeWWN, portWWN;
489 	FCOE_PORT_WWN	pwwn, nwwn;
490 	FCOE_UINT8	macLinkName[FCOE_MAX_MAC_NAME_LEN];
491 	FCOE_UINT8	promiscuous = 0;
492 	int		createini = 0, createtgt = 0;
493 
494 	/* check the mac name operand */
495 	assert(objects == 1);
496 
497 	strcpy((char *)macLinkName, argv[0]);
498 	bzero(&pwwn, 8);
499 	bzero(&nwwn, 8);
500 
501 	for (; options->optval; options++) {
502 		switch (options->optval) {
503 		case 'i':
504 			createini = 1;
505 			break;
506 
507 		case 't':
508 			createtgt = 1;
509 			break;
510 		case 'p':
511 			if (!isValidWWN(options->optarg)) {
512 				fprintf(stderr,
513 				    gettext("Error: Invalid Port WWN\n"));
514 				return (1);
515 			}
516 			sscanf(options->optarg, "%016llx", &portWWN);
517 			portWWN = htonll(portWWN);
518 			memcpy(&pwwn, &portWWN, sizeof (portWWN));
519 			break;
520 
521 		case 'n':
522 			if (!isValidWWN(options->optarg)) {
523 				fprintf(stderr,
524 				    gettext("Error: Invalid Node WWN\n"));
525 				return (1);
526 			}
527 			sscanf(options->optarg, "%016llx", &nodeWWN);
528 			nodeWWN = htonll(nodeWWN);
529 			memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
530 			break;
531 		case 'f':
532 			promiscuous = 1;
533 			break;
534 
535 		default:
536 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
537 			    options->optval);
538 			return (1);
539 		}
540 	}
541 
542 	if (createini == 1 && createtgt == 1) {
543 		fprintf(stderr, "Error: Option -i and -t should "
544 		    "not be both specified\n");
545 		return (1);
546 	}
547 	status = FCOE_CreatePort(macLinkName,
548 	    createtgt == 1 ? FCOE_PORTTYPE_TARGET :
549 	    FCOE_PORTTYPE_INITIATOR, pwwn, nwwn, promiscuous);
550 
551 	if (status != FCOE_STATUS_OK) {
552 		switch (status) {
553 		case  FCOE_STATUS_ERROR_BUSY:
554 			fprintf(stderr,
555 			    gettext("Error: fcoe driver is busy\n"));
556 			break;
557 
558 		case  FCOE_STATUS_ERROR_ALREADY:
559 			fprintf(stderr,
560 			    gettext("Error: Existing FCoE port "
561 			    "found on the specified MAC link\n"));
562 			break;
563 
564 		case  FCOE_STATUS_ERROR_PERM:
565 			fprintf(stderr,
566 			    gettext("Error: Not enough permission to "
567 			    "open fcoe device\n"));
568 			break;
569 
570 		case  FCOE_STATUS_ERROR_OPEN_DEV:
571 			fprintf(stderr,
572 			    gettext("Error: Failed to open fcoe device\n"));
573 			break;
574 
575 		case  FCOE_STATUS_ERROR_WWN_SAME:
576 			fprintf(stderr,
577 			    gettext("Error: Port WWN is same as Node "
578 			    "WWN\n"));
579 			break;
580 
581 		case  FCOE_STATUS_ERROR_MAC_LEN:
582 			fprintf(stderr,
583 			    gettext("Error: MAC name exceeds maximum "
584 			    "length\n"));
585 			break;
586 
587 		case  FCOE_STATUS_ERROR_PWWN_CONFLICTED:
588 			fprintf(stderr,
589 			    gettext("Error: The specified Port WWN "
590 			    "is already in use\n"));
591 			break;
592 
593 		case  FCOE_STATUS_ERROR_NWWN_CONFLICTED:
594 			fprintf(stderr,
595 			    gettext("Error: The specified Node WWN "
596 			    "is already in use\n"));
597 			break;
598 
599 		case  FCOE_STATUS_ERROR_NEED_JUMBO_FRAME:
600 			fprintf(stderr,
601 			    gettext("Error: MTU size of the specified "
602 			    "MAC link needs to be increased to 2500 "
603 			    "or above\n"));
604 			break;
605 
606 		case  FCOE_STATUS_ERROR_CREATE_MAC:
607 			fprintf(stderr,
608 			    gettext("Error: Out of memory\n"));
609 			break;
610 
611 
612 		case  FCOE_STATUS_ERROR_OPEN_MAC:
613 			fprintf(stderr,
614 			    gettext("Error: Failed to open the "
615 			    "specified MAC link\n"));
616 			break;
617 
618 		case  FCOE_STATUS_ERROR_CREATE_PORT:
619 			fprintf(stderr,
620 			    gettext("Error: Failed to create FCoE "
621 			    "port on the specified MAC link\n"));
622 			break;
623 
624 		case  FCOE_STATUS_ERROR_VNIC_UNSUPPORT:
625 			fprintf(stderr,
626 			    gettext("Error: VNIC is not supported\n"));
627 			break;
628 
629 		case FCOE_STATUS_ERROR:
630 		default:
631 			fprintf(stderr,
632 			    gettext("Error: Due to reason code %d\n"), status);
633 		}
634 		return (1);
635 	} else {
636 		char cpwwn[17], cnwwn[17];
637 
638 		WWN2str(cpwwn, &pwwn);
639 		WWN2str(cnwwn, &nwwn);
640 
641 		fcoe_adm_add_remove_scf_entry((char *)macLinkName,
642 		    cpwwn,
643 		    cnwwn,
644 		    createtgt,
645 		    promiscuous,
646 		    FCOE_SCF_ADD);
647 		return (0);
648 	}
649 }
650 
651 int
652 fcoe_adm_delete_port(int objects, char *argv[])
653 {
654 	FCOE_STATUS status;
655 	FCOE_UINT8	*macLinkName;
656 
657 	/* check the mac name operand */
658 	assert(objects == 1);
659 
660 	macLinkName = (FCOE_UINT8 *) argv[0];
661 
662 	status = FCOE_DeletePort(macLinkName);
663 	if (status != FCOE_STATUS_OK) {
664 		switch (status) {
665 		case  FCOE_STATUS_ERROR_BUSY:
666 			fprintf(stderr,
667 			    gettext("Error: fcoe driver is busy\n"));
668 			break;
669 
670 		case  FCOE_STATUS_ERROR_ALREADY:
671 			fprintf(stderr,
672 			    gettext("Error: FCoE port not found on the "
673 			    "specified MAC link\n"));
674 			break;
675 
676 		case  FCOE_STATUS_ERROR_PERM:
677 			fprintf(stderr,
678 			    gettext("Error: Not enough permission to "
679 			    "open fcoe device\n"));
680 			break;
681 
682 		case  FCOE_STATUS_ERROR_MAC_LEN:
683 			fprintf(stderr,
684 			    gettext("Failed: MAC name exceeds maximum "
685 			    "length 32\n"));
686 			break;
687 
688 		case  FCOE_STATUS_ERROR_OPEN_DEV:
689 			fprintf(stderr,
690 			    gettext("Error: Failed to open fcoe device\n"));
691 			break;
692 
693 		case  FCOE_STATUS_ERROR_MAC_NOT_FOUND:
694 			fprintf(stderr,
695 			    gettext("Error: FCoE port not found on the "
696 			    "specified MAC link\n"));
697 			break;
698 
699 		case  FCOE_STATUS_ERROR_OFFLINE_DEV:
700 			fprintf(stderr,
701 			    gettext("Error: Please use stmfadm to offline "
702 			    "the FCoE target first\n"));
703 			break;
704 
705 		case FCOE_STATUS_ERROR:
706 		default:
707 			fprintf(stderr,
708 			    gettext("Error: Due to reason code %d\n"), status);
709 		}
710 		return (1);
711 	} else {
712 		fcoe_adm_add_remove_scf_entry((char *)macLinkName,
713 		    "",
714 		    "",
715 		    0,
716 		    0,
717 		    FCOE_SCF_REMOVE);
718 		return (0);
719 	}
720 }
721 
722 int
723 fcoe_adm_list_ports(cmdOptions_t *options)
724 {
725 	FCOE_STATUS	status;
726 	int	showini = 0, showtgt = 0;
727 	FCOE_UINT32	port_num;
728 	FCOE_PORT_ATTRIBUTE	*portlist = NULL;
729 	int i;
730 	int ret;
731 
732 	for (; options->optval; options++) {
733 		switch (options->optval) {
734 		case 'i':
735 			showini = 1;
736 			break;
737 
738 		case 't':
739 			showtgt = 1;
740 			break;
741 
742 		default:
743 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
744 			    options->optval);
745 			return (1);
746 		}
747 	}
748 	if (showini == 0 && showtgt == 0) {
749 		showini = 1;
750 		showtgt = 1;
751 	}
752 
753 	status = FCOE_GetPortList(&port_num, &portlist);
754 
755 	if (status != FCOE_STATUS_OK) {
756 		switch (status) {
757 		case  FCOE_STATUS_ERROR_BUSY:
758 			fprintf(stderr,
759 			    gettext("Error: fcoe driver is busy\n"));
760 			break;
761 
762 		case  FCOE_STATUS_ERROR_PERM:
763 			fprintf(stderr,
764 			    gettext("Error: Not enough permission to "
765 			    "open fcoe device\n"));
766 			break;
767 
768 		case  FCOE_STATUS_ERROR_OPEN_DEV:
769 			fprintf(stderr,
770 			    gettext("Error: Failed to open fcoe device\n"));
771 			break;
772 
773 		case  FCOE_STATUS_ERROR_INVAL_ARG:
774 			fprintf(stderr,
775 			    gettext("Error: Invalid argument\n"));
776 			break;
777 
778 		case  FCOE_STATUS_ERROR_MORE_DATA:
779 			fprintf(stderr,
780 			    gettext("Error: More data\n"));
781 			break;
782 
783 		case FCOE_STATUS_ERROR:
784 		default:
785 			fprintf(stderr,
786 			    gettext("Error: Due to reason code %d\n"), status);
787 		}
788 		ret = 1;
789 	} else {
790 		if (port_num == 0) {
791 			fprintf(stdout, gettext("No FCoE Ports Found!\n"));
792 		} else {
793 			for (i = 0; i < port_num; i++) {
794 				if ((portlist[i].port_type ==
795 				    FCOE_PORTTYPE_INITIATOR &&
796 				    showini == 1) || (showtgt == 1 &&
797 				    portlist[i].port_type ==
798 				    FCOE_PORTTYPE_TARGET)) {
799 					printFCOEPortInfo(&portlist[i]);
800 				}
801 			}
802 		}
803 		ret = 0;
804 	}
805 
806 	if (portlist != NULL) {
807 		free(portlist);
808 	}
809 	return (ret);
810 
811 }
812 
813 int
814 fcoe_adm_create_portlist(cmdOptions_t *options)
815 {
816 	scf_handle_t	*handle = NULL;
817 	scf_service_t	*svc = NULL;
818 	scf_propertygroup_t	*pg = NULL;
819 	scf_transaction_t	*tran = NULL;
820 	scf_transaction_entry_t	*entry = NULL;
821 	scf_property_t		*prop = NULL;
822 	scf_value_t	*valueLookup = NULL;
823 	scf_iter_t	*valueIter = NULL;
824 	char		buf[FCOE_PORT_LIST_LENGTH] = {0};
825 	int		commitRet;
826 	int		create_target = 0, create_initiator = 0;
827 
828 	/* Check what type of port list will be created */
829 	for (; options->optval; options++) {
830 		switch (options->optval) {
831 		case 'i':
832 			create_initiator = 1;
833 			break;
834 		case 't':
835 			create_target = 1;
836 			break;
837 		default:
838 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
839 			    options->optval);
840 			return (1);
841 		}
842 	}
843 
844 	if (create_initiator == 0 && create_target == 0) {
845 		create_initiator = 1;
846 		create_target = 1;
847 	}
848 
849 	commitRet = fcoe_cfg_scf_init(&handle, &svc);
850 	if (commitRet != FCOE_SUCCESS) {
851 		goto out;
852 	}
853 
854 	if (((pg = scf_pg_create(handle)) == NULL) ||
855 	    ((tran = scf_transaction_create(handle)) == NULL) ||
856 	    ((entry = scf_entry_create(handle)) == NULL) ||
857 	    ((prop = scf_property_create(handle)) == NULL) ||
858 	    ((valueIter = scf_iter_create(handle)) == NULL)) {
859 		goto out;
860 	}
861 
862 	/* get property group or create it */
863 	if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
864 		goto out;
865 	}
866 
867 	if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
868 		syslog(LOG_ERR, "get property failed - %s",
869 		    scf_strerror(scf_error()));
870 		goto out;
871 	}
872 
873 	valueLookup = scf_value_create(handle);
874 	if (valueLookup == NULL) {
875 		syslog(LOG_ERR, "scf value alloc failed - %s",
876 		    scf_strerror(scf_error()));
877 		goto out;
878 	}
879 
880 	if (scf_iter_property_values(valueIter, prop) == -1) {
881 		syslog(LOG_ERR, "iter value failed - %s",
882 		    scf_strerror(scf_error()));
883 		goto out;
884 	}
885 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
886 		uint8_t *macLinkName = NULL;
887 		char *remainder = NULL;
888 		FCOE_PORT_WWN pwwn, nwwn;
889 		uint64_t	nodeWWN, portWWN;
890 		int is_target, is_promiscuous;
891 
892 		bzero(buf, sizeof (buf));
893 		bzero(&pwwn, sizeof (pwwn));
894 		bzero(&nwwn, sizeof (nwwn));
895 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
896 			syslog(LOG_ERR, "iter value failed - %s",
897 			    scf_strerror(scf_error()));
898 			break;
899 		}
900 		macLinkName = (uint8_t *)strtok(buf, ":");
901 		remainder = strtok(NULL, "#");
902 		sscanf(remainder, "%016llx:%016llx:%d:%d",
903 		    &portWWN, &nodeWWN, &is_target, &is_promiscuous);
904 		if ((!create_target && is_target) ||
905 		    (!create_initiator && !is_target)) {
906 			continue;
907 		}
908 
909 		nodeWWN = htonll(nodeWWN);
910 		memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
911 		portWWN = htonll(portWWN);
912 		memcpy(&pwwn, &portWWN, sizeof (portWWN));
913 
914 		FCOE_CreatePort(macLinkName,
915 		    is_target ? FCOE_PORTTYPE_TARGET : FCOE_PORTTYPE_INITIATOR,
916 		    pwwn, nwwn, is_promiscuous);
917 	}
918 
919 out:
920 	/*
921 	 * Free resources
922 	 */
923 	if (handle != NULL) {
924 		scf_handle_destroy(handle);
925 	}
926 	if (svc != NULL) {
927 		scf_service_destroy(svc);
928 	}
929 	if (pg != NULL) {
930 		scf_pg_destroy(pg);
931 	}
932 	if (tran != NULL) {
933 		scf_transaction_destroy(tran);
934 	}
935 	if (entry != NULL) {
936 		scf_entry_destroy(entry);
937 	}
938 	if (prop != NULL) {
939 		scf_property_destroy(prop);
940 	}
941 	if (valueIter != NULL) {
942 		scf_iter_destroy(valueIter);
943 	}
944 	if (valueLookup != NULL) {
945 		scf_value_destroy(valueLookup);
946 	}
947 
948 	return (0);
949 }
950