1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  *  Copyright (c) 2002-2009 Neterion, Inc.
  29  *  All right Reserved.
  30  *
  31  *  FileName :    xgell.c
  32  *
  33  *  Description:  Xge Link Layer data path implementation
  34  *
  35  */
  36 
  37 #include "xgell.h"
  38 
  39 #include <netinet/ip.h>
  40 #include <netinet/tcp.h>
  41 #include <netinet/udp.h>
  42 
  43 #define XGELL_MAX_FRAME_SIZE(hldev)     ((hldev)->config.mtu +       \
  44     sizeof (struct ether_vlan_header))
  45 
  46 #define HEADROOM                2       /* for DIX-only packets */
  47 
  48 void header_free_func(void *arg) { }
  49 frtn_t header_frtn = {header_free_func, NULL};
  50 
  51 /* DMA attributes used for Tx side */
  52 static struct ddi_dma_attr tx_dma_attr = {
  53         DMA_ATTR_V0,                    /* dma_attr_version */
  54         0x0ULL,                         /* dma_attr_addr_lo */
  55         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_addr_hi */
  56         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_count_max */
  57 #if defined(__sparc)
  58         0x2000,                         /* dma_attr_align */
  59 #else
  60         0x1000,                         /* dma_attr_align */
  61 #endif
  62         0xFC00FC,                       /* dma_attr_burstsizes */
  63         0x1,                            /* dma_attr_minxfer */
  64         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_maxxfer */
  65         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_seg */
  66         18,                             /* dma_attr_sgllen */
  67         (unsigned int)1,                /* dma_attr_granular */
  68         0                               /* dma_attr_flags */
  69 };
  70 
  71 /*
  72  * DMA attributes used when using ddi_dma_mem_alloc to
  73  * allocat HAL descriptors and Rx buffers during replenish
  74  */
  75 static struct ddi_dma_attr hal_dma_attr = {
  76         DMA_ATTR_V0,                    /* dma_attr_version */
  77         0x0ULL,                         /* dma_attr_addr_lo */
  78         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_addr_hi */
  79         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_count_max */
  80 #if defined(__sparc)
  81         0x2000,                         /* dma_attr_align */
  82 #else
  83         0x1000,                         /* dma_attr_align */
  84 #endif
  85         0xFC00FC,                       /* dma_attr_burstsizes */
  86         0x1,                            /* dma_attr_minxfer */
  87         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_maxxfer */
  88         0xFFFFFFFFFFFFFFFFULL,          /* dma_attr_seg */
  89         1,                              /* dma_attr_sgllen */
  90         (unsigned int)1,                /* dma_attr_sgllen */
  91         DDI_DMA_RELAXED_ORDERING        /* dma_attr_flags */
  92 };
  93 
  94 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
  95 
  96 static int              xgell_m_stat(void *, uint_t, uint64_t *);
  97 static int              xgell_m_start(void *);
  98 static void             xgell_m_stop(void *);
  99 static int              xgell_m_promisc(void *, boolean_t);
 100 static int              xgell_m_multicst(void *, boolean_t, const uint8_t *);
 101 static void             xgell_m_ioctl(void *, queue_t *, mblk_t *);
 102 static boolean_t        xgell_m_getcapab(void *, mac_capab_t, void *);
 103 
 104 #define XGELL_M_CALLBACK_FLAGS  (MC_IOCTL | MC_GETCAPAB)
 105 
 106 static mac_callbacks_t xgell_m_callbacks = {
 107         XGELL_M_CALLBACK_FLAGS,
 108         xgell_m_stat,
 109         xgell_m_start,
 110         xgell_m_stop,
 111         xgell_m_promisc,
 112         xgell_m_multicst,
 113         NULL,
 114         NULL,
 115         NULL,
 116         xgell_m_ioctl,
 117         xgell_m_getcapab
 118 };
 119 
 120 /*
 121  * xge_device_poll
 122  *
 123  * Timeout should call me every 1s. xge_callback_event_queued should call me
 124  * when HAL hope event was rescheduled.
 125  */
 126 /*ARGSUSED*/
 127 void
 128 xge_device_poll(void *data)
 129 {
 130         xgelldev_t *lldev = xge_hal_device_private(data);
 131 
 132         mutex_enter(&lldev->genlock);
 133         if (lldev->is_initialized) {
 134                 xge_hal_device_poll(data);
 135                 lldev->timeout_id = timeout(xge_device_poll, data,
 136                     XGE_DEV_POLL_TICKS);
 137         } else if (lldev->in_reset == 1) {
 138                 lldev->timeout_id = timeout(xge_device_poll, data,
 139                     XGE_DEV_POLL_TICKS);
 140         } else {
 141                 lldev->timeout_id = 0;
 142         }
 143         mutex_exit(&lldev->genlock);
 144 }
 145 
 146 /*
 147  * xge_device_poll_now
 148  *
 149  * Will call xge_device_poll() immediately
 150  */
 151 void
 152 xge_device_poll_now(void *data)
 153 {
 154         xgelldev_t *lldev = xge_hal_device_private(data);
 155 
 156         mutex_enter(&lldev->genlock);
 157         if (lldev->is_initialized) {
 158                 xge_hal_device_poll(data);
 159         }
 160         mutex_exit(&lldev->genlock);
 161 }
 162 
 163 /*
 164  * xgell_callback_link_up
 165  *
 166  * This function called by HAL to notify HW link up state change.
 167  */
 168 void
 169 xgell_callback_link_up(void *userdata)
 170 {
 171         xgelldev_t *lldev = (xgelldev_t *)userdata;
 172 
 173         mac_link_update(lldev->mh, LINK_STATE_UP);
 174 }
 175 
 176 /*
 177  * xgell_callback_link_down
 178  *
 179  * This function called by HAL to notify HW link down state change.
 180  */
 181 void
 182 xgell_callback_link_down(void *userdata)
 183 {
 184         xgelldev_t *lldev = (xgelldev_t *)userdata;
 185 
 186         mac_link_update(lldev->mh, LINK_STATE_DOWN);
 187 }
 188 
 189 /*
 190  * xgell_rx_buffer_replenish_all
 191  *
 192  * To replenish all freed dtr(s) with buffers in free pool. It's called by
 193  * xgell_rx_buffer_recycle() or xgell_rx_1b_callback().
 194  * Must be called with pool_lock held.
 195  */
 196 static void
 197 xgell_rx_buffer_replenish_all(xgell_rx_ring_t *ring)
 198 {
 199         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 200         xge_hal_dtr_h dtr;
 201         xgell_rx_buffer_t *rx_buffer;
 202         xgell_rxd_priv_t *rxd_priv;
 203 
 204         xge_assert(mutex_owned(&bf_pool->pool_lock));
 205 
 206         while ((bf_pool->free > 0) &&
 207             (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == XGE_HAL_OK)) {
 208                 xge_assert(bf_pool->head);
 209 
 210                 rx_buffer = bf_pool->head;
 211 
 212                 bf_pool->head = rx_buffer->next;
 213                 bf_pool->free--;
 214 
 215                 xge_assert(rx_buffer->dma_addr);
 216 
 217                 rxd_priv = (xgell_rxd_priv_t *)
 218                     xge_hal_ring_dtr_private(ring->channelh, dtr);
 219                 xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
 220                     bf_pool->size);
 221 
 222                 rxd_priv->rx_buffer = rx_buffer;
 223                 xge_hal_ring_dtr_post(ring->channelh, dtr);
 224         }
 225 }
 226 
 227 /*
 228  * xgell_rx_buffer_release
 229  *
 230  * The only thing done here is to put the buffer back to the pool.
 231  * Calling this function need be protected by mutex, bf_pool.pool_lock.
 232  */
 233 static void
 234 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
 235 {
 236         xgell_rx_ring_t *ring = rx_buffer->ring;
 237         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 238 
 239         xge_assert(mutex_owned(&bf_pool->pool_lock));
 240 
 241         /* Put the buffer back to pool */
 242         rx_buffer->next = bf_pool->head;
 243         bf_pool->head = rx_buffer;
 244 
 245         bf_pool->free++;
 246 }
 247 
 248 /*
 249  * xgell_rx_buffer_recycle
 250  *
 251  * Called by desballoc() to "free" the resource.
 252  * We will try to replenish all descripters.
 253  */
 254 
 255 /*
 256  * Previously there were much lock contention between xgell_rx_1b_compl() and
 257  * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad
 258  * effect on rx performance. A separate recycle list is introduced to overcome
 259  * this. The recycle list is used to record the rx buffer that has been recycled
 260  * and these buffers will be retuned back to the free list in bulk instead of
 261  * one-by-one.
 262  */
 263 
 264 static void
 265 xgell_rx_buffer_recycle(char *arg)
 266 {
 267         xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
 268         xgell_rx_ring_t *ring = rx_buffer->ring;
 269         xgelldev_t *lldev = ring->lldev;
 270         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 271 
 272         mutex_enter(&bf_pool->recycle_lock);
 273 
 274         rx_buffer->next = bf_pool->recycle_head;
 275         bf_pool->recycle_head = rx_buffer;
 276         if (bf_pool->recycle_tail == NULL)
 277                 bf_pool->recycle_tail = rx_buffer;
 278         bf_pool->recycle++;
 279 
 280         /*
 281          * Before finding a good way to set this hiwat, just always call to
 282          * replenish_all. *TODO*
 283          */
 284         if ((lldev->is_initialized != 0) && (ring->live) &&
 285             (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) {
 286                 mutex_enter(&bf_pool->pool_lock);
 287                 bf_pool->recycle_tail->next = bf_pool->head;
 288                 bf_pool->head = bf_pool->recycle_head;
 289                 bf_pool->recycle_head = bf_pool->recycle_tail = NULL;
 290                 bf_pool->post -= bf_pool->recycle;
 291                 bf_pool->free += bf_pool->recycle;
 292                 bf_pool->recycle = 0;
 293                 xgell_rx_buffer_replenish_all(ring);
 294                 mutex_exit(&bf_pool->pool_lock);
 295         }
 296 
 297         mutex_exit(&bf_pool->recycle_lock);
 298 }
 299 
 300 /*
 301  * xgell_rx_buffer_alloc
 302  *
 303  * Allocate one rx buffer and return with the pointer to the buffer.
 304  * Return NULL if failed.
 305  */
 306 static xgell_rx_buffer_t *
 307 xgell_rx_buffer_alloc(xgell_rx_ring_t *ring)
 308 {
 309         xgelldev_t *lldev = ring->lldev;
 310         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 311         xge_hal_device_t *hldev;
 312         void *vaddr;
 313         ddi_dma_handle_t dma_handle;
 314         ddi_acc_handle_t dma_acch;
 315         dma_addr_t dma_addr;
 316         uint_t ncookies;
 317         ddi_dma_cookie_t dma_cookie;
 318         size_t real_size;
 319         extern ddi_device_acc_attr_t *p_xge_dev_attr;
 320         xgell_rx_buffer_t *rx_buffer;
 321 
 322         hldev = (xge_hal_device_t *)lldev->devh;
 323 
 324         if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
 325             0, &dma_handle) != DDI_SUCCESS) {
 326                 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
 327                     XGELL_IFNAME, lldev->instance);
 328                 goto handle_failed;
 329         }
 330 
 331         /* reserve some space at the end of the buffer for recycling */
 332         if (ddi_dma_mem_alloc(dma_handle, HEADROOM + bf_pool->size +
 333             sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
 334             DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
 335             DDI_SUCCESS) {
 336                 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
 337                     XGELL_IFNAME, lldev->instance);
 338                 goto mem_failed;
 339         }
 340 
 341         if (HEADROOM + bf_pool->size + sizeof (xgell_rx_buffer_t) >
 342             real_size) {
 343                 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
 344                     XGELL_IFNAME, lldev->instance);
 345                 goto bind_failed;
 346         }
 347 
 348         if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
 349             bf_pool->size, DDI_DMA_READ | DDI_DMA_STREAMING,
 350             DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
 351                 xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
 352                     XGELL_IFNAME, lldev->instance);
 353                 goto bind_failed;
 354         }
 355 
 356         if (ncookies != 1 || dma_cookie.dmac_size < bf_pool->size) {
 357                 xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
 358                     XGELL_IFNAME, lldev->instance);
 359                 goto check_failed;
 360         }
 361 
 362         dma_addr = dma_cookie.dmac_laddress;
 363 
 364         rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
 365             sizeof (xgell_rx_buffer_t));
 366         rx_buffer->next = NULL;
 367         rx_buffer->vaddr = vaddr;
 368         rx_buffer->dma_addr = dma_addr;
 369         rx_buffer->dma_handle = dma_handle;
 370         rx_buffer->dma_acch = dma_acch;
 371         rx_buffer->ring = ring;
 372         rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
 373         rx_buffer->frtn.free_arg = (void *)rx_buffer;
 374 
 375         return (rx_buffer);
 376 
 377 check_failed:
 378         (void) ddi_dma_unbind_handle(dma_handle);
 379 bind_failed:
 380         XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
 381         ddi_dma_mem_free(&dma_acch);
 382 mem_failed:
 383         ddi_dma_free_handle(&dma_handle);
 384 handle_failed:
 385 
 386         return (NULL);
 387 }
 388 
 389 /*
 390  * xgell_rx_destroy_buffer_pool
 391  *
 392  * Destroy buffer pool. If there is still any buffer hold by upper layer,
 393  * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
 394  */
 395 static boolean_t
 396 xgell_rx_destroy_buffer_pool(xgell_rx_ring_t *ring)
 397 {
 398         xgelldev_t *lldev = ring->lldev;
 399         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 400         xgell_rx_buffer_t *rx_buffer;
 401         ddi_dma_handle_t  dma_handle;
 402         ddi_acc_handle_t  dma_acch;
 403         int i;
 404 
 405         /*
 406          * If the pool has been destroied, just return B_TRUE
 407          */
 408         if (!bf_pool->live)
 409                 return (B_TRUE);
 410 
 411         mutex_enter(&bf_pool->recycle_lock);
 412         if (bf_pool->recycle > 0) {
 413                 mutex_enter(&bf_pool->pool_lock);
 414                 bf_pool->recycle_tail->next = bf_pool->head;
 415                 bf_pool->head = bf_pool->recycle_head;
 416                 bf_pool->recycle_tail = bf_pool->recycle_head = NULL;
 417                 bf_pool->post -= bf_pool->recycle;
 418                 bf_pool->free += bf_pool->recycle;
 419                 bf_pool->recycle = 0;
 420                 mutex_exit(&bf_pool->pool_lock);
 421         }
 422         mutex_exit(&bf_pool->recycle_lock);
 423 
 424         /*
 425          * If there is any posted buffer, the driver should reject to be
 426          * detached. Need notice upper layer to release them.
 427          */
 428         if (bf_pool->post != 0) {
 429                 xge_debug_ll(XGE_ERR,
 430                     "%s%d has some buffers not be recycled, try later!",
 431                     XGELL_IFNAME, lldev->instance);
 432                 return (B_FALSE);
 433         }
 434 
 435         /*
 436          * Release buffers one by one.
 437          */
 438         for (i = bf_pool->total; i > 0; i--) {
 439                 rx_buffer = bf_pool->head;
 440                 xge_assert(rx_buffer != NULL);
 441 
 442                 bf_pool->head = rx_buffer->next;
 443 
 444                 dma_handle = rx_buffer->dma_handle;
 445                 dma_acch = rx_buffer->dma_acch;
 446 
 447                 if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
 448                         xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!");
 449                         bf_pool->head = rx_buffer;
 450                         return (B_FALSE);
 451                 }
 452                 ddi_dma_mem_free(&dma_acch);
 453                 ddi_dma_free_handle(&dma_handle);
 454 
 455                 bf_pool->total--;
 456                 bf_pool->free--;
 457         }
 458 
 459         xge_assert(!mutex_owned(&bf_pool->pool_lock));
 460 
 461         mutex_destroy(&bf_pool->recycle_lock);
 462         mutex_destroy(&bf_pool->pool_lock);
 463         bf_pool->live = B_FALSE;
 464 
 465         return (B_TRUE);
 466 }
 467 
 468 /*
 469  * xgell_rx_create_buffer_pool
 470  *
 471  * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
 472  */
 473 static boolean_t
 474 xgell_rx_create_buffer_pool(xgell_rx_ring_t *ring)
 475 {
 476         xgelldev_t *lldev = ring->lldev;
 477         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 478         xge_hal_device_t *hldev;
 479         xgell_rx_buffer_t *rx_buffer;
 480         int i;
 481 
 482         if (bf_pool->live)
 483                 return (B_TRUE);
 484 
 485         hldev = (xge_hal_device_t *)lldev->devh;
 486 
 487         bf_pool->total = 0;
 488         bf_pool->size = XGELL_MAX_FRAME_SIZE(hldev);
 489         bf_pool->head = NULL;
 490         bf_pool->free = 0;
 491         bf_pool->post = 0;
 492         bf_pool->post_hiwat = lldev->config.rx_buffer_post_hiwat;
 493         bf_pool->recycle = 0;
 494         bf_pool->recycle_head = NULL;
 495         bf_pool->recycle_tail = NULL;
 496         bf_pool->live = B_TRUE;
 497 
 498         mutex_init(&bf_pool->pool_lock, NULL, MUTEX_DRIVER,
 499             DDI_INTR_PRI(hldev->irqh));
 500         mutex_init(&bf_pool->recycle_lock, NULL, MUTEX_DRIVER,
 501             DDI_INTR_PRI(hldev->irqh));
 502 
 503         /*
 504          * Allocate buffers one by one. If failed, destroy whole pool by
 505          * call to xgell_rx_destroy_buffer_pool().
 506          */
 507 
 508         for (i = 0; i < lldev->config.rx_buffer_total; i++) {
 509                 if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) {
 510                         (void) xgell_rx_destroy_buffer_pool(ring);
 511                         return (B_FALSE);
 512                 }
 513 
 514                 rx_buffer->next = bf_pool->head;
 515                 bf_pool->head = rx_buffer;
 516 
 517                 bf_pool->total++;
 518                 bf_pool->free++;
 519         }
 520 
 521         return (B_TRUE);
 522 }
 523 
 524 /*
 525  * xgell_rx_dtr_replenish
 526  *
 527  * Replenish descriptor with rx_buffer in RX buffer pool.
 528  * The dtr should be post right away.
 529  */
 530 xge_hal_status_e
 531 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
 532     void *userdata, xge_hal_channel_reopen_e reopen)
 533 {
 534         xgell_rx_ring_t *ring = userdata;
 535         xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
 536         xgell_rx_buffer_t *rx_buffer;
 537         xgell_rxd_priv_t *rxd_priv;
 538 
 539         mutex_enter(&bf_pool->pool_lock);
 540         if (bf_pool->head == NULL) {
 541                 xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!");
 542                 return (XGE_HAL_FAIL);
 543         }
 544         rx_buffer = bf_pool->head;
 545         xge_assert(rx_buffer);
 546         xge_assert(rx_buffer->dma_addr);
 547 
 548         bf_pool->head = rx_buffer->next;
 549         bf_pool->free--;
 550         mutex_exit(&bf_pool->pool_lock);
 551 
 552         rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr);
 553         xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, bf_pool->size);
 554 
 555         rxd_priv->rx_buffer = rx_buffer;
 556 
 557         return (XGE_HAL_OK);
 558 }
 559 
 560 /*
 561  * xgell_get_ip_offset
 562  *
 563  * Calculate the offset to IP header.
 564  */
 565 static inline int
 566 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
 567 {
 568         int ip_off;
 569 
 570         /* get IP-header offset */
 571         switch (ext_info->frame) {
 572         case XGE_HAL_FRAME_TYPE_DIX:
 573                 ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
 574                 break;
 575         case XGE_HAL_FRAME_TYPE_IPX:
 576                 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
 577                     XGE_HAL_HEADER_802_2_SIZE +
 578                     XGE_HAL_HEADER_SNAP_SIZE);
 579                 break;
 580         case XGE_HAL_FRAME_TYPE_LLC:
 581                 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
 582                     XGE_HAL_HEADER_802_2_SIZE);
 583                 break;
 584         case XGE_HAL_FRAME_TYPE_SNAP:
 585                 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
 586                     XGE_HAL_HEADER_SNAP_SIZE);
 587                 break;
 588         default:
 589                 ip_off = 0;
 590                 break;
 591         }
 592 
 593         if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
 594             ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
 595             (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
 596                 ip_off += XGE_HAL_HEADER_VLAN_SIZE;
 597         }
 598 
 599         return (ip_off);
 600 }
 601 
 602 /*
 603  * xgell_rx_hcksum_assoc
 604  *
 605  * Judge the packet type and then call to hcksum_assoc() to associate
 606  * h/w checksum information.
 607  */
 608 static inline void
 609 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
 610     xge_hal_dtr_info_t *ext_info)
 611 {
 612         int cksum_flags = 0;
 613 
 614         if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
 615                 if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
 616                         if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
 617                                 cksum_flags |= HCK_IPV4_HDRCKSUM_OK;
 618                         }
 619                         if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
 620                                 cksum_flags |= HCK_FULLCKSUM_OK;
 621                         }
 622                         if (cksum_flags != 0) {
 623                                 mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
 624                         }
 625                 }
 626         } else if (ext_info->proto &
 627             (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
 628                 /*
 629                  * Just pass the partial cksum up to IP.
 630                  */
 631                 int ip_off = xgell_get_ip_offset(ext_info);
 632                 int start, end = pkt_length - ip_off;
 633 
 634                 if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
 635                         struct ip *ip =
 636                             (struct ip *)(vaddr + ip_off);
 637                         start = ip->ip_hl * 4;
 638                 } else {
 639                         start = 40;
 640                 }
 641                 cksum_flags |= HCK_PARTIALCKSUM;
 642                 mac_hcksum_set(mp, start, 0, end,
 643                     ntohs(ext_info->l4_cksum), cksum_flags);
 644         }
 645 }
 646 
 647 /*
 648  * xgell_rx_1b_msg_alloc
 649  *
 650  * Allocate message header for data buffer, and decide if copy the packet to
 651  * new data buffer to release big rx_buffer to save memory.
 652  *
 653  * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
 654  * new message and copy the payload in.
 655  */
 656 static mblk_t *
 657 xgell_rx_1b_msg_alloc(xgell_rx_ring_t *ring, xgell_rx_buffer_t *rx_buffer,
 658     int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
 659 {
 660         xgelldev_t *lldev = ring->lldev;
 661         mblk_t *mp;
 662         char *vaddr;
 663 
 664         vaddr = (char *)rx_buffer->vaddr + HEADROOM;
 665         /*
 666          * Copy packet into new allocated message buffer, if pkt_length
 667          * is less than XGELL_RX_DMA_LOWAT
 668          */
 669         if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
 670                 if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) {
 671                         return (NULL);
 672                 }
 673                 mp->b_rptr += HEADROOM;
 674                 bcopy(vaddr, mp->b_rptr, pkt_length);
 675                 mp->b_wptr = mp->b_rptr + pkt_length;
 676                 *copyit = B_TRUE;
 677                 return (mp);
 678         }
 679 
 680         /*
 681          * Just allocate mblk for current data buffer
 682          */
 683         if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
 684             &rx_buffer->frtn)) == NULL) {
 685                 /* Drop it */
 686                 return (NULL);
 687         }
 688         /*
 689          * Adjust the b_rptr/b_wptr in the mblk_t structure.
 690          */
 691         mp->b_wptr += pkt_length;
 692 
 693         return (mp);
 694 }
 695 
 696 /*
 697  * xgell_rx_1b_callback
 698  *
 699  * If the interrupt is because of a received frame or if the receive ring
 700  * contains fresh as yet un-processed frames, this function is called.
 701  */
 702 static xge_hal_status_e
 703 xgell_rx_1b_callback(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
 704     void *userdata)
 705 {
 706         xgell_rx_ring_t *ring = (xgell_rx_ring_t *)userdata;
 707         xgelldev_t *lldev = ring->lldev;
 708         xgell_rx_buffer_t *rx_buffer;
 709         mblk_t *mp_head = NULL;
 710         mblk_t *mp_end  = NULL;
 711         int pkt_burst = 0;
 712 
 713         xge_debug_ll(XGE_TRACE, "xgell_rx_1b_callback on ring %d", ring->index);
 714 
 715         mutex_enter(&ring->bf_pool.pool_lock);
 716         do {
 717                 int pkt_length;
 718                 dma_addr_t dma_data;
 719                 mblk_t *mp;
 720                 boolean_t copyit = B_FALSE;
 721 
 722                 xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
 723                     xge_hal_ring_dtr_private(channelh, dtr));
 724                 xge_hal_dtr_info_t ext_info;
 725 
 726                 rx_buffer = rxd_priv->rx_buffer;
 727 
 728                 xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
 729                 xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
 730 
 731                 xge_assert(dma_data == rx_buffer->dma_addr);
 732 
 733                 if (t_code != 0) {
 734                         xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
 735                             " completed due to error t_code %01x", XGELL_IFNAME,
 736                             lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
 737 
 738                         (void) xge_hal_device_handle_tcode(channelh, dtr,
 739                             t_code);
 740                         xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
 741                         xgell_rx_buffer_release(rx_buffer);
 742                         continue;
 743                 }
 744 
 745                 /*
 746                  * Sync the DMA memory
 747                  */
 748                 if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
 749                     DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
 750                         xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
 751                             XGELL_IFNAME, lldev->instance);
 752                         xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
 753                         xgell_rx_buffer_release(rx_buffer);
 754                         continue;
 755                 }
 756 
 757                 /*
 758                  * Allocate message for the packet.
 759                  */
 760                 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
 761                         copyit = B_TRUE;
 762                 } else {
 763                         copyit = B_FALSE;
 764                 }
 765 
 766                 mp = xgell_rx_1b_msg_alloc(ring, rx_buffer, pkt_length,
 767                     &ext_info, &copyit);
 768 
 769                 xge_hal_ring_dtr_free(channelh, dtr);
 770 
 771                 /*
 772                  * Release the buffer and recycle it later
 773                  */
 774                 if ((mp == NULL) || copyit) {
 775                         xgell_rx_buffer_release(rx_buffer);
 776                 } else {
 777                         /*
 778                          * Count it since the buffer should be loaned up.
 779                          */
 780                         ring->bf_pool.post++;
 781                 }
 782                 if (mp == NULL) {
 783                         xge_debug_ll(XGE_ERR,
 784                             "%s%d: rx: can not allocate mp mblk",
 785                             XGELL_IFNAME, lldev->instance);
 786                         continue;
 787                 }
 788 
 789                 /*
 790                  * Associate cksum_flags per packet type and h/w
 791                  * cksum flags.
 792                  */
 793                 xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + HEADROOM,
 794                     pkt_length, &ext_info);
 795 
 796                 ring->rx_pkts++;
 797                 ring->rx_bytes += pkt_length;
 798 
 799                 if (mp_head == NULL) {
 800                         mp_head = mp;
 801                         mp_end = mp;
 802                 } else {
 803                         mp_end->b_next = mp;
 804                         mp_end = mp;
 805                 }
 806 
 807                 /*
 808                  * Inlined implemented polling function.
 809                  */
 810                 if ((ring->poll_mp == NULL) && (ring->poll_bytes > 0)) {
 811                         ring->poll_mp = mp_head;
 812                 }
 813                 if (ring->poll_mp != NULL) {
 814                         if ((ring->poll_bytes -= pkt_length) <= 0) {
 815                                 /* have polled enough packets. */
 816                                 break;
 817                         } else {
 818                                 /* continue polling packets. */
 819                                 continue;
 820                         }
 821                 }
 822 
 823                 /*
 824                  * We're not in polling mode, so try to chain more messages
 825                  * or send the chain up according to pkt_burst.
 826                  */
 827                 if (++pkt_burst < lldev->config.rx_pkt_burst)
 828                         continue;
 829 
 830                 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
 831                         /* Replenish rx buffers */
 832                         xgell_rx_buffer_replenish_all(ring);
 833                 }
 834                 mutex_exit(&ring->bf_pool.pool_lock);
 835                 if (mp_head != NULL) {
 836                         mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
 837                             ring->ring_gen_num);
 838                 }
 839                 mp_head = mp_end  = NULL;
 840                 pkt_burst = 0;
 841                 mutex_enter(&ring->bf_pool.pool_lock);
 842 
 843         } while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
 844             XGE_HAL_OK);
 845 
 846         /*
 847          * Always call replenish_all to recycle rx_buffers.
 848          */
 849         xgell_rx_buffer_replenish_all(ring);
 850         mutex_exit(&ring->bf_pool.pool_lock);
 851 
 852         /*
 853          * If we're not in polling cycle, call mac_rx(), otherwise
 854          * just return while leaving packets chained to ring->poll_mp.
 855          */
 856         if ((ring->poll_mp == NULL) && (mp_head != NULL)) {
 857                 mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
 858                     ring->ring_gen_num);
 859         }
 860 
 861         return (XGE_HAL_OK);
 862 }
 863 
 864 mblk_t *
 865 xgell_rx_poll(void *arg, int bytes_to_pickup)
 866 {
 867         xgell_rx_ring_t *ring = (xgell_rx_ring_t *)arg;
 868         int got_rx = 0;
 869         mblk_t *mp;
 870 
 871         xge_debug_ll(XGE_TRACE, "xgell_rx_poll on ring %d", ring->index);
 872 
 873         ring->poll_mp = NULL;
 874         ring->poll_bytes = bytes_to_pickup;
 875         (void) xge_hal_device_poll_rx_channel(ring->channelh, &got_rx);
 876 
 877         mp = ring->poll_mp;
 878         ring->poll_bytes = -1;
 879         ring->polled_bytes += got_rx;
 880         ring->poll_mp = NULL;
 881 
 882         return (mp);
 883 }
 884 
 885 /*
 886  * xgell_xmit_compl
 887  *
 888  * If an interrupt was raised to indicate DMA complete of the Tx packet,
 889  * this function is called. It identifies the last TxD whose buffer was
 890  * freed and frees all skbs whose data have already DMA'ed into the NICs
 891  * internal memory.
 892  */
 893 static xge_hal_status_e
 894 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
 895     void *userdata)
 896 {
 897         xgell_tx_ring_t *ring = userdata;
 898         xgelldev_t *lldev = ring->lldev;
 899 
 900         do {
 901                 xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
 902                     xge_hal_fifo_dtr_private(dtr));
 903                 int i;
 904 
 905                 if (t_code) {
 906                         xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
 907                             " completed due to error t_code %01x", XGELL_IFNAME,
 908                             lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
 909 
 910                         (void) xge_hal_device_handle_tcode(channelh, dtr,
 911                             t_code);
 912                 }
 913 
 914                 for (i = 0; i < txd_priv->handle_cnt; i++) {
 915                         if (txd_priv->dma_handles[i] != NULL) {
 916                                 xge_assert(txd_priv->dma_handles[i]);
 917                                 (void) ddi_dma_unbind_handle(
 918                                     txd_priv->dma_handles[i]);
 919                                 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
 920                                 txd_priv->dma_handles[i] = 0;
 921                         }
 922                 }
 923                 txd_priv->handle_cnt = 0;
 924 
 925                 xge_hal_fifo_dtr_free(channelh, dtr);
 926 
 927                 if (txd_priv->mblk != NULL) {
 928                         freemsg(txd_priv->mblk);
 929                         txd_priv->mblk = NULL;
 930                 }
 931 
 932         } while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
 933             XGE_HAL_OK);
 934 
 935         if (ring->need_resched)
 936                 mac_tx_ring_update(lldev->mh, ring->ring_handle);
 937 
 938         return (XGE_HAL_OK);
 939 }
 940 
 941 mblk_t *
 942 xgell_ring_tx(void *arg, mblk_t *mp)
 943 {
 944         xgell_tx_ring_t *ring = (xgell_tx_ring_t *)arg;
 945         mblk_t *bp;
 946         xgelldev_t *lldev = ring->lldev;
 947         xge_hal_device_t *hldev = lldev->devh;
 948         xge_hal_status_e status;
 949         xge_hal_dtr_h dtr;
 950         xgell_txd_priv_t *txd_priv;
 951         uint32_t hckflags;
 952         uint32_t lsoflags;
 953         uint32_t mss;
 954         int handle_cnt, frag_cnt, ret, i, copied;
 955         boolean_t used_copy;
 956         uint64_t sent_bytes;
 957 
 958 _begin:
 959         handle_cnt = frag_cnt = 0;
 960         sent_bytes = 0;
 961 
 962         if (!lldev->is_initialized || lldev->in_reset)
 963                 return (mp);
 964 
 965         /*
 966          * If the free Tx dtrs count reaches the lower threshold,
 967          * inform the gld to stop sending more packets till the free
 968          * dtrs count exceeds higher threshold. Driver informs the
 969          * gld through gld_sched call, when the free dtrs count exceeds
 970          * the higher threshold.
 971          */
 972         if (xge_hal_channel_dtr_count(ring->channelh)
 973             <= XGELL_TX_LEVEL_LOW) {
 974                 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
 975                     "free descriptors count at low threshold %d",
 976                     XGELL_IFNAME, lldev->instance,
 977                     ((xge_hal_channel_t *)ring->channelh)->post_qid,
 978                     XGELL_TX_LEVEL_LOW);
 979                 goto _exit;
 980         }
 981 
 982         status = xge_hal_fifo_dtr_reserve(ring->channelh, &dtr);
 983         if (status != XGE_HAL_OK) {
 984                 switch (status) {
 985                 case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
 986                         xge_debug_ll(XGE_ERR,
 987                             "%s%d: channel %d is not ready.", XGELL_IFNAME,
 988                             lldev->instance,
 989                             ((xge_hal_channel_t *)
 990                             ring->channelh)->post_qid);
 991                         goto _exit;
 992                 case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
 993                         xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
 994                             " out of descriptors.", XGELL_IFNAME,
 995                             lldev->instance,
 996                             ((xge_hal_channel_t *)
 997                             ring->channelh)->post_qid);
 998                         goto _exit;
 999                 default:
1000                         return (mp);
1001                 }
1002         }
1003 
1004         txd_priv = xge_hal_fifo_dtr_private(dtr);
1005         txd_priv->mblk = mp;
1006 
1007         /*
1008          * VLAN tag should be passed down along with MAC header, so h/w needn't
1009          * do insertion.
1010          *
1011          * For NIC driver that has to strip and re-insert VLAN tag, the example
1012          * is the other implementation for xge. The driver can simple bcopy()
1013          * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
1014          * automatically, since it's impossible that GLD sends down mp(s) with
1015          * splited ether_vlan_header.
1016          *
1017          * struct ether_vlan_header *evhp;
1018          * uint16_t tci;
1019          *
1020          * evhp = (struct ether_vlan_header *)mp->b_rptr;
1021          * if (evhp->ether_tpid == htons(VLAN_TPID)) {
1022          *      tci = ntohs(evhp->ether_tci);
1023          *      (void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
1024          *          2 * ETHERADDRL);
1025          *      mp->b_rptr += VLAN_TAGSZ;
1026          *
1027          *      xge_hal_fifo_dtr_vlan_set(dtr, tci);
1028          * }
1029          */
1030 
1031         copied = 0;
1032         used_copy = B_FALSE;
1033         for (bp = mp; bp != NULL; bp = bp->b_cont) {
1034                 int mblen;
1035                 uint_t ncookies;
1036                 ddi_dma_cookie_t dma_cookie;
1037                 ddi_dma_handle_t dma_handle;
1038 
1039                 /* skip zero-length message blocks */
1040                 mblen = MBLKL(bp);
1041                 if (mblen == 0) {
1042                         continue;
1043                 }
1044 
1045                 sent_bytes += mblen;
1046 
1047                 /*
1048                  * Check the message length to decide to DMA or bcopy() data
1049                  * to tx descriptor(s).
1050                  */
1051                 if (mblen < lldev->config.tx_dma_lowat &&
1052                     (copied + mblen) < lldev->tx_copied_max) {
1053                         xge_hal_status_e rc;
1054                         rc = xge_hal_fifo_dtr_buffer_append(ring->channelh,
1055                             dtr, bp->b_rptr, mblen);
1056                         if (rc == XGE_HAL_OK) {
1057                                 used_copy = B_TRUE;
1058                                 copied += mblen;
1059                                 continue;
1060                         } else if (used_copy) {
1061                                 xge_hal_fifo_dtr_buffer_finalize(
1062                                     ring->channelh, dtr, frag_cnt++);
1063                                 used_copy = B_FALSE;
1064                         }
1065                 } else if (used_copy) {
1066                         xge_hal_fifo_dtr_buffer_finalize(ring->channelh,
1067                             dtr, frag_cnt++);
1068                         used_copy = B_FALSE;
1069                 }
1070 
1071                 ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
1072                     DDI_DMA_DONTWAIT, 0, &dma_handle);
1073                 if (ret != DDI_SUCCESS) {
1074                         xge_debug_ll(XGE_ERR,
1075                             "%s%d: can not allocate dma handle", XGELL_IFNAME,
1076                             lldev->instance);
1077                         goto _exit_cleanup;
1078                 }
1079 
1080                 ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
1081                     (caddr_t)bp->b_rptr, mblen,
1082                     DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
1083                     &dma_cookie, &ncookies);
1084 
1085                 switch (ret) {
1086                 case DDI_DMA_MAPPED:
1087                         /* everything's fine */
1088                         break;
1089 
1090                 case DDI_DMA_NORESOURCES:
1091                         xge_debug_ll(XGE_ERR,
1092                             "%s%d: can not bind dma address",
1093                             XGELL_IFNAME, lldev->instance);
1094                         ddi_dma_free_handle(&dma_handle);
1095                         goto _exit_cleanup;
1096 
1097                 case DDI_DMA_NOMAPPING:
1098                 case DDI_DMA_INUSE:
1099                 case DDI_DMA_TOOBIG:
1100                 default:
1101                         /* drop packet, don't retry */
1102                         xge_debug_ll(XGE_ERR,
1103                             "%s%d: can not map message buffer",
1104                             XGELL_IFNAME, lldev->instance);
1105                         ddi_dma_free_handle(&dma_handle);
1106                         goto _exit_cleanup;
1107                 }
1108 
1109                 if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
1110                         xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
1111                             "requested c:%d+f:%d", XGELL_IFNAME,
1112                             lldev->instance, ncookies, frag_cnt);
1113                         (void) ddi_dma_unbind_handle(dma_handle);
1114                         ddi_dma_free_handle(&dma_handle);
1115                         goto _exit_cleanup;
1116                 }
1117 
1118                 /* setup the descriptors for this data buffer */
1119                 while (ncookies) {
1120                         xge_hal_fifo_dtr_buffer_set(ring->channelh, dtr,
1121                             frag_cnt++, dma_cookie.dmac_laddress,
1122                             dma_cookie.dmac_size);
1123                         if (--ncookies) {
1124                                 ddi_dma_nextcookie(dma_handle, &dma_cookie);
1125                         }
1126 
1127                 }
1128 
1129                 txd_priv->dma_handles[handle_cnt++] = dma_handle;
1130 
1131                 if (bp->b_cont &&
1132                     (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
1133                     hldev->config.fifo.max_frags)) {
1134                         mblk_t *nmp;
1135 
1136                         xge_debug_ll(XGE_TRACE,
1137                             "too many FRAGs [%d], pull up them", frag_cnt);
1138 
1139                         if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
1140                                 /* Drop packet, don't retry */
1141                                 xge_debug_ll(XGE_ERR,
1142                                     "%s%d: can not pullup message buffer",
1143                                     XGELL_IFNAME, lldev->instance);
1144                                 goto _exit_cleanup;
1145                         }
1146                         freemsg(bp->b_cont);
1147                         bp->b_cont = nmp;
1148                 }
1149         }
1150 
1151         /* finalize unfinished copies */
1152         if (used_copy) {
1153                 xge_hal_fifo_dtr_buffer_finalize(ring->channelh, dtr,
1154                     frag_cnt++);
1155         }
1156 
1157         txd_priv->handle_cnt = handle_cnt;
1158 
1159         /*
1160          * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
1161          * do all necessary work.
1162          */
1163         mac_lso_get(mp, &mss, &lsoflags);
1164 
1165         if (lsoflags & HW_LSO) {
1166                 xge_assert((mss != 0) && (mss <= XGE_HAL_DEFAULT_MTU));
1167                 xge_hal_fifo_dtr_mss_set(dtr, mss);
1168         }
1169 
1170         mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &hckflags);
1171         if (hckflags & HCK_IPV4_HDRCKSUM) {
1172                 xge_hal_fifo_dtr_cksum_set_bits(dtr,
1173                     XGE_HAL_TXD_TX_CKO_IPV4_EN);
1174         }
1175         if (hckflags & HCK_FULLCKSUM) {
1176                 xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
1177                     XGE_HAL_TXD_TX_CKO_UDP_EN);
1178         }
1179 
1180         xge_hal_fifo_dtr_post(ring->channelh, dtr);
1181 
1182         /* Update per-ring tx statistics */
1183         atomic_add_64(&ring->tx_pkts, 1);
1184         atomic_add_64(&ring->tx_bytes, sent_bytes);
1185 
1186         return (NULL);
1187 
1188 _exit_cleanup:
1189         /*
1190          * Could not successfully transmit but have changed the message,
1191          * so just free it and return NULL
1192          */
1193         for (i = 0; i < handle_cnt; i++) {
1194                 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1195                 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1196                 txd_priv->dma_handles[i] = 0;
1197         }
1198 
1199         xge_hal_fifo_dtr_free(ring->channelh, dtr);
1200 
1201         freemsg(mp);
1202         return (NULL);
1203 
1204 _exit:
1205         ring->need_resched = B_TRUE;
1206         return (mp);
1207 }
1208 
1209 /*
1210  * xgell_ring_macaddr_init
1211  */
1212 static void
1213 xgell_rx_ring_maddr_init(xgell_rx_ring_t *ring)
1214 {
1215         int i;
1216         xgelldev_t *lldev = ring->lldev;
1217         xge_hal_device_t *hldev = lldev->devh;
1218         int slot_start;
1219 
1220         xge_debug_ll(XGE_TRACE, "%s", "xgell_rx_ring_maddr_init");
1221 
1222         ring->mmac.naddr = XGE_RX_MULTI_MAC_ADDRESSES_MAX;
1223         ring->mmac.naddrfree = ring->mmac.naddr;
1224 
1225         /*
1226          * For the default rx ring, the first MAC address is the factory one.
1227          * This will be set by the framework, so need to clear it for now.
1228          */
1229         (void) xge_hal_device_macaddr_clear(hldev, 0);
1230 
1231         /*
1232          * Read the MAC address Configuration Memory from HAL.
1233          * The first slot will hold a factory MAC address, contents in other
1234          * slots will be FF:FF:FF:FF:FF:FF.
1235          */
1236         slot_start = ring->index * 32;
1237         for (i = 0; i < ring->mmac.naddr; i++) {
1238                 (void) xge_hal_device_macaddr_get(hldev, slot_start + i,
1239                     ring->mmac.mac_addr + i);
1240                 ring->mmac.mac_addr_set[i] = B_FALSE;
1241         }
1242 }
1243 
1244 static int xgell_maddr_set(xgelldev_t *, int, uint8_t *);
1245 
1246 static int
1247 xgell_addmac(void *arg, const uint8_t *mac_addr)
1248 {
1249         xgell_rx_ring_t *ring = arg;
1250         xgelldev_t *lldev = ring->lldev;
1251         xge_hal_device_t *hldev = lldev->devh;
1252         int slot;
1253         int slot_start;
1254 
1255         xge_debug_ll(XGE_TRACE, "%s", "xgell_addmac");
1256 
1257         mutex_enter(&lldev->genlock);
1258 
1259         if (ring->mmac.naddrfree == 0) {
1260                 mutex_exit(&lldev->genlock);
1261                 return (ENOSPC);
1262         }
1263 
1264         /* First slot is for factory MAC address */
1265         for (slot = 0; slot < ring->mmac.naddr; slot++) {
1266                 if (ring->mmac.mac_addr_set[slot] == B_FALSE) {
1267                         break;
1268                 }
1269         }
1270 
1271         ASSERT(slot < ring->mmac.naddr);
1272 
1273         slot_start = ring->index * 32;
1274 
1275         if (xgell_maddr_set(lldev, slot_start + slot, (uint8_t *)mac_addr) !=
1276             0) {
1277                 mutex_exit(&lldev->genlock);
1278                 return (EIO);
1279         }
1280 
1281         /* Simply enable RTS for the whole section. */
1282         (void) xge_hal_device_rts_section_enable(hldev, slot_start + slot);
1283 
1284         /*
1285          * Read back the MAC address from HAL to keep the array up to date.
1286          */
1287         if (xge_hal_device_macaddr_get(hldev, slot_start + slot,
1288             ring->mmac.mac_addr + slot) != XGE_HAL_OK) {
1289                 (void) xge_hal_device_macaddr_clear(hldev, slot_start + slot);
1290                 return (EIO);
1291         }
1292 
1293         ring->mmac.mac_addr_set[slot] = B_TRUE;
1294         ring->mmac.naddrfree--;
1295 
1296         mutex_exit(&lldev->genlock);
1297 
1298         return (0);
1299 }
1300 
1301 static int
1302 xgell_remmac(void *arg, const uint8_t *mac_addr)
1303 {
1304         xgell_rx_ring_t *ring = arg;
1305         xgelldev_t *lldev = ring->lldev;
1306         xge_hal_device_t *hldev = lldev->devh;
1307         xge_hal_status_e status;
1308         int slot;
1309         int slot_start;
1310 
1311         xge_debug_ll(XGE_TRACE, "%s", "xgell_remmac");
1312 
1313         slot = xge_hal_device_macaddr_find(hldev, (uint8_t *)mac_addr);
1314         if (slot == -1)
1315                 return (EINVAL);
1316 
1317         slot_start = ring->index * 32;
1318 
1319         /*
1320          * Adjust slot to the offset in the MAC array of this ring (group).
1321          */
1322         slot -= slot_start;
1323 
1324         /*
1325          * Only can remove a pre-set MAC address for this ring (group).
1326          */
1327         if (slot < 0 || slot >= ring->mmac.naddr)
1328                 return (EINVAL);
1329 
1330 
1331         xge_assert(ring->mmac.mac_addr_set[slot]);
1332 
1333         mutex_enter(&lldev->genlock);
1334         if (!ring->mmac.mac_addr_set[slot]) {
1335                 mutex_exit(&lldev->genlock);
1336                 /*
1337                  * The result will be unexpected when reach here. WARNING!
1338                  */
1339                 xge_debug_ll(XGE_ERR,
1340                     "%s%d: caller is trying to remove an unset MAC address",
1341                     XGELL_IFNAME, lldev->instance);
1342                 return (ENXIO);
1343         }
1344 
1345         status = xge_hal_device_macaddr_clear(hldev, slot_start + slot);
1346         if (status != XGE_HAL_OK) {
1347                 mutex_exit(&lldev->genlock);
1348                 return (EIO);
1349         }
1350 
1351         ring->mmac.mac_addr_set[slot] = B_FALSE;
1352         ring->mmac.naddrfree++;
1353 
1354         /*
1355          * TODO: Disable MAC RTS if all addresses have been cleared.
1356          */
1357 
1358         /*
1359          * Read back the MAC address from HAL to keep the array up to date.
1360          */
1361         (void) xge_hal_device_macaddr_get(hldev, slot_start + slot,
1362             ring->mmac.mac_addr + slot);
1363         mutex_exit(&lldev->genlock);
1364 
1365         return (0);
1366 }
1367 
1368 /*
1369  * Temporarily calling hal function.
1370  *
1371  * With MSI-X implementation, no lock is needed, so that the interrupt
1372  * handling could be faster.
1373  */
1374 int
1375 xgell_rx_ring_intr_enable(mac_intr_handle_t ih)
1376 {
1377         xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
1378 
1379         mutex_enter(&ring->ring_lock);
1380         xge_hal_device_rx_channel_disable_polling(ring->channelh);
1381         mutex_exit(&ring->ring_lock);
1382 
1383         return (0);
1384 }
1385 
1386 int
1387 xgell_rx_ring_intr_disable(mac_intr_handle_t ih)
1388 {
1389         xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
1390 
1391         mutex_enter(&ring->ring_lock);
1392         xge_hal_device_rx_channel_enable_polling(ring->channelh);
1393         mutex_exit(&ring->ring_lock);
1394 
1395         return (0);
1396 }
1397 
1398 static int
1399 xgell_rx_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
1400 {
1401         xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
1402 
1403         rx_ring->ring_gen_num = mr_gen_num;
1404 
1405         return (0);
1406 }
1407 
1408 /*ARGSUSED*/
1409 static void
1410 xgell_rx_ring_stop(mac_ring_driver_t rh)
1411 {
1412 }
1413 
1414 /*ARGSUSED*/
1415 static int
1416 xgell_tx_ring_start(mac_ring_driver_t rh, uint64_t useless)
1417 {
1418         return (0);
1419 }
1420 
1421 /*ARGSUSED*/
1422 static void
1423 xgell_tx_ring_stop(mac_ring_driver_t rh)
1424 {
1425 }
1426 
1427 /*
1428  * Callback funtion for MAC layer to register all rings.
1429  *
1430  * Xframe hardware doesn't support grouping explicitly, so the driver needs
1431  * to pretend having resource groups. We may also optionally group all 8 rx
1432  * rings into a single group for increased scalability on CMT architectures,
1433  * or group one rx ring per group for maximum virtualization.
1434  *
1435  * TX grouping is actually done by framework, so, just register all TX
1436  * resources without grouping them.
1437  */
1438 void
1439 xgell_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
1440     const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
1441 {
1442         xgelldev_t *lldev = (xgelldev_t *)arg;
1443         mac_intr_t *mintr;
1444 
1445         switch (rtype) {
1446         case MAC_RING_TYPE_RX: {
1447                 xgell_rx_ring_t *rx_ring;
1448 
1449                 xge_assert(index < lldev->init_rx_rings);
1450                 xge_assert(rg_index < lldev->init_rx_groups);
1451 
1452                 /*
1453                  * Performance vs. Virtualization
1454                  */
1455                 if (lldev->init_rx_rings == lldev->init_rx_groups)
1456                         rx_ring = lldev->rx_ring + rg_index;
1457                 else
1458                         rx_ring = lldev->rx_ring + index;
1459 
1460                 rx_ring->ring_handle = rh;
1461 
1462                 infop->mri_driver = (mac_ring_driver_t)rx_ring;
1463                 infop->mri_start = xgell_rx_ring_start;
1464                 infop->mri_stop = xgell_rx_ring_stop;
1465                 infop->mri_poll = xgell_rx_poll;
1466                 infop->mri_stat = xgell_rx_ring_stat;
1467 
1468                 mintr = &infop->mri_intr;
1469                 mintr->mi_handle = (mac_intr_handle_t)rx_ring;
1470                 mintr->mi_enable = xgell_rx_ring_intr_enable;
1471                 mintr->mi_disable = xgell_rx_ring_intr_disable;
1472 
1473                 break;
1474         }
1475         case MAC_RING_TYPE_TX: {
1476                 xgell_tx_ring_t *tx_ring;
1477 
1478                 xge_assert(rg_index == -1);
1479 
1480                 xge_assert((index >= 0) && (index < lldev->init_tx_rings));
1481 
1482                 tx_ring = lldev->tx_ring + index;
1483                 tx_ring->ring_handle = rh;
1484 
1485                 infop->mri_driver = (mac_ring_driver_t)tx_ring;
1486                 infop->mri_start = xgell_tx_ring_start;
1487                 infop->mri_stop = xgell_tx_ring_stop;
1488                 infop->mri_tx = xgell_ring_tx;
1489                 infop->mri_stat = xgell_tx_ring_stat;
1490 
1491                 break;
1492         }
1493         default:
1494                 break;
1495         }
1496 }
1497 
1498 void
1499 xgell_fill_group(void *arg, mac_ring_type_t rtype, const int index,
1500     mac_group_info_t *infop, mac_group_handle_t gh)
1501 {
1502         xgelldev_t *lldev = (xgelldev_t *)arg;
1503 
1504         switch (rtype) {
1505         case MAC_RING_TYPE_RX: {
1506                 xgell_rx_ring_t *rx_ring;
1507 
1508                 xge_assert(index < lldev->init_rx_groups);
1509 
1510                 rx_ring = lldev->rx_ring + index;
1511 
1512                 rx_ring->group_handle = gh;
1513 
1514                 infop->mgi_driver = (mac_group_driver_t)rx_ring;
1515                 infop->mgi_start = NULL;
1516                 infop->mgi_stop = NULL;
1517                 infop->mgi_addmac = xgell_addmac;
1518                 infop->mgi_remmac = xgell_remmac;
1519                 infop->mgi_count = lldev->init_rx_rings / lldev->init_rx_groups;
1520 
1521                 break;
1522         }
1523         case MAC_RING_TYPE_TX:
1524                 xge_assert(0);
1525                 break;
1526         default:
1527                 break;
1528         }
1529 }
1530 
1531 /*
1532  * xgell_macaddr_set
1533  */
1534 static int
1535 xgell_maddr_set(xgelldev_t *lldev, int index, uint8_t *macaddr)
1536 {
1537         xge_hal_device_t *hldev = lldev->devh;
1538         xge_hal_status_e status;
1539 
1540         xge_debug_ll(XGE_TRACE, "%s", "xgell_maddr_set");
1541 
1542         xge_debug_ll(XGE_TRACE,
1543             "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
1544             macaddr[0], macaddr[1], macaddr[2],
1545             macaddr[3], macaddr[4], macaddr[5]);
1546 
1547         status = xge_hal_device_macaddr_set(hldev, index, (uchar_t *)macaddr);
1548 
1549         if (status != XGE_HAL_OK) {
1550                 xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
1551                     XGELL_IFNAME, lldev->instance);
1552                 return (EIO);
1553         }
1554 
1555         return (0);
1556 }
1557 
1558 /*
1559  * xgell_rx_dtr_term
1560  *
1561  * Function will be called by HAL to terminate all DTRs for
1562  * Ring(s) type of channels.
1563  */
1564 static void
1565 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1566     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1567 {
1568         xgell_rxd_priv_t *rxd_priv =
1569             ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
1570         xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
1571 
1572         if (state == XGE_HAL_DTR_STATE_POSTED) {
1573                 xgell_rx_ring_t *ring = rx_buffer->ring;
1574 
1575                 mutex_enter(&ring->bf_pool.pool_lock);
1576                 xge_hal_ring_dtr_free(channelh, dtrh);
1577                 xgell_rx_buffer_release(rx_buffer);
1578                 mutex_exit(&ring->bf_pool.pool_lock);
1579         }
1580 }
1581 
1582 /*
1583  * To open a rx ring.
1584  */
1585 static boolean_t
1586 xgell_rx_ring_open(xgell_rx_ring_t *rx_ring)
1587 {
1588         xge_hal_status_e status;
1589         xge_hal_channel_attr_t attr;
1590         xgelldev_t *lldev = rx_ring->lldev;
1591         xge_hal_device_t *hldev = lldev->devh;
1592 
1593         if (rx_ring->live)
1594                 return (B_TRUE);
1595 
1596         /* Create the buffer pool first */
1597         if (!xgell_rx_create_buffer_pool(rx_ring)) {
1598                 xge_debug_ll(XGE_ERR, "can not create buffer pool for ring: %d",
1599                     rx_ring->index);
1600                 return (B_FALSE);
1601         }
1602 
1603         /* Default ring initialization */
1604         attr.post_qid           = rx_ring->index;
1605         attr.compl_qid          = 0;
1606         attr.callback           = xgell_rx_1b_callback;
1607         attr.per_dtr_space      = sizeof (xgell_rxd_priv_t);
1608         attr.flags              = 0;
1609         attr.type               = XGE_HAL_CHANNEL_TYPE_RING;
1610         attr.dtr_init           = xgell_rx_dtr_replenish;
1611         attr.dtr_term           = xgell_rx_dtr_term;
1612         attr.userdata           = rx_ring;
1613 
1614         status = xge_hal_channel_open(lldev->devh, &attr, &rx_ring->channelh,
1615             XGE_HAL_CHANNEL_OC_NORMAL);
1616         if (status != XGE_HAL_OK) {
1617                 xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status "
1618                     " code %d", XGELL_IFNAME, lldev->instance, status);
1619                 (void) xgell_rx_destroy_buffer_pool(rx_ring);
1620                 return (B_FALSE);
1621         }
1622 
1623         xgell_rx_ring_maddr_init(rx_ring);
1624 
1625         mutex_init(&rx_ring->ring_lock, NULL, MUTEX_DRIVER,
1626             DDI_INTR_PRI(hldev->irqh));
1627 
1628         rx_ring->poll_bytes = -1;
1629         rx_ring->polled_bytes = 0;
1630         rx_ring->poll_mp = NULL;
1631         rx_ring->live = B_TRUE;
1632 
1633         xge_debug_ll(XGE_TRACE, "RX ring [%d] is opened successfully",
1634             rx_ring->index);
1635 
1636         return (B_TRUE);
1637 }
1638 
1639 static void
1640 xgell_rx_ring_close(xgell_rx_ring_t *rx_ring)
1641 {
1642         if (!rx_ring->live)
1643                 return;
1644         xge_hal_channel_close(rx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1645         rx_ring->channelh = NULL;
1646         /* This may not clean up all used buffers, driver will handle it */
1647         if (xgell_rx_destroy_buffer_pool(rx_ring))
1648                 rx_ring->live = B_FALSE;
1649 
1650         mutex_destroy(&rx_ring->ring_lock);
1651 }
1652 
1653 /*
1654  * xgell_rx_open
1655  * @lldev: the link layer object
1656  *
1657  * Initialize and open all RX channels.
1658  */
1659 static boolean_t
1660 xgell_rx_open(xgelldev_t *lldev)
1661 {
1662         xgell_rx_ring_t *rx_ring;
1663         int i;
1664 
1665         if (lldev->live_rx_rings != 0)
1666                 return (B_TRUE);
1667 
1668         lldev->live_rx_rings = 0;
1669 
1670         /*
1671          * Initialize all rings
1672          */
1673         for (i = 0; i < lldev->init_rx_rings; i++) {
1674                 rx_ring = &lldev->rx_ring[i];
1675                 rx_ring->index = i;
1676                 rx_ring->lldev = lldev;
1677                 rx_ring->live = B_FALSE;
1678 
1679                 if (!xgell_rx_ring_open(rx_ring))
1680                         return (B_FALSE);
1681 
1682                 lldev->live_rx_rings++;
1683         }
1684 
1685         return (B_TRUE);
1686 }
1687 
1688 static void
1689 xgell_rx_close(xgelldev_t *lldev)
1690 {
1691         xgell_rx_ring_t *rx_ring;
1692         int i;
1693 
1694         if (lldev->live_rx_rings == 0)
1695                 return;
1696 
1697         /*
1698          * Close all rx rings
1699          */
1700         for (i = 0; i < lldev->init_rx_rings; i++) {
1701                 rx_ring = &lldev->rx_ring[i];
1702 
1703                 if (rx_ring->live) {
1704                         xgell_rx_ring_close(rx_ring);
1705                         lldev->live_rx_rings--;
1706                 }
1707         }
1708 
1709         xge_assert(lldev->live_rx_rings == 0);
1710 }
1711 
1712 /*
1713  * xgell_tx_term
1714  *
1715  * Function will be called by HAL to terminate all DTRs for
1716  * Fifo(s) type of channels.
1717  */
1718 static void
1719 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1720     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1721 {
1722         xgell_txd_priv_t *txd_priv =
1723             ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
1724         mblk_t *mp = txd_priv->mblk;
1725         int i;
1726 
1727         /*
1728          * for Tx we must clean up the DTR *only* if it has been
1729          * posted!
1730          */
1731         if (state != XGE_HAL_DTR_STATE_POSTED) {
1732                 return;
1733         }
1734 
1735         for (i = 0; i < txd_priv->handle_cnt; i++) {
1736                 xge_assert(txd_priv->dma_handles[i]);
1737                 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1738                 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1739                 txd_priv->dma_handles[i] = 0;
1740         }
1741 
1742         xge_hal_fifo_dtr_free(channelh, dtrh);
1743 
1744         if (mp) {
1745                 txd_priv->mblk = NULL;
1746                 freemsg(mp);
1747         }
1748 }
1749 
1750 static boolean_t
1751 xgell_tx_ring_open(xgell_tx_ring_t *tx_ring)
1752 {
1753         xge_hal_status_e status;
1754         xge_hal_channel_attr_t attr;
1755         xgelldev_t *lldev = tx_ring->lldev;
1756 
1757         if (tx_ring->live)
1758                 return (B_TRUE);
1759 
1760         attr.post_qid           = tx_ring->index;
1761         attr.compl_qid          = 0;
1762         attr.callback           = xgell_xmit_compl;
1763         attr.per_dtr_space      = sizeof (xgell_txd_priv_t);
1764         attr.flags              = 0;
1765         attr.type               = XGE_HAL_CHANNEL_TYPE_FIFO;
1766         attr.dtr_init           = NULL;
1767         attr.dtr_term           = xgell_tx_term;
1768         attr.userdata           = tx_ring;
1769 
1770         status = xge_hal_channel_open(lldev->devh, &attr, &tx_ring->channelh,
1771             XGE_HAL_CHANNEL_OC_NORMAL);
1772         if (status != XGE_HAL_OK) {
1773                 xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel got status "
1774                     "code %d", XGELL_IFNAME, lldev->instance, status);
1775                 return (B_FALSE);
1776         }
1777 
1778         tx_ring->live = B_TRUE;
1779 
1780         return (B_TRUE);
1781 }
1782 
1783 static void
1784 xgell_tx_ring_close(xgell_tx_ring_t *tx_ring)
1785 {
1786         if (!tx_ring->live)
1787                 return;
1788         xge_hal_channel_close(tx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1789         tx_ring->live = B_FALSE;
1790 }
1791 
1792 /*
1793  * xgell_tx_open
1794  * @lldev: the link layer object
1795  *
1796  * Initialize and open all TX channels.
1797  */
1798 static boolean_t
1799 xgell_tx_open(xgelldev_t *lldev)
1800 {
1801         xgell_tx_ring_t *tx_ring;
1802         int i;
1803 
1804         if (lldev->live_tx_rings != 0)
1805                 return (B_TRUE);
1806 
1807         lldev->live_tx_rings = 0;
1808 
1809         /*
1810          * Enable rings by reserve sequence to match the h/w sequences.
1811          */
1812         for (i = 0; i < lldev->init_tx_rings; i++) {
1813                 tx_ring = &lldev->tx_ring[i];
1814                 tx_ring->index = i;
1815                 tx_ring->lldev = lldev;
1816                 tx_ring->live = B_FALSE;
1817 
1818                 if (!xgell_tx_ring_open(tx_ring))
1819                         return (B_FALSE);
1820 
1821                 lldev->live_tx_rings++;
1822         }
1823 
1824         return (B_TRUE);
1825 }
1826 
1827 static void
1828 xgell_tx_close(xgelldev_t *lldev)
1829 {
1830         xgell_tx_ring_t *tx_ring;
1831         int i;
1832 
1833         if (lldev->live_tx_rings == 0)
1834                 return;
1835 
1836         /*
1837          * Enable rings by reserve sequence to match the h/w sequences.
1838          */
1839         for (i = 0; i < lldev->init_tx_rings; i++) {
1840                 tx_ring = &lldev->tx_ring[i];
1841                 if (tx_ring->live) {
1842                         xgell_tx_ring_close(tx_ring);
1843                         lldev->live_tx_rings--;
1844                 }
1845         }
1846 }
1847 
1848 static int
1849 xgell_initiate_start(xgelldev_t *lldev)
1850 {
1851         xge_hal_status_e status;
1852         xge_hal_device_t *hldev = lldev->devh;
1853         int maxpkt = hldev->config.mtu;
1854 
1855         /* check initial mtu before enabling the device */
1856         status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
1857         if (status != XGE_HAL_OK) {
1858                 xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
1859                     XGELL_IFNAME, lldev->instance, maxpkt);
1860                 return (EINVAL);
1861         }
1862 
1863         /* set initial mtu before enabling the device */
1864         status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
1865         if (status != XGE_HAL_OK) {
1866                 xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
1867                     XGELL_IFNAME, lldev->instance, maxpkt);
1868                 return (EIO);
1869         }
1870 
1871         /* tune jumbo/normal frame UFC counters */
1872         hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_b =
1873             (maxpkt > XGE_HAL_DEFAULT_MTU) ?
1874             XGE_HAL_DEFAULT_RX_UFC_B_J :
1875             XGE_HAL_DEFAULT_RX_UFC_B_N;
1876 
1877         hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_c =
1878             (maxpkt > XGE_HAL_DEFAULT_MTU) ?
1879             XGE_HAL_DEFAULT_RX_UFC_C_J :
1880             XGE_HAL_DEFAULT_RX_UFC_C_N;
1881 
1882         /* now, enable the device */
1883         status = xge_hal_device_enable(lldev->devh);
1884         if (status != XGE_HAL_OK) {
1885                 xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
1886                     XGELL_IFNAME, lldev->instance);
1887                 return (EIO);
1888         }
1889 
1890         if (!xgell_rx_open(lldev)) {
1891                 status = xge_hal_device_disable(lldev->devh);
1892                 if (status != XGE_HAL_OK) {
1893                         u64 adapter_status;
1894                         (void) xge_hal_device_status(lldev->devh,
1895                             &adapter_status);
1896                         xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1897                             "the device. adaper status 0x%"PRIx64
1898                             " returned status %d",
1899                             XGELL_IFNAME, lldev->instance,
1900                             (uint64_t)adapter_status, status);
1901                 }
1902                 xgell_rx_close(lldev);
1903                 xge_os_mdelay(1500);
1904                 return (ENOMEM);
1905         }
1906 
1907         if (!xgell_tx_open(lldev)) {
1908                 status = xge_hal_device_disable(lldev->devh);
1909                 if (status != XGE_HAL_OK) {
1910                         u64 adapter_status;
1911                         (void) xge_hal_device_status(lldev->devh,
1912                             &adapter_status);
1913                         xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1914                             "the device. adaper status 0x%"PRIx64
1915                             " returned status %d",
1916                             XGELL_IFNAME, lldev->instance,
1917                             (uint64_t)adapter_status, status);
1918                 }
1919                 xgell_tx_close(lldev);
1920                 xgell_rx_close(lldev);
1921                 xge_os_mdelay(1500);
1922                 return (ENOMEM);
1923         }
1924 
1925         /* time to enable interrupts */
1926         (void) xge_enable_intrs(lldev);
1927         xge_hal_device_intr_enable(lldev->devh);
1928 
1929         lldev->is_initialized = 1;
1930 
1931         return (0);
1932 }
1933 
1934 static void
1935 xgell_initiate_stop(xgelldev_t *lldev)
1936 {
1937         xge_hal_status_e status;
1938 
1939         lldev->is_initialized = 0;
1940 
1941         status = xge_hal_device_disable(lldev->devh);
1942         if (status != XGE_HAL_OK) {
1943                 u64 adapter_status;
1944                 (void) xge_hal_device_status(lldev->devh, &adapter_status);
1945                 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1946                     "the device. adaper status 0x%"PRIx64" returned status %d",
1947                     XGELL_IFNAME, lldev->instance,
1948                     (uint64_t)adapter_status, status);
1949         }
1950         xge_hal_device_intr_disable(lldev->devh);
1951         /* disable OS ISR's */
1952         xge_disable_intrs(lldev);
1953 
1954         xge_debug_ll(XGE_TRACE, "%s",
1955             "waiting for device irq to become quiescent...");
1956         xge_os_mdelay(1500);
1957 
1958         xge_queue_flush(xge_hal_device_queue(lldev->devh));
1959 
1960         xgell_rx_close(lldev);
1961         xgell_tx_close(lldev);
1962 }
1963 
1964 /*
1965  * xgell_m_start
1966  * @arg: pointer to device private strucutre(hldev)
1967  *
1968  * This function is called by MAC Layer to enable the XFRAME
1969  * firmware to generate interrupts and also prepare the
1970  * driver to call mac_rx for delivering receive packets
1971  * to MAC Layer.
1972  */
1973 static int
1974 xgell_m_start(void *arg)
1975 {
1976         xgelldev_t *lldev = arg;
1977         xge_hal_device_t *hldev = lldev->devh;
1978         int ret;
1979 
1980         xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
1981             lldev->instance);
1982 
1983         mutex_enter(&lldev->genlock);
1984 
1985         if (lldev->is_initialized) {
1986                 xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
1987                     XGELL_IFNAME, lldev->instance);
1988                 mutex_exit(&lldev->genlock);
1989                 return (EINVAL);
1990         }
1991 
1992         hldev->terminating = 0;
1993         if (ret = xgell_initiate_start(lldev)) {
1994                 mutex_exit(&lldev->genlock);
1995                 return (ret);
1996         }
1997 
1998         lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
1999 
2000         mutex_exit(&lldev->genlock);
2001 
2002         return (0);
2003 }
2004 
2005 /*
2006  * xgell_m_stop
2007  * @arg: pointer to device private data (hldev)
2008  *
2009  * This function is called by the MAC Layer to disable
2010  * the XFRAME firmware for generating any interrupts and
2011  * also stop the driver from calling mac_rx() for
2012  * delivering data packets to the MAC Layer.
2013  */
2014 static void
2015 xgell_m_stop(void *arg)
2016 {
2017         xgelldev_t *lldev = arg;
2018         xge_hal_device_t *hldev = lldev->devh;
2019 
2020         xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
2021 
2022         mutex_enter(&lldev->genlock);
2023         if (!lldev->is_initialized) {
2024                 xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
2025                 mutex_exit(&lldev->genlock);
2026                 return;
2027         }
2028 
2029         xge_hal_device_terminating(hldev);
2030         xgell_initiate_stop(lldev);
2031 
2032         /* reset device */
2033         (void) xge_hal_device_reset(lldev->devh);
2034 
2035         mutex_exit(&lldev->genlock);
2036 
2037         if (lldev->timeout_id != 0) {
2038                 (void) untimeout(lldev->timeout_id);
2039         }
2040 
2041         xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
2042 }
2043 
2044 /*
2045  * xgell_onerr_reset
2046  * @lldev: pointer to xgelldev_t structure
2047  *
2048  * This function is called by HAL Event framework to reset the HW
2049  * This function is must be called with genlock taken.
2050  */
2051 int
2052 xgell_onerr_reset(xgelldev_t *lldev)
2053 {
2054         int rc = 0;
2055 
2056         if (!lldev->is_initialized) {
2057                 xge_debug_ll(XGE_ERR, "%s%d: can not reset",
2058                     XGELL_IFNAME, lldev->instance);
2059                 return (rc);
2060         }
2061 
2062         lldev->in_reset = 1;
2063         xgell_initiate_stop(lldev);
2064 
2065         /* reset device */
2066         (void) xge_hal_device_reset(lldev->devh);
2067 
2068         rc = xgell_initiate_start(lldev);
2069         lldev->in_reset = 0;
2070 
2071         return (rc);
2072 }
2073 
2074 /*
2075  * xgell_m_multicst
2076  * @arg: pointer to device private strucutre(hldev)
2077  * @add:
2078  * @mc_addr:
2079  *
2080  * This function is called by MAC Layer to enable or
2081  * disable device-level reception of specific multicast addresses.
2082  */
2083 static int
2084 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
2085 {
2086         xge_hal_status_e status;
2087         xgelldev_t *lldev = (xgelldev_t *)arg;
2088         xge_hal_device_t *hldev = lldev->devh;
2089 
2090         xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
2091 
2092         mutex_enter(&lldev->genlock);
2093 
2094         if (!lldev->is_initialized) {
2095                 xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
2096                     XGELL_IFNAME, lldev->instance);
2097                 mutex_exit(&lldev->genlock);
2098                 return (EIO);
2099         }
2100 
2101         /* FIXME: missing HAL functionality: enable_one() */
2102 
2103         status = (add) ?
2104             xge_hal_device_mcast_enable(hldev) :
2105             xge_hal_device_mcast_disable(hldev);
2106 
2107         if (status != XGE_HAL_OK) {
2108                 xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
2109                     add ? "enable" : "disable", status);
2110                 mutex_exit(&lldev->genlock);
2111                 return (EIO);
2112         }
2113 
2114         mutex_exit(&lldev->genlock);
2115 
2116         return (0);
2117 }
2118 
2119 
2120 /*
2121  * xgell_m_promisc
2122  * @arg: pointer to device private strucutre(hldev)
2123  * @on:
2124  *
2125  * This function is called by MAC Layer to enable or
2126  * disable the reception of all the packets on the medium
2127  */
2128 static int
2129 xgell_m_promisc(void *arg, boolean_t on)
2130 {
2131         xgelldev_t *lldev = (xgelldev_t *)arg;
2132         xge_hal_device_t *hldev = lldev->devh;
2133 
2134         mutex_enter(&lldev->genlock);
2135 
2136         xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
2137 
2138         if (!lldev->is_initialized) {
2139                 xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
2140                     XGELL_IFNAME, lldev->instance);
2141                 mutex_exit(&lldev->genlock);
2142                 return (EIO);
2143         }
2144 
2145         if (on) {
2146                 xge_hal_device_promisc_enable(hldev);
2147         } else {
2148                 xge_hal_device_promisc_disable(hldev);
2149         }
2150 
2151         mutex_exit(&lldev->genlock);
2152 
2153         return (0);
2154 }
2155 
2156 /*
2157  * xgell_m_stat
2158  * @arg: pointer to device private strucutre(hldev)
2159  *
2160  * This function is called by MAC Layer to get network statistics
2161  * from the driver.
2162  */
2163 static int
2164 xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
2165 {
2166         xge_hal_stats_hw_info_t *hw_info;
2167         xgelldev_t *lldev = (xgelldev_t *)arg;
2168         xge_hal_device_t *hldev = lldev->devh;
2169 
2170         xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
2171 
2172         mutex_enter(&lldev->genlock);
2173 
2174         if (!lldev->is_initialized) {
2175                 mutex_exit(&lldev->genlock);
2176                 return (EAGAIN);
2177         }
2178 
2179         if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
2180                 mutex_exit(&lldev->genlock);
2181                 return (EAGAIN);
2182         }
2183 
2184         switch (stat) {
2185         case MAC_STAT_IFSPEED:
2186                 *val = 10000000000ull; /* 10G */
2187                 break;
2188 
2189         case MAC_STAT_MULTIRCV:
2190                 *val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
2191                     hw_info->rmac_vld_mcst_frms;
2192                 break;
2193 
2194         case MAC_STAT_BRDCSTRCV:
2195                 *val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
2196                     hw_info->rmac_vld_bcst_frms;
2197                 break;
2198 
2199         case MAC_STAT_MULTIXMT:
2200                 *val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
2201                     hw_info->tmac_mcst_frms;
2202                 break;
2203 
2204         case MAC_STAT_BRDCSTXMT:
2205                 *val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
2206                     hw_info->tmac_bcst_frms;
2207                 break;
2208 
2209         case MAC_STAT_RBYTES:
2210                 *val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
2211                     hw_info->rmac_ttl_octets;
2212                 break;
2213 
2214         case MAC_STAT_NORCVBUF:
2215                 *val = hw_info->rmac_drop_frms;
2216                 break;
2217 
2218         case MAC_STAT_IERRORS:
2219                 *val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
2220                     hw_info->rmac_discarded_frms;
2221                 break;
2222 
2223         case MAC_STAT_OBYTES:
2224                 *val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
2225                     hw_info->tmac_ttl_octets;
2226                 break;
2227 
2228         case MAC_STAT_NOXMTBUF:
2229                 *val = hw_info->tmac_drop_frms;
2230                 break;
2231 
2232         case MAC_STAT_OERRORS:
2233                 *val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
2234                     hw_info->tmac_any_err_frms;
2235                 break;
2236 
2237         case MAC_STAT_IPACKETS:
2238                 *val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
2239                     hw_info->rmac_vld_frms;
2240                 break;
2241 
2242         case MAC_STAT_OPACKETS:
2243                 *val = ((u64) hw_info->tmac_frms_oflow << 32) |
2244                     hw_info->tmac_frms;
2245                 break;
2246 
2247         case ETHER_STAT_FCS_ERRORS:
2248                 *val = hw_info->rmac_fcs_err_frms;
2249                 break;
2250 
2251         case ETHER_STAT_TOOLONG_ERRORS:
2252                 *val = hw_info->rmac_long_frms;
2253                 break;
2254 
2255         case ETHER_STAT_LINK_DUPLEX:
2256                 *val = LINK_DUPLEX_FULL;
2257                 break;
2258 
2259         default:
2260                 mutex_exit(&lldev->genlock);
2261                 return (ENOTSUP);
2262         }
2263 
2264         mutex_exit(&lldev->genlock);
2265 
2266         return (0);
2267 }
2268 
2269 /*
2270  * Retrieve a value for one of the statistics for a particular rx ring
2271  */
2272 int
2273 xgell_rx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2274 {
2275         xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
2276 
2277         switch (stat) {
2278         case MAC_STAT_RBYTES:
2279                 *val = rx_ring->rx_bytes;
2280                 break;
2281 
2282         case MAC_STAT_IPACKETS:
2283                 *val = rx_ring->rx_pkts;
2284                 break;
2285 
2286         default:
2287                 *val = 0;
2288                 return (ENOTSUP);
2289         }
2290 
2291         return (0);
2292 }
2293 
2294 /*
2295  * Retrieve a value for one of the statistics for a particular tx ring
2296  */
2297 int
2298 xgell_tx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2299 {
2300         xgell_tx_ring_t *tx_ring = (xgell_tx_ring_t *)rh;
2301 
2302         switch (stat) {
2303         case MAC_STAT_OBYTES:
2304                 *val = tx_ring->tx_bytes;
2305                 break;
2306 
2307         case MAC_STAT_OPACKETS:
2308                 *val = tx_ring->tx_pkts;
2309                 break;
2310 
2311         default:
2312                 *val = 0;
2313                 return (ENOTSUP);
2314         }
2315 
2316         return (0);
2317 }
2318 
2319 /*
2320  * xgell_device_alloc - Allocate new LL device
2321  */
2322 int
2323 xgell_device_alloc(xge_hal_device_h devh,
2324     dev_info_t *dev_info, xgelldev_t **lldev_out)
2325 {
2326         xgelldev_t *lldev;
2327         xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
2328         int instance = ddi_get_instance(dev_info);
2329 
2330         *lldev_out = NULL;
2331 
2332         xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
2333             XGELL_IFNAME, instance);
2334 
2335         lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
2336 
2337         lldev->devh = hldev;
2338         lldev->instance = instance;
2339         lldev->dev_info = dev_info;
2340 
2341         *lldev_out = lldev;
2342 
2343         ddi_set_driver_private(dev_info, (caddr_t)hldev);
2344 
2345         return (DDI_SUCCESS);
2346 }
2347 
2348 /*
2349  * xgell_device_free
2350  */
2351 void
2352 xgell_device_free(xgelldev_t *lldev)
2353 {
2354         xge_debug_ll(XGE_TRACE, "freeing device %s%d",
2355             XGELL_IFNAME, lldev->instance);
2356 
2357         kmem_free(lldev, sizeof (xgelldev_t));
2358 }
2359 
2360 /*
2361  * xgell_ioctl
2362  */
2363 static void
2364 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
2365 {
2366         xgelldev_t *lldev = arg;
2367         struct iocblk *iocp;
2368         int err = 0;
2369         int cmd;
2370         int need_privilege = 1;
2371         int ret = 0;
2372 
2373 
2374         iocp = (struct iocblk *)mp->b_rptr;
2375         iocp->ioc_error = 0;
2376         cmd = iocp->ioc_cmd;
2377         xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
2378         switch (cmd) {
2379         case ND_GET:
2380                 need_privilege = 0;
2381                 /* FALLTHRU */
2382         case ND_SET:
2383                 break;
2384         default:
2385                 xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
2386                 miocnak(wq, mp, 0, EINVAL);
2387                 return;
2388         }
2389 
2390         if (need_privilege) {
2391                 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
2392                 if (err != 0) {
2393                         xge_debug_ll(XGE_ERR,
2394                             "drv_priv(): rejected cmd 0x%x, err %d",
2395                             cmd, err);
2396                         miocnak(wq, mp, 0, err);
2397                         return;
2398                 }
2399         }
2400 
2401         switch (cmd) {
2402         case ND_GET:
2403                 /*
2404                  * If nd_getset() returns B_FALSE, the command was
2405                  * not valid (e.g. unknown name), so we just tell the
2406                  * top-level ioctl code to send a NAK (with code EINVAL).
2407                  *
2408                  * Otherwise, nd_getset() will have built the reply to
2409                  * be sent (but not actually sent it), so we tell the
2410                  * caller to send the prepared reply.
2411                  */
2412                 ret = nd_getset(wq, lldev->ndp, mp);
2413                 xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl");
2414                 break;
2415 
2416         case ND_SET:
2417                 ret = nd_getset(wq, lldev->ndp, mp);
2418                 xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl");
2419                 break;
2420 
2421         default:
2422                 break;
2423         }
2424 
2425         if (ret == B_FALSE) {
2426                 xge_debug_ll(XGE_ERR,
2427                     "nd_getset(): rejected cmd 0x%x, err %d",
2428                     cmd, err);
2429                 miocnak(wq, mp, 0, EINVAL);
2430         } else {
2431                 mp->b_datap->db_type = iocp->ioc_error == 0 ?
2432                     M_IOCACK : M_IOCNAK;
2433                 qreply(wq, mp);
2434         }
2435 }
2436 
2437 
2438 static boolean_t
2439 xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
2440 {
2441         xgelldev_t *lldev = arg;
2442 
2443         xge_debug_ll(XGE_TRACE, "xgell_m_getcapab: %x", cap);
2444 
2445         switch (cap) {
2446         case MAC_CAPAB_HCKSUM: {
2447                 uint32_t *hcksum_txflags = cap_data;
2448                 *hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
2449                     HCKSUM_IPHDRCKSUM;
2450                 break;
2451         }
2452         case MAC_CAPAB_LSO: {
2453                 mac_capab_lso_t *cap_lso = cap_data;
2454 
2455                 if (lldev->config.lso_enable) {
2456                         cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
2457                         cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
2458                         break;
2459                 } else {
2460                         return (B_FALSE);
2461                 }
2462         }
2463         case MAC_CAPAB_RINGS: {
2464                 mac_capab_rings_t *cap_rings = cap_data;
2465 
2466                 switch (cap_rings->mr_type) {
2467                 case MAC_RING_TYPE_RX:
2468                         cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2469                         cap_rings->mr_rnum = lldev->init_rx_rings;
2470                         cap_rings->mr_gnum = lldev->init_rx_groups;
2471                         cap_rings->mr_rget = xgell_fill_ring;
2472                         cap_rings->mr_gget = xgell_fill_group;
2473                         break;
2474                 case MAC_RING_TYPE_TX:
2475                         cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
2476                         cap_rings->mr_rnum = lldev->init_tx_rings;
2477                         cap_rings->mr_gnum = 0;
2478                         cap_rings->mr_rget = xgell_fill_ring;
2479                         cap_rings->mr_gget = NULL;
2480                         break;
2481                 default:
2482                         break;
2483                 }
2484                 break;
2485         }
2486         default:
2487                 return (B_FALSE);
2488         }
2489         return (B_TRUE);
2490 }
2491 
2492 static int
2493 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2494 {
2495         xgelldev_t *lldev = (xgelldev_t *)cp;
2496         xge_hal_status_e status;
2497         int count = 0, retsize;
2498         char *buf;
2499 
2500         buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
2501         if (buf == NULL) {
2502                 return (ENOSPC);
2503         }
2504 
2505         status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
2506             buf, &retsize);
2507         if (status != XGE_HAL_OK) {
2508                 kmem_free(buf, XGELL_STATS_BUFSIZE);
2509                 xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
2510                 return (EINVAL);
2511         }
2512         count += retsize;
2513 
2514         status = xge_hal_aux_stats_rmac_read(lldev->devh,
2515             XGELL_STATS_BUFSIZE - count,
2516             buf+count, &retsize);
2517         if (status != XGE_HAL_OK) {
2518                 kmem_free(buf, XGELL_STATS_BUFSIZE);
2519                 xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
2520                 return (EINVAL);
2521         }
2522         count += retsize;
2523 
2524         status = xge_hal_aux_stats_pci_read(lldev->devh,
2525             XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2526         if (status != XGE_HAL_OK) {
2527                 kmem_free(buf, XGELL_STATS_BUFSIZE);
2528                 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
2529                 return (EINVAL);
2530         }
2531         count += retsize;
2532 
2533         status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
2534             XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2535         if (status != XGE_HAL_OK) {
2536                 kmem_free(buf, XGELL_STATS_BUFSIZE);
2537                 xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
2538                 return (EINVAL);
2539         }
2540         count += retsize;
2541 
2542         status = xge_hal_aux_stats_hal_read(lldev->devh,
2543             XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
2544         if (status != XGE_HAL_OK) {
2545                 kmem_free(buf, XGELL_STATS_BUFSIZE);
2546                 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
2547                 return (EINVAL);
2548         }
2549         count += retsize;
2550 
2551         *(buf + count - 1) = '\0'; /* remove last '\n' */
2552         (void) mi_mpprintf(mp, "%s", buf);
2553         kmem_free(buf, XGELL_STATS_BUFSIZE);
2554 
2555         return (0);
2556 }
2557 
2558 static int
2559 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2560 {
2561         xgelldev_t *lldev = (xgelldev_t *)cp;
2562         xge_hal_status_e status;
2563         int retsize;
2564         char *buf;
2565 
2566         buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
2567         if (buf == NULL) {
2568                 return (ENOSPC);
2569         }
2570         status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
2571             buf, &retsize);
2572         if (status != XGE_HAL_OK) {
2573                 kmem_free(buf, XGELL_PCICONF_BUFSIZE);
2574                 xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
2575                 return (EINVAL);
2576         }
2577         *(buf + retsize - 1) = '\0'; /* remove last '\n' */
2578         (void) mi_mpprintf(mp, "%s", buf);
2579         kmem_free(buf, XGELL_PCICONF_BUFSIZE);
2580 
2581         return (0);
2582 }
2583 
2584 static int
2585 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2586 {
2587         xgelldev_t *lldev = (xgelldev_t *)cp;
2588         xge_hal_status_e status;
2589         int retsize;
2590         char *buf;
2591 
2592         buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
2593         if (buf == NULL) {
2594                 return (ENOSPC);
2595         }
2596         status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
2597             buf, &retsize);
2598         if (status != XGE_HAL_OK) {
2599                 kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2600                 xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
2601                 return (EINVAL);
2602         }
2603         *(buf + retsize - 1) = '\0'; /* remove last '\n' */
2604         (void) mi_mpprintf(mp, "%s", buf);
2605         kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2606 
2607         return (0);
2608 }
2609 
2610 static unsigned long bar0_offset = 0x110; /* adapter_control */
2611 
2612 static int
2613 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2614 {
2615         xgelldev_t *lldev = (xgelldev_t *)cp;
2616         xge_hal_status_e status;
2617         int retsize;
2618         char *buf;
2619 
2620         buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2621         if (buf == NULL) {
2622                 return (ENOSPC);
2623         }
2624         status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
2625             XGELL_IOCTL_BUFSIZE, buf, &retsize);
2626         if (status != XGE_HAL_OK) {
2627                 kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2628                 xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
2629                 return (EINVAL);
2630         }
2631         *(buf + retsize - 1) = '\0'; /* remove last '\n' */
2632         (void) mi_mpprintf(mp, "%s", buf);
2633         kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2634 
2635         return (0);
2636 }
2637 
2638 static int
2639 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
2640 {
2641         unsigned long old_offset = bar0_offset;
2642         char *end;
2643 
2644         if (value && *value == '0' &&
2645             (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2646                 value += 2;
2647         }
2648 
2649         bar0_offset = mi_strtol(value, &end, 16);
2650         if (end == value) {
2651                 bar0_offset = old_offset;
2652                 return (EINVAL);
2653         }
2654 
2655         xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
2656 
2657         return (0);
2658 }
2659 
2660 static int
2661 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2662 {
2663         char *buf;
2664 
2665         buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2666         if (buf == NULL) {
2667                 return (ENOSPC);
2668         }
2669         (void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
2670         kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2671 
2672         return (0);
2673 }
2674 
2675 static int
2676 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2677     cred_t *credp)
2678 {
2679         int level;
2680         char *end;
2681 
2682         level = mi_strtol(value, &end, 10);
2683         if (level < XGE_NONE || level > XGE_ERR || end == value) {
2684                 return (EINVAL);
2685         }
2686 
2687         xge_hal_driver_debug_level_set(level);
2688 
2689         return (0);
2690 }
2691 
2692 static int
2693 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2694 {
2695         char *buf;
2696 
2697         buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2698         if (buf == NULL) {
2699                 return (ENOSPC);
2700         }
2701         (void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
2702             xge_hal_driver_debug_module_mask());
2703         kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2704 
2705         return (0);
2706 }
2707 
2708 static int
2709 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2710                             cred_t *credp)
2711 {
2712         u32 mask;
2713         char *end;
2714 
2715         if (value && *value == '0' &&
2716             (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2717                 value += 2;
2718         }
2719 
2720         mask = mi_strtol(value, &end, 16);
2721         if (end == value) {
2722                 return (EINVAL);
2723         }
2724 
2725         xge_hal_driver_debug_module_mask_set(mask);
2726 
2727         return (0);
2728 }
2729 
2730 static int
2731 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2732 {
2733         xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
2734         xge_hal_status_e status;
2735         int retsize;
2736         char *buf;
2737 
2738         buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
2739         if (buf == NULL) {
2740                 return (ENOSPC);
2741         }
2742         status = xge_hal_aux_device_config_read(lldev->devh,
2743             XGELL_DEVCONF_BUFSIZE, buf, &retsize);
2744         if (status != XGE_HAL_OK) {
2745                 kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2746                 xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
2747                     status);
2748                 return (EINVAL);
2749         }
2750         *(buf + retsize - 1) = '\0'; /* remove last '\n' */
2751         (void) mi_mpprintf(mp, "%s", buf);
2752         kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2753 
2754         return (0);
2755 }
2756 
2757 /*
2758  * xgell_device_register
2759  * @devh: pointer on HAL device
2760  * @config: pointer on this network device configuration
2761  * @ll_out: output pointer. Will be assigned to valid LL device.
2762  *
2763  * This function will allocate and register network device
2764  */
2765 int
2766 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
2767 {
2768         mac_register_t *macp = NULL;
2769         xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
2770 
2771         /*
2772          * Initialize some NDD interface for internal debug.
2773          */
2774         if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
2775             (caddr_t)lldev) == B_FALSE)
2776                 goto xgell_ndd_fail;
2777 
2778         if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
2779             (caddr_t)lldev) == B_FALSE)
2780                 goto xgell_ndd_fail;
2781 
2782         if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
2783             (caddr_t)lldev) == B_FALSE)
2784                 goto xgell_ndd_fail;
2785 
2786         if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
2787             (caddr_t)lldev) == B_FALSE)
2788                 goto xgell_ndd_fail;
2789 
2790         if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
2791             xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
2792                 goto xgell_ndd_fail;
2793 
2794         if (nd_load(&lldev->ndp, "debug_module_mask",
2795             xgell_debug_module_mask_get, xgell_debug_module_mask_set,
2796             (caddr_t)lldev) == B_FALSE)
2797                 goto xgell_ndd_fail;
2798 
2799         if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
2800             (caddr_t)lldev) == B_FALSE)
2801                 goto xgell_ndd_fail;
2802 
2803         bcopy(config, &lldev->config, sizeof (xgell_config_t));
2804 
2805         mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER,
2806             DDI_INTR_PRI(hldev->irqh));
2807 
2808         if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2809                 goto xgell_register_fail;
2810         macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2811         macp->m_driver = lldev;
2812         macp->m_dip = lldev->dev_info;
2813         macp->m_src_addr = hldev->macaddr[0];
2814         macp->m_callbacks = &xgell_m_callbacks;
2815         macp->m_min_sdu = 0;
2816         macp->m_max_sdu = hldev->config.mtu;
2817         macp->m_margin = VLAN_TAGSZ;
2818         macp->m_v12n = MAC_VIRT_LEVEL1;
2819 
2820         /*
2821          * MAC Registration.
2822          */
2823         if (mac_register(macp, &lldev->mh) != 0)
2824                 goto xgell_register_fail;
2825 
2826         /* Always free the macp after register */
2827         if (macp != NULL)
2828                 mac_free(macp);
2829 
2830         /* Calculate tx_copied_max here ??? */
2831         lldev->tx_copied_max = hldev->config.fifo.max_frags *
2832             hldev->config.fifo.alignment_size *
2833             hldev->config.fifo.max_aligned_frags;
2834 
2835         xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
2836             XGELL_IFNAME, lldev->instance);
2837 
2838         return (DDI_SUCCESS);
2839 
2840 xgell_ndd_fail:
2841         nd_free(&lldev->ndp);
2842         xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
2843         return (DDI_FAILURE);
2844 
2845 xgell_register_fail:
2846         if (macp != NULL)
2847                 mac_free(macp);
2848         nd_free(&lldev->ndp);
2849         mutex_destroy(&lldev->genlock);
2850         xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
2851         return (DDI_FAILURE);
2852 }
2853 
2854 /*
2855  * xgell_device_unregister
2856  * @devh: pointer on HAL device
2857  * @lldev: pointer to valid LL device.
2858  *
2859  * This function will unregister and free network device
2860  */
2861 int
2862 xgell_device_unregister(xgelldev_t *lldev)
2863 {
2864         if (mac_unregister(lldev->mh) != 0) {
2865                 xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
2866                     XGELL_IFNAME, lldev->instance);
2867                 return (DDI_FAILURE);
2868         }
2869 
2870         mutex_destroy(&lldev->genlock);
2871 
2872         nd_free(&lldev->ndp);
2873 
2874         xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
2875             XGELL_IFNAME, lldev->instance);
2876 
2877         return (DDI_SUCCESS);
2878 }