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 /*
  17  * Nexus driver for AoE initiator and COMSTAR target
  18  *
  19  * Common AoE interface interacts with MAC, managing AoE ports,
  20  * doing MAC address discovery/managment, and AoE frame
  21  * encapsulation/decapsulation
  22  */
  23 
  24 #include <sys/aoe.h>
  25 #include <sys/bootconf.h>
  26 #include <sys/conf.h>
  27 #include <sys/ddi.h>
  28 #include <sys/debug.h>
  29 #include <sys/devops.h>
  30 #include <sys/dls.h>
  31 #include <sys/dls_mgmt.h>
  32 #include <sys/errno.h>
  33 #include <sys/file.h>
  34 #include <sys/kmem.h>
  35 #include <sys/kmem.h>
  36 #include <sys/ksynch.h>
  37 #include <sys/log.h>
  38 #include <sys/mac_client.h>
  39 #include <sys/modctl.h>
  40 #include <sys/modctl.h>
  41 #include <sys/param.h>
  42 #include <sys/pci.h>
  43 #include <sys/stat.h>
  44 #include <sys/stream.h>
  45 #include <sys/stropts.h>
  46 #include <sys/strsubr.h>
  47 #include <sys/strsun.h>
  48 #include <sys/sunndi.h>
  49 #include <sys/sysmacros.h>
  50 #include <sys/types.h>
  51 #include <sys/ethernet.h>
  52 
  53 /*
  54  * There will be only one aoe instance
  55  */
  56 typedef struct aoe_soft_state {
  57         dev_info_t      *ss_dip;
  58         uint32_t         ss_flags;
  59         list_t           ss_mac_list;
  60         list_t           ss_port_list;
  61         uint32_t         ss_ioctl_flags;
  62         kmutex_t         ss_ioctl_mutex;
  63 } aoe_soft_state_t;
  64 
  65 /*
  66  * One for each ethernet interface
  67  */
  68 struct aoe_port;
  69 typedef struct aoe_mac
  70 {
  71         list_node_t             am_ss_node;
  72         datalink_id_t           am_linkid;
  73         char                    am_ifname[MAXNAMELEN];
  74 
  75         struct aoe_port         *am_port;
  76         aoe_soft_state_t        *am_ss;
  77 
  78         mac_handle_t            am_handle;
  79         mac_client_handle_t     am_cli_handle;
  80         mac_promisc_handle_t    am_promisc_handle;
  81         mac_notify_handle_t     am_notify_handle;
  82         mac_unicast_handle_t    am_unicst_handle;
  83         ether_addr_t            am_primary_addr;
  84         ether_addr_t            am_current_addr;
  85         uint32_t                am_running:1,
  86                                 am_force_promisc:1,
  87                                 am_rsvd:22,
  88                                 am_link_state:8;
  89         uint32_t                am_use_cnt;
  90         uint32_t                am_frm_cnt;
  91         uint32_t                am_link_speed;
  92         uint32_t                am_mtu;
  93         uint64_t                am_rtt_cnt;
  94         uint64_t                am_rx_frames;
  95         uint64_t                am_tx_frames;
  96         kcondvar_t              am_tx_cv;
  97         kmutex_t                am_mutex;
  98 } aoe_mac_t;
  99 
 100 typedef struct aoe_path
 101 {
 102         aoe_mac_t               *ap_mac;
 103         ether_addr_t            ap_addr;
 104         uint16_t                ap_state;
 105         uint32_t                ap_link_speed; /* in Mbps */
 106         uint32_t                ap_weight;
 107         uint32_t                ap_wait_cnt;
 108 } aoe_path_t;
 109 
 110 #define WLB_MAX_RETRY_COUNT     100
 111 #define WLB_RTT_WEIGHT(x)       (x << 1)
 112 
 113 typedef struct aoe_unit
 114 {
 115         unsigned long           au_unit;
 116         aoe_path_t              au_path[AOE_MAX_MACOBJ];
 117         uint32_t                au_path_cnt;
 118         uint32_t                au_rrp_next;
 119 } aoe_unit_t;
 120 
 121 typedef struct aoe_port
 122 {
 123         list_node_t             p_ss_node;
 124         aoe_eport_t             p_eport;
 125         aoe_soft_state_t        *p_ss;
 126         dev_info_t              *p_client_dev;
 127         aoe_client_t            p_client;
 128         kmem_cache_t            *p_frame_cache;
 129         aoe_cli_policy_t        p_policy;
 130         aoe_cli_type_t          p_type;
 131         uint32_t                p_portid;
 132         uint32_t                p_rsvd:28,
 133                                 p_state:4;
 134         uint32_t                p_flags;
 135         uint32_t                p_mac_cnt;
 136         uint32_t                p_unit_cnt;
 137         aoe_unit_t              p_unit[AOE_MAX_UNIT];
 138         aoe_mac_t               *p_mac[AOE_MAX_MACOBJ];
 139 } aoe_port_t;
 140 
 141 #define EPORT2PORT(x_eport)     ((aoe_port_t *)(x_eport)->eport_aoe_private)
 142 #define FRM2MAC(x_frm)          ((aoe_mac_t *)(x_frm)->af_mac)
 143 
 144 #define AOE_PORT_FLAG_BOUND     0x01
 145 #define AOE_PORT_FLAG_BUSY      0x02
 146 
 147 #define AOE_STR_LEN             32
 148 #define MAX_RESERVE_SIZE        (AOE_MAX_MACOBJ * ETHERADDRL)
 149 
 150 /*
 151  * Ethernet functions
 152  */
 153 static int      aoe_open_mac(aoe_mac_t *, int);
 154 static int      aoe_close_mac(aoe_mac_t *);
 155 static void     aoe_destroy_mac(aoe_mac_t *);
 156 static void     aoe_destroy_port(aoe_port_t *port);
 157 static aoe_mac_t  *aoe_lookup_mac_by_id(datalink_id_t);
 158 static aoe_port_t *aoe_lookup_port_by_id(uint32_t);
 159 static aoe_mac_t  *aoe_create_mac_by_id(uint32_t, datalink_id_t, int *);
 160 static int      aoe_mac_set_address(aoe_mac_t *, uint8_t *, boolean_t);
 161 static void     aoe_port_notify_link_up(void *);
 162 static void     aoe_port_notify_link_down(void *);
 163 static void     aoe_mac_notify(void *, mac_notify_type_t);
 164 static mblk_t   *aoe_get_mblk(aoe_mac_t *, uint32_t);
 165 
 166 /*
 167  * Driver's global variables
 168  */
 169 static char     aoe_ident[] = "Common AOE library and nexus driver";
 170 static void     *aoe_state = NULL;
 171 aoe_soft_state_t *aoe_global_ss = NULL;
 172 
 173 /*
 174  * Nexus driver functions
 175  */
 176 static int      aoe_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
 177     void *, void *result);
 178 static int      aoe_initchild(dev_info_t *, dev_info_t *);
 179 static int      aoe_uninitchild(dev_info_t *, dev_info_t *);
 180 static int      aoe_attach(dev_info_t *, ddi_attach_cmd_t);
 181 static int      aoe_detach(dev_info_t *, ddi_detach_cmd_t);
 182 static int      aoe_open(dev_t *, int, int, cred_t *);
 183 static int      aoe_close(dev_t, int, int, cred_t *);
 184 static int      aoe_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
 185 static int      aoe_copyin_iocdata(intptr_t, int, aoeio_t **, void **, void **,
 186     void **);
 187 static int      aoe_copyout_iocdata(intptr_t, int, aoeio_t *, void *);
 188 static int      aoe_iocmd(aoe_soft_state_t *, intptr_t, int);
 189 static int      aoe_create_port(dev_info_t *, aoe_port_t *, aoe_cli_type_t,
 190     aoe_cli_policy_t, char *);
 191 static int      aoe_delete_port(dev_info_t *, aoeio_t *, uint32_t);
 192 static int      aoe_get_port_list(aoe_port_instance_t *, int);
 193 static int      aoe_i_port_autoconf(uint32_t);
 194 static void     aoe_unit_update(aoe_port_t *, aoe_mac_t *, int, int);
 195 
 196 /*
 197  * Client functions
 198  */
 199 static void     aoe_deregister_client(aoe_eport_t *);
 200 static void     aoe_rx(void *, mac_resource_handle_t, mblk_t *, boolean_t);
 201 static int      aoe_enable_callback(aoe_mac_t *);
 202 static int      aoe_disable_callback(aoe_mac_t *);
 203 static int      aoe_ctl(aoe_eport_t *, void *, int, void *);
 204 static int      aoe_report_unit(aoe_eport_t *, void *, unsigned long, char *);
 205 static void     aoe_tx_frame(aoe_frame_t *);
 206 static void     aoe_release_frame(aoe_frame_t *);
 207 static void     *aoe_alloc_netb(aoe_frame_t *, uint32_t, caddr_t, int);
 208 static void     aoe_free_netb(void *);
 209 static aoe_frame_t *aoe_allocate_frame(aoe_eport_t *, int, void *, int);
 210 static uint8_t  *aoe_get_mac_addr(void *);
 211 static int      aoe_get_mac_link_state(void *);
 212 static uint32_t aoe_allow_port_detach(aoe_eport_t *);
 213 
 214 /*
 215  * Driver identificaton stuff
 216  */
 217 static struct cb_ops aoe_cb_ops = {
 218         aoe_open,
 219         aoe_close,
 220         nodev,
 221         nodev,
 222         nodev,
 223         nodev,
 224         nodev,
 225         aoe_ioctl,
 226         nodev,
 227         nodev,
 228         nodev,
 229         nochpoll,
 230         ddi_prop_op,
 231         0,
 232         D_MP | D_NEW | D_HOTPLUG,
 233         CB_REV,
 234         nodev,
 235         nodev
 236 };
 237 
 238 static struct bus_ops aoe_busops = {
 239         BUSO_REV,
 240         nullbusmap,                     /* bus_map */
 241         NULL,                           /* bus_get_intrspec */
 242         NULL,                           /* bus_add_intrspec */
 243         NULL,                           /* bus_remove_intrspec */
 244         i_ddi_map_fault,                /* bus_map_fault */
 245         NULL,                           /* bus_dma_map (OBSOLETE) */
 246         ddi_dma_allochdl,               /* bus_dma_allochdl */
 247         ddi_dma_freehdl,                /* bus_dma_freehdl */
 248         ddi_dma_bindhdl,                /* bus_dma_bindhdl */
 249         ddi_dma_unbindhdl,              /* bus_unbindhdl */
 250         ddi_dma_flush,                  /* bus_dma_flush */
 251         ddi_dma_win,                    /* bus_dma_win */
 252         ddi_dma_mctl,                   /* bus_dma_ctl */
 253         aoe_bus_ctl,                    /* bus_ctl */
 254         ddi_bus_prop_op,                /* bus_prop_op */
 255         NULL,                           /* bus_get_eventcookie */
 256         NULL,                           /* bus_add_eventcall */
 257         NULL,                           /* bus_remove_event */
 258         NULL,                           /* bus_post_event */
 259         NULL,                           /* bus_intr_ctl */
 260         NULL,                           /* bus_config */
 261         NULL,                           /* bus_unconfig */
 262         NULL,                           /* bus_fm_init */
 263         NULL,                           /* bus_fm_fini */
 264         NULL,                           /* bus_fm_access_enter */
 265         NULL,                           /* bus_fm_access_exit */
 266         NULL,                           /* bus_power */
 267         NULL
 268 };
 269 
 270 static struct dev_ops aoe_dev_ops = {
 271         DEVO_REV,
 272         0,
 273         ddi_no_info,
 274         nulldev,                        /* identify */
 275         nulldev,                        /* probe */
 276         aoe_attach,                     /* attach */
 277         aoe_detach,                     /* detach */
 278         nodev,                          /* reset */
 279         &aoe_cb_ops,                        /* cb_ops */
 280         &aoe_busops,                        /* bus_ops */
 281         NULL,                           /* power */
 282         ddi_quiesce_not_supported       /* quiesce */
 283 };
 284 
 285 extern char *aoepath_prop;
 286 
 287 /* Standard Module linkage initialization for a Streams driver */
 288 extern struct mod_ops mod_driverops;
 289 
 290 static struct modldrv modldrv = {
 291         &mod_driverops,         /* Type of module.  This one is a driver */
 292         aoe_ident,          /* short description */
 293         &aoe_dev_ops            /* driver specific ops */
 294 };
 295 
 296 static struct modlinkage modlinkage = {
 297         MODREV_1,
 298         {
 299                 (void *)&modldrv,
 300                 NULL,
 301         },
 302 };
 303 
 304 /*
 305  * Bus control operations for nexus drivers.
 306  */
 307 static int
 308 aoe_bus_ctl(dev_info_t *aoe_dip, dev_info_t *rip,
 309     ddi_ctl_enum_t op, void *clientarg, void *result)
 310 {
 311         int ret;
 312         switch (op) {
 313         case DDI_CTLOPS_REPORTDEV:
 314         case DDI_CTLOPS_IOMIN:
 315                 ret = DDI_SUCCESS;
 316                 break;
 317 
 318         case DDI_CTLOPS_INITCHILD:
 319                 ret = aoe_initchild(aoe_dip, (dev_info_t *)clientarg);
 320                 break;
 321 
 322         case DDI_CTLOPS_UNINITCHILD:
 323                 ret = aoe_uninitchild(aoe_dip, (dev_info_t *)clientarg);
 324                 break;
 325 
 326         default:
 327                 ret = ddi_ctlops(aoe_dip, rip, op, clientarg, result);
 328                 break;
 329         }
 330 
 331         return (ret);
 332 }
 333 
 334 /*
 335  * We need specify the dev address for client driver's instance, or we
 336  * can't online client driver's instance.
 337  */
 338 /* ARGSUSED */
 339 static int
 340 aoe_initchild(dev_info_t *aoe_dip, dev_info_t *client_dip)
 341 {
 342         char    client_addr[AOE_STR_LEN];
 343         int     rval;
 344 
 345         rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip,
 346             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "port_id", -1);
 347         if (rval == -1) {
 348                 dev_err(aoe_dip, CE_WARN, "no port_id property: %p",
 349                     (void *)client_dip);
 350                 return (DDI_FAILURE);
 351         }
 352 
 353         bzero(client_addr, AOE_STR_LEN);
 354         (void) sprintf((char *)client_addr, "%x,0", rval);
 355         ddi_set_name_addr(client_dip, client_addr);
 356         return (DDI_SUCCESS);
 357 }
 358 
 359 /* ARGSUSED */
 360 static int
 361 aoe_uninitchild(dev_info_t *aoe_dip, dev_info_t *client_dip)
 362 {
 363         ddi_set_name_addr(client_dip, NULL);
 364         return (DDI_SUCCESS);
 365 }
 366 
 367 static int
 368 aoe_open_mac(aoe_mac_t *mac, int force_promisc)
 369 {
 370         int             ret;
 371         char            cli_name[MAXNAMELEN];
 372         mac_diag_t      diag;
 373         uint16_t        am_open_flag = 0;
 374 
 375         /*
 376          * Open MAC interface
 377          */
 378         ret = mac_open_by_linkid(mac->am_linkid, &mac->am_handle);
 379         if (ret != 0) {
 380                 if (mac->am_ifname)
 381                         ret = mac_open(mac->am_ifname, &mac->am_handle);
 382                 if (ret != 0) {
 383                         cmn_err(CE_WARN, "mac_open %d failed %x",
 384                             mac->am_linkid, ret);
 385                         return (DDI_FAILURE);
 386                 }
 387         }
 388 
 389         (void) sprintf(cli_name, "%s-%d", "aoe", mac->am_linkid);
 390 
 391         ret = mac_client_open(mac->am_handle,
 392             &mac->am_cli_handle, cli_name, am_open_flag);
 393         if (ret != 0) {
 394                 (void) aoe_close_mac(mac);
 395                 return (DDI_FAILURE);
 396         }
 397 
 398         /*
 399          * Cache the pointer of the immutable MAC inforamtion and
 400          * the current and primary MAC address
 401          */
 402         mac_unicast_primary_get(mac->am_handle, mac->am_primary_addr);
 403         ether_copy((void *)mac->am_primary_addr, (void *)mac->am_current_addr);
 404 
 405         ret = mac_unicast_add(mac->am_cli_handle, NULL, MAC_UNICAST_PRIMARY,
 406             &mac->am_unicst_handle, 0, &diag);
 407         if (ret != 0) {
 408                 cmn_err(CE_WARN, "mac_unicast_add failed. ret=%d", ret);
 409                 (void) aoe_close_mac(mac);
 410                 return (DDI_FAILURE);
 411         }
 412 
 413         if (force_promisc) {
 414                 mac->am_force_promisc = B_TRUE;
 415         }
 416 
 417         /* Get mtu */
 418         mac_sdu_get(mac->am_handle, NULL, &mac->am_mtu);
 419 
 420         /* Get link speed */
 421         mac->am_link_speed =
 422             mac_client_stat_get(mac->am_cli_handle, MAC_STAT_IFSPEED);
 423 
 424         cv_init(&mac->am_tx_cv, NULL, CV_DRIVER, NULL);
 425         mutex_init(&mac->am_mutex, NULL, MUTEX_DRIVER, NULL);
 426         mac->am_running = B_TRUE;
 427 
 428         return (DDI_SUCCESS);
 429 }
 430 
 431 static int
 432 aoe_close_mac(aoe_mac_t *mac)
 433 {
 434         int ret;
 435 
 436         if (mac->am_handle == NULL) {
 437                 return (DDI_SUCCESS);
 438         }
 439 
 440         if (mac->am_running) {
 441                 cv_destroy(&mac->am_tx_cv);
 442                 mutex_destroy(&mac->am_mutex);
 443                 mac->am_running = B_FALSE;
 444         }
 445 
 446         if (mac->am_promisc_handle != NULL) {
 447                 mac_promisc_remove(mac->am_promisc_handle);
 448                 mac->am_promisc_handle = NULL;
 449         } else {
 450                 mac_rx_clear(mac->am_cli_handle);
 451         }
 452 
 453         if (mac->am_notify_handle != NULL) {
 454                 ret = mac_notify_remove(mac->am_notify_handle, B_TRUE);
 455                 ASSERT(ret == 0);
 456                 mac->am_notify_handle = NULL;
 457         }
 458 
 459         if (mac->am_unicst_handle != NULL) {
 460                 (void) mac_unicast_remove(mac->am_cli_handle,
 461                     mac->am_unicst_handle);
 462                 mac->am_unicst_handle = NULL;
 463         }
 464 
 465         mac_client_close(mac->am_cli_handle, 0);
 466         mac->am_cli_handle = NULL;
 467 
 468         (void) mac_close(mac->am_handle);
 469         mac->am_handle = NULL;
 470         return (DDI_SUCCESS);
 471 }
 472 
 473 /*
 474  * Return mac instance if it exist, or else return NULL.
 475  */
 476 static aoe_mac_t *
 477 aoe_lookup_mac_by_id(datalink_id_t linkid)
 478 {
 479         aoe_mac_t *mac = NULL;
 480 
 481         ASSERT(MUTEX_HELD(&aoe_global_ss->ss_ioctl_mutex));
 482         for (mac = list_head(&aoe_global_ss->ss_mac_list); mac;
 483             mac = list_next(&aoe_global_ss->ss_mac_list, mac)) {
 484                 if (linkid == mac->am_linkid)
 485                         return (mac);
 486         }
 487         return (NULL);
 488 }
 489 
 490 /*
 491  * Return port instance if it exist, or else return NULL.
 492  */
 493 static aoe_port_t *
 494 aoe_lookup_port_by_id(uint32_t portid)
 495 {
 496         aoe_port_t *port = NULL;
 497 
 498         ASSERT(MUTEX_HELD(&aoe_global_ss->ss_ioctl_mutex));
 499         for (port = list_head(&aoe_global_ss->ss_port_list); port;
 500             port = list_next(&aoe_global_ss->ss_port_list, port)) {
 501                 if (portid == port->p_portid)
 502                         return (port);
 503         }
 504         return (NULL);
 505 }
 506 
 507 /*
 508  * Return aoe_mac if it exists, otherwise create a new one
 509  */
 510 static aoe_mac_t *
 511 aoe_create_mac_by_id(uint32_t portid, datalink_id_t linkid,
 512     int *is_port_created)
 513 {
 514         aoe_port_t *port;
 515         aoe_mac_t *mac;
 516         int port_created = 0;
 517         ASSERT(MUTEX_HELD(&aoe_global_ss->ss_ioctl_mutex));
 518 
 519         *is_port_created = 0;
 520         port = aoe_lookup_port_by_id(portid);
 521         if (port == NULL) {
 522                 port = kmem_zalloc(sizeof (aoe_port_t), KM_SLEEP);
 523                 if (!port)
 524                         return (NULL);
 525                 port->p_portid = portid;
 526                 port->p_ss = aoe_global_ss;
 527                 port->p_mac_cnt = 0;
 528 
 529                 list_insert_tail(&port->p_ss->ss_port_list, port);
 530                 port_created = 1;
 531         }
 532 
 533         mac = aoe_lookup_mac_by_id(linkid);
 534         if (mac != NULL) {
 535                 if (port_created)
 536                         aoe_destroy_port(port);
 537                 return (NULL);
 538         }
 539 
 540         mac = kmem_zalloc(sizeof (aoe_mac_t), KM_SLEEP);
 541         if (!mac) {
 542                 if (port_created)
 543                         aoe_destroy_port(port);
 544                 return (NULL);
 545         }
 546         mac->am_linkid = linkid;
 547         mac->am_ss = aoe_global_ss;
 548         mac->am_port = port;
 549         port->p_mac[port->p_mac_cnt++] = mac;
 550 
 551         list_insert_tail(&mac->am_ss->ss_mac_list, mac);
 552         *is_port_created = port_created;
 553         return (mac);
 554 }
 555 
 556 static void
 557 aoe_destroy_port(aoe_port_t *port)
 558 {
 559         ASSERT(port != NULL);
 560         ASSERT(port->p_mac_cnt == 0);
 561         list_remove(&port->p_ss->ss_port_list, port);
 562         kmem_free(port, sizeof (aoe_port_t));
 563 }
 564 
 565 static void
 566 aoe_destroy_mac(aoe_mac_t *mac)
 567 {
 568         aoe_port_t *port;
 569         ASSERT(mac != NULL);
 570 
 571         port = mac->am_port;
 572         list_remove(&mac->am_ss->ss_mac_list, mac);
 573         kmem_free(mac, sizeof (aoe_mac_t));
 574 
 575         port->p_mac_cnt--;
 576 }
 577 
 578 
 579 /*
 580  * The following routines will be called through vectors in aoe_eport_t
 581  */
 582 
 583 /*
 584  * Deregister aoet/aoei modules, client should make sure the port is in
 585  * offline status already
 586  */
 587 static void
 588 aoe_deregister_client(aoe_eport_t *eport)
 589 {
 590         aoe_port_t *port = EPORT2PORT(eport);
 591         int i, found = 0;
 592 
 593         /*
 594          * Wait for all the related frame to be freed, this should be fast
 595          * because before deregister aoei/aoet will make sure its port
 596          * is already in offline status so no frame will be received or sent
 597          * any more
 598          */
 599         for (i = 0; i < port->p_mac_cnt; i++) {
 600                 if (port->p_mac[i]->am_frm_cnt > 0) {
 601                         found = 1;
 602                         break;
 603                 }
 604         }
 605         if (found)
 606                 delay(100);
 607 
 608         kmem_cache_destroy(port->p_frame_cache);
 609 
 610         atomic_and_32(&port->p_flags, ~AOE_PORT_FLAG_BOUND);
 611 }
 612 
 613 /* ARGSUSED */
 614 static void
 615 aoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback)
 616 {
 617         aoe_mac_t *mac = (aoe_mac_t *)arg;
 618         mblk_t *next;
 619         aoe_frame_t *frm;
 620         uint16_t frm_type;
 621         aoe_port_t *port;
 622 
 623         port = mac->am_port;
 624 
 625         while (mp != NULL) {
 626                 next = mp->b_next;
 627                 mp->b_next = NULL;
 628                 frm_type = ntohs(*(uint16_t *)((uintptr_t)mp->b_rptr + 12));
 629 
 630                 if (frm_type != ETHERTYPE_AOE ||
 631                     !(port->p_flags & AOE_PORT_FLAG_BOUND)) {
 632                         /*
 633                          * This mp is not allocated in AoE, we must free it...
 634                          *
 635                          * We are using freemsg because we haven't done the
 636                          * b_cont check yet. Most of the time it WILL be a
 637                          * single mblk, but freemsg is more conservative here.
 638                          */
 639                         freemsg(mp);
 640                         mp = next;
 641                         continue;
 642                 }
 643 
 644                 if (mp->b_cont != NULL) {
 645                         mblk_t *nmp = msgpullup(mp, -1);
 646                         if (nmp == NULL) {
 647                                 freemsg(mp);
 648                                 mp = next;
 649                                 continue;
 650                         }
 651                         /* Reset it to new collapsed mp */
 652                         freemsg(mp);
 653                         mp = nmp;
 654                 }
 655 
 656                 frm = aoe_allocate_frame(&port->p_eport, -1, mac, KM_NOSLEEP);
 657                 if (frm != NULL) {
 658                         aoe_hdr_t *h = (aoe_hdr_t *)mp->b_rptr;
 659 
 660                         ether_copy((void *)h->aoeh_src, (void *)frm->af_addr);
 661                         frm->af_netb = mp;
 662                         frm->af_data = (uint8_t *)mp->b_rptr;
 663                         port->p_client.ect_rx_frame(frm);
 664                         mac->am_rx_frames++;
 665                 } else
 666                         /* Using freeb because we know it is a single mblk */
 667                         freeb(mp);
 668 
 669                 mp = next;
 670         }
 671 }
 672 
 673 static int
 674 aoe_enable_callback(aoe_mac_t *mac)
 675 {
 676         int ret;
 677 
 678         /*
 679          * Set message callback
 680          */
 681         if (mac->am_force_promisc) {
 682                 ret = mac_promisc_add(mac->am_cli_handle,
 683                     MAC_CLIENT_PROMISC_FILTERED, aoe_rx, mac,
 684                     &mac->am_promisc_handle,
 685                     MAC_PROMISC_FLAGS_NO_TX_LOOP);
 686                 if (ret != 0) {
 687                         dev_err(mac->am_port->p_client_dev, CE_WARN,
 688                             "mac_promisc_add on %d failed (%x)",
 689                             mac->am_linkid, ret);
 690                         return (DDI_FAILURE);
 691                 }
 692         } else {
 693                 mac_rx_set(mac->am_cli_handle, aoe_rx, mac);
 694         }
 695 
 696         /* Get the link state, if it's up, we will need to notify client */
 697         mac->am_link_state =
 698             mac_stat_get(mac->am_handle, MAC_STAT_LINK_UP)?
 699             AOE_MAC_LINK_STATE_UP:AOE_MAC_LINK_STATE_DOWN;
 700 
 701         /*
 702          * Add a notify function so that we get updates from MAC
 703          */
 704         mac->am_notify_handle = mac_notify_add(mac->am_handle,
 705             aoe_mac_notify, (void *)mac);
 706         return (DDI_SUCCESS);
 707 }
 708 
 709 static int
 710 aoe_disable_callback(aoe_mac_t *mac)
 711 {
 712         int ret;
 713 
 714         if (mac->am_promisc_handle) {
 715                 mac_promisc_remove(mac->am_promisc_handle);
 716                 mac->am_promisc_handle = NULL;
 717         } else {
 718                 mac_rx_clear(mac->am_cli_handle);
 719         }
 720 
 721         if (mac->am_notify_handle) {
 722                 ret = mac_notify_remove(mac->am_notify_handle, B_TRUE);
 723                 ASSERT(ret == 0);
 724                 mac->am_notify_handle = NULL;
 725         }
 726 
 727         ret = aoe_mac_set_address(mac, mac->am_primary_addr, B_FALSE);
 728 
 729         return (ret);
 730 }
 731 
 732 static void
 733 aoe_update_path_info(aoe_unit_t *u, aoe_path_t *p)
 734 {
 735         aoe_path_t *xp;
 736         unsigned int i;
 737         uint32_t max_speed;
 738 
 739         p->ap_link_speed = p->ap_mac->am_link_speed / 1000000;
 740 
 741         /* find the maximum speed */
 742         max_speed = 0;
 743         for (i = 0; i < u->au_path_cnt; i++) {
 744                 xp = &u->au_path[i];
 745                 if (xp->ap_link_speed > max_speed)
 746                         max_speed = xp->ap_link_speed;
 747         }
 748 
 749         /* update per-path weight */
 750         for (i = 0; i < u->au_path_cnt; i++) {
 751                 xp = &u->au_path[i];
 752                 if (xp->ap_link_speed)
 753                         xp->ap_weight = max_speed / xp->ap_link_speed;
 754                 else
 755                         xp->ap_weight = 100; /* an arbitrary number */
 756         }
 757 
 758         /* update per-path wait count */
 759         for (i = 0; i < u->au_path_cnt; i++) {
 760                 xp = &u->au_path[i];
 761                 xp->ap_wait_cnt = xp->ap_weight;
 762         }
 763 }
 764 
 765 static int
 766 aoe_report_unit(aoe_eport_t *eport, void *mac, unsigned long unit,
 767     char *dst_addr)
 768 {
 769         int i, j;
 770         aoe_unit_t *u = NULL;
 771         aoe_path_t *p = NULL;
 772         aoe_port_t *port = EPORT2PORT(eport);
 773 
 774         for (i = 0; i < port->p_unit_cnt; i++) {
 775                 if (port->p_unit[i].au_unit == unit) {
 776                         u = &port->p_unit[i];
 777                         break;
 778                 }
 779         }
 780 
 781         if (u == NULL) {
 782                 /*
 783                  * Record new unit
 784                  */
 785                 u = &port->p_unit[i];
 786                 u->au_unit = unit;
 787                 p = &u->au_path[u->au_path_cnt++];
 788                 p->ap_mac = mac;
 789                 p->ap_state = AOE_CMD_PORT_UNIT_ONLINE;
 790                 if (port->p_policy == AOE_POLICY_LOADBALANCE)
 791                         aoe_update_path_info(u, p);
 792                 ether_copy((void *)dst_addr, (void *)p->ap_addr);
 793                 port->p_unit_cnt++;
 794                 return (i);
 795         }
 796 
 797         /*
 798          * See if it is a new path... and log new path if so
 799          */
 800         for (j = 0; j < u->au_path_cnt; j++) {
 801                 if (u->au_path[j].ap_mac == mac) {
 802                         p = &u->au_path[j];
 803                         break;
 804                 }
 805         }
 806 
 807         if (p == NULL) {
 808                 p = &u->au_path[u->au_path_cnt++];
 809                 p->ap_mac = mac;
 810                 p->ap_state = AOE_CMD_PORT_UNIT_ONLINE;
 811                 if (port->p_policy == AOE_POLICY_LOADBALANCE)
 812                         aoe_update_path_info(u, p);
 813         }
 814         ether_copy((void *)dst_addr, (void *)p->ap_addr);
 815 
 816         return (i);
 817 }
 818 
 819 static void
 820 aoe_unit_update(aoe_port_t *port, aoe_mac_t *mac, int cmd, int unit_id)
 821 {
 822         aoe_unit_t *u;
 823         aoe_path_t *p = NULL;
 824         int j;
 825 
 826         /*
 827          * Must report unit first
 828          */
 829         ASSERT(unit_id <= port->p_unit_cnt);
 830 
 831         u = &port->p_unit[unit_id];
 832 
 833         /*
 834          * Log state to the matching path
 835          */
 836         for (j = 0; j < u->au_path_cnt; j++) {
 837                 if (u->au_path[j].ap_mac == mac) {
 838                         p = &u->au_path[j];
 839                         break;
 840                 }
 841         }
 842 
 843         if (p) {
 844                 if (cmd == AOE_CMD_PORT_UNIT_RETRANSMIT)
 845                         p->ap_mac->am_rtt_cnt++;
 846                 else
 847                         p->ap_state = (uint16_t)cmd;
 848         }
 849 }
 850 
 851 /* ARGSUSED */
 852 static int
 853 aoe_ctl(aoe_eport_t *eport, void *mac, int cmd, void *arg)
 854 {
 855         aoe_port_t *port = EPORT2PORT(eport);
 856         int i;
 857 
 858         switch (cmd) {
 859                 case AOE_CMD_PORT_ONLINE:
 860                         for (i = 0; i < port->p_mac_cnt; i++) {
 861                                 if (aoe_enable_callback(port->p_mac[i])
 862                                     == DDI_FAILURE) {
 863                                         int j;
 864                                         for (j = i - 1; j >= 0; j--)
 865                                                 (void) aoe_disable_callback(
 866                                                     port->p_mac[j]);
 867                                         return (DDI_FAILURE);
 868                                 }
 869                         }
 870                         port->p_state = AOE_PORT_STATE_ONLINE;
 871                         break;
 872                 case AOE_CMD_PORT_OFFLINE:
 873                         for (i = 0; i < port->p_mac_cnt; i++) {
 874                                 if (aoe_disable_callback(port->p_mac[i])
 875                                     == DDI_FAILURE) {
 876                                         int j;
 877                                         for (j = i - 1; j >= 0; j--)
 878                                                 (void) aoe_enable_callback(
 879                                                     port->p_mac[j]);
 880                                         return (DDI_FAILURE);
 881                                 }
 882                         }
 883                         port->p_state = AOE_PORT_STATE_OFFLINE;
 884 
 885                         /*
 886                          * in case there are threads waiting
 887                          */
 888                         for (i = 0; i < port->p_mac_cnt; i++) {
 889                                 mutex_enter(&port->p_mac[i]->am_mutex);
 890                                 cv_broadcast(&port->p_mac[i]->am_tx_cv);
 891                                 mutex_exit(&port->p_mac[i]->am_mutex);
 892                         }
 893                         break;
 894                 case AOE_CMD_PORT_UNIT_ONLINE:
 895                         aoe_unit_update(port, mac, cmd, (unsigned long)arg);
 896                         break;
 897                 case AOE_CMD_PORT_UNIT_OFFLINE:
 898                         aoe_unit_update(port, mac, cmd, (unsigned long)arg);
 899                         break;
 900                 case AOE_CMD_PORT_UNIT_RETRANSMIT:
 901                         aoe_unit_update(port, mac, cmd, (unsigned long)arg);
 902                         break;
 903                 default:
 904                         dev_err(port->p_client_dev, CE_WARN,
 905                             "aoe_ctl, unsupported cmd %x", cmd);
 906                         break;
 907         }
 908 
 909         return (DDI_SUCCESS);
 910 }
 911 
 912 /*
 913  * Transmit the specified frame to the link
 914  */
 915 static void
 916 aoe_tx_frame(aoe_frame_t *af)
 917 {
 918         mblk_t *ret_mblk = NULL;
 919         aoe_mac_t *mac = FRM2MAC(af);
 920         mac_tx_cookie_t ret_cookie;
 921 
 922 tx_frame:
 923         ret_cookie = mac_tx(mac->am_cli_handle, af->af_netb, 0,
 924             MAC_TX_NO_ENQUEUE, &ret_mblk);
 925         if (ret_cookie != NULL) {
 926                 mutex_enter(&mac->am_mutex);
 927                 (void) cv_reltimedwait(&mac->am_tx_cv, &mac->am_mutex,
 928                     drv_usectohz(100000), TR_CLOCK_TICK);
 929                 mutex_exit(&mac->am_mutex);
 930 
 931                 if (mac->am_port->p_state == AOE_PORT_STATE_OFFLINE) {
 932                         /*
 933                          * we are doing offline, so just tell the upper that
 934                          * this is finished, the cmd will be aborted soon.
 935                          */
 936                         aoe_free_netb(ret_mblk);
 937                 } else {
 938                         goto tx_frame;
 939                 }
 940         }
 941 
 942         /*
 943          * MAC driver will release the mblk of the frame
 944          */
 945 
 946         mac->am_tx_frames++;
 947 }
 948 
 949 /*
 950  * raw frame layout:
 951  * AoE header + AoE command + AoE payload
 952  */
 953 /* ARGSUSED */
 954 static mblk_t *
 955 aoe_get_mblk(aoe_mac_t *mac, uint32_t raw_frame_size)
 956 {
 957         mblk_t  *mp;
 958         int      err;
 959 
 960         while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) {
 961                 if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) {
 962                         dev_err(mac->am_port->p_client_dev, CE_WARN,
 963                             "strwaitbuf return %d", err);
 964                         return (NULL);
 965                 }
 966         }
 967         mp->b_wptr = mp->b_rptr + raw_frame_size;
 968 
 969         return (mp);
 970 }
 971 
 972 static void *
 973 aoe_alloc_netb(aoe_frame_t *af, uint32_t buf_size, caddr_t buf, int kmflag)
 974 {
 975         mblk_t *mp;
 976         aoe_mac_t *mac = FRM2MAC(af);
 977 
 978         if (buf)
 979                 mp = kmflag == KM_NOSLEEP ?
 980                     esballoc((unsigned char *)buf, buf_size, 0, &frnop) :
 981                     esballoc_wait((unsigned char *)buf, buf_size, 0, &frnop);
 982         else
 983                 mp = aoe_get_mblk(mac, buf_size);
 984 
 985         if (mp) {
 986                 if (af->af_netb == NULL) {
 987                         aoe_hdr_t *h = (aoe_hdr_t *)mp->b_rptr;
 988 
 989                         af->af_netb = mp;
 990                         af->af_data = (uint8_t *)mp->b_rptr;
 991                         ether_copy((void *)mac->am_current_addr,
 992                             (void *)h->aoeh_src);
 993                         ether_copy((void *)af->af_addr,
 994                             (void *)h->aoeh_dst);
 995                 } else
 996                         ((mblk_t *)af->af_netb)->b_cont = mp;
 997                 mp->b_wptr = mp->b_rptr + buf_size;
 998         }
 999 
1000         return (mp);
1001 }
1002 
1003 static void
1004 aoe_free_netb(void *netb)
1005 {
1006         freeb((mblk_t *)netb);
1007 }
1008 
1009 static void
1010 aoe_release_frame(aoe_frame_t *af)
1011 {
1012         aoe_port_t *port = EPORT2PORT(af->af_eport);
1013         aoe_mac_t *mac = FRM2MAC(af);
1014         aoe_hdr_t *h = (aoe_hdr_t *)af->af_data;
1015 
1016         if (h->aoeh_cmd == AOECMD_ATA && mac->am_rtt_cnt)
1017                 mac->am_rtt_cnt--;
1018         kmem_cache_free(port->p_frame_cache, af);
1019         mac->am_frm_cnt--;
1020 }
1021 
1022 static aoe_path_t *
1023 load_balancing(aoe_unit_t *u)
1024 {
1025         aoe_mac_t       *mac;
1026         aoe_path_t      *p = NULL;
1027         aoe_path_t      *xp = NULL;
1028         int             i;
1029         int             j = 0;
1030         int             mst;
1031         int             pst;
1032         int             retry = 0;
1033 
1034         for (;;) {
1035                 if (u->au_rrp_next >= u->au_path_cnt)
1036                         i = u->au_rrp_next = 0;
1037                 else
1038                         i = u->au_rrp_next++;
1039                 if (j > u->au_path_cnt) {
1040                         /*
1041                          * We have already scanned all the paths,
1042                          * if there is one online, use it!
1043                          */
1044                         if (xp) {
1045                                 p = xp;
1046                                 break;
1047                         } else {
1048                                 retry++;
1049                                 if (retry > WLB_MAX_RETRY_COUNT) {
1050                                         p = NULL;
1051                                         break;
1052                                 }
1053                                 j = 0;
1054                                 delay(30);
1055                                 continue;
1056                         }
1057                 }
1058                 j++;    /* number of paths scanned so far */
1059                 p = &u->au_path[i];
1060                 mac = p->ap_mac;
1061                 if (mac == NULL)
1062                         continue;
1063                 mst = mac->am_link_state;
1064                 pst = p->ap_state;
1065                 if (mst == AOE_MAC_LINK_STATE_UP &&
1066                     pst == AOE_CMD_PORT_UNIT_ONLINE) {
1067                         /* found an online path */
1068                         if (--p->ap_wait_cnt) {
1069                                 /* weight has not fully dropped yet */
1070                                 xp = p;
1071                                 continue;
1072                         } else {
1073                                 /* reset weight & return the path */
1074                                 p->ap_wait_cnt = p->ap_weight +
1075                                     WLB_RTT_WEIGHT(mac->am_rtt_cnt);
1076                                 break;
1077                         }
1078                 }
1079         }
1080         return (p);
1081 }
1082 
1083 static aoe_frame_t *
1084 aoe_allocate_frame(aoe_eport_t *eport, int unit_id, void *xmac, int kmflag)
1085 {
1086         aoe_port_t *port = EPORT2PORT(eport);
1087         aoe_frame_t *af;
1088         aoe_mac_t *mac = xmac;
1089         int i;
1090 
1091         /*
1092          * aoe_frame_t initialization
1093          */
1094         af = (aoe_frame_t *)kmem_cache_alloc(port->p_frame_cache, kmflag);
1095         if (af == NULL)
1096                 return (NULL);
1097         bzero(af, sizeof (*af) + port->p_client.ect_private_frame_struct_size);
1098 
1099         if (mac == NULL) {
1100                 aoe_path_t *p = NULL;
1101 
1102                 ASSERT(unit_id <= port->p_unit_cnt);
1103                 ASSERT(port->p_unit_cnt);
1104 
1105                 /*
1106                  * Apply selected port policy
1107                  */
1108                 if (port->p_policy == AOE_POLICY_NONE) {
1109                         p = &port->p_unit[unit_id].au_path[0];
1110                 } else if (port->p_policy == AOE_POLICY_FAILOVER) {
1111                         aoe_unit_t *u = &port->p_unit[unit_id];
1112 
1113                         /*
1114                          * Select first ONLINE path
1115                          */
1116                         for (i = 0; i < u->au_path_cnt; i++) {
1117                                 int mst = u->au_path[i].ap_mac->am_link_state;
1118                                 int pst = u->au_path[i].ap_state;
1119 
1120                                 if (mst == AOE_MAC_LINK_STATE_UP &&
1121                                     pst == AOE_CMD_PORT_UNIT_ONLINE) {
1122                                         p = &u->au_path[i];
1123                                         break;
1124                                 }
1125                         }
1126                 } else if (port->p_policy == AOE_POLICY_ROUNDROBIN) {
1127                         aoe_unit_t *u = &port->p_unit[unit_id];
1128                         int j = 0;
1129 
1130                         /*
1131                          * Just round-robin through ONLINE paths
1132                          */
1133 round2:
1134                         for (i = u->au_rrp_next++; i < u->au_path_cnt; i++) {
1135                                 int mst = u->au_path[i].ap_mac->am_link_state;
1136                                 int pst = u->au_path[i].ap_state;
1137 
1138                                 if (mst == AOE_MAC_LINK_STATE_UP &&
1139                                     pst == AOE_CMD_PORT_UNIT_ONLINE) {
1140                                         p = &u->au_path[i];
1141                                         break;
1142                                 }
1143                                 j++;
1144                         }
1145                         if (p == NULL && j < u->au_path_cnt) {
1146                                 u->au_rrp_next = 0;
1147                                 goto round2;
1148                         }
1149                         if (p == NULL || u->au_rrp_next == u->au_path_cnt)
1150                                 u->au_rrp_next = 0;
1151                 } else if (port->p_policy == AOE_POLICY_LOADBALANCE) {
1152                         /*
1153                          * Weighted balancing
1154                          */
1155                         p = load_balancing(&port->p_unit[unit_id]);
1156                 } else {
1157                         ASSERT(0);
1158                 }
1159 
1160                 if (p == NULL) {
1161                         kmem_cache_free(port->p_frame_cache, af);
1162                         return (NULL);
1163                 }
1164 
1165                 mac = p->ap_mac;
1166                 ether_copy((void *)p->ap_addr, (void *)af->af_addr);
1167         } else if (unit_id >= 0) {
1168                 aoe_unit_t *u = &port->p_unit[unit_id];
1169 
1170                 /*
1171                  * If unit_id and xmac specified, we should select the right
1172                  * target address
1173                  */
1174                 for (i = 0; i < u->au_path_cnt; i++) {
1175                         if (u->au_path[i].ap_mac == mac) {
1176                                 aoe_path_t *p = &u->au_path[i];
1177                                 ether_copy((void *)p->ap_addr,
1178                                     (void *)af->af_addr);
1179                                 break;
1180                         }
1181                 }
1182         }
1183 
1184         af->af_eport = eport;
1185         af->af_mac = mac;
1186 
1187         mac->am_frm_cnt++;
1188 
1189         return (af);
1190 }
1191 
1192 static int
1193 aoe_get_mac_link_state(void *xmac)
1194 {
1195         aoe_mac_t *mac = xmac;
1196 
1197         return (mac->am_link_state);
1198 }
1199 
1200 static uint8_t *
1201 aoe_get_mac_addr(void *xmac)
1202 {
1203         aoe_mac_t       *mac = xmac;
1204 
1205         return (mac->am_current_addr);
1206 }
1207 
1208 /*
1209  * Only this function will be called explicitly by clients
1210  * Register the specified client port (initiator/target)
1211  */
1212 aoe_eport_t *
1213 aoe_register_client(aoe_client_t *client)
1214 {
1215         aoe_eport_t     *eport;
1216         char            cache_string[32];
1217         aoe_port_t      *port;
1218         uint32_t        alloc_size;
1219         uint32_t        i;
1220         uint32_t        min_mtu = 0;
1221 
1222         /*
1223          * We will not come here, when someone is changing ss_port_list,
1224          * so it's safe to go through ss_port_list.
1225          */
1226         for (port = list_head(&aoe_global_ss->ss_port_list); port;
1227             port = list_next(&aoe_global_ss->ss_port_list, port)) {
1228                 if (client->ect_channelid == port->p_portid)
1229                         break;
1230         }
1231 
1232         if (port == NULL) {
1233                 cmn_err(CE_WARN, "can't find the port to bind");
1234                 return (NULL);
1235         }
1236 
1237         if (port->p_flags & AOE_PORT_FLAG_BOUND) {
1238                 dev_err(port->p_client_dev, CE_WARN,
1239                     "the port you want to bind is bound already");
1240                 return (NULL);
1241         }
1242 
1243         atomic_or_32(&port->p_flags, AOE_PORT_FLAG_BOUND);
1244         bcopy(client, &port->p_client, sizeof (aoe_client_t));
1245 
1246         alloc_size = sizeof (aoe_frame_t) +
1247             port->p_client.ect_private_frame_struct_size + MAX_RESERVE_SIZE;
1248 
1249         (void) sprintf(cache_string, "port_frame_cache_%d", port->p_portid);
1250         port->p_frame_cache = kmem_cache_create(cache_string,
1251             alloc_size, 0, NULL, NULL, NULL, port, NULL, KM_SLEEP);
1252         if (!port->p_frame_cache) {
1253                 return (NULL);
1254         }
1255         atomic_or_32(&port->p_flags, AOE_PORT_FLAG_BUSY);
1256 
1257         /*
1258          * aoe_eport_t initialization
1259          */
1260         eport = &port->p_eport;
1261         eport->eport_aoe_private = port;
1262         eport->eport_client_private = client->ect_client_port_struct;
1263         eport->eport_mac = (void **)port->p_mac;
1264         eport->eport_mac_cnt = port->p_mac_cnt;
1265 
1266         for (i = 0; i < port->p_mac_cnt; i++) {
1267                 aoe_mac_t *mac = port->p_mac[i];
1268 
1269                 if (min_mtu == 0 || mac->am_mtu < min_mtu)
1270                         min_mtu = mac->am_mtu;
1271         }
1272 
1273         eport->cache_unit_size = alloc_size;
1274         eport->eport_maxxfer = (min_mtu - AOEHDRSZ) & ~(DEV_BSIZE - 1);
1275         eport->eport_tx_frame = aoe_tx_frame;
1276         eport->eport_alloc_frame = aoe_allocate_frame;
1277         eport->eport_release_frame = aoe_release_frame;
1278         eport->eport_alloc_netb = aoe_alloc_netb;
1279         eport->eport_free_netb = aoe_free_netb;
1280         eport->eport_deregister_client = aoe_deregister_client;
1281         eport->eport_get_mac_addr = aoe_get_mac_addr;
1282         eport->eport_get_mac_link_state = aoe_get_mac_link_state;
1283         eport->eport_ctl = aoe_ctl;
1284         eport->eport_report_unit = aoe_report_unit;
1285         eport->eport_allow_port_detach = aoe_allow_port_detach;
1286 
1287         return (eport);
1288 }
1289 
1290 static int
1291 aoe_mac_set_address(aoe_mac_t *mac, uint8_t *addr, boolean_t assigned)
1292 {
1293         int ret;
1294 
1295         if (ether_cmp((void *)addr, (void *)mac->am_current_addr) == 0) {
1296                 return (DDI_SUCCESS);
1297         }
1298 
1299         mutex_enter(&mac->am_mutex);
1300         if (mac->am_promisc_handle == NULL) {
1301                 ret = mac_unicast_primary_set(mac->am_handle, addr);
1302                 if (ret != 0) {
1303                         mutex_exit(&mac->am_mutex);
1304                         dev_err(mac->am_port->p_client_dev, CE_WARN,
1305                             "mac_unicast_primary_set on %d "
1306                             "failed %x", mac->am_linkid, ret);
1307                         return (DDI_FAILURE);
1308                 }
1309         }
1310         if (assigned) {
1311                 ether_copy((void *)addr,
1312                     (void *)mac->am_current_addr);
1313         } else {
1314                 ether_copy((void *)mac->am_primary_addr,
1315                     (void *)mac->am_current_addr);
1316         }
1317         mutex_exit(&mac->am_mutex);
1318         return (DDI_SUCCESS);
1319 }
1320 
1321 static void
1322 aoe_port_notify_link_up(void *arg)
1323 {
1324         aoe_port_t *port = (aoe_port_t *)arg;
1325 
1326         ASSERT(port->p_flags & AOE_PORT_FLAG_BOUND);
1327 
1328         port->p_client.ect_port_event(&port->p_eport,
1329             AOE_NOTIFY_EPORT_LINK_UP);
1330 }
1331 
1332 static void
1333 aoe_port_notify_link_down(void *arg)
1334 {
1335         aoe_port_t *port = (aoe_port_t *)arg;
1336 
1337         if (port->p_flags & AOE_PORT_FLAG_BOUND) {
1338                 port->p_client.ect_port_event(&port->p_eport,
1339                     AOE_NOTIFY_EPORT_LINK_DOWN);
1340         }
1341 }
1342 
1343 static void
1344 aoe_mac_notify(void *arg, mac_notify_type_t type)
1345 {
1346         aoe_mac_t *mac = (aoe_mac_t *)arg;
1347         int link_cnt = 0, i;
1348         aoe_port_t *port;
1349 
1350         port = mac->am_port;
1351 
1352         /*
1353          * We assume that the calls to this notification callback are serialized
1354          * by MAC layer.
1355          *
1356          * Notes for GLDv3: There is one notification thread per mac_handle_t
1357          * (mac_impl_t), so if a given callback was only added once on a single
1358          * mac_handle_t, then it will not be called concurrently.
1359          *
1360          * This is based on the current implementation of mac_handle_t.  If that
1361          * implementation changes, so should we.
1362          */
1363 
1364         switch (type) {
1365         case MAC_NOTE_LINK:
1366                 /*
1367                  * This notification is sent every time the MAC driver
1368                  * updates the link state.
1369                  */
1370                 if (mac_stat_get(mac->am_handle, MAC_STAT_LINK_UP) != 0) {
1371                         if (mac->am_link_state == AOE_MAC_LINK_STATE_UP) {
1372                                 break;
1373                         }
1374 
1375                         (void) aoe_mac_set_address(mac,
1376                             mac->am_primary_addr, B_FALSE);
1377 
1378                         mac->am_link_state = AOE_MAC_LINK_STATE_UP;
1379 
1380                         for (i = 0; i < port->p_mac_cnt; i++) {
1381                                 if (port->p_mac[i]->am_link_state ==
1382                                     AOE_MAC_LINK_STATE_UP)
1383                                         link_cnt++;
1384                         }
1385 
1386                         /*
1387                          * Signal only once... we can have 2+ MACs with
1388                          * different states, but if at least one is green
1389                          * we are in "good" shape
1390                          */
1391                         if (link_cnt == 1) {
1392                                 dev_err(port->p_client_dev, CE_WARN,
1393                                     "aoe_mac_notify: link/%d arg/%p LINK up",
1394                                     mac->am_linkid, arg);
1395                                 aoe_port_notify_link_up(port);
1396                         }
1397                 } else {
1398                         if (mac->am_link_state == AOE_MAC_LINK_STATE_DOWN) {
1399                                 break;
1400                         }
1401 
1402                         mac->am_link_state = AOE_MAC_LINK_STATE_DOWN;
1403 
1404                         for (i = 0; i < port->p_mac_cnt; i++) {
1405                                 if (port->p_mac[i]->am_link_state ==
1406                                     AOE_MAC_LINK_STATE_UP)
1407                                         link_cnt++;
1408                         }
1409 
1410                         /*
1411                          * Signal only once
1412                          */
1413                         if (link_cnt == 0) {
1414                                 dev_err(port->p_client_dev, CE_WARN,
1415                                     "aoe_mac_notify: link/%d arg/%p LINK down",
1416                                     mac->am_linkid, arg);
1417                                 aoe_port_notify_link_down(port);
1418                         }
1419                 }
1420                 break;
1421 
1422         case MAC_NOTE_TX:
1423                 /*
1424                  * MAC is not so busy now, then wake up aoe_tx_frame to try
1425                  */
1426                 mutex_enter(&mac->am_mutex);
1427                 cv_broadcast(&mac->am_tx_cv);
1428                 mutex_exit(&mac->am_mutex);
1429                 break;
1430 
1431         case MAC_NOTE_CAPAB_CHG:
1432                 /*
1433                  * This notification is sent whenever the MAC resources
1434                  * change or capabilities change. We need to renegotiate
1435                  * the capabilities. This driver does not support this feature.
1436                  */
1437                 break;
1438 
1439         case MAC_NOTE_LOWLINK:
1440                 /*
1441                  * LOWLINK refers to the actual link status. For links that
1442                  * are not part of a bridge instance LOWLINK and LINK state
1443                  * are the same (this is handled above). This driver only
1444                  * support this case.
1445                  */
1446                 break;
1447 
1448         default:
1449                 dev_err(port->p_client_dev, CE_WARN,
1450                     "aoe_mac_notify: not supported arg/%p, type/%d",
1451                     arg, type);
1452                 break;
1453         }
1454 }
1455 
1456 /*
1457  * Device access entry points
1458  */
1459 static int
1460 aoe_open(dev_t *devp, int flag, int otype, cred_t *credp)
1461 {
1462         int instance;
1463         aoe_soft_state_t *ss;
1464 
1465         if (otype != OTYP_CHR) {
1466                 return (EINVAL);
1467         }
1468 
1469         /*
1470          * Only allow root to issue ioctl
1471          */
1472         if (drv_priv(credp) != 0) {
1473                 return (EPERM);
1474         }
1475 
1476         instance = (int)getminor(*devp);
1477         ss = ddi_get_soft_state(aoe_state, instance);
1478         if (ss == NULL) {
1479                 return (ENXIO);
1480         }
1481 
1482         mutex_enter(&ss->ss_ioctl_mutex);
1483         if (ss->ss_ioctl_flags & AOE_IOCTL_FLAG_EXCL) {
1484                 /*
1485                  * It is already open for exclusive access.
1486                  * So shut the door on this caller.
1487                  */
1488                 mutex_exit(&ss->ss_ioctl_mutex);
1489                 return (EBUSY);
1490         }
1491 
1492         if (flag & FEXCL) {
1493                 if (ss->ss_ioctl_flags & AOE_IOCTL_FLAG_OPEN) {
1494                         /*
1495                          * Exclusive operation not possible
1496                          * as it is already opened
1497                          */
1498                         mutex_exit(&ss->ss_ioctl_mutex);
1499                         return (EBUSY);
1500                 }
1501                 ss->ss_ioctl_flags |= AOE_IOCTL_FLAG_EXCL;
1502         }
1503 
1504         ss->ss_ioctl_flags |= AOE_IOCTL_FLAG_OPEN;
1505         mutex_exit(&ss->ss_ioctl_mutex);
1506 
1507         return (0);
1508 }
1509 
1510 /* ARGSUSED */
1511 static int
1512 aoe_close(dev_t dev, int flag, int otype, cred_t *credp)
1513 {
1514         int instance;
1515         aoe_soft_state_t *ss;
1516 
1517         if (otype != OTYP_CHR) {
1518                 return (EINVAL);
1519         }
1520 
1521         instance = (int)getminor(dev);
1522         ss = ddi_get_soft_state(aoe_state, instance);
1523         if (ss == NULL) {
1524                 return (ENXIO);
1525         }
1526 
1527         mutex_enter(&ss->ss_ioctl_mutex);
1528         if ((ss->ss_ioctl_flags & AOE_IOCTL_FLAG_OPEN) == 0) {
1529                 mutex_exit(&ss->ss_ioctl_mutex);
1530                 return (ENODEV);
1531         }
1532 
1533         ss->ss_ioctl_flags &= ~AOE_IOCTL_FLAG_MASK;
1534         mutex_exit(&ss->ss_ioctl_mutex);
1535 
1536         return (0);
1537 }
1538 
1539 static int
1540 aoe_create_port(dev_info_t *parent, aoe_port_t *port,
1541     aoe_cli_type_t type, aoe_cli_policy_t policy, char *module)
1542 {
1543         int rval = 0, i;
1544         dev_info_t *child = NULL;
1545         char *devname;
1546 
1547         if (module != NULL)
1548                 devname = module;
1549         else
1550                 devname = type ? AOET_DRIVER_NAME : AOEI_DRIVER_NAME;
1551 
1552         ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child);
1553         if (child == NULL) {
1554                 dev_err(parent, CE_WARN, "fail to create new devinfo '%s'",
1555                     devname);
1556                 return (NDI_FAILURE);
1557         }
1558 
1559         if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
1560             "port_id", port->p_portid) != DDI_PROP_SUCCESS) {
1561                 dev_err(parent, CE_WARN,
1562                     "prop_update port_id failed for port %d", port->p_portid);
1563                 (void) ndi_devi_free(child);
1564                 return (NDI_FAILURE);
1565         }
1566 
1567         rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
1568         if (rval != NDI_SUCCESS) {
1569                 dev_err(parent, CE_WARN,
1570                     "online_driver failed for port %d (%s)", port->p_portid,
1571                     devname);
1572                 return (NDI_FAILURE);
1573         }
1574 
1575         port->p_client_dev = child;
1576         port->p_policy = policy;
1577         port->p_type = type;
1578 
1579         for (i = 0; i < port->p_mac_cnt; i++)
1580                 port->p_mac[i]->am_use_cnt++;
1581 
1582         return (DDI_SUCCESS);
1583 }
1584 
1585 static int
1586 aoe_delete_port(dev_info_t *parent, aoeio_t *aoeio, uint32_t portid)
1587 {
1588         int rval, i, mac_cnt;
1589         aoe_port_t *port;
1590         int mac_in_use = 0;
1591 
1592         port = aoe_lookup_port_by_id(portid);
1593         if (port == NULL) {
1594                 aoeio->aoeio_status = AOEIOE_INVAL_ARG;
1595                 return (EINVAL);
1596         }
1597 
1598         for (i = 0; i < port->p_mac_cnt; i++) {
1599                 aoe_mac_t *mac = port->p_mac[i];
1600 
1601                 mac = aoe_lookup_mac_by_id(mac->am_linkid);
1602                 if (mac == NULL) {
1603                         aoeio->aoeio_status = AOEIOE_MAC_NOT_FOUND;
1604                         return (EINVAL);
1605                 }
1606         }
1607 
1608         if (port->p_flags & AOE_PORT_FLAG_BOUND) {
1609                 /*
1610                  * Offline it first
1611                  */
1612                 atomic_and_32(&port->p_flags, ~AOE_PORT_FLAG_BUSY);
1613                 rval = ndi_devi_offline(port->p_client_dev, NDI_DEVI_REMOVE);
1614                 if (rval != NDI_SUCCESS) {
1615                         atomic_or_32(&port->p_flags, AOE_PORT_FLAG_BUSY);
1616                         aoeio->aoeio_status = AOEIOE_OFFLINE_FAILURE;
1617                         dev_err(parent, CE_WARN, "offline_driver %s failed",
1618                             ddi_get_name(port->p_client_dev));
1619                         return (EBUSY);
1620                 }
1621                 atomic_and_32(&port->p_flags, ~AOE_PORT_FLAG_BOUND);
1622         }
1623 
1624         /*
1625          * If AOE_PORT_FLAG_BOUND flag is clear, it means that deferred
1626          * detach has finished of last delete operation
1627          */
1628 
1629         /*
1630          * aoe_destroy_mac() will decrement it.. so we need to
1631          * loop using stack variable...
1632          */
1633         mac_cnt = port->p_mac_cnt;
1634         for (i = mac_cnt - 1; i >= 0; i--) {
1635                 aoe_mac_t *mac = port->p_mac[i];
1636                 if (mac->am_use_cnt <= 1) {
1637                         (void) aoe_close_mac(mac);
1638                         aoe_destroy_mac(mac);
1639                 } else {
1640                         mac_in_use = 1;
1641                         break;
1642                 }
1643         }
1644         if (!port->p_mac_cnt && !mac_in_use)
1645                 aoe_destroy_port(port);
1646         else {
1647                 cmn_err(CE_WARN, "Can't delete port due to mac in use\n");
1648                 return (EINVAL);
1649         }
1650 
1651         return (0);
1652 }
1653 
1654 static int
1655 aoe_get_port_list(aoe_port_instance_t *ports, int count)
1656 {
1657         int i = 0;
1658         int j;
1659         aoe_port_t *port;
1660 
1661         ASSERT(ports != NULL);
1662         ASSERT(MUTEX_HELD(&aoe_global_ss->ss_ioctl_mutex));
1663 
1664         for (port = list_head(&aoe_global_ss->ss_port_list); port;
1665             port = list_next(&aoe_global_ss->ss_port_list, port)) {
1666                 if (i >= count)
1667                         break;
1668                 ports[i].api_mac_cnt = port->p_mac_cnt;
1669                 ports[i].api_maxxfer = port->p_eport.eport_maxxfer;
1670                 ports[i].api_port_id = port->p_portid;
1671                 ports[i].api_port_policy = port->p_policy;
1672                 ports[i].api_port_state = port->p_state;
1673                 ports[i].api_port_type = port->p_type;
1674                 for (j = 0; j < port->p_mac_cnt; j++) {
1675                         aoe_mac_t *mac = port->p_mac[j];
1676 
1677                         ports[i].api_mac[j].ami_mac_rx_frames =
1678                             mac->am_rx_frames;
1679 
1680                         ports[i].api_mac[j].ami_mac_tx_frames =
1681                             mac->am_tx_frames;
1682 
1683                         ports[i].api_mac[j].ami_mac_link_state =
1684                             mac->am_link_state;
1685 
1686                         ports[i].api_mac[j].ami_mac_linkid = mac->am_linkid;
1687 
1688                         ether_copy((void *)mac->am_current_addr,
1689                             (void *)ports[i].api_mac[j].ami_mac_current_addr);
1690 
1691                         ether_copy((void *)mac->am_primary_addr,
1692                             (void *)ports[i].api_mac[j].ami_mac_factory_addr);
1693 
1694                         ports[i].api_mac[j].ami_mtu_size = mac->am_mtu;
1695 
1696                         ports[i].api_mac[j].ami_mac_promisc =
1697                             mac->am_promisc_handle != NULL ? 1 : 0;
1698                 }
1699                 i++;
1700         }
1701         return (i);
1702 }
1703 
1704 /* ARGSUSED */
1705 static int
1706 aoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
1707     cred_t *credp, int *rval)
1708 {
1709         aoe_soft_state_t        *ss;
1710         int                     ret = 0;
1711 
1712         if (drv_priv(credp) != 0) {
1713                 return (EPERM);
1714         }
1715 
1716         ss = ddi_get_soft_state(aoe_state, (int32_t)getminor(dev));
1717         if (ss == NULL) {
1718                 return (ENXIO);
1719         }
1720 
1721         mutex_enter(&ss->ss_ioctl_mutex);
1722         if ((ss->ss_ioctl_flags & AOE_IOCTL_FLAG_OPEN) == 0) {
1723                 mutex_exit(&ss->ss_ioctl_mutex);
1724                 return (ENXIO);
1725         }
1726         mutex_exit(&ss->ss_ioctl_mutex);
1727 
1728         switch (cmd) {
1729         case AOEIO_CMD:
1730                 ret = aoe_iocmd(ss, data, mode);
1731                 break;
1732         default:
1733                 ret = ENOTTY;
1734                 break;
1735         }
1736 
1737         return (ret);
1738 }
1739 
1740 static int
1741 aoe_copyin_iocdata(intptr_t data, int mode, aoeio_t **aoeio,
1742     void **ibuf, void **abuf, void **obuf)
1743 {
1744         int     ret = 0;
1745 
1746         *ibuf = NULL;
1747         *abuf = NULL;
1748         *obuf = NULL;
1749         *aoeio = kmem_zalloc(sizeof (aoeio_t), KM_SLEEP);
1750         if (ddi_copyin((void *)data, *aoeio, sizeof (aoeio_t), mode) != 0) {
1751                 ret = EFAULT;
1752                 goto copyin_iocdata_fail;
1753         }
1754 
1755         if ((*aoeio)->aoeio_ilen > AOEIO_MAX_BUF_LEN ||
1756             (*aoeio)->aoeio_alen > AOEIO_MAX_BUF_LEN ||
1757             (*aoeio)->aoeio_olen > AOEIO_MAX_BUF_LEN) {
1758                 ret = EFAULT;
1759                 goto copyin_iocdata_fail;
1760         }
1761 
1762         if ((*aoeio)->aoeio_ilen) {
1763                 *ibuf = kmem_zalloc((*aoeio)->aoeio_ilen, KM_SLEEP);
1764                 if (ddi_copyin((void *)(unsigned long)(*aoeio)->aoeio_ibuf,
1765                     *ibuf, (*aoeio)->aoeio_ilen, mode) != 0) {
1766                         ret = EFAULT;
1767                         goto copyin_iocdata_fail;
1768                 }
1769         }
1770 
1771         if ((*aoeio)->aoeio_alen) {
1772                 *abuf = kmem_zalloc((*aoeio)->aoeio_alen, KM_SLEEP);
1773                 if (ddi_copyin((void *)(unsigned long)(*aoeio)->aoeio_abuf,
1774                     *abuf, (*aoeio)->aoeio_alen, mode) != 0) {
1775                         ret = EFAULT;
1776                         goto copyin_iocdata_fail;
1777                 }
1778         }
1779 
1780         if ((*aoeio)->aoeio_olen) {
1781                 *obuf = kmem_zalloc((*aoeio)->aoeio_olen, KM_SLEEP);
1782         }
1783         return (ret);
1784 
1785 copyin_iocdata_fail:
1786         if (*abuf) {
1787                 kmem_free(*abuf, (*aoeio)->aoeio_alen);
1788                 *abuf = NULL;
1789         }
1790 
1791         if (*ibuf) {
1792                 kmem_free(*ibuf, (*aoeio)->aoeio_ilen);
1793                 *ibuf = NULL;
1794         }
1795 
1796         kmem_free(*aoeio, sizeof (aoeio_t));
1797         return (ret);
1798 }
1799 
1800 static int
1801 aoe_copyout_iocdata(intptr_t data, int mode, aoeio_t *aoeio, void *obuf)
1802 {
1803 
1804         if (aoeio->aoeio_olen) {
1805                 if (ddi_copyout(obuf,
1806                     (void *)(unsigned long)aoeio->aoeio_obuf,
1807                     aoeio->aoeio_olen, mode) != 0) {
1808                         return (EFAULT);
1809                 }
1810         }
1811 
1812         if (ddi_copyout(aoeio, (void *)data, sizeof (aoeio_t), mode) != 0) {
1813                 return (EFAULT);
1814         }
1815         return (0);
1816 }
1817 
1818 static int
1819 aoe_iocmd(aoe_soft_state_t *ss, intptr_t data, int mode)
1820 {
1821         aoe_mac_t       *aoe_mac[AOE_MAX_MACOBJ];
1822         aoeio_t         *aoeio;
1823         int             i;
1824         int             j;
1825         int             ret = 0;
1826         void            *abuf = NULL;
1827         void            *ibuf = NULL;
1828         void            *obuf = NULL;
1829 
1830         ret = aoe_copyin_iocdata(data, mode, &aoeio, &ibuf, &abuf, &obuf);
1831         if (ret != 0)
1832                 goto aoeiocmd_release_buf;
1833 
1834         /*
1835          * If an exclusive open was demanded during open, ensure that
1836          * only one thread can execute an ioctl at a time
1837          */
1838         mutex_enter(&ss->ss_ioctl_mutex);
1839         if (ss->ss_ioctl_flags & AOE_IOCTL_FLAG_EXCL) {
1840                 if (ss->ss_ioctl_flags & AOE_IOCTL_FLAG_EXCL_BUSY) {
1841                         mutex_exit(&ss->ss_ioctl_mutex);
1842                         aoeio->aoeio_status = AOEIOE_BUSY;
1843                         ret = EBUSY;
1844                         goto aoeiocmd_release_buf;
1845                 }
1846                 ss->ss_ioctl_flags |= AOE_IOCTL_FLAG_EXCL_BUSY;
1847         }
1848         mutex_exit(&ss->ss_ioctl_mutex);
1849 
1850         aoeio->aoeio_status = 0;
1851 
1852         switch (aoeio->aoeio_cmd) {
1853         case AOEIO_CREATE_PORT: {
1854                 aoe_port_t *created_port = NULL;
1855                 aoe_mac_t *created_mac[AOE_MAX_MACOBJ];
1856                 aoe_mac_t *opened_mac[AOE_MAX_MACOBJ];
1857                 int mac_used = 0, m = 0, n = 0;
1858                 int is_port_created = 0;
1859                 aoeio_create_port_param_t *param =
1860                     (aoeio_create_port_param_t *)ibuf;
1861                 int portid = param->acp_port_id;
1862 
1863                 if (aoeio->aoeio_ilen != sizeof (aoeio_create_port_param_t) ||
1864                     aoeio->aoeio_xfer != AOEIO_XFER_WRITE) {
1865                         aoeio->aoeio_status = AOEIOE_INVAL_ARG;
1866                         ret = EINVAL;
1867                         break;
1868                 }
1869 
1870                 mutex_enter(&ss->ss_ioctl_mutex);
1871 
1872                 if (aoe_lookup_port_by_id(portid) != NULL) {
1873                         aoeio->aoeio_status = AOEIOE_ALREADY;
1874                         ret = EINVAL;
1875                         mutex_exit(&ss->ss_ioctl_mutex);
1876                         break;
1877                 }
1878 
1879                 /*
1880                  * In case of error, we should destroy all the
1881                  * created macs and the created port.
1882                  */
1883                 for (i = 0; i < AOE_MAX_MACOBJ; i++) {
1884                         int linkid = param->acp_mac_linkid[i];
1885                         aoe_mac_t *mac;
1886 
1887                         /* last one */
1888                         if (linkid == 0)
1889                                 break;
1890 
1891                         aoe_mac[i] = NULL;
1892                         mac = aoe_create_mac_by_id(portid, linkid,
1893                             &is_port_created);
1894                         if (mac == NULL) {
1895                                 aoeio->aoeio_status = AOEIOE_CREATE_MAC;
1896                                 ret = EIO;
1897                                 goto error_1;
1898                         }
1899                         if (mac->am_port->p_mac_cnt == 1)
1900                                 created_port = mac->am_port;
1901                         created_mac[m++] = mac;
1902                         if (mac->am_use_cnt) {
1903                                 aoe_mac[i] = mac;
1904                                 continue;
1905                         }
1906                         for (j = i - 1; j >= 0; j--) {
1907                                 if (aoe_mac[j] == mac) {
1908                                         aoeio->aoeio_status = AOEIOE_ALREADY;
1909                                         ret = EINVAL;
1910                                         goto error_1;
1911                                 }
1912                         }
1913                         ret = aoe_open_mac(mac, param->acp_force_promisc);
1914                         if (ret != 0) {
1915                                 ret = EIO;
1916                                 if (aoeio->aoeio_status == 0)
1917                                         aoeio->aoeio_status = AOEIOE_OPEN_MAC;
1918                                 goto error_1;
1919                         }
1920                         opened_mac[n++] = mac;
1921                         aoe_mac[i] = mac;
1922                 }
1923 
1924                 ret = aoe_create_port(ss->ss_dip, aoe_mac[0]->am_port,
1925                     param->acp_port_type, param->acp_port_policy,
1926                     (*param->acp_module) ? param->acp_module : NULL);
1927                 if (!ret)
1928                         goto exit_1;
1929                 aoeio->aoeio_status = AOEIOE_CREATE_PORT;
1930                 ret = EIO;
1931 
1932 error_1:
1933                 for (i = 0; i < n; i++) {
1934                         if (!opened_mac[i]->am_use_cnt)
1935                                 (void) aoe_close_mac(opened_mac[i]);
1936                         else
1937                                 mac_used = 1;
1938                 }
1939                 for (i = 0; i < m; i++) {
1940                         if (!created_mac[i]->am_use_cnt)
1941                                 aoe_destroy_mac(created_mac[i]);
1942                         else
1943                                 mac_used = 1;
1944                 }
1945                 if (is_port_created) {
1946                         if (!mac_used) {
1947                                 created_port = aoe_lookup_port_by_id(portid);
1948                                 aoe_destroy_port(created_port);
1949                         } else {
1950                                 cmn_err(CE_WARN, "Cannot delete port after "
1951                                     "failed port creation due to "
1952                                     "a mac is in use!\n");
1953                         }
1954                 }
1955 exit_1:
1956                 mutex_exit(&ss->ss_ioctl_mutex);
1957                 break;
1958         }
1959 
1960         case AOEIO_DELETE_PORT: {
1961                 aoeio_delete_port_param_t *del_port_param =
1962                     (aoeio_delete_port_param_t *)ibuf;
1963 
1964                 if (aoeio->aoeio_ilen < sizeof (aoeio_delete_port_param_t) ||
1965                     aoeio->aoeio_xfer != AOEIO_XFER_READ) {
1966                         aoeio->aoeio_status = AOEIOE_INVAL_ARG;
1967                         ret = EINVAL;
1968                         break;
1969                 }
1970 
1971                 mutex_enter(&ss->ss_ioctl_mutex);
1972                 ret = aoe_delete_port(ss->ss_dip, aoeio,
1973                     del_port_param->adp_port_id);
1974                 mutex_exit(&ss->ss_ioctl_mutex);
1975                 break;
1976         }
1977 
1978         case AOEIO_GET_PORT_LIST: {
1979                 aoe_port_list_t *list = (aoe_port_list_t *)obuf;
1980                 int count;
1981 
1982                 if (aoeio->aoeio_xfer != AOEIO_XFER_READ ||
1983                     aoeio->aoeio_olen < sizeof (aoe_port_list_t)) {
1984                         aoeio->aoeio_status = AOEIOE_INVAL_ARG;
1985                         ret = EINVAL;
1986                         break;
1987                 }
1988                 mutex_enter(&ss->ss_ioctl_mutex);
1989 
1990                 list->num_ports = 1 + (aoeio->aoeio_olen -
1991                     sizeof (aoe_port_list_t))/sizeof (aoe_port_instance_t);
1992 
1993                 count = aoe_get_port_list(list->ports, list->num_ports);
1994 
1995                 if (count > list->num_ports) {
1996                         aoeio->aoeio_status = AOEIOE_MORE_DATA;
1997                         ret = ENOSPC;
1998                 }
1999                 list->num_ports = count;
2000                 mutex_exit(&ss->ss_ioctl_mutex);
2001 
2002                 break;
2003 
2004         }
2005 
2006         default:
2007                 return (ENOTTY);
2008         }
2009 
2010 aoeiocmd_release_buf:
2011         if (ret == 0) {
2012                 ret = aoe_copyout_iocdata(data, mode, aoeio, obuf);
2013         } else if (aoeio->aoeio_status) {
2014                 (void) aoe_copyout_iocdata(data, mode, aoeio, obuf);
2015         }
2016 
2017         if (obuf != NULL) {
2018                 kmem_free(obuf, aoeio->aoeio_olen);
2019                 obuf = NULL;
2020         }
2021         if (abuf != NULL) {
2022                 kmem_free(abuf, aoeio->aoeio_alen);
2023                 abuf = NULL;
2024         }
2025 
2026         if (ibuf != NULL) {
2027                 kmem_free(ibuf, aoeio->aoeio_ilen);
2028                 ibuf = NULL;
2029         }
2030         kmem_free(aoeio, sizeof (aoeio_t));
2031 
2032         return (ret);
2033 }
2034 
2035 static int
2036 aoe_i_port_autoconf(uint32_t portid)
2037 {
2038         aoeio_t iost;
2039         int ret, i;
2040         aoe_soft_state_t *ss = aoe_global_ss;
2041         aoe_mac_t *mac;
2042         uint32_t linkid = rootfs.bo_ppa;
2043         aoe_port_t *created_port = NULL;
2044         int is_port_created = 0;
2045 
2046         /*
2047          * Automatically discover MAC interfaces with AoE targets on it
2048          * One MAC per port will be created. Means that if you have
2049          * multi-pathed AoE target setup, system will see two disks
2050          */
2051         mutex_enter(&ss->ss_ioctl_mutex);
2052         mac = aoe_create_mac_by_id(portid, linkid, &is_port_created);
2053         if (mac == NULL) {
2054                 cmn_err(CE_WARN, "Error while creating mac linkid=%d", linkid);
2055                 if (is_port_created) {
2056                         created_port = aoe_lookup_port_by_id(portid);
2057                         aoe_destroy_port(created_port);
2058                 }
2059                 mutex_exit(&ss->ss_ioctl_mutex);
2060                 return (0);
2061         }
2062 
2063         (void) strlcpy(mac->am_ifname, rootfs.bo_ifname,
2064             sizeof (mac->am_ifname));
2065 
2066         ret = aoe_open_mac(mac, B_FALSE);
2067         if (ret != 0) {
2068                 cmn_err(CE_WARN, "Error while opening mac linkid=%d", linkid);
2069                 aoe_destroy_mac(mac);
2070                 if (is_port_created) {
2071                         created_port = aoe_lookup_port_by_id(portid);
2072                         aoe_destroy_port(created_port);
2073                 }
2074                 mutex_exit(&ss->ss_ioctl_mutex);
2075                 return (0);
2076         }
2077 
2078         ret = aoe_create_port(ss->ss_dip, mac->am_port,
2079             AOE_CLIENT_INITIATOR, AOE_POLICY_FAILOVER, NULL);
2080         if (ret != 0) {
2081                 cmn_err(CE_WARN, "Error while creating port linkid=%d", linkid);
2082                 (void) aoe_close_mac(mac);
2083                 aoe_destroy_mac(mac);
2084                 if (is_port_created) {
2085                         created_port = aoe_lookup_port_by_id(portid);
2086                         aoe_destroy_port(created_port);
2087                 }
2088                 mutex_exit(&ss->ss_ioctl_mutex);
2089                 return (0);
2090         }
2091         mutex_exit(&ss->ss_ioctl_mutex);
2092 
2093         /*
2094          * We got that far means port in a good shape,
2095          * lets poll for state change...
2096          *
2097          * Timeout is 30 seconds so that at least two attempts of periodic
2098          * disk discovery would fit while brining up boot device...
2099          */
2100         for (i = 0; i < 30; i++) {
2101                 delay(100);
2102                 if (mac->am_port->p_unit_cnt > 0) {
2103                         cmn_err(CE_NOTE, "AoE autoconf: %d disks detected",
2104                             mac->am_port->p_unit_cnt);
2105                         /*
2106                          * TODO: If boot-aoepath is set to "auto",
2107                          * configure first found AoE device. This is
2108                          * to be done in the future.
2109                          */
2110                         if (aoepath_prop != NULL &&
2111                             strcmp(aoepath_prop, "auto") == 0)
2112                                 cmn_err(CE_PANIC, "FIXME autoconf bootpath");
2113 
2114                         /* keep port open */
2115                         return (1);
2116                 }
2117         }
2118 
2119         mutex_enter(&ss->ss_ioctl_mutex);
2120         ret = aoe_delete_port(ss->ss_dip, &iost, portid);
2121         mutex_exit(&ss->ss_ioctl_mutex);
2122 
2123         return (0);
2124 }
2125 
2126 static int
2127 aoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2128 {
2129         int ret;
2130         int instance;
2131         aoe_soft_state_t *ss;
2132 
2133         instance = ddi_get_instance(dip);
2134         switch (cmd) {
2135         case DDI_ATTACH:
2136                 break;
2137 
2138         case DDI_RESUME:
2139         case DDI_PM_RESUME:
2140                 dev_err(dip, CE_WARN, "resume not supported yet");
2141                 ret = DDI_FAILURE;
2142                 goto exit;
2143 
2144         default:
2145                 dev_err(dip, CE_WARN, "cmd 0x%x not recognized", cmd);
2146                 ret = DDI_FAILURE;
2147                 goto exit;
2148         }
2149 
2150         ret = ddi_soft_state_zalloc(aoe_state, instance);
2151         if (ret != DDI_SUCCESS) {
2152                 dev_err(dip, CE_WARN, "soft_state_zalloc-%x/%x", ret,
2153                     instance);
2154                 goto exit;
2155         }
2156 
2157         ss = ddi_get_soft_state(aoe_state, instance);
2158         ss->ss_dip = dip;
2159         ss->ss_ioctl_flags = 0;
2160         mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL);
2161         list_create(&ss->ss_mac_list, sizeof (aoe_mac_t),
2162             offsetof(aoe_mac_t, am_ss_node));
2163         list_create(&ss->ss_port_list, sizeof (aoe_port_t),
2164             offsetof(aoe_port_t, p_ss_node));
2165 
2166         ret = ddi_create_minor_node(dip, "admin", S_IFCHR,
2167             ddi_get_instance(dip), DDI_PSEUDO, 0);
2168         if (ret != DDI_SUCCESS) {
2169                 dev_err(dip, CE_WARN, "ddi_create_minor_node failed");
2170                 goto exit;
2171         }
2172 
2173         ASSERT(aoe_global_ss == NULL);
2174         aoe_global_ss = ss;
2175 
2176         if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(),
2177             DDI_PROP_DONTPASS, "boot-mac"))
2178                 (void) aoe_i_port_autoconf(0);
2179 
2180         ddi_report_dev(dip);
2181         return (DDI_SUCCESS);
2182 
2183 exit:
2184         return (ret);
2185 }
2186 
2187 static int
2188 aoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2189 {
2190         aoe_soft_state_t        *ss;
2191         int                     instance;
2192 
2193         instance = ddi_get_instance(dip);
2194         ss = ddi_get_soft_state(aoe_state, instance);
2195         if (ss == NULL)
2196                 return (DDI_FAILURE);
2197 
2198         ASSERT(aoe_global_ss != NULL);
2199         ASSERT(dip == aoe_global_ss->ss_dip);
2200 
2201         switch (cmd) {
2202         case DDI_DETACH:
2203                 break;
2204         case DDI_PM_SUSPEND:
2205                 dev_err(dip, CE_WARN, "suspend not supported yet");
2206                 return (DDI_FAILURE);
2207         default:
2208                 dev_err(dip, CE_WARN, "cmd 0x%x unrecognized", cmd);
2209                 return (DDI_FAILURE);
2210         }
2211 
2212         if (!list_is_empty(&ss->ss_mac_list)) {
2213                 dev_err(dip, CE_WARN, "ss_mac_list is not empty when detach");
2214                 return (DDI_FAILURE);
2215         }
2216 
2217         ddi_remove_minor_node(ss->ss_dip, NULL);
2218         mutex_destroy(&ss->ss_ioctl_mutex);
2219         list_destroy(&ss->ss_mac_list);
2220         list_destroy(&ss->ss_port_list);
2221 
2222         return (DDI_SUCCESS);
2223 }
2224 
2225 /*
2226  * Check if AoE port can be detached
2227  */
2228 static uint32_t
2229 aoe_allow_port_detach(aoe_eport_t *eport)
2230 {
2231         aoe_port_t *port = EPORT2PORT(eport);
2232 
2233         return (port->p_flags & AOE_PORT_FLAG_BUSY);
2234 }
2235 
2236 int
2237 _init(void)
2238 {
2239         int     rv;
2240 
2241         rv = ddi_soft_state_init(&aoe_state, sizeof (aoe_soft_state_t), 0);
2242         if (rv != 0)
2243                 return (rv);
2244 
2245         if ((rv = mod_install(&modlinkage)) != 0)
2246                 ddi_soft_state_fini(&aoe_state);
2247 
2248         return (rv);
2249 }
2250 
2251 int
2252 _fini(void)
2253 {
2254         int     rv;
2255 
2256         if ((rv = mod_remove(&modlinkage)) == 0)
2257                 ddi_soft_state_fini(&aoe_state);
2258 
2259         return (rv);
2260 }
2261 
2262 int
2263 _info(struct modinfo *modinfop)
2264 {
2265 
2266         return (mod_info(&modlinkage, modinfop));
2267 }