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