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