19087SZhong.Wang@Sun.COM /*
29087SZhong.Wang@Sun.COM  * CDDL HEADER START
39087SZhong.Wang@Sun.COM  *
49087SZhong.Wang@Sun.COM  * The contents of this file are subject to the terms of the
59087SZhong.Wang@Sun.COM  * Common Development and Distribution License (the "License").
69087SZhong.Wang@Sun.COM  * You may not use this file except in compliance with the License.
79087SZhong.Wang@Sun.COM  *
89087SZhong.Wang@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99087SZhong.Wang@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109087SZhong.Wang@Sun.COM  * See the License for the specific language governing permissions
119087SZhong.Wang@Sun.COM  * and limitations under the License.
129087SZhong.Wang@Sun.COM  *
139087SZhong.Wang@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149087SZhong.Wang@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159087SZhong.Wang@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169087SZhong.Wang@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179087SZhong.Wang@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189087SZhong.Wang@Sun.COM  *
199087SZhong.Wang@Sun.COM  * CDDL HEADER END
209087SZhong.Wang@Sun.COM  */
219087SZhong.Wang@Sun.COM /*
229087SZhong.Wang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239087SZhong.Wang@Sun.COM  * Use is subject to license terms.
249087SZhong.Wang@Sun.COM  */
259087SZhong.Wang@Sun.COM 
269087SZhong.Wang@Sun.COM #include <stdlib.h>
279087SZhong.Wang@Sun.COM #include <stdio.h>
289087SZhong.Wang@Sun.COM #include <wchar.h>
299087SZhong.Wang@Sun.COM #include <strings.h>
309087SZhong.Wang@Sun.COM #include <sys/types.h>
319087SZhong.Wang@Sun.COM #include <sys/stat.h>
329087SZhong.Wang@Sun.COM #include <fcntl.h>
339087SZhong.Wang@Sun.COM #include <unistd.h>
349087SZhong.Wang@Sun.COM #include <libintl.h>
359087SZhong.Wang@Sun.COM #include <errno.h>
369087SZhong.Wang@Sun.COM #include <string.h>
379087SZhong.Wang@Sun.COM #include <assert.h>
389087SZhong.Wang@Sun.COM #include <syslog.h>
399087SZhong.Wang@Sun.COM #include <libfcoe.h>
40*9307Skelly.hu@Sun.COM #include <libdllink.h>
419087SZhong.Wang@Sun.COM #include <fcoeio.h>
429087SZhong.Wang@Sun.COM 
439087SZhong.Wang@Sun.COM #define	FCOE_DEV_PATH	 "/devices/fcoe:admin"
449087SZhong.Wang@Sun.COM 
459087SZhong.Wang@Sun.COM #define	OPEN_FCOE 0
469087SZhong.Wang@Sun.COM #define	OPEN_EXCL_FCOE O_EXCL
479087SZhong.Wang@Sun.COM 
489087SZhong.Wang@Sun.COM /*
499087SZhong.Wang@Sun.COM  * Open for fcoe module
509087SZhong.Wang@Sun.COM  *
519087SZhong.Wang@Sun.COM  * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE)
529087SZhong.Wang@Sun.COM  * fd - pointer to integer. On success, contains the fcoe file descriptor
539087SZhong.Wang@Sun.COM  */
549087SZhong.Wang@Sun.COM static int
559087SZhong.Wang@Sun.COM openFcoe(int flag, int *fd)
569087SZhong.Wang@Sun.COM {
579087SZhong.Wang@Sun.COM 	int ret = FCOE_STATUS_ERROR;
589087SZhong.Wang@Sun.COM 
599087SZhong.Wang@Sun.COM 	if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
609087SZhong.Wang@Sun.COM 		ret = FCOE_STATUS_OK;
619087SZhong.Wang@Sun.COM 	} else {
629087SZhong.Wang@Sun.COM 		if (errno == EPERM || errno == EACCES) {
639087SZhong.Wang@Sun.COM 			ret = FCOE_STATUS_ERROR_PERM;
649087SZhong.Wang@Sun.COM 		} else {
659087SZhong.Wang@Sun.COM 			ret = FCOE_STATUS_ERROR_OPEN_DEV;
669087SZhong.Wang@Sun.COM 		}
679087SZhong.Wang@Sun.COM 		syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)",
689087SZhong.Wang@Sun.COM 		    FCOE_DEV_PATH, errno);
699087SZhong.Wang@Sun.COM 	}
709087SZhong.Wang@Sun.COM 
719087SZhong.Wang@Sun.COM 	return (ret);
729087SZhong.Wang@Sun.COM }
739087SZhong.Wang@Sun.COM 
749087SZhong.Wang@Sun.COM static int
759087SZhong.Wang@Sun.COM isWWNZero(FCOE_PORT_WWN portwwn)
769087SZhong.Wang@Sun.COM {
779087SZhong.Wang@Sun.COM 	int i;
789087SZhong.Wang@Sun.COM 	int size = sizeof (FCOE_PORT_WWN);
799087SZhong.Wang@Sun.COM 
809087SZhong.Wang@Sun.COM 	for (i = 0; i < size; i++) {
819087SZhong.Wang@Sun.COM 		if (portwwn.wwn[i] != 0) {
829087SZhong.Wang@Sun.COM 			return (0);
839087SZhong.Wang@Sun.COM 		}
849087SZhong.Wang@Sun.COM 	}
859087SZhong.Wang@Sun.COM 	return (1);
869087SZhong.Wang@Sun.COM }
879087SZhong.Wang@Sun.COM 
889087SZhong.Wang@Sun.COM FCOE_STATUS
899087SZhong.Wang@Sun.COM FCOE_CreatePort(
909087SZhong.Wang@Sun.COM 	const FCOE_UINT8		*macLinkName,
919087SZhong.Wang@Sun.COM 	FCOE_UINT8		portType,
929087SZhong.Wang@Sun.COM 	FCOE_PORT_WWN		pwwn,
939087SZhong.Wang@Sun.COM 	FCOE_PORT_WWN		nwwn,
949087SZhong.Wang@Sun.COM 	FCOE_UINT8		promiscuous)
959087SZhong.Wang@Sun.COM {
96*9307Skelly.hu@Sun.COM 	FCOE_STATUS		status = FCOE_STATUS_OK;
97*9307Skelly.hu@Sun.COM 	int			fcoe_fd;
98*9307Skelly.hu@Sun.COM 	fcoeio_t		fcoeio;
999087SZhong.Wang@Sun.COM 	fcoeio_create_port_param_t	param;
100*9307Skelly.hu@Sun.COM 	dladm_handle_t		handle;
101*9307Skelly.hu@Sun.COM 	datalink_id_t		linkid;
102*9307Skelly.hu@Sun.COM 	datalink_class_t	class;
1039087SZhong.Wang@Sun.COM 
1049087SZhong.Wang@Sun.COM 	bzero(&param, sizeof (fcoeio_create_port_param_t));
1059087SZhong.Wang@Sun.COM 
1069087SZhong.Wang@Sun.COM 	if (macLinkName == NULL) {
1079087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_INVAL_ARG);
1089087SZhong.Wang@Sun.COM 	}
1099087SZhong.Wang@Sun.COM 
110*9307Skelly.hu@Sun.COM 	if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) {
111*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR_MAC_LEN);
112*9307Skelly.hu@Sun.COM 	}
113*9307Skelly.hu@Sun.COM 
114*9307Skelly.hu@Sun.COM 	if (dladm_open(&handle) != DLADM_STATUS_OK) {
115*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR);
116*9307Skelly.hu@Sun.COM 	}
117*9307Skelly.hu@Sun.COM 
118*9307Skelly.hu@Sun.COM 	if (dladm_name2info(handle, (const char *)macLinkName,
119*9307Skelly.hu@Sun.COM 	    &linkid, NULL, &class, NULL) != DLADM_STATUS_OK) {
120*9307Skelly.hu@Sun.COM 		dladm_close(handle);
121*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR_GET_LINKINFO);
122*9307Skelly.hu@Sun.COM 	}
123*9307Skelly.hu@Sun.COM 	dladm_close(handle);
124*9307Skelly.hu@Sun.COM 
125*9307Skelly.hu@Sun.COM 	if (class != DATALINK_CLASS_PHYS) {
126*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR_CLASS_UNSUPPORT);
127*9307Skelly.hu@Sun.COM 	}
128*9307Skelly.hu@Sun.COM 
1299087SZhong.Wang@Sun.COM 	if (portType != FCOE_PORTTYPE_INITIATOR &&
1309087SZhong.Wang@Sun.COM 	    portType != FCOE_PORTTYPE_TARGET) {
1319087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_INVAL_ARG);
1329087SZhong.Wang@Sun.COM 	}
1339087SZhong.Wang@Sun.COM 
1349087SZhong.Wang@Sun.COM 	if (!isWWNZero(pwwn)) {
1359087SZhong.Wang@Sun.COM 		param.fcp_pwwn_provided = 1;
1369087SZhong.Wang@Sun.COM 		bcopy(pwwn.wwn, param.fcp_pwwn, 8);
1379087SZhong.Wang@Sun.COM 	}
1389087SZhong.Wang@Sun.COM 
1399087SZhong.Wang@Sun.COM 	if (!isWWNZero(nwwn)) {
1409087SZhong.Wang@Sun.COM 		param.fcp_nwwn_provided = 1;
1419087SZhong.Wang@Sun.COM 		bcopy(nwwn.wwn, param.fcp_nwwn, 8);
1429087SZhong.Wang@Sun.COM 	}
1439087SZhong.Wang@Sun.COM 
1449087SZhong.Wang@Sun.COM 	if (param.fcp_pwwn_provided == 1 &&
1459087SZhong.Wang@Sun.COM 	    param.fcp_nwwn_provided == 1 &&
1469087SZhong.Wang@Sun.COM 	    bcmp(&pwwn, &nwwn, 8) == 0) {
1479087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_WWN_SAME);
1489087SZhong.Wang@Sun.COM 	}
1499087SZhong.Wang@Sun.COM 
1509087SZhong.Wang@Sun.COM 	param.fcp_force_promisc = promiscuous;
151*9307Skelly.hu@Sun.COM 	param.fcp_mac_linkid = linkid;
1529087SZhong.Wang@Sun.COM 	param.fcp_port_type = (fcoe_cli_type_t)portType;
1539087SZhong.Wang@Sun.COM 
1549087SZhong.Wang@Sun.COM 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
1559087SZhong.Wang@Sun.COM 		return (status);
1569087SZhong.Wang@Sun.COM 	}
1579087SZhong.Wang@Sun.COM 
1589087SZhong.Wang@Sun.COM 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
1599087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT;
1609087SZhong.Wang@Sun.COM 
1619087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_ilen = sizeof (param);
1629087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
1639087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_ibuf = (uintptr_t)&param;
1649087SZhong.Wang@Sun.COM 
1659087SZhong.Wang@Sun.COM 	if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
1669087SZhong.Wang@Sun.COM 		switch (fcoeio.fcoeio_status) {
1679087SZhong.Wang@Sun.COM 		case FCOEIOE_INVAL_ARG:
1689087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_INVAL_ARG;
1699087SZhong.Wang@Sun.COM 			break;
1709087SZhong.Wang@Sun.COM 
1719087SZhong.Wang@Sun.COM 		case FCOEIOE_BUSY:
1729087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_BUSY;
1739087SZhong.Wang@Sun.COM 			break;
1749087SZhong.Wang@Sun.COM 
1759087SZhong.Wang@Sun.COM 		case FCOEIOE_ALREADY:
1769087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_ALREADY;
1779087SZhong.Wang@Sun.COM 			break;
1789087SZhong.Wang@Sun.COM 
1799087SZhong.Wang@Sun.COM 		case FCOEIOE_PWWN_CONFLICTED:
1809087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_PWWN_CONFLICTED;
1819087SZhong.Wang@Sun.COM 			break;
1829087SZhong.Wang@Sun.COM 
1839087SZhong.Wang@Sun.COM 		case FCOEIOE_NWWN_CONFLICTED:
1849087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_NWWN_CONFLICTED;
1859087SZhong.Wang@Sun.COM 			break;
1869087SZhong.Wang@Sun.COM 
1879087SZhong.Wang@Sun.COM 		case FCOEIOE_CREATE_MAC:
1889087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_CREATE_MAC;
1899087SZhong.Wang@Sun.COM 			break;
1909087SZhong.Wang@Sun.COM 
1919087SZhong.Wang@Sun.COM 		case FCOEIOE_OPEN_MAC:
1929087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_OPEN_MAC;
1939087SZhong.Wang@Sun.COM 			break;
1949087SZhong.Wang@Sun.COM 
1959087SZhong.Wang@Sun.COM 		case FCOEIOE_CREATE_PORT:
1969087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_CREATE_PORT;
1979087SZhong.Wang@Sun.COM 			break;
1989087SZhong.Wang@Sun.COM 
1999087SZhong.Wang@Sun.COM 		case FCOEIOE_NEED_JUMBO_FRAME:
2009087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME;
2019087SZhong.Wang@Sun.COM 			break;
2029087SZhong.Wang@Sun.COM 
2039087SZhong.Wang@Sun.COM 		default:
2049087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR;
2059087SZhong.Wang@Sun.COM 		}
2069087SZhong.Wang@Sun.COM 	} else {
2079087SZhong.Wang@Sun.COM 		status = FCOE_STATUS_OK;
2089087SZhong.Wang@Sun.COM 	}
2099087SZhong.Wang@Sun.COM 	(void) close(fcoe_fd);
2109087SZhong.Wang@Sun.COM 	return (status);
2119087SZhong.Wang@Sun.COM }
2129087SZhong.Wang@Sun.COM 
2139087SZhong.Wang@Sun.COM FCOE_STATUS
2149087SZhong.Wang@Sun.COM FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
2159087SZhong.Wang@Sun.COM {
2169087SZhong.Wang@Sun.COM 	FCOE_STATUS status = FCOE_STATUS_OK;
2179087SZhong.Wang@Sun.COM 	int fcoe_fd;
2189087SZhong.Wang@Sun.COM 	fcoeio_t	fcoeio;
219*9307Skelly.hu@Sun.COM 	dladm_handle_t		handle;
220*9307Skelly.hu@Sun.COM 	datalink_id_t		linkid;
221*9307Skelly.hu@Sun.COM 	fcoeio_delete_port_param_t fc_del_port;
2229087SZhong.Wang@Sun.COM 
2239087SZhong.Wang@Sun.COM 	if (macLinkName == NULL) {
2249087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_INVAL_ARG);
2259087SZhong.Wang@Sun.COM 	}
2269087SZhong.Wang@Sun.COM 
227*9307Skelly.hu@Sun.COM 	if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) {
2289087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_MAC_LEN);
2299087SZhong.Wang@Sun.COM 	}
230*9307Skelly.hu@Sun.COM 	if (dladm_open(&handle) != DLADM_STATUS_OK) {
231*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR);
232*9307Skelly.hu@Sun.COM 	}
233*9307Skelly.hu@Sun.COM 
234*9307Skelly.hu@Sun.COM 	if (dladm_name2info(handle, (const char *)macLinkName,
235*9307Skelly.hu@Sun.COM 	    &linkid, NULL, NULL, NULL) != DLADM_STATUS_OK) {
236*9307Skelly.hu@Sun.COM 		dladm_close(handle);
237*9307Skelly.hu@Sun.COM 		return (FCOE_STATUS_ERROR_GET_LINKINFO);
238*9307Skelly.hu@Sun.COM 	}
239*9307Skelly.hu@Sun.COM 	dladm_close(handle);
2409087SZhong.Wang@Sun.COM 
2419087SZhong.Wang@Sun.COM 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
2429087SZhong.Wang@Sun.COM 		return (status);
2439087SZhong.Wang@Sun.COM 	}
2449087SZhong.Wang@Sun.COM 
245*9307Skelly.hu@Sun.COM 	fc_del_port.fdp_mac_linkid = linkid;
246*9307Skelly.hu@Sun.COM 
2479087SZhong.Wang@Sun.COM 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
2489087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT;
2499087SZhong.Wang@Sun.COM 
250*9307Skelly.hu@Sun.COM 	/* only 4 bytes here, need to change */
251*9307Skelly.hu@Sun.COM 	fcoeio.fcoeio_ilen = sizeof (fcoeio_delete_port_param_t);
2529087SZhong.Wang@Sun.COM 	fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
253*9307Skelly.hu@Sun.COM 	fcoeio.fcoeio_ibuf = (uintptr_t)&fc_del_port;
2549087SZhong.Wang@Sun.COM 
2559087SZhong.Wang@Sun.COM 	if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
2569087SZhong.Wang@Sun.COM 		switch (fcoeio.fcoeio_status) {
2579087SZhong.Wang@Sun.COM 		case FCOEIOE_INVAL_ARG:
2589087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_INVAL_ARG;
2599087SZhong.Wang@Sun.COM 			break;
2609087SZhong.Wang@Sun.COM 
2619087SZhong.Wang@Sun.COM 		case FCOEIOE_BUSY:
2629087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_BUSY;
2639087SZhong.Wang@Sun.COM 			break;
2649087SZhong.Wang@Sun.COM 
2659087SZhong.Wang@Sun.COM 		case FCOEIOE_ALREADY:
2669087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_ALREADY;
2679087SZhong.Wang@Sun.COM 			break;
2689087SZhong.Wang@Sun.COM 
2699087SZhong.Wang@Sun.COM 		case FCOEIOE_MAC_NOT_FOUND:
2709087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_MAC_NOT_FOUND;
2719087SZhong.Wang@Sun.COM 			break;
2729087SZhong.Wang@Sun.COM 
2739087SZhong.Wang@Sun.COM 		case FCOEIOE_OFFLINE_FAILURE:
2749087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR_OFFLINE_DEV;
2759087SZhong.Wang@Sun.COM 			break;
2769087SZhong.Wang@Sun.COM 
2779087SZhong.Wang@Sun.COM 		default:
2789087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_ERROR;
2799087SZhong.Wang@Sun.COM 		}
2809087SZhong.Wang@Sun.COM 	} else {
2819087SZhong.Wang@Sun.COM 		status = FCOE_STATUS_OK;
2829087SZhong.Wang@Sun.COM 	}
2839087SZhong.Wang@Sun.COM 	(void) close(fcoe_fd);
2849087SZhong.Wang@Sun.COM 	return (status);
2859087SZhong.Wang@Sun.COM }
2869087SZhong.Wang@Sun.COM 
2879087SZhong.Wang@Sun.COM FCOE_STATUS
2889087SZhong.Wang@Sun.COM FCOE_GetPortList(
2899087SZhong.Wang@Sun.COM 	FCOE_UINT32		*port_num,
2909087SZhong.Wang@Sun.COM 	FCOE_PORT_ATTRIBUTE	**portlist)
2919087SZhong.Wang@Sun.COM {
2929087SZhong.Wang@Sun.COM 	FCOE_STATUS	status = FCOE_STATUS_OK;
293*9307Skelly.hu@Sun.COM 	int		fcoe_fd;
2949087SZhong.Wang@Sun.COM 	fcoeio_t	fcoeio;
295*9307Skelly.hu@Sun.COM 	fcoe_port_list_t	*inportlist = NULL;
2969087SZhong.Wang@Sun.COM 	FCOE_PORT_ATTRIBUTE	*outportlist = NULL;
297*9307Skelly.hu@Sun.COM 	int		i;
298*9307Skelly.hu@Sun.COM 	int		size = 64; /* default first attempt */
299*9307Skelly.hu@Sun.COM 	int		retry = 0;
300*9307Skelly.hu@Sun.COM 	int		bufsize;
301*9307Skelly.hu@Sun.COM 	dladm_handle_t	handle;
302*9307Skelly.hu@Sun.COM 	char		mac_name[MAXLINKNAMELEN];
3039087SZhong.Wang@Sun.COM 
3049087SZhong.Wang@Sun.COM 	if (port_num == NULL || portlist == NULL) {
3059087SZhong.Wang@Sun.COM 		return (FCOE_STATUS_ERROR_INVAL_ARG);
3069087SZhong.Wang@Sun.COM 	}
3079087SZhong.Wang@Sun.COM 	*port_num = 0;
3089087SZhong.Wang@Sun.COM 
3099087SZhong.Wang@Sun.COM 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
3109087SZhong.Wang@Sun.COM 		return (status);
3119087SZhong.Wang@Sun.COM 	}
3129087SZhong.Wang@Sun.COM 
3139087SZhong.Wang@Sun.COM 	/* Get fcoe port list */
3149087SZhong.Wang@Sun.COM 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
3159087SZhong.Wang@Sun.COM 	retry = 0;
3169087SZhong.Wang@Sun.COM 
3179087SZhong.Wang@Sun.COM 	do {
3189087SZhong.Wang@Sun.COM 		bufsize = sizeof (fcoe_port_instance_t) * (size - 1) +
3199087SZhong.Wang@Sun.COM 		    sizeof (fcoe_port_list_t);
3209087SZhong.Wang@Sun.COM 		inportlist = (fcoe_port_list_t *)malloc(bufsize);
3219087SZhong.Wang@Sun.COM 		fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST;
3229087SZhong.Wang@Sun.COM 		fcoeio.fcoeio_olen = bufsize;
3239087SZhong.Wang@Sun.COM 		fcoeio.fcoeio_xfer = FCOEIO_XFER_READ;
3249087SZhong.Wang@Sun.COM 		fcoeio.fcoeio_obuf = (uintptr_t)inportlist;
3259087SZhong.Wang@Sun.COM 
3269087SZhong.Wang@Sun.COM 		if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
3279087SZhong.Wang@Sun.COM 			if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) {
3289087SZhong.Wang@Sun.COM 				size = inportlist->numPorts;
3299087SZhong.Wang@Sun.COM 			}
3309087SZhong.Wang@Sun.COM 			free(inportlist);
3319087SZhong.Wang@Sun.COM 			switch (fcoeio.fcoeio_status) {
3329087SZhong.Wang@Sun.COM 			case FCOEIOE_INVAL_ARG:
3339087SZhong.Wang@Sun.COM 				status = FCOE_STATUS_ERROR_INVAL_ARG;
3349087SZhong.Wang@Sun.COM 				(void) close(fcoe_fd);
3359087SZhong.Wang@Sun.COM 				return (status);
3369087SZhong.Wang@Sun.COM 
3379087SZhong.Wang@Sun.COM 			case FCOEIOE_BUSY:
3389087SZhong.Wang@Sun.COM 				status = FCOE_STATUS_ERROR_BUSY;
3399087SZhong.Wang@Sun.COM 				retry++;
3409087SZhong.Wang@Sun.COM 				break;
3419087SZhong.Wang@Sun.COM 
3429087SZhong.Wang@Sun.COM 			case FCOEIOE_MORE_DATA:
3439087SZhong.Wang@Sun.COM 				status = FCOE_STATUS_ERROR_MORE_DATA;
3449087SZhong.Wang@Sun.COM 				retry++;
3459087SZhong.Wang@Sun.COM 			default:
3469087SZhong.Wang@Sun.COM 				status = FCOE_STATUS_ERROR;
3479087SZhong.Wang@Sun.COM 			}
3489087SZhong.Wang@Sun.COM 		} else {
3499087SZhong.Wang@Sun.COM 			status = FCOE_STATUS_OK;
3509087SZhong.Wang@Sun.COM 			break;
3519087SZhong.Wang@Sun.COM 		}
3529087SZhong.Wang@Sun.COM 	} while (retry <= 3 && status != FCOE_STATUS_OK);
3539087SZhong.Wang@Sun.COM 
354*9307Skelly.hu@Sun.COM 	if (status == FCOE_STATUS_OK && inportlist->numPorts > 0) {
355*9307Skelly.hu@Sun.COM 		if (dladm_open(&handle) != DLADM_STATUS_OK) {
356*9307Skelly.hu@Sun.COM 			handle = NULL;
357*9307Skelly.hu@Sun.COM 		}
358*9307Skelly.hu@Sun.COM 
3599087SZhong.Wang@Sun.COM 		outportlist = (PFCOE_PORT_ATTRIBUTE)
3609087SZhong.Wang@Sun.COM 		    malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts);
3619087SZhong.Wang@Sun.COM 
3629087SZhong.Wang@Sun.COM 		for (i = 0; i < inportlist->numPorts; i++) {
3639087SZhong.Wang@Sun.COM 			fcoe_port_instance_t *pi = &inportlist->ports[i];
3649087SZhong.Wang@Sun.COM 			FCOE_PORT_ATTRIBUTE *po = &outportlist[i];
3659087SZhong.Wang@Sun.COM 			bcopy(pi->fpi_pwwn, &po->port_wwn, 8);
366*9307Skelly.hu@Sun.COM 
367*9307Skelly.hu@Sun.COM 			if (handle == NULL ||
368*9307Skelly.hu@Sun.COM 			    dladm_datalink_id2info(handle, pi->fpi_mac_linkid,
369*9307Skelly.hu@Sun.COM 			    NULL, NULL, NULL, mac_name, sizeof (mac_name))
370*9307Skelly.hu@Sun.COM 			    != DLADM_STATUS_OK) {
371*9307Skelly.hu@Sun.COM 				(void) strcpy((char *)po->mac_link_name,
372*9307Skelly.hu@Sun.COM 				    "<unknown>");
373*9307Skelly.hu@Sun.COM 			} else {
374*9307Skelly.hu@Sun.COM 				(void) strcpy((char *)po->mac_link_name,
375*9307Skelly.hu@Sun.COM 				    mac_name);
376*9307Skelly.hu@Sun.COM 			}
3779087SZhong.Wang@Sun.COM 			bcopy(pi->fpi_mac_factory_addr,
3789087SZhong.Wang@Sun.COM 			    po->mac_factory_addr, 6);
3799087SZhong.Wang@Sun.COM 			bcopy(pi->fpi_mac_current_addr,
3809087SZhong.Wang@Sun.COM 			    po->mac_current_addr, 6);
3819087SZhong.Wang@Sun.COM 			po->port_type = (FCOE_UINT8)pi->fpi_port_type;
3829087SZhong.Wang@Sun.COM 			po->mtu_size = pi->fpi_mtu_size;
3839087SZhong.Wang@Sun.COM 			po->mac_promisc = pi->fpi_mac_promisc;
3849087SZhong.Wang@Sun.COM 		}
385*9307Skelly.hu@Sun.COM 
386*9307Skelly.hu@Sun.COM 		if (handle != NULL) {
387*9307Skelly.hu@Sun.COM 			dladm_close(handle);
388*9307Skelly.hu@Sun.COM 		}
3899087SZhong.Wang@Sun.COM 		*port_num = inportlist->numPorts;
3909087SZhong.Wang@Sun.COM 		*portlist = outportlist;
3919087SZhong.Wang@Sun.COM 		free(inportlist);
3929087SZhong.Wang@Sun.COM 	} else {
3939087SZhong.Wang@Sun.COM 		*port_num = 0;
3949087SZhong.Wang@Sun.COM 		*portlist = NULL;
3959087SZhong.Wang@Sun.COM 	}
3969087SZhong.Wang@Sun.COM 	(void) close(fcoe_fd);
3979087SZhong.Wang@Sun.COM 	return (status);
3989087SZhong.Wang@Sun.COM }
399