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(&param, 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)&param;
 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 }