1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 #include <libaoe.h>
17 #include <dbus/dbus.h>
18
19 static const char *AOE_DEV_PATH = "/devices/aoe:admin";
20
21 #define OPEN_AOE 0
22 #define OPEN_EXCL_AOE O_EXCL
23
24 static struct {
25 int errnum;
26 const char *errmsg;
27 } errtab[] = {
28 { AOE_STATUS_ERROR_ALREADY, "already exists" },
29 { AOE_STATUS_ERROR_BUSY, "driver busy" },
30 { AOE_STATUS_ERROR_CREATE_MAC, "cannot create link" },
31 { AOE_STATUS_ERROR_CREATE_PORT, "general failure" },
32 { AOE_STATUS_ERROR_GET_LINKINFO, "cannot get link information" },
33 { AOE_STATUS_ERROR_INVAL_ARG, "invalid argument" },
34 { AOE_STATUS_ERROR_MAC_LEN, "linkname too long" },
35 { AOE_STATUS_ERROR_MAC_NOT_FOUND, "not found" },
36 { AOE_STATUS_ERROR_MORE_DATA, "more data" },
37 { AOE_STATUS_ERROR_OFFLINE_DEV, "port busy" },
38 { AOE_STATUS_ERROR_OPEN_DEV, "cannot open aoe device" },
39 { AOE_STATUS_ERROR_OPEN_MAC, "cannot open link" },
40 { AOE_STATUS_ERROR_PERM, "permission denied" }
41 };
42
43 static int aoe_cfg_scf_init(scf_handle_t **, scf_service_t **, int);
44
45 static int
46 aoe_convert_error_code(aoeio_stat_t aoeio_status)
47 {
48 int status;
49 switch (aoeio_status) {
50 case AOEIOE_INVAL_ARG:
51 status = AOE_STATUS_ERROR_INVAL_ARG;
52 break;
53 case AOEIOE_BUSY:
54 status = AOE_STATUS_ERROR_BUSY;
55 break;
56 case AOEIOE_ALREADY:
57 status = AOE_STATUS_ERROR_ALREADY;
58 break;
59 case AOEIOE_CREATE_MAC:
60 status = AOE_STATUS_ERROR_CREATE_MAC;
61 break;
62 case AOEIOE_OPEN_MAC:
63 status = AOE_STATUS_ERROR_OPEN_MAC;
64 break;
65 case AOEIOE_CREATE_PORT:
66 status = AOE_STATUS_ERROR_CREATE_PORT;
67 break;
68 case AOEIOE_MAC_NOT_FOUND:
69 status = AOE_STATUS_ERROR_MAC_NOT_FOUND;
70 break;
71 case AOEIOE_OFFLINE_FAILURE:
72 status = AOE_STATUS_ERROR_OFFLINE_DEV;
73 break;
74 case AOEIOE_MORE_DATA:
75 status = AOE_STATUS_ERROR_MORE_DATA;
76 break;
77 default:
78 status = AOE_STATUS_ERROR;
79 }
80
81 return (status);
82 }
83
84 /*
85 * Open for aoe module
86 *
87 * flag - open flag (OPEN_AOE, OPEN_EXCL_AOE)
88 * fd - pointer to integer. On success, contains the aoe file descriptor
89 */
90 static AOE_STATUS
91 aoe_open(int flag, int *fd)
92 {
93 int ret;
94
95 if ((*fd = open(AOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
96 ret = AOE_STATUS_OK;
97 } else {
98 if (errno == EPERM || errno == EACCES)
99 ret = AOE_STATUS_ERROR_PERM;
100 else
101 ret = AOE_STATUS_ERROR_OPEN_DEV;
102 }
103
104 return (ret);
105 }
106
107 /*
108 * This routine is used to remove a single entry in the
109 * SCF database for a given AoE port.
110 * Input:
111 * portid - The integer of the AoE port ID.
112 * linknames - A comma-separated string of link interface names. e.g.
113 * e1000g1,e1000g2,e1000g3
114 * module - The optional module name string, or NULL.
115 * is_promisc - (The value is 1 or 0) 1 if promiscuous mode is
116 * to be set for the MAC interfaces. Otherwise, 0.
117 * is_target - (The value is 1 or 0) 1 if the AoE port is to be
118 * used as a target port. Otherwise, 0, that is, the
119 * port is used as an initiator port.
120 * policy - The port policy of sending packets:
121 * 0 - no policy.
122 * 1 - failover policy
123 * 2 - round robin policy
124 * 3 - weighted load balancing policy
125 * as defined in aoe_cli_policy_t.
126 * add_remove_flag - AOE_SCF_ADD or AOE_SCF_REMOVE.
127 */
128 static int
129 aoe_add_remove_scf_entry(uint32_t portid, char *linknames, char *module,
130 int is_promisc, int is_target, aoe_cli_policy_t policy,
131 int add_remove_flag)
132 {
133 boolean_t create_prop = B_FALSE;
134 boolean_t found = B_FALSE;
135 char buf[AOE_PORT_LIST_LEN] = {0};
136 char member_name[AOE_PORT_LIST_LEN] = {0};
137 int commit_ret;
138 int i = 0;
139 int last_alloc = 0;
140 int ret = AOE_STATUS_OK;
141 int value_array_size = 0;
142 int port_list_alloc = 100;
143 scf_handle_t *handle = NULL;
144 scf_iter_t *value_iter = NULL;
145 scf_property_t *prop = NULL;
146 scf_propertygroup_t *pg = NULL;
147 scf_service_t *svc = NULL;
148 scf_transaction_entry_t *entry = NULL;
149 scf_transaction_t *tran = NULL;
150 scf_value_t **value_set = NULL;
151 scf_value_t *value_lookup = NULL;
152
153 /*
154 * Definition of the string 'member_name' used in this routine:
155 *
156 * The string member_name is a semi-colon (':') separated
157 * string of the parameters to describe an AoE port. The current
158 * format is a string for the snprintf routine : "%s:%s:%d:%d:%d:%d".
159 * The output lookes like
160 * <linknames>:<module>:<portid>:<is_promisc>:<is_target>:<policy>
161 * where the values of linknames, module, portid, is_promisc,
162 * is_target, and policy are defined above as the input parameters
163 * of this routine.
164 *
165 * The member_name is the string to be add or removed in the
166 * SCF database.
167 */
168 (void) snprintf(member_name, AOE_PORT_LIST_LEN, "%s:%s:%d:%d:%d:%d",
169 linknames, module, portid, is_promisc, is_target, policy);
170
171 ret = aoe_cfg_scf_init(&handle, &svc, is_target);
172 if (ret != AOE_STATUS_OK)
173 goto out;
174
175 if (((pg = scf_pg_create(handle)) == NULL) ||
176 ((tran = scf_transaction_create(handle)) == NULL) ||
177 ((entry = scf_entry_create(handle)) == NULL) ||
178 ((prop = scf_property_create(handle)) == NULL) ||
179 ((value_iter = scf_iter_create(handle)) == NULL)) {
180 ret = AOE_STATUS_ERROR;
181 goto out;
182 }
183
184 /* Get property group or create it */
185 if (scf_service_get_pg(svc, AOE_PG_NAME, pg) == -1) {
186 if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
187 if (scf_service_add_pg(svc, AOE_PG_NAME,
188 SCF_GROUP_APPLICATION, 0, pg) == -1) {
189 syslog(LOG_ERR, "add pg failed - %s",
190 scf_strerror(scf_error()));
191 ret = AOE_STATUS_ERROR;
192 } else {
193 create_prop = B_TRUE;
194 }
195 } else {
196 syslog(LOG_ERR, "get pg failed - %s",
197 scf_strerror(scf_error()));
198 ret = AOE_STATUS_ERROR;
199 }
200 if (ret != AOE_STATUS_OK)
201 goto out;
202 }
203
204 /* Make sure property exists */
205 if (create_prop == B_FALSE) {
206 if (scf_pg_get_property(pg, AOE_PORT_LIST_PROP, prop) == -1) {
207 if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
208 create_prop = B_TRUE;
209 } else {
210 syslog(LOG_ERR, "get property failed - %s",
211 scf_strerror(scf_error()));
212 ret = AOE_STATUS_ERROR;
213 goto out;
214 }
215 }
216 }
217
218 /* Begin the transaction */
219 if (scf_transaction_start(tran, pg) == -1) {
220 syslog(LOG_ERR, "start transaction failed - %s",
221 scf_strerror(scf_error()));
222 ret = AOE_STATUS_ERROR;
223 goto out;
224 }
225
226 value_set = (scf_value_t **)calloc(1,
227 sizeof (*value_set) * (last_alloc = port_list_alloc));
228 if (value_set == NULL) {
229 ret = AOE_STATUS_ERROR_NOMEM;
230 goto out;
231 }
232
233 if (create_prop) {
234 if (scf_transaction_property_new(tran, entry,
235 AOE_PORT_LIST_PROP, SCF_TYPE_USTRING) == -1) {
236 if (scf_error() == SCF_ERROR_EXISTS) {
237 ret = AOE_STATUS_ERROR_EXISTS;
238 } else {
239 syslog(LOG_ERR,
240 "transaction property new failed - %s",
241 scf_strerror(scf_error()));
242 ret = AOE_STATUS_ERROR;
243 }
244 goto out;
245 }
246 } else {
247 if (scf_transaction_property_change(tran, entry,
248 AOE_PORT_LIST_PROP, SCF_TYPE_USTRING) == -1) {
249 syslog(LOG_ERR,
250 "transaction property change failed - %s",
251 scf_strerror(scf_error()));
252 ret = AOE_STATUS_ERROR;
253 goto out;
254 }
255
256 if (scf_pg_get_property(pg, AOE_PORT_LIST_PROP, prop) == -1) {
257 syslog(LOG_ERR, "get property failed - %s",
258 scf_strerror(scf_error()));
259 ret = AOE_STATUS_ERROR;
260 goto out;
261 }
262
263 value_lookup = scf_value_create(handle);
264 if (value_lookup == NULL) {
265 syslog(LOG_ERR, "scf value alloc failed - %s",
266 scf_strerror(scf_error()));
267 ret = AOE_STATUS_ERROR;
268 goto out;
269 }
270
271 if (scf_iter_property_values(value_iter, prop) == -1) {
272 syslog(LOG_ERR, "iter value failed - %s",
273 scf_strerror(scf_error()));
274 ret = AOE_STATUS_ERROR;
275 goto out;
276 }
277
278 while (scf_iter_next_value(value_iter, value_lookup) == 1) {
279 char *linknames_iter = NULL;
280 char buftmp[AOE_PORT_LIST_LEN] = {0};
281
282 bzero(buf, sizeof (buf));
283 if (scf_value_get_ustring(value_lookup,
284 buf, MAXNAMELEN) == -1) {
285 syslog(LOG_ERR, "iter value failed- %s",
286 scf_strerror(scf_error()));
287 ret = AOE_STATUS_ERROR;
288 break;
289 }
290 (void) strcpy(buftmp, buf);
291 linknames_iter = strtok(buftmp, ":");
292 if (strncmp(linknames_iter, linknames,
293 MAXLINKNAMELEN) == 0) {
294 if (add_remove_flag == AOE_SCF_ADD) {
295 ret = AOE_STATUS_ERROR_EXISTS;
296 break;
297 } else {
298 found = B_TRUE;
299 continue;
300 }
301 }
302
303 value_set[i] = scf_value_create(handle);
304 if (value_set[i] == NULL) {
305 syslog(LOG_ERR, "scf value alloc failed - %s",
306 scf_strerror(scf_error()));
307 ret = AOE_STATUS_ERROR;
308 break;
309 }
310
311 if (scf_value_set_ustring(value_set[i], buf) == -1) {
312 syslog(LOG_ERR, "set value failed 1- %s",
313 scf_strerror(scf_error()));
314 ret = AOE_STATUS_ERROR;
315 break;
316 }
317
318 if (scf_entry_add_value(entry, value_set[i]) == -1) {
319 syslog(LOG_ERR, "add value failed - %s",
320 scf_strerror(scf_error()));
321 ret = AOE_STATUS_ERROR;
322 break;
323 }
324
325 i++;
326
327 if (i >= last_alloc) {
328 last_alloc += port_list_alloc;
329 value_set = realloc(value_set,
330 sizeof (*value_set) * last_alloc);
331 if (value_set == NULL) {
332 ret = AOE_STATUS_ERROR;
333 break;
334 }
335 }
336 }
337 }
338
339 value_array_size = i;
340 if (!found && (add_remove_flag == AOE_SCF_REMOVE))
341 ret = AOE_STATUS_ERROR_MEMBER_NOT_FOUND;
342 if (ret != AOE_STATUS_OK)
343 goto out;
344
345 if (add_remove_flag == AOE_SCF_ADD) {
346 /* Create the new entry */
347 value_set[i] = scf_value_create(handle);
348 if (value_set[i] == NULL) {
349 syslog(LOG_ERR, "scf value alloc failed - %s",
350 scf_strerror(scf_error()));
351 ret = AOE_STATUS_ERROR;
352 goto out;
353 } else {
354 value_array_size++;
355 }
356
357 /* Set the new member name */
358 if (scf_value_set_ustring(value_set[i], member_name) == -1) {
359 syslog(LOG_ERR, "set value failed 2- %s",
360 scf_strerror(scf_error()));
361 ret = AOE_STATUS_ERROR;
362 goto out;
363 }
364
365 /* Add the new member */
366 if (scf_entry_add_value(entry, value_set[i]) == -1) {
367 syslog(LOG_ERR, "add value failed - %s",
368 scf_strerror(scf_error()));
369 ret = AOE_STATUS_ERROR;
370 goto out;
371 }
372 }
373
374 if ((commit_ret = scf_transaction_commit(tran)) != 1) {
375 syslog(LOG_ERR, "transaction commit failed - %s",
376 scf_strerror(scf_error()));
377 if (commit_ret == 0)
378 ret = AOE_STATUS_ERROR_BUSY;
379 else
380 ret = AOE_STATUS_ERROR;
381 goto out;
382 }
383
384 out:
385 /* Free resources */
386 if (handle != NULL)
387 scf_handle_destroy(handle);
388 if (svc != NULL)
389 scf_service_destroy(svc);
390 if (pg != NULL)
391 scf_pg_destroy(pg);
392 if (tran != NULL)
393 scf_transaction_destroy(tran);
394 if (entry != NULL)
395 scf_entry_destroy(entry);
396 if (prop != NULL)
397 scf_property_destroy(prop);
398 if (value_iter != NULL)
399 scf_iter_destroy(value_iter);
400 if (value_lookup != NULL)
401 scf_value_destroy(value_lookup);
402
403 /* Free value_set scf resources */
404 if (value_array_size > 0) {
405 for (i = 0; i < value_array_size; i++)
406 scf_value_destroy(value_set[i]);
407 }
408 /* Free the pointer array to the resources */
409 if (value_set != NULL)
410 free(value_set);
411
412 return (ret);
413 }
414
415 /*
416 * This routine is used to remove all the entries in the
417 * SCF database for a given AoE port.
418 * Input:
419 * portid - The AoE port ID.
420 * module - The optional modules name, or NULL.
421 * add_remove_flag - AOE_SCF_ADD or AOE_SCF_REMOVE.
422 */
423 static AOE_STATUS
424 aoe_add_remove_scf_entries(uint32_t portid, char *module, int add_remove_flag)
425 {
426 AOE_STATUS status;
427 aoe_port_list_t *portlist = NULL;
428 dladm_handle_t handle;
429 int i, j;
430 uint32_t port_num;
431
432 status = aoe_get_port_list(&port_num, &portlist);
433
434 if (status != AOE_STATUS_OK)
435 return (AOE_STATUS_ERROR);
436
437 if (port_num == 0) {
438 /* No AoE Ports Found! */
439 free(portlist);
440 return (AOE_STATUS_OK);
441 }
442
443 if (dladm_open(&handle) != DLADM_STATUS_OK)
444 handle = NULL;
445
446 for (i = 0; i < port_num; i++) {
447 aoe_port_instance_t *pi = &portlist->ports[i];
448 char linknames[MAXLINKNAMELEN];
449 int promisc = 0;
450
451 if (pi->api_port_id != portid)
452 continue;
453
454 bzero(linknames, sizeof (linknames));
455 for (j = 0; j < pi->api_mac_cnt; j++) {
456 aoe_mac_instance_t *mi = &pi->api_mac[j];
457 char linkname[MAXLINKNAMELEN];
458 dladm_status_t rc;
459
460 rc = dladm_datalink_id2info(handle,
461 mi->ami_mac_linkid, NULL, NULL, NULL,
462 linkname, MAXLINKNAMELEN - 1);
463
464 if (handle == NULL || rc != DLADM_STATUS_OK)
465 continue;
466
467 if (j > 0)
468 (void) strcat(linknames, ",");
469 (void) strcat(linknames, linkname);
470 promisc = mi->ami_mac_promisc;
471 }
472 (void) aoe_add_remove_scf_entry(portid, (char *)linknames,
473 module, promisc, (pi->api_port_type == AOE_CLIENT_TARGET),
474 pi->api_port_policy, add_remove_flag);
475 break;
476 }
477
478 if (handle != NULL)
479 dladm_close(handle);
480 free(portlist);
481
482 return (AOE_STATUS_OK);
483 }
484
485 /*
486 * portid : numeric id of the port
487 * linknames : interface names list
488 * promisc : whether to enable promisc mode for interface
489 * type : 0 - initiator, 1 - target
490 * policy : 0 - disabled, 1 - failover, 2 - round-robin, 3 - load balance
491 * module : module name
492 */
493 AOE_STATUS
494 aoe_create_port(int portid, char *linknames, int promisc, aoe_cli_type_t type,
495 aoe_cli_policy_t policy, char *module)
496 {
497 AOE_STATUS status;
498 aoeio_create_port_param_t param;
499 aoeio_t aoeio;
500 char *clntoken;
501 char *nlntoken;
502 char *olinknames;
503 datalink_class_t class;
504 datalink_id_t linkid;
505 dladm_handle_t handle;
506 int aoe_fd;
507 int i = 0;
508
509 bzero(¶m, sizeof (aoeio_create_port_param_t));
510 bzero(&aoeio, sizeof (aoeio_t));
511
512 if (linknames == NULL)
513 return (AOE_STATUS_ERROR_INVAL_ARG);
514
515 param.acp_force_promisc = promisc;
516 param.acp_port_id = portid;
517 param.acp_port_policy = policy;
518 param.acp_port_type = type;
519
520 if (module != NULL &&
521 strncmp(module, "(null)", AOE_ACP_MODLEN) &&
522 strlcpy(param.acp_module, module, AOE_ACP_MODLEN) >=
523 AOE_ACP_MODLEN)
524 return (AOE_STATUS_ERROR_INVAL_ARG);
525
526 /* Parse interface names */
527 if (dladm_open(&handle) != DLADM_STATUS_OK)
528 return (AOE_STATUS_ERROR);
529
530 olinknames = clntoken = nlntoken = strdup(linknames);
531 for (;;) {
532 clntoken = strsep(&nlntoken, ",");
533 if (strlen(clntoken) > MAXLINKNAMELEN - 1) {
534 dladm_close(handle);
535 free(olinknames);
536 return (AOE_STATUS_ERROR_MAC_LEN);
537 }
538 if (dladm_name2info(handle, clntoken, &linkid, NULL, &class,
539 NULL) != DLADM_STATUS_OK) {
540 dladm_close(handle);
541 (void) aoe_add_remove_scf_entry(portid, linknames,
542 module, promisc, (type == AOE_CLIENT_TARGET),
543 policy, AOE_SCF_REMOVE);
544 free(olinknames);
545 return (AOE_STATUS_ERROR_GET_LINKINFO);
546 }
547 param.acp_mac_linkid[i++] = linkid;
548 if (nlntoken == NULL)
549 break;
550 };
551
552 dladm_close(handle);
553 free(olinknames);
554
555 if ((status = aoe_open(OPEN_AOE, &aoe_fd)) != AOE_STATUS_OK)
556 return (status);
557
558 aoeio.aoeio_cmd = AOEIO_CREATE_PORT;
559 aoeio.aoeio_ibuf = (uintptr_t)¶m;
560 aoeio.aoeio_ilen = sizeof (aoeio_create_port_param_t);
561 aoeio.aoeio_xfer = AOEIO_XFER_WRITE;
562
563 if (ioctl(aoe_fd, AOEIO_CMD, &aoeio) == 0) {
564 (void) aoe_add_remove_scf_entries(param.acp_port_id,
565 module, AOE_SCF_ADD);
566 status = AOE_STATUS_OK;
567 } else
568 {
569 status = aoe_convert_error_code(aoeio.aoeio_status);
570 syslog(LOG_ERR, "AoE ioctl failed. status=%u", status);
571 }
572 (void) close(aoe_fd);
573
574 return (status);
575 }
576
577 #define MAX_SIGN_SIZE 10
578
579 void
580 aoe_detach_devices_from_hal(int portid)
581 {
582 char sign[MAX_SIGN_SIZE];
583 const char aoe_sign[] = "aoeblk";
584 DBusConnection *conn;
585 DBusError err;
586 DBusMessage *msg;
587 DBusPendingCall *pending;
588 char **dev_list;
589 char **dev_iter;
590 int dev_amount;
591
592 (void) snprintf(sign, MAX_SIGN_SIZE, "%x", portid);
593
594 dbus_error_init(&err);
595
596 /* Establish D-Bus connection */
597 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
598 if (dbus_error_is_set(&err)) {
599 dbus_error_free(&err);
600 return;
601 }
602 (void) dbus_connection_ref(conn);
603
604 /* Get list of devices handled by hal */
605 msg = dbus_message_new_method_call(
606 DBUS_HAL_DESTINATION,
607 DBUS_HAL_PATH,
608 DBUS_HAL_INTERFACE,
609 DBUS_HAL_COM_DEV_LIST);
610 if (!msg)
611 goto exit_ref;
612 (void) dbus_connection_send_with_reply(conn, msg, &pending, -1);
613 dbus_connection_flush(conn);
614 dbus_message_unref(msg);
615 dbus_pending_call_block(pending);
616 msg = dbus_pending_call_steal_reply(pending);
617 dbus_pending_call_unref(pending);
618 if (!msg)
619 goto exit_ref;
620 (void) dbus_message_get_args(msg, &err, DBUS_TYPE_ARRAY,
621 DBUS_TYPE_STRING, &dev_list, &dev_amount, DBUS_TYPE_INVALID);
622 dbus_message_unref(msg);
623 if (dbus_error_is_set(&err)) {
624 dbus_error_free(&err);
625 goto exit_ref;
626 }
627
628 /*
629 * walk through the list and send "remove" for all aoeblk devices
630 * with appropriate portid.
631 */
632 for (dev_iter = dev_list; *dev_iter; ++dev_iter)
633 if (strstr(*dev_iter, aoe_sign) && strstr(*dev_iter, sign)) {
634 msg = dbus_message_new_method_call(
635 DBUS_HAL_DESTINATION,
636 DBUS_HAL_PATH,
637 DBUS_HAL_INTERFACE,
638 DBUS_HAL_COM_DEV_REM);
639 if (!msg)
640 break;
641 (void) dbus_message_append_args(msg, DBUS_TYPE_STRING,
642 dev_iter, DBUS_TYPE_INVALID);
643 (void) dbus_connection_send_with_reply(conn,
644 msg, &pending, -1);
645 dbus_connection_flush(conn);
646 dbus_message_unref(msg);
647 dbus_pending_call_block(pending);
648 dbus_pending_call_unref(pending);
649 }
650
651 dbus_free_string_array(dev_list);
652
653 exit_ref:
654 dbus_connection_unref(conn);
655 }
656
657 AOE_STATUS
658 aoe_delete_port(int portid)
659 {
660 aoeio_delete_port_param_t aoe_del_port;
661 aoeio_t aoeio;
662 int aoe_fd;
663 int io_ret = 0;
664 uint32_t status;
665
666 aoe_detach_devices_from_hal(portid);
667
668 if ((status = aoe_open(OPEN_AOE, &aoe_fd)) != AOE_STATUS_OK)
669 return (status);
670
671 aoe_del_port.adp_port_id = portid;
672 (void) aoe_add_remove_scf_entries(aoe_del_port.adp_port_id,
673 NULL, AOE_SCF_REMOVE);
674
675 bzero(&aoeio, sizeof (aoeio));
676 aoeio.aoeio_cmd = AOEIO_DELETE_PORT;
677
678 /* Only 4 bytes here, need to change */
679 aoeio.aoeio_ilen = sizeof (aoeio_delete_port_param_t);
680 aoeio.aoeio_xfer = AOEIO_XFER_READ;
681 aoeio.aoeio_ibuf = (uintptr_t)&aoe_del_port;
682
683 io_ret = ioctl(aoe_fd, AOEIO_CMD, &aoeio);
684 if (io_ret != 0) {
685 status = aoe_convert_error_code(aoeio.aoeio_status);
686 syslog(LOG_ERR, "AoE ioctl failed. status=%u", status);
687 }
688 else
689 status = AOE_STATUS_OK;
690
691 (void) close(aoe_fd);
692 return (status);
693 }
694
695 AOE_STATUS
696 aoe_get_port_list(uint32_t *port_num, aoe_port_list_t **ports)
697 {
698 aoe_port_list_t *inportlist = NULL;
699 aoeio_t aoeio;
700 int aoe_fd;
701 int bufsize;
702 int retry = 0;
703 int size = 64; /* default first attempt */
704 uint32_t status = AOE_STATUS_OK;
705
706 if (port_num == NULL || ports == NULL)
707 return (AOE_STATUS_ERROR_INVAL_ARG);
708
709 *port_num = 0;
710 *ports = NULL;
711
712 if ((status = aoe_open(OPEN_AOE, &aoe_fd)) != AOE_STATUS_OK)
713 return (status);
714
715 /* Get AoE port list */
716 bzero(&aoeio, sizeof (aoeio_t));
717 retry = 0;
718
719 do {
720 bufsize = sizeof (aoe_port_instance_t) * (size - 1) +
721 sizeof (aoe_port_list_t);
722 inportlist = (aoe_port_list_t *)malloc(bufsize);
723 aoeio.aoeio_cmd = AOEIO_GET_PORT_LIST;
724 aoeio.aoeio_olen = bufsize;
725 aoeio.aoeio_xfer = AOEIO_XFER_READ;
726 aoeio.aoeio_obuf = (uintptr_t)inportlist;
727
728 if (ioctl(aoe_fd, AOEIO_CMD, &aoeio) != 0) {
729 if (aoeio.aoeio_status == AOEIOE_MORE_DATA) {
730 size = inportlist->num_ports;
731 }
732 free(inportlist);
733 switch (aoeio.aoeio_status) {
734 case AOEIOE_INVAL_ARG:
735 status = AOE_STATUS_ERROR_INVAL_ARG;
736 (void) close(aoe_fd);
737 return (status);
738 case AOEIOE_BUSY:
739 status = AOE_STATUS_ERROR_BUSY;
740 retry++;
741 break;
742 case AOEIOE_MORE_DATA:
743 status = AOE_STATUS_ERROR_MORE_DATA;
744 retry++;
745 default:
746 status = AOE_STATUS_ERROR;
747 (void) close(aoe_fd);
748 return (status);
749 }
750 } else {
751 status = AOE_STATUS_OK;
752 break;
753 }
754 } while (retry <= 3 && status != AOE_STATUS_OK);
755
756 if (status == AOE_STATUS_OK && inportlist->num_ports > 0) {
757 *port_num = inportlist->num_ports;
758 *ports = inportlist;
759 }
760 (void) close(aoe_fd);
761 return (status);
762 }
763
764 const char *
765 aoe_strerror(AOE_STATUS error)
766 {
767 int i;
768
769 for (i = 0; i < sizeof (errtab) / sizeof (errtab[0]); i++) {
770 if (errtab[i].errnum == error)
771 return (errtab[i].errmsg);
772 };
773
774 return ("unknown error");
775 }
776
777 /*
778 * Initialize scf aoe service access
779 * handle - returned handle
780 * service - returned service handle
781 */
782 static int
783 aoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service, int is_target)
784 {
785 int ret;
786 scf_scope_t *scope = NULL;
787
788 if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
789 syslog(LOG_ERR, "scf_handle_create failed - %s",
790 scf_strerror(scf_error()));
791 ret = AOE_STATUS_ERROR;
792 goto err;
793 }
794
795 if (scf_handle_bind(*handle) == -1) {
796 syslog(LOG_ERR, "scf_handle_bind failed - %s",
797 scf_strerror(scf_error()));
798 ret = AOE_STATUS_ERROR;
799 goto err;
800 }
801
802 if ((*service = scf_service_create(*handle)) == NULL) {
803 syslog(LOG_ERR, "scf_service_create failed - %s",
804 scf_strerror(scf_error()));
805 ret = AOE_STATUS_ERROR;
806 goto err;
807 }
808
809 if ((scope = scf_scope_create(*handle)) == NULL) {
810 syslog(LOG_ERR, "scf_scope_create failed - %s",
811 scf_strerror(scf_error()));
812 ret = AOE_STATUS_ERROR;
813 goto err;
814 }
815
816 if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
817 syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
818 scf_strerror(scf_error()));
819 ret = AOE_STATUS_ERROR;
820 goto err;
821 }
822
823 if (scf_scope_get_service(scope,
824 is_target ? AOE_TARGET_SERVICE : AOE_INITIATOR_SERVICE,
825 *service) == -1) {
826 syslog(LOG_ERR, "scf_scope_get_service failed - %s",
827 scf_strerror(scf_error()));
828 ret = AOE_STATUS_ERROR_SERVICE_NOT_FOUND;
829 goto err;
830 }
831
832 scf_scope_destroy(scope);
833
834 return (AOE_STATUS_OK);
835
836 err:
837 if (*handle != NULL)
838 scf_handle_destroy(*handle);
839
840 if (*service != NULL) {
841 scf_service_destroy(*service);
842 *service = NULL;
843 }
844
845 if (scope != NULL)
846 scf_scope_destroy(scope);
847
848 return (ret);
849 }
850
851 AOE_STATUS
852 aoe_load_config(uint32_t port_type, AOE_SMF_PORT_LIST **portlist)
853 {
854 PAOE_SMF_PORT_INSTANCE pi;
855 char buf[AOE_PORT_LIST_LEN] = {0};
856 int bufsize, retry;
857 int commit_ret;
858 int pg_or_prop_not_found = 0;
859 int size = AOE_MAX_MACOBJ; /* default first attempt */
860 scf_handle_t *handle = NULL;
861 scf_iter_t *value_iter = NULL;
862 scf_property_t *prop = NULL;
863 scf_propertygroup_t *pg = NULL;
864 scf_service_t *svc = NULL;
865 scf_transaction_entry_t *entry = NULL;
866 scf_transaction_t *tran = NULL;
867 scf_value_t *value_lookup = NULL;
868 unsigned int port_index;
869
870 commit_ret = aoe_cfg_scf_init(&handle, &svc,
871 (port_type == AOE_PORTTYPE_TARGET));
872 if (commit_ret != AOE_STATUS_OK) {
873 goto out;
874 }
875
876 if (((pg = scf_pg_create(handle)) == NULL) ||
877 ((tran = scf_transaction_create(handle)) == NULL) ||
878 ((entry = scf_entry_create(handle)) == NULL) ||
879 ((prop = scf_property_create(handle)) == NULL) ||
880 ((value_iter = scf_iter_create(handle)) == NULL))
881 goto out;
882
883 if (scf_service_get_pg(svc, AOE_PG_NAME, pg) == -1) {
884 pg_or_prop_not_found = 1;
885 goto out;
886 }
887
888 if (scf_pg_get_property(pg, AOE_PORT_LIST_PROP, prop) == -1) {
889 pg_or_prop_not_found = 1;
890 goto out;
891 }
892
893 value_lookup = scf_value_create(handle);
894 if (value_lookup == NULL) {
895 syslog(LOG_ERR, "scf value alloc failed - %s",
896 scf_strerror(scf_error()));
897 goto out;
898 }
899
900 port_index = 0;
901
902 do {
903 if (scf_iter_property_values(value_iter, prop) == -1) {
904 syslog(LOG_ERR, "iter value failed - %s",
905 scf_strerror(scf_error()));
906 goto out;
907 }
908
909 retry = 0;
910 bufsize = sizeof (AOE_SMF_PORT_INSTANCE) * (size - 1) +
911 sizeof (AOE_SMF_PORT_LIST);
912 *portlist = (PAOE_SMF_PORT_LIST)malloc(bufsize);
913
914 while (scf_iter_next_value(value_iter, value_lookup) == 1) {
915 aoe_cli_policy_t policy;
916 aoe_cli_type_t type;
917 int promisc;
918 int portid;
919 char *remainder = NULL;
920 uint8_t *linknames = NULL;
921 uint8_t *module = NULL;
922
923 bzero(buf, sizeof (buf));
924 if (scf_value_get_ustring(value_lookup,
925 buf, MAXNAMELEN) == -1) {
926 syslog(LOG_ERR, "iter value failed - %s",
927 scf_strerror(scf_error()));
928 break;
929 }
930 linknames = (uint8_t *)strtok(buf, ":");
931 module = (uint8_t *)strtok(NULL, ":");
932 remainder = strtok(NULL, "#");
933 (void) sscanf(remainder, "%d:%d:%d:%d",
934 &portid, &promisc, &type, &policy);
935 if (port_index >= size) {
936 free(*portlist);
937 retry = 1;
938 size *= 2;
939 break;
940 } else {
941 pi = &(*portlist)->ports[port_index++];
942 (void) strlcpy((char *)pi->linknames,
943 (char *)linknames, MAXLINKNAMELEN);
944 pi->promisc = promisc;
945 pi->type = type;
946 pi->policy = policy;
947 pi->id = portid;
948 if (module == NULL ||
949 strncmp((char *)module, "(null)",
950 AOE_ACP_MODLEN) == 0)
951 bzero(pi->module,
952 AOE_ACP_MODLEN);
953 else
954 (void) strlcpy(pi->module,
955 (char *)module, AOE_ACP_MODLEN);
956 }
957 }
958 (*portlist)->port_num = port_index;
959 } while (retry == 1);
960
961 return (AOE_STATUS_OK);
962 out:
963 /* Free resources */
964 if (handle != NULL)
965 scf_handle_destroy(handle);
966 if (svc != NULL)
967 scf_service_destroy(svc);
968 if (pg != NULL)
969 scf_pg_destroy(pg);
970 if (tran != NULL)
971 scf_transaction_destroy(tran);
972 if (entry != NULL)
973 scf_entry_destroy(entry);
974 if (prop != NULL)
975 scf_property_destroy(prop);
976 if (value_iter != NULL)
977 scf_iter_destroy(value_iter);
978 if (value_lookup != NULL)
979 scf_value_destroy(value_lookup);
980
981 if (pg_or_prop_not_found == 1)
982 return (AOE_STATUS_OK);
983 else
984 return (AOE_STATUS_ERROR);
985 }