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