xref: /illumos-gate/usr/src/lib/libfcoe/common/libfcoe.c (revision 7a088f03b431bdffa96c3b2175964d4d38420caa)
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 <fcoeio.h>
41 
42 #define	FCOE_DEV_PATH	 "/devices/fcoe:admin"
43 
44 #define	OPEN_FCOE 0
45 #define	OPEN_EXCL_FCOE O_EXCL
46 
47 /*
48  * Open for fcoe module
49  *
50  * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE)
51  * fd - pointer to integer. On success, contains the fcoe file descriptor
52  */
53 static int
54 openFcoe(int flag, int *fd)
55 {
56 	int ret = FCOE_STATUS_ERROR;
57 
58 	if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
59 		ret = FCOE_STATUS_OK;
60 	} else {
61 		if (errno == EPERM || errno == EACCES) {
62 			ret = FCOE_STATUS_ERROR_PERM;
63 		} else {
64 			ret = FCOE_STATUS_ERROR_OPEN_DEV;
65 		}
66 		syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)",
67 		    FCOE_DEV_PATH, errno);
68 	}
69 
70 	return (ret);
71 }
72 
73 static int
74 isWWNZero(FCOE_PORT_WWN portwwn)
75 {
76 	int i;
77 	int size = sizeof (FCOE_PORT_WWN);
78 
79 	for (i = 0; i < size; i++) {
80 		if (portwwn.wwn[i] != 0) {
81 			return (0);
82 		}
83 	}
84 	return (1);
85 }
86 
87 FCOE_STATUS
88 FCOE_CreatePort(
89 	const FCOE_UINT8		*macLinkName,
90 	FCOE_UINT8		portType,
91 	FCOE_PORT_WWN		pwwn,
92 	FCOE_PORT_WWN		nwwn,
93 	FCOE_UINT8		promiscuous)
94 {
95 	FCOE_STATUS status = FCOE_STATUS_OK;
96 	int fcoe_fd;
97 	fcoeio_t	fcoeio;
98 	fcoeio_create_port_param_t	param;
99 
100 	bzero(&param, sizeof (fcoeio_create_port_param_t));
101 
102 	if (macLinkName == NULL) {
103 		return (FCOE_STATUS_ERROR_INVAL_ARG);
104 	}
105 
106 	if (portType != FCOE_PORTTYPE_INITIATOR &&
107 	    portType != FCOE_PORTTYPE_TARGET) {
108 		return (FCOE_STATUS_ERROR_INVAL_ARG);
109 	}
110 
111 	if (!isWWNZero(pwwn)) {
112 		param.fcp_pwwn_provided = 1;
113 		bcopy(pwwn.wwn, param.fcp_pwwn, 8);
114 	}
115 
116 	if (!isWWNZero(nwwn)) {
117 		param.fcp_nwwn_provided = 1;
118 		bcopy(nwwn.wwn, param.fcp_nwwn, 8);
119 	}
120 
121 	if (param.fcp_pwwn_provided == 1 &&
122 	    param.fcp_nwwn_provided == 1 &&
123 	    bcmp(&pwwn, &nwwn, 8) == 0) {
124 		return (FCOE_STATUS_ERROR_WWN_SAME);
125 	}
126 
127 	if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) {
128 		return (FCOE_STATUS_ERROR_MAC_LEN);
129 	}
130 
131 	param.fcp_force_promisc = promiscuous;
132 	(void) strcpy((char *)param.fcp_mac_name, (char *)macLinkName);
133 	param.fcp_port_type = (fcoe_cli_type_t)portType;
134 
135 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
136 		return (status);
137 	}
138 
139 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
140 	fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT;
141 
142 	fcoeio.fcoeio_ilen = sizeof (param);
143 	fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
144 	fcoeio.fcoeio_ibuf = (uintptr_t)&param;
145 
146 	if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
147 		switch (fcoeio.fcoeio_status) {
148 		case FCOEIOE_INVAL_ARG:
149 			status = FCOE_STATUS_ERROR_INVAL_ARG;
150 			break;
151 
152 		case FCOEIOE_BUSY:
153 			status = FCOE_STATUS_ERROR_BUSY;
154 			break;
155 
156 		case FCOEIOE_ALREADY:
157 			status = FCOE_STATUS_ERROR_ALREADY;
158 			break;
159 
160 		case FCOEIOE_PWWN_CONFLICTED:
161 			status = FCOE_STATUS_ERROR_PWWN_CONFLICTED;
162 			break;
163 
164 		case FCOEIOE_NWWN_CONFLICTED:
165 			status = FCOE_STATUS_ERROR_NWWN_CONFLICTED;
166 			break;
167 
168 		case FCOEIOE_CREATE_MAC:
169 			status = FCOE_STATUS_ERROR_CREATE_MAC;
170 			break;
171 
172 		case FCOEIOE_OPEN_MAC:
173 			status = FCOE_STATUS_ERROR_OPEN_MAC;
174 			break;
175 
176 		case FCOEIOE_CREATE_PORT:
177 			status = FCOE_STATUS_ERROR_CREATE_PORT;
178 			break;
179 
180 		case FCOEIOE_NEED_JUMBO_FRAME:
181 			status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME;
182 			break;
183 
184 		case FCOEIOE_VNIC_UNSUPPORT:
185 			status = FCOE_STATUS_ERROR_VNIC_UNSUPPORT;
186 			break;
187 
188 		default:
189 			status = FCOE_STATUS_ERROR;
190 		}
191 	} else {
192 		status = FCOE_STATUS_OK;
193 	}
194 	(void) close(fcoe_fd);
195 	return (status);
196 }
197 
198 FCOE_STATUS
199 FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
200 {
201 	FCOE_STATUS status = FCOE_STATUS_OK;
202 	int fcoe_fd;
203 	fcoeio_t	fcoeio;
204 
205 	if (macLinkName == NULL) {
206 		return (FCOE_STATUS_ERROR_INVAL_ARG);
207 	}
208 
209 	if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) {
210 		return (FCOE_STATUS_ERROR_MAC_LEN);
211 	}
212 
213 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
214 		return (status);
215 	}
216 
217 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
218 	fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT;
219 
220 	fcoeio.fcoeio_ilen = strlen((char *)macLinkName)+1;
221 	fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
222 	fcoeio.fcoeio_ibuf = (uintptr_t)macLinkName;
223 
224 	if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
225 		switch (fcoeio.fcoeio_status) {
226 		case FCOEIOE_INVAL_ARG:
227 			status = FCOE_STATUS_ERROR_INVAL_ARG;
228 			break;
229 
230 		case FCOEIOE_BUSY:
231 			status = FCOE_STATUS_ERROR_BUSY;
232 			break;
233 
234 		case FCOEIOE_ALREADY:
235 			status = FCOE_STATUS_ERROR_ALREADY;
236 			break;
237 
238 		case FCOEIOE_MAC_NOT_FOUND:
239 			status = FCOE_STATUS_ERROR_MAC_NOT_FOUND;
240 			break;
241 
242 		case FCOEIOE_OFFLINE_FAILURE:
243 			status = FCOE_STATUS_ERROR_OFFLINE_DEV;
244 			break;
245 
246 		default:
247 			status = FCOE_STATUS_ERROR;
248 		}
249 	} else {
250 		status = FCOE_STATUS_OK;
251 	}
252 	(void) close(fcoe_fd);
253 	return (status);
254 }
255 
256 FCOE_STATUS
257 FCOE_GetPortList(
258 	FCOE_UINT32		*port_num,
259 	FCOE_PORT_ATTRIBUTE	**portlist)
260 {
261 	FCOE_STATUS	status = FCOE_STATUS_OK;
262 	int	fcoe_fd;
263 	fcoeio_t	fcoeio;
264 	fcoe_port_list_t		*inportlist = NULL;
265 	FCOE_PORT_ATTRIBUTE	*outportlist = NULL;
266 	int	i;
267 	int	size = 64; /* default first attempt */
268 	int	retry = 0;
269 	int	bufsize;
270 
271 	if (port_num == NULL || portlist == NULL) {
272 		return (FCOE_STATUS_ERROR_INVAL_ARG);
273 	}
274 	*port_num = 0;
275 
276 	if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
277 		return (status);
278 	}
279 
280 	/* Get fcoe port list */
281 	(void) memset(&fcoeio, 0, sizeof (fcoeio));
282 	retry = 0;
283 
284 	do {
285 		bufsize = sizeof (fcoe_port_instance_t) * (size - 1) +
286 		    sizeof (fcoe_port_list_t);
287 		inportlist = (fcoe_port_list_t *)malloc(bufsize);
288 		fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST;
289 		fcoeio.fcoeio_olen = bufsize;
290 		fcoeio.fcoeio_xfer = FCOEIO_XFER_READ;
291 		fcoeio.fcoeio_obuf = (uintptr_t)inportlist;
292 
293 		if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
294 			if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) {
295 				size = inportlist->numPorts;
296 			}
297 			free(inportlist);
298 			switch (fcoeio.fcoeio_status) {
299 			case FCOEIOE_INVAL_ARG:
300 				status = FCOE_STATUS_ERROR_INVAL_ARG;
301 				(void) close(fcoe_fd);
302 				return (status);
303 
304 			case FCOEIOE_BUSY:
305 				status = FCOE_STATUS_ERROR_BUSY;
306 				retry++;
307 				break;
308 
309 			case FCOEIOE_MORE_DATA:
310 				status = FCOE_STATUS_ERROR_MORE_DATA;
311 				retry++;
312 			default:
313 				status = FCOE_STATUS_ERROR;
314 			}
315 		} else {
316 			status = FCOE_STATUS_OK;
317 			break;
318 		}
319 	} while (retry <= 3 && status != FCOE_STATUS_OK);
320 
321 	if (status == FCOE_STATUS_OK) {
322 		outportlist = (PFCOE_PORT_ATTRIBUTE)
323 		    malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts);
324 
325 		for (i = 0; i < inportlist->numPorts; i++) {
326 			fcoe_port_instance_t *pi = &inportlist->ports[i];
327 			FCOE_PORT_ATTRIBUTE *po = &outportlist[i];
328 			bcopy(pi->fpi_pwwn, &po->port_wwn, 8);
329 			bcopy(pi->fpi_mac_link_name, po->mac_link_name, 32);
330 			bcopy(pi->fpi_mac_factory_addr,
331 			    po->mac_factory_addr, 6);
332 			bcopy(pi->fpi_mac_current_addr,
333 			    po->mac_current_addr, 6);
334 			po->port_type = (FCOE_UINT8)pi->fpi_port_type;
335 			po->mtu_size = pi->fpi_mtu_size;
336 			po->mac_promisc = pi->fpi_mac_promisc;
337 		}
338 		*port_num = inportlist->numPorts;
339 		*portlist = outportlist;
340 		free(inportlist);
341 	} else {
342 		*port_num = 0;
343 		*portlist = NULL;
344 	}
345 	(void) close(fcoe_fd);
346 	return (status);
347 }
348