xref: /titanic_52/usr/src/cmd/fcinfo/fcoeadm.c (revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8)
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_CLASS_UNSUPPORT:
625 			fprintf(stderr,
626 			    gettext("Error: Link class other than physical "
627 			    "link is not supported\n"));
628 			break;
629 
630 		case FCOE_STATUS_ERROR_GET_LINKINFO:
631 			fprintf(stderr,
632 			    gettext("Error: Failed to get link infomation "
633 			    "for %s\n"), macLinkName);
634 			break;
635 
636 		case FCOE_STATUS_ERROR:
637 		default:
638 			fprintf(stderr,
639 			    gettext("Error: Due to reason code %d\n"), status);
640 		}
641 		return (1);
642 	} else {
643 		char cpwwn[17], cnwwn[17];
644 
645 		WWN2str(cpwwn, &pwwn);
646 		WWN2str(cnwwn, &nwwn);
647 
648 		fcoe_adm_add_remove_scf_entry((char *)macLinkName,
649 		    cpwwn,
650 		    cnwwn,
651 		    createtgt,
652 		    promiscuous,
653 		    FCOE_SCF_ADD);
654 		return (0);
655 	}
656 }
657 
658 int
659 fcoe_adm_delete_port(int objects, char *argv[])
660 {
661 	FCOE_STATUS status;
662 	FCOE_UINT8	*macLinkName;
663 
664 	/* check the mac name operand */
665 	assert(objects == 1);
666 
667 	macLinkName = (FCOE_UINT8 *) argv[0];
668 
669 	status = FCOE_DeletePort(macLinkName);
670 	if (status != FCOE_STATUS_OK) {
671 		switch (status) {
672 		case  FCOE_STATUS_ERROR_BUSY:
673 			fprintf(stderr,
674 			    gettext("Error: fcoe driver is busy\n"));
675 			break;
676 
677 		case  FCOE_STATUS_ERROR_ALREADY:
678 			fprintf(stderr,
679 			    gettext("Error: FCoE port not found on the "
680 			    "specified MAC link\n"));
681 			break;
682 
683 		case  FCOE_STATUS_ERROR_PERM:
684 			fprintf(stderr,
685 			    gettext("Error: Not enough permission to "
686 			    "open fcoe device\n"));
687 			break;
688 
689 		case  FCOE_STATUS_ERROR_MAC_LEN:
690 			fprintf(stderr,
691 			    gettext("Failed: MAC name exceeds maximum "
692 			    "length 32\n"));
693 			break;
694 
695 		case  FCOE_STATUS_ERROR_OPEN_DEV:
696 			fprintf(stderr,
697 			    gettext("Error: Failed to open fcoe device\n"));
698 			break;
699 
700 		case  FCOE_STATUS_ERROR_MAC_NOT_FOUND:
701 			fprintf(stderr,
702 			    gettext("Error: FCoE port not found on the "
703 			    "specified MAC link\n"));
704 			break;
705 
706 		case  FCOE_STATUS_ERROR_OFFLINE_DEV:
707 			fprintf(stderr,
708 			    gettext("Error: Please use stmfadm to offline "
709 			    "the FCoE target first\n"));
710 			break;
711 
712 		case FCOE_STATUS_ERROR_GET_LINKINFO:
713 			fprintf(stderr,
714 			    gettext("Error: Failed to get link information "
715 			    "for %s\n"), macLinkName);
716 			break;
717 
718 		case FCOE_STATUS_ERROR:
719 		default:
720 			fprintf(stderr,
721 			    gettext("Error: Due to reason code %d\n"), status);
722 		}
723 		return (1);
724 	} else {
725 		fcoe_adm_add_remove_scf_entry((char *)macLinkName,
726 		    "",
727 		    "",
728 		    0,
729 		    0,
730 		    FCOE_SCF_REMOVE);
731 		return (0);
732 	}
733 }
734 
735 int
736 fcoe_adm_list_ports(cmdOptions_t *options)
737 {
738 	FCOE_STATUS	status;
739 	int	showini = 0, showtgt = 0;
740 	FCOE_UINT32	port_num;
741 	FCOE_PORT_ATTRIBUTE	*portlist = NULL;
742 	int i;
743 	int ret;
744 
745 	for (; options->optval; options++) {
746 		switch (options->optval) {
747 		case 'i':
748 			showini = 1;
749 			break;
750 
751 		case 't':
752 			showtgt = 1;
753 			break;
754 
755 		default:
756 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
757 			    options->optval);
758 			return (1);
759 		}
760 	}
761 	if (showini == 0 && showtgt == 0) {
762 		showini = 1;
763 		showtgt = 1;
764 	}
765 
766 	status = FCOE_GetPortList(&port_num, &portlist);
767 
768 	if (status != FCOE_STATUS_OK) {
769 		switch (status) {
770 		case  FCOE_STATUS_ERROR_BUSY:
771 			fprintf(stderr,
772 			    gettext("Error: fcoe driver is busy\n"));
773 			break;
774 
775 		case  FCOE_STATUS_ERROR_PERM:
776 			fprintf(stderr,
777 			    gettext("Error: Not enough permission to "
778 			    "open fcoe device\n"));
779 			break;
780 
781 		case  FCOE_STATUS_ERROR_OPEN_DEV:
782 			fprintf(stderr,
783 			    gettext("Error: Failed to open fcoe device\n"));
784 			break;
785 
786 		case  FCOE_STATUS_ERROR_INVAL_ARG:
787 			fprintf(stderr,
788 			    gettext("Error: Invalid argument\n"));
789 			break;
790 
791 		case  FCOE_STATUS_ERROR_MORE_DATA:
792 			fprintf(stderr,
793 			    gettext("Error: More data\n"));
794 			break;
795 
796 		case FCOE_STATUS_ERROR:
797 		default:
798 			fprintf(stderr,
799 			    gettext("Error: Due to reason code %d\n"), status);
800 		}
801 		ret = 1;
802 	} else {
803 		if (port_num == 0) {
804 			fprintf(stdout, gettext("No FCoE Ports Found!\n"));
805 		} else {
806 			for (i = 0; i < port_num; i++) {
807 				if ((portlist[i].port_type ==
808 				    FCOE_PORTTYPE_INITIATOR &&
809 				    showini == 1) || (showtgt == 1 &&
810 				    portlist[i].port_type ==
811 				    FCOE_PORTTYPE_TARGET)) {
812 					printFCOEPortInfo(&portlist[i]);
813 				}
814 			}
815 		}
816 		ret = 0;
817 	}
818 
819 	if (portlist != NULL) {
820 		free(portlist);
821 	}
822 	return (ret);
823 
824 }
825 
826 int
827 fcoe_adm_create_portlist(cmdOptions_t *options)
828 {
829 	scf_handle_t	*handle = NULL;
830 	scf_service_t	*svc = NULL;
831 	scf_propertygroup_t	*pg = NULL;
832 	scf_transaction_t	*tran = NULL;
833 	scf_transaction_entry_t	*entry = NULL;
834 	scf_property_t		*prop = NULL;
835 	scf_value_t	*valueLookup = NULL;
836 	scf_iter_t	*valueIter = NULL;
837 	char		buf[FCOE_PORT_LIST_LENGTH] = {0};
838 	int		commitRet;
839 	int		create_target = 0, create_initiator = 0;
840 
841 	/* Check what type of port list will be created */
842 	for (; options->optval; options++) {
843 		switch (options->optval) {
844 		case 'i':
845 			create_initiator = 1;
846 			break;
847 		case 't':
848 			create_target = 1;
849 			break;
850 		default:
851 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
852 			    options->optval);
853 			return (1);
854 		}
855 	}
856 
857 	if (create_initiator == 0 && create_target == 0) {
858 		create_initiator = 1;
859 		create_target = 1;
860 	}
861 
862 	commitRet = fcoe_cfg_scf_init(&handle, &svc);
863 	if (commitRet != FCOE_SUCCESS) {
864 		goto out;
865 	}
866 
867 	if (((pg = scf_pg_create(handle)) == NULL) ||
868 	    ((tran = scf_transaction_create(handle)) == NULL) ||
869 	    ((entry = scf_entry_create(handle)) == NULL) ||
870 	    ((prop = scf_property_create(handle)) == NULL) ||
871 	    ((valueIter = scf_iter_create(handle)) == NULL)) {
872 		goto out;
873 	}
874 
875 	/* get property group or create it */
876 	if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
877 		goto out;
878 	}
879 
880 	if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
881 		syslog(LOG_ERR, "get property failed - %s",
882 		    scf_strerror(scf_error()));
883 		goto out;
884 	}
885 
886 	valueLookup = scf_value_create(handle);
887 	if (valueLookup == NULL) {
888 		syslog(LOG_ERR, "scf value alloc failed - %s",
889 		    scf_strerror(scf_error()));
890 		goto out;
891 	}
892 
893 	if (scf_iter_property_values(valueIter, prop) == -1) {
894 		syslog(LOG_ERR, "iter value failed - %s",
895 		    scf_strerror(scf_error()));
896 		goto out;
897 	}
898 	while (scf_iter_next_value(valueIter, valueLookup) == 1) {
899 		uint8_t *macLinkName = NULL;
900 		char *remainder = NULL;
901 		FCOE_PORT_WWN pwwn, nwwn;
902 		uint64_t	nodeWWN, portWWN;
903 		int is_target, is_promiscuous;
904 
905 		bzero(buf, sizeof (buf));
906 		bzero(&pwwn, sizeof (pwwn));
907 		bzero(&nwwn, sizeof (nwwn));
908 		if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
909 			syslog(LOG_ERR, "iter value failed - %s",
910 			    scf_strerror(scf_error()));
911 			break;
912 		}
913 		macLinkName = (uint8_t *)strtok(buf, ":");
914 		remainder = strtok(NULL, "#");
915 		sscanf(remainder, "%016llx:%016llx:%d:%d",
916 		    &portWWN, &nodeWWN, &is_target, &is_promiscuous);
917 		if ((!create_target && is_target) ||
918 		    (!create_initiator && !is_target)) {
919 			continue;
920 		}
921 
922 		nodeWWN = htonll(nodeWWN);
923 		memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
924 		portWWN = htonll(portWWN);
925 		memcpy(&pwwn, &portWWN, sizeof (portWWN));
926 
927 		FCOE_CreatePort(macLinkName,
928 		    is_target ? FCOE_PORTTYPE_TARGET : FCOE_PORTTYPE_INITIATOR,
929 		    pwwn, nwwn, is_promiscuous);
930 	}
931 
932 out:
933 	/*
934 	 * Free resources
935 	 */
936 	if (handle != NULL) {
937 		scf_handle_destroy(handle);
938 	}
939 	if (svc != NULL) {
940 		scf_service_destroy(svc);
941 	}
942 	if (pg != NULL) {
943 		scf_pg_destroy(pg);
944 	}
945 	if (tran != NULL) {
946 		scf_transaction_destroy(tran);
947 	}
948 	if (entry != NULL) {
949 		scf_entry_destroy(entry);
950 	}
951 	if (prop != NULL) {
952 		scf_property_destroy(prop);
953 	}
954 	if (valueIter != NULL) {
955 		scf_iter_destroy(valueIter);
956 	}
957 	if (valueLookup != NULL) {
958 		scf_value_destroy(valueLookup);
959 	}
960 
961 	return (0);
962 }
963