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