xref: /illumos-gate/usr/src/cmd/fcinfo/fcoeadm.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 "fcinfo.h"
27 #include <libintl.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <sys/list.h>
33 #include <stddef.h>
34 #include <strings.h>
35 #include <libfcoe.h>
36 #include <syslog.h>
37 
38 static const char *FCOE_DRIVER_PATH	= "/devices/fcoe:admin";
39 
40 static int
41 isValidWWN(char *wwn)
42 {
43 	int index;
44 
45 	if (wwn == NULL) {
46 		return (0);
47 	}
48 
49 	if (strlen(wwn) != 16) {
50 		return (0);
51 	}
52 
53 	for (index = 0; index < 16; index++) {
54 		if (isxdigit(wwn[index])) {
55 			continue;
56 		}
57 		return (0);
58 	}
59 	return (1);
60 }
61 
62 static uint64_t wwnconvert(uchar_t *wwn)
63 {
64 	uint64_t tmp;
65 	memcpy(&tmp, wwn, sizeof (uint64_t));
66 	return (ntohll(tmp));
67 }
68 
69 /*
70  * prints out all the HBA port information
71  */
72 void
73 printFCOEPortInfo(FCOE_PORT_ATTRIBUTE *attr)
74 {
75 	int i;
76 	if (attr == NULL) {
77 		return;
78 	}
79 	fprintf(stdout, gettext("HBA Port WWN: %016llx\n"),
80 	    wwnconvert((unsigned char *)&attr->port_wwn));
81 
82 	fprintf(stdout, gettext("\tPort Type: %s\n"),
83 	    (attr->port_type == 0) ? "Initiator" : "Target");
84 
85 	fprintf(stdout, gettext("\tMAC Name: %s\n"), attr->mac_link_name);
86 
87 	fprintf(stdout, gettext("\tMTU Size: %d\n"), attr->mtu_size);
88 
89 	fprintf(stdout, gettext("\tPrimary MAC Address: "));
90 	for (i = 0; i < 6; i++) {
91 		fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]);
92 	}
93 	fprintf(stdout, gettext("\n\tCurrent MAC Address: "));
94 	for (i = 0; i < 6; i++) {
95 		fprintf(stdout, gettext("%02x"), attr->mac_current_addr[i]);
96 	}
97 	fprintf(stdout, gettext("\n\tPromiscuous Mode: %s\n"),
98 	    attr->mac_promisc == 1 ? "On" : "Off");
99 }
100 
101 
102 int
103 fcoe_adm_create_port(int objects, char *argv[],
104     cmdOptions_t *options)
105 {
106 	FCOE_STATUS status = FCOE_STATUS_OK;
107 	uint64_t	nodeWWN, portWWN;
108 	FCOE_PORT_WWN	pwwn, nwwn;
109 	FCOE_UINT8	macLinkName[FCOE_MAX_MAC_NAME_LEN];
110 	FCOE_UINT8	promiscuous = 0;
111 	int		createini = 0, createtgt = 0;
112 
113 	/* check the mac name operand */
114 	assert(objects == 1);
115 
116 	strcpy((char *)macLinkName, argv[0]);
117 	bzero(&pwwn, 8);
118 	bzero(&nwwn, 8);
119 
120 	for (; options->optval; options++) {
121 		switch (options->optval) {
122 		case 'i':
123 			createini = 1;
124 			break;
125 
126 		case 't':
127 			createtgt = 1;
128 			break;
129 		case 'p':
130 			if (!isValidWWN(options->optarg)) {
131 				fprintf(stderr,
132 				    gettext("Error: Invalid Port WWN\n"));
133 				return (1);
134 			}
135 			sscanf(options->optarg, "%016llx", &portWWN);
136 			portWWN = htonll(portWWN);
137 			memcpy(&pwwn, &portWWN, sizeof (portWWN));
138 			break;
139 
140 		case 'n':
141 			if (!isValidWWN(options->optarg)) {
142 				fprintf(stderr,
143 				    gettext("Error: Invalid Node WWN\n"));
144 				return (1);
145 			}
146 			sscanf(options->optarg, "%016llx", &nodeWWN);
147 			nodeWWN = htonll(nodeWWN);
148 			memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
149 			break;
150 		case 'f':
151 			promiscuous = 1;
152 			break;
153 
154 		default:
155 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
156 			    options->optval);
157 			return (1);
158 		}
159 	}
160 
161 	if (createini == 1 && createtgt == 1) {
162 		fprintf(stderr, "Error: Option -i and -t should "
163 		    "not be both specified\n");
164 		return (1);
165 	}
166 	status = FCOE_CreatePort(macLinkName,
167 	    createtgt == 1 ? FCOE_PORTTYPE_TARGET :
168 	    FCOE_PORTTYPE_INITIATOR, pwwn, nwwn, promiscuous);
169 
170 	if (status != FCOE_STATUS_OK) {
171 		switch (status) {
172 		case  FCOE_STATUS_ERROR_BUSY:
173 			fprintf(stderr,
174 			    gettext("Error: fcoe driver is busy\n"));
175 			break;
176 
177 		case  FCOE_STATUS_ERROR_ALREADY:
178 			fprintf(stderr,
179 			    gettext("Error: Existing FCoE port "
180 			    "found on the specified MAC link\n"));
181 			break;
182 
183 		case  FCOE_STATUS_ERROR_PERM:
184 			fprintf(stderr,
185 			    gettext("Error: Not enough permission to "
186 			    "open fcoe device\n"));
187 			break;
188 
189 		case  FCOE_STATUS_ERROR_OPEN_DEV:
190 			fprintf(stderr,
191 			    gettext("Error: Failed to open fcoe device\n"));
192 			break;
193 
194 		case  FCOE_STATUS_ERROR_WWN_SAME:
195 			fprintf(stderr,
196 			    gettext("Error: Port WWN is same as Node "
197 			    "WWN\n"));
198 			break;
199 
200 		case  FCOE_STATUS_ERROR_MAC_LEN:
201 			fprintf(stderr,
202 			    gettext("Error: MAC name exceeds maximum "
203 			    "length\n"));
204 			break;
205 
206 		case  FCOE_STATUS_ERROR_PWWN_CONFLICTED:
207 			fprintf(stderr,
208 			    gettext("Error: The specified Port WWN "
209 			    "is already in use\n"));
210 			break;
211 
212 		case  FCOE_STATUS_ERROR_NWWN_CONFLICTED:
213 			fprintf(stderr,
214 			    gettext("Error: The specified Node WWN "
215 			    "is already in use\n"));
216 			break;
217 
218 		case  FCOE_STATUS_ERROR_NEED_JUMBO_FRAME:
219 			fprintf(stderr,
220 			    gettext("Error: MTU size of the specified "
221 			    "MAC link needs to be increased to 2500 "
222 			    "or above\n"));
223 			break;
224 
225 		case  FCOE_STATUS_ERROR_CREATE_MAC:
226 			fprintf(stderr,
227 			    gettext("Error: Out of memory\n"));
228 			break;
229 
230 
231 		case  FCOE_STATUS_ERROR_OPEN_MAC:
232 			fprintf(stderr,
233 			    gettext("Error: Failed to open the "
234 			    "specified MAC link\n"));
235 			break;
236 
237 		case  FCOE_STATUS_ERROR_CREATE_PORT:
238 			fprintf(stderr,
239 			    gettext("Error: Failed to create FCoE "
240 			    "port on the specified MAC link\n"));
241 			break;
242 
243 		case  FCOE_STATUS_ERROR_CLASS_UNSUPPORT:
244 			fprintf(stderr,
245 			    gettext("Error: Link class other than physical "
246 			    "link is not supported\n"));
247 			break;
248 
249 		case FCOE_STATUS_ERROR_GET_LINKINFO:
250 			fprintf(stderr,
251 			    gettext("Error: Failed to get link information "
252 			    "for %s\n"), macLinkName);
253 			break;
254 
255 		case FCOE_STATUS_ERROR:
256 		default:
257 			fprintf(stderr,
258 			    gettext("Error: Due to reason code %d\n"), status);
259 		}
260 		return (1);
261 	} else {
262 		return (0);
263 	}
264 }
265 
266 int
267 fcoe_adm_delete_port(int objects, char *argv[])
268 {
269 	FCOE_STATUS status;
270 	FCOE_UINT8	*macLinkName;
271 	FCOE_UINT32		port_num;
272 	FCOE_PORT_ATTRIBUTE	*portlist = NULL;
273 	int			i;
274 
275 	/* check the mac name operand */
276 	assert(objects == 1);
277 
278 	macLinkName = (FCOE_UINT8 *) argv[0];
279 
280 	status = FCOE_DeletePort(macLinkName);
281 	if (status != FCOE_STATUS_OK) {
282 		switch (status) {
283 		case  FCOE_STATUS_ERROR_BUSY:
284 			fprintf(stderr,
285 			    gettext("Error: fcoe driver is busy\n"));
286 			break;
287 
288 		case  FCOE_STATUS_ERROR_ALREADY:
289 			fprintf(stderr,
290 			    gettext("Error: FCoE port not found on the "
291 			    "specified MAC link\n"));
292 			break;
293 
294 		case  FCOE_STATUS_ERROR_PERM:
295 			fprintf(stderr,
296 			    gettext("Error: Not enough permission to "
297 			    "open fcoe device\n"));
298 			break;
299 
300 		case  FCOE_STATUS_ERROR_MAC_LEN:
301 			fprintf(stderr,
302 			    gettext("Failed: MAC name exceeds maximum "
303 			    "length 32\n"));
304 			break;
305 
306 		case  FCOE_STATUS_ERROR_OPEN_DEV:
307 			fprintf(stderr,
308 			    gettext("Error: Failed to open fcoe device\n"));
309 			break;
310 
311 		case  FCOE_STATUS_ERROR_MAC_NOT_FOUND:
312 			fprintf(stderr,
313 			    gettext("Error: FCoE port not found on the "
314 			    "specified MAC link\n"));
315 			break;
316 
317 		case  FCOE_STATUS_ERROR_OFFLINE_DEV:
318 			status = FCOE_GetPortList(&port_num, &portlist);
319 			if (status != FCOE_STATUS_OK || port_num == 0) {
320 				fprintf(stderr,
321 				    gettext("Error: FCoE port not found on the "
322 				    "specified MAC link\n"));
323 				break;
324 			}
325 			for (i = 0; i < port_num; i++) {
326 				if (strcmp(
327 				    (char *)portlist[i].mac_link_name,
328 				    (char *)macLinkName) == 0) {
329 					if (portlist[i].port_type ==
330 					    FCOE_PORTTYPE_TARGET) {
331 						fprintf(stderr,
332 						    gettext("Error: Please use "
333 						    "stmfadm to offline the "
334 						    "FCoE target first\n"));
335 					} else {
336 						fprintf(stderr,
337 						    gettext("Error: Failed to "
338 						    "delete FCoE port because "
339 						    "unable to offline the "
340 						    "device\n"));
341 					}
342 					break;
343 				}
344 			}
345 			free(portlist);
346 			if (i == port_num) {
347 				fprintf(stderr,
348 				    gettext("Error: FCoE port not found on the "
349 				    "specified MAC link\n"));
350 			}
351 			break;
352 
353 		case FCOE_STATUS_ERROR_GET_LINKINFO:
354 			fprintf(stderr,
355 			    gettext("Error: Failed to get link information "
356 			    "for %s\n"), macLinkName);
357 			break;
358 
359 		case FCOE_STATUS_ERROR:
360 		default:
361 			fprintf(stderr,
362 			    gettext("Error: Due to reason code %d\n"), status);
363 		}
364 		return (1);
365 	} else {
366 		return (0);
367 	}
368 }
369 
370 int
371 fcoe_adm_list_ports(cmdOptions_t *options)
372 {
373 	FCOE_STATUS	status;
374 	int	showini = 0, showtgt = 0;
375 	FCOE_UINT32	port_num;
376 	FCOE_PORT_ATTRIBUTE	*portlist = NULL;
377 	int i;
378 	int ret;
379 
380 	for (; options->optval; options++) {
381 		switch (options->optval) {
382 		case 'i':
383 			showini = 1;
384 			break;
385 
386 		case 't':
387 			showtgt = 1;
388 			break;
389 
390 		default:
391 			fprintf(stderr, gettext("Error: Illegal option: %c\n"),
392 			    options->optval);
393 			return (1);
394 		}
395 	}
396 	if (showini == 0 && showtgt == 0) {
397 		showini = 1;
398 		showtgt = 1;
399 	}
400 
401 	status = FCOE_GetPortList(&port_num, &portlist);
402 
403 	if (status != FCOE_STATUS_OK) {
404 		switch (status) {
405 		case  FCOE_STATUS_ERROR_BUSY:
406 			fprintf(stderr,
407 			    gettext("Error: fcoe driver is busy\n"));
408 			break;
409 
410 		case  FCOE_STATUS_ERROR_PERM:
411 			fprintf(stderr,
412 			    gettext("Error: Not enough permission to "
413 			    "open fcoe device\n"));
414 			break;
415 
416 		case  FCOE_STATUS_ERROR_OPEN_DEV:
417 			fprintf(stderr,
418 			    gettext("Error: Failed to open fcoe device\n"));
419 			break;
420 
421 		case  FCOE_STATUS_ERROR_INVAL_ARG:
422 			fprintf(stderr,
423 			    gettext("Error: Invalid argument\n"));
424 			break;
425 
426 		case  FCOE_STATUS_ERROR_MORE_DATA:
427 			fprintf(stderr,
428 			    gettext("Error: More data\n"));
429 			break;
430 
431 		case FCOE_STATUS_ERROR:
432 		default:
433 			fprintf(stderr,
434 			    gettext("Error: Due to reason code %d\n"), status);
435 		}
436 		ret = 1;
437 	} else {
438 		if (port_num == 0) {
439 			fprintf(stdout, gettext("No FCoE Ports Found!\n"));
440 		} else {
441 			for (i = 0; i < port_num; i++) {
442 				if ((portlist[i].port_type ==
443 				    FCOE_PORTTYPE_INITIATOR &&
444 				    showini == 1) || (showtgt == 1 &&
445 				    portlist[i].port_type ==
446 				    FCOE_PORTTYPE_TARGET)) {
447 					printFCOEPortInfo(&portlist[i]);
448 				}
449 			}
450 		}
451 		ret = 0;
452 	}
453 
454 	if (portlist != NULL) {
455 		free(portlist);
456 	}
457 	return (ret);
458 
459 }
460