Home | History | Annotate | Download | only in drv
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  *  Copyright (c) 2002-2005 Neterion, Inc.
     29  *  All right Reserved.
     30  *
     31  *  FileName :    xge.c
     32  *
     33  *  Description:  Xge main Solaris specific initialization & routines
     34  *		  for upper layer driver
     35  *
     36  */
     37 #include "xgell.h"
     38 
     39 static int xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
     40 static int xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
     41 static int xge_quiesce(dev_info_t *dev_info);
     42 
     43 DDI_DEFINE_STREAM_OPS(xge_ops, nulldev, nulldev, xge_attach, xge_detach,
     44     nodev, NULL, D_MP, NULL, xge_quiesce);
     45 
     46 /* Standard Module linkage initialization for a Streams driver */
     47 extern struct mod_ops mod_driverops;
     48 
     49 static struct modldrv modldrv = {
     50 	&mod_driverops,		/* Type of module.  This one is a driver */
     51 	XGELL_DESC,		/* short description */
     52 	&xge_ops		/* driver specific ops */
     53 };
     54 
     55 static struct modlinkage modlinkage = {
     56 	MODREV_1, {(void *)&modldrv, NULL}
     57 };
     58 
     59 /* Xge device attributes */
     60 ddi_device_acc_attr_t xge_dev_attr = {
     61 	DDI_DEVICE_ATTR_V0,
     62 	DDI_NEVERSWAP_ACC,
     63 	DDI_STRICTORDER_ACC
     64 };
     65 ddi_device_acc_attr_t *p_xge_dev_attr = &xge_dev_attr;
     66 
     67 /*
     68  * xgell_callback_crit_err
     69  *
     70  * This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR.
     71  * Upper layer must analyze it based on %type.
     72  */
     73 static void
     74 xge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
     75 {
     76 	(void) xgell_onerr_reset(userdata);
     77 }
     78 
     79 /*
     80  * xge_xpak_alarm_log
     81  * This function called by HAL on XPAK alarms. Upper layer must log the msg
     82  * based on the xpak alarm type
     83  */
     84 static void
     85 xge_xpak_alarm_log(void *userdata, xge_hal_xpak_alarm_type_e type)
     86 {
     87 	switch (type) {
     88 	case XGE_HAL_XPAK_ALARM_EXCESS_TEMP:
     89 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
     90 		    "service. Excessive temperatures may result in "
     91 		    "premature transceiver failure \n");
     92 
     93 		break;
     94 	case XGE_HAL_XPAK_ALARM_EXCESS_BIAS_CURRENT:
     95 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
     96 		    "service Excessive bias currents may indicate "
     97 		    "imminent laser diode failure \n");
     98 
     99 		break;
    100 	case XGE_HAL_XPAK_ALARM_EXCESS_LASER_OUTPUT:
    101 		xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
    102 		    "service Excessive laser output power may saturate "
    103 		    "far-end receiver\n");
    104 
    105 		break;
    106 	default:
    107 		xge_debug_osdep(XGE_ERR, "%s", "Undefined Xpak Alarm");
    108 		break;
    109 	}
    110 
    111 }
    112 
    113 /*
    114  * xge_driver_init_hal
    115  *
    116  * To initialize HAL portion of driver.
    117  */
    118 static xge_hal_status_e
    119 xge_driver_init_hal(void)
    120 {
    121 	static xge_hal_driver_config_t driver_config;
    122 	xge_hal_uld_cbs_t uld_callbacks;
    123 
    124 	driver_config.queue_size_initial = 1;
    125 	driver_config.queue_size_max = 4;
    126 
    127 	uld_callbacks.link_up = xgell_callback_link_up;
    128 	uld_callbacks.link_down = xgell_callback_link_down;
    129 	uld_callbacks.crit_err = xge_callback_crit_err;
    130 	uld_callbacks.event = NULL;
    131 	uld_callbacks.event_queued = NULL;
    132 	uld_callbacks.before_device_poll = NULL;
    133 	uld_callbacks.after_device_poll = NULL;
    134 	uld_callbacks.sched_timer = NULL;
    135 	uld_callbacks.xpak_alarm_log = xge_xpak_alarm_log;
    136 
    137 	return (xge_hal_driver_initialize(&driver_config, &uld_callbacks));
    138 
    139 }
    140 
    141 /*
    142  * _init
    143  *
    144  * Solaris standard _init function for a device driver
    145  */
    146 int
    147 _init(void)
    148 {
    149 	int ret = 0;
    150 	xge_hal_status_e status;
    151 
    152 	status = xge_driver_init_hal();
    153 	if (status != XGE_HAL_OK) {
    154 		xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)",
    155 		    status);
    156 		return (EINVAL);
    157 	}
    158 
    159 	xge_hal_driver_debug_module_mask_set(0xffffffff);
    160 	xge_hal_driver_debug_level_set(XGE_TRACE);
    161 
    162 	mac_init_ops(&xge_ops, "xge");
    163 	if ((ret = mod_install(&modlinkage)) != 0) {
    164 		xge_hal_driver_terminate();
    165 		mac_fini_ops(&xge_ops);
    166 		xge_debug_osdep(XGE_ERR, "%s",
    167 		    "Unable to install the driver");
    168 		return (ret);
    169 	}
    170 
    171 	return (0);
    172 }
    173 
    174 /*
    175  * _fini
    176  *
    177  * Solaris standard _fini function for device driver
    178  */
    179 int
    180 _fini(void)
    181 {
    182 	int ret;
    183 
    184 	ret = mod_remove(&modlinkage);
    185 	if (ret == 0) {
    186 		xge_hal_driver_terminate();
    187 		mac_fini_ops(&xge_ops);
    188 	}
    189 
    190 	return (ret);
    191 }
    192 
    193 /*
    194  * _info
    195  *
    196  * Solaris standard _info function for device driver
    197  */
    198 int
    199 _info(struct modinfo *pModinfo)
    200 {
    201 	return (mod_info(&modlinkage, pModinfo));
    202 }
    203 
    204 /*
    205  * xge_isr
    206  * @arg: pointer to device private strucutre(hldev)
    207  *
    208  * This is the ISR scheduled by the OS to indicate to the
    209  * driver that the receive/transmit operation is completed.
    210  */
    211 /* ARGSUSED */
    212 static uint_t
    213 xge_isr(caddr_t arg0, caddr_t arg1)
    214 {
    215 	xge_hal_status_e status;
    216 	xge_hal_device_t *hldev = (xge_hal_device_t *)arg0;
    217 	xgelldev_t *lldev = xge_hal_device_private(hldev);
    218 
    219 	if (!lldev->is_initialized) {
    220 		return (DDI_INTR_UNCLAIMED);
    221 	}
    222 
    223 	status = xge_hal_device_handle_irq(hldev);
    224 
    225 	return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
    226 	    DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
    227 }
    228 
    229 /*
    230  * Interrupt handler for transmit when MSI-X interrupt mechasnism is used
    231  */
    232 /* ARGSUSED */
    233 static uint_t
    234 xge_fifo_msix_isr(caddr_t arg0, caddr_t arg1)
    235 {
    236 	int got_tx;
    237 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
    238 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
    239 
    240 	if (!lldev->is_initialized) {
    241 		return (DDI_INTR_UNCLAIMED);
    242 	}
    243 	(void) xge_hal_device_poll_tx_channel(channel, &got_tx);
    244 
    245 	return (DDI_INTR_CLAIMED);
    246 }
    247 
    248 /*
    249  * Interrupt handler for receive when MSI-X interrupt mechasnism is used
    250  */
    251 /* ARGSUSED */
    252 static uint_t
    253 xge_ring_msix_isr(caddr_t arg0, caddr_t arg1)
    254 {
    255 	int got_rx;
    256 	xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
    257 	xgelldev_t *lldev = xge_hal_device_private(channel->devh);
    258 
    259 	if (!lldev->is_initialized) {
    260 		return (DDI_INTR_UNCLAIMED);
    261 	}
    262 	(void) xge_hal_device_poll_rx_channel(channel, &got_rx);
    263 
    264 	return (DDI_INTR_CLAIMED);
    265 }
    266 
    267 /*
    268  * Configure single ring
    269  */
    270 static void
    271 xge_ring_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
    272     int index)
    273 {
    274 	char msg[MSG_SIZE];
    275 
    276 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_configured", index);
    277 	device_config->ring.queue[index].configured =
    278 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
    279 	    msg, index < XGELL_RX_RING_NUM_MAX ? 1 : 0);
    280 
    281 	/* no point to configure it further if unconfigured */
    282 	if (!device_config->ring.queue[index].configured)
    283 		return;
    284 
    285 #if defined(__sparc)
    286 	device_config->ring.queue[index].no_snoop_bits = 1;
    287 #endif
    288 
    289 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max", index);
    290 	device_config->ring.queue[index].max =
    291 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    292 	    dev_info, DDI_PROP_DONTPASS, msg,
    293 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    294 
    295 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_initial", index);
    296 	device_config->ring.queue[index].initial =
    297 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    298 	    dev_info, DDI_PROP_DONTPASS, msg,
    299 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    300 
    301 	if (device_config->ring.queue[index].initial ==
    302 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
    303 		device_config->ring.queue[index].initial =
    304 		    device_config->ring.queue[index].max =
    305 		    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS;
    306 	}
    307 
    308 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_buffer_mode", index);
    309 	device_config->ring.queue[index].buffer_mode =
    310 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    311 	    dev_info, DDI_PROP_DONTPASS, msg,
    312 	    XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
    313 
    314 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_dram_size_mb", index);
    315 	device_config->ring.queue[index].dram_size_mb =
    316 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    317 	    dev_info, DDI_PROP_DONTPASS, msg,
    318 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    319 
    320 	(void) xge_os_snprintf(msg, MSG_SIZE,
    321 	    "ring%d_backoff_interval_us", index);
    322 	device_config->ring.queue[index].backoff_interval_us =
    323 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    324 	    dev_info, DDI_PROP_DONTPASS, msg,
    325 	    XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
    326 
    327 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max_frm_len", index);
    328 	device_config->ring.queue[index].max_frm_len =
    329 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    330 	    dev_info, DDI_PROP_DONTPASS, msg,
    331 	    XGE_HAL_RING_USE_MTU);
    332 
    333 
    334 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_priority", index);
    335 	device_config->ring.queue[index].priority =
    336 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    337 	    dev_info, DDI_PROP_DONTPASS, msg,
    338 	    XGE_HAL_DEFAULT_RING_PRIORITY);
    339 
    340 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_a", index);
    341 	device_config->ring.queue[index].rti.urange_a =
    342 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    343 	    dev_info, DDI_PROP_DONTPASS, msg,
    344 	    XGE_HAL_DEFAULT_RX_URANGE_A);
    345 
    346 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_a", index);
    347 	device_config->ring.queue[index].rti.ufc_a =
    348 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    349 	    dev_info, DDI_PROP_DONTPASS, msg,
    350 	    XGE_HAL_DEFAULT_RX_UFC_A);
    351 
    352 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_b", index);
    353 	device_config->ring.queue[index].rti.urange_b =
    354 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    355 	    dev_info, DDI_PROP_DONTPASS, msg,
    356 	    XGE_HAL_DEFAULT_RX_URANGE_B);
    357 
    358 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_b", index);
    359 	device_config->ring.queue[index].rti.ufc_b =
    360 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    361 	    dev_info, DDI_PROP_DONTPASS, msg,
    362 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
    363 	    XGE_HAL_DEFAULT_RX_UFC_B_J:
    364 	    XGE_HAL_DEFAULT_RX_UFC_B_N);
    365 
    366 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_c", index);
    367 	device_config->ring.queue[index].rti.urange_c =
    368 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    369 	    dev_info, DDI_PROP_DONTPASS, msg,
    370 	    XGE_HAL_DEFAULT_RX_URANGE_C);
    371 
    372 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_c", index);
    373 	device_config->ring.queue[index].rti.ufc_c =
    374 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    375 	    dev_info, DDI_PROP_DONTPASS, msg,
    376 	    device_config->mtu > XGE_HAL_DEFAULT_MTU ?
    377 	    XGE_HAL_DEFAULT_RX_UFC_C_J:
    378 	    XGE_HAL_DEFAULT_RX_UFC_C_N);
    379 
    380 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_d", index);
    381 	device_config->ring.queue[index].rti.ufc_d =
    382 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    383 	    dev_info, DDI_PROP_DONTPASS, msg,
    384 	    XGE_HAL_DEFAULT_RX_UFC_D);
    385 
    386 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_val", index);
    387 	device_config->ring.queue[index].rti.timer_val_us =
    388 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    389 	    dev_info, DDI_PROP_DONTPASS, msg,
    390 	    XGE_HAL_DEFAULT_RX_TIMER_VAL);
    391 
    392 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_ac_en", index);
    393 	device_config->ring.queue[index].rti.timer_ac_en =
    394 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    395 	    dev_info, DDI_PROP_DONTPASS, msg,
    396 	    XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
    397 
    398 	(void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_indicate_max_pkts",
    399 	    index);
    400 	device_config->ring.queue[index].indicate_max_pkts =
    401 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    402 	    dev_info, DDI_PROP_DONTPASS, msg,
    403 	    (device_config->bimodal_interrupts ?
    404 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B :
    405 	    XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N));
    406 
    407 	/*
    408 	 * Enable RTH steering if needed HERE!!!!
    409 	 */
    410 	if (device_config->rth_en == XGE_HAL_RTH_ENABLE)
    411 		device_config->ring.queue[index].rth_en = 1;
    412 }
    413 
    414 /*
    415  * Configure single fifo
    416  */
    417 static void
    418 xge_fifo_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
    419     int index)
    420 {
    421 	char msg[MSG_SIZE];
    422 
    423 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_configured", index);
    424 	device_config->fifo.queue[index].configured =
    425 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
    426 	    msg, index < XGELL_TX_RING_NUM_MAX ? 1 : 0);
    427 
    428 	/* no point to configure it further */
    429 	if (!device_config->fifo.queue[index].configured)
    430 		return;
    431 
    432 #if defined(__sparc)
    433 	device_config->fifo.queue[index].no_snoop_bits = 1;
    434 #endif
    435 
    436 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_max", index);
    437 	device_config->fifo.queue[index].max = ddi_prop_get_int(DDI_DEV_T_ANY,
    438 	    dev_info, DDI_PROP_DONTPASS, msg,
    439 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    440 
    441 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_initial", index);
    442 	device_config->fifo.queue[index].initial =
    443 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    444 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    445 
    446 #if 0
    447 	if (device_config->fifo.queue[index].initial ==
    448 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
    449 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
    450 			device_config->fifo.queue[index].initial =
    451 			    device_config->fifo.queue[index].max =
    452 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
    453 		} else {
    454 			device_config->fifo.queue[index].initial =
    455 			    device_config->fifo.queue[index].max =
    456 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
    457 		}
    458 	}
    459 #else
    460 	if (device_config->fifo.queue[index].initial ==
    461 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
    462 		device_config->fifo.queue[index].max =
    463 		    device_config->fifo.queue[index].initial =
    464 		    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_A;
    465 	}
    466 #endif
    467 
    468 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_intr", index);
    469 	device_config->fifo.queue[index].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
    470 	    dev_info, DDI_PROP_DONTPASS, msg,
    471 	    XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
    472 
    473 	/*
    474 	 * TTI 0 configuration
    475 	 */
    476 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_enable", index);
    477 	device_config->fifo.queue[index].tti[index].enabled = ddi_prop_get_int(
    478 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 1);
    479 
    480 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_a", index);
    481 	device_config->fifo.queue[index].tti[index].urange_a = ddi_prop_get_int(
    482 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    483 	    XGE_HAL_DEFAULT_TX_URANGE_A);
    484 
    485 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_a", index);
    486 	device_config->fifo.queue[index].tti[index].ufc_a = ddi_prop_get_int(
    487 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    488 	    XGE_HAL_DEFAULT_TX_UFC_A);
    489 
    490 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_b", index);
    491 	device_config->fifo.queue[index].tti[index].urange_b = ddi_prop_get_int(
    492 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    493 	    XGE_HAL_DEFAULT_TX_URANGE_B);
    494 
    495 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_b", index);
    496 	device_config->fifo.queue[index].tti[index].ufc_b = ddi_prop_get_int(
    497 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    498 	    XGE_HAL_DEFAULT_TX_UFC_B);
    499 
    500 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_c", index);
    501 	device_config->fifo.queue[index].tti[index].urange_c = ddi_prop_get_int(
    502 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    503 	    XGE_HAL_DEFAULT_TX_URANGE_C);
    504 
    505 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_c", index);
    506 	device_config->fifo.queue[index].tti[index].ufc_c = ddi_prop_get_int(
    507 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    508 	    XGE_HAL_DEFAULT_TX_UFC_C);
    509 
    510 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_d", index);
    511 	device_config->fifo.queue[index].tti[index].ufc_d = ddi_prop_get_int(
    512 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    513 	    XGE_HAL_DEFAULT_TX_UFC_D);
    514 
    515 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_timer_ac_en", index);
    516 	device_config->fifo.queue[index].tti[index].timer_ac_en =
    517 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    518 	    XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
    519 
    520 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_val", index);
    521 	device_config->fifo.queue[index].tti[index].timer_val_us =
    522 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    523 	    XGE_HAL_DEFAULT_TX_TIMER_VAL);
    524 
    525 	(void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_ci_en", index);
    526 	device_config->fifo.queue[index].tti[index].timer_ci_en =
    527 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
    528 	    XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
    529 }
    530 
    531 /*
    532  * xge_configuration_init
    533  * @device_config: pointer to xge_hal_device_config_t
    534  *
    535  * This function will lookup properties from .conf file to init
    536  * the configuration data structure. If a property is not in .conf
    537  * file, the default value should be set.
    538  */
    539 static void
    540 xge_configuration_init(dev_info_t *dev_info,
    541     xge_hal_device_config_t *device_config, xgell_config_t *xgell_config)
    542 {
    543 	int i, rings_configured = 0, fifos_configured = 0;
    544 
    545 	/*
    546 	 * Initialize link layer configuration first
    547 	 */
    548 	xgell_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
    549 	    DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT);
    550 	xgell_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY,
    551 	    dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst", XGELL_RX_PKT_BURST);
    552 	xgell_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
    553 	    DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT);
    554 	xgell_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
    555 	    DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
    556 	xgell_config->msix_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
    557 	    DDI_PROP_DONTPASS, "msix_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
    558 
    559 	xgell_config->grouping = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
    560 	    DDI_PROP_DONTPASS, "grouping", XGELL_CONF_GROUP_POLICY_DEFAULT);
    561 
    562 	switch (xgell_config->grouping) {
    563 	case XGELL_CONF_GROUP_POLICY_VIRT:
    564 		/*
    565 		 * Enable layer 2 steering for better virtualization
    566 		 */
    567 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
    568 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_ENABLE;
    569 		break;
    570 	case XGELL_CONF_GROUP_POLICY_PERF:
    571 		/*
    572 		 * Configure layer 4 RTH to hashing inbound traffic
    573 		 */
    574 		device_config->rth_en = XGE_HAL_RTH_ENABLE;
    575 		device_config->rth_bucket_size = XGE_HAL_MAX_RTH_BUCKET_SIZE;
    576 		device_config->rth_spdm_en = XGE_HAL_RTH_SPDM_DISABLE;
    577 		device_config->rth_spdm_use_l4 = XGE_HAL_RTH_SPDM_USE_L4;
    578 
    579 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
    580 		break;
    581 	case XGELL_CONF_GROUP_POLICY_BASIC:
    582 	default:
    583 		/*
    584 		 * Disable both RTS and RTH for single ring configuration
    585 		 */
    586 		device_config->rth_en = XGE_HAL_RTH_DISABLE;
    587 		device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
    588 		break;
    589 	}
    590 
    591 	/*
    592 	 * Initialize common properties
    593 	 */
    594 	device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
    595 	    dev_info, DDI_PROP_DONTPASS, "default_mtu",
    596 	    XGE_HAL_DEFAULT_INITIAL_MTU);
    597 	device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
    598 	    dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
    599 	    XGE_HAL_DEFAULT_ISR_POLLING_CNT);
    600 	device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
    601 	    dev_info, DDI_PROP_DONTPASS, "latency_timer",
    602 	    XGE_HAL_DEFAULT_LATENCY_TIMER);
    603 	device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
    604 	    dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
    605 	    XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
    606 	device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
    607 	    dev_info, DDI_PROP_DONTPASS, "mmrb_count",
    608 	    XGE_HAL_DEFAULT_MMRB_COUNT);
    609 	device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
    610 	    dev_info, DDI_PROP_DONTPASS, "shared_splits",
    611 	    XGE_HAL_DEFAULT_SHARED_SPLITS);
    612 	device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
    613 	    dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
    614 	    XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
    615 	device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
    616 	    dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
    617 	    XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
    618 	device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
    619 	    dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz",
    620 	    XGE_HAL_DEFAULT_USE_HARDCODE);
    621 
    622 	/*
    623 	 * Initialize ring properties
    624 	 */
    625 	device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
    626 	    dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
    627 	    XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
    628 	device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
    629 
    630 	/*
    631 	 * Bimodal Interrupts - TTI 56 configuration
    632 	 */
    633 	device_config->bimodal_interrupts = ddi_prop_get_int(
    634 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts",
    635 	    XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS);
    636 	device_config->bimodal_timer_lo_us = ddi_prop_get_int(
    637 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us",
    638 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US);
    639 	device_config->bimodal_timer_hi_us = ddi_prop_get_int(
    640 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us",
    641 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US);
    642 
    643 	/*
    644 	 * Go through all possibly configured rings. Each ring could be
    645 	 * configured individually. To enable/disable specific ring, just
    646 	 * set ring->configured = [1|0].
    647 	 *
    648 	 * By default *all* rings enabled.
    649 	 */
    650 	for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
    651 		xge_ring_config(dev_info, device_config, i);
    652 		if (device_config->ring.queue[i].configured)
    653 			rings_configured++;
    654 	}
    655 
    656 	/*
    657 	 * Initialize mac properties
    658 	 */
    659 	device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
    660 	    dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
    661 	    XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
    662 	device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
    663 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
    664 	    XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
    665 	device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
    666 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
    667 	    1); /* HAL never provide a good named macro */
    668 	device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY,
    669 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en",
    670 	    XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS);
    671 	device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY,
    672 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en",
    673 	    XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS);
    674 	device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
    675 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
    676 	    XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
    677 	device_config->mac.mc_pause_threshold_q0q3 =
    678 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    679 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
    680 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
    681 	device_config->mac.mc_pause_threshold_q4q7 =
    682 	    ddi_prop_get_int(DDI_DEV_T_ANY,
    683 	    dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
    684 	    XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
    685 
    686 	/*
    687 	 * Initialize fifo properties
    688 	 */
    689 	device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
    690 	    dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
    691 	    XGE_HAL_DEFAULT_FIFO_FRAGS);
    692 	device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
    693 	    dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
    694 	    XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
    695 	device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
    696 	    dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
    697 	    XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
    698 #ifdef XGE_HAL_ALIGN_XMIT
    699 	device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY,
    700 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size",
    701 	    XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE);
    702 	device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
    703 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags",
    704 	    XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS);
    705 #endif
    706 
    707 	/*
    708 	 * Go through all possibly configured fifos. Each fifo could be
    709 	 * configured individually. To enable/disable specific fifo, just
    710 	 * set fifo->configured = [0|1].
    711 	 *
    712 	 * By default *all* fifos enabled.
    713 	 */
    714 	for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
    715 		xge_fifo_config(dev_info, device_config, i);
    716 		if (device_config->fifo.queue[i].configured)
    717 			fifos_configured++;
    718 	}
    719 
    720 	/*
    721 	 * Initialize errors dumping
    722 	 */
    723 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
    724 	    dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
    725 	    0);
    726 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
    727 	    dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
    728 	    0);
    729 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
    730 	    dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
    731 	    0);
    732 
    733 	/*
    734 	 * LRO tunables
    735 	 */
    736 	device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY,
    737 	    dev_info, DDI_PROP_DONTPASS, "lro_sg_size",
    738 	    XGE_HAL_DEFAULT_LRO_SG_SIZE);
    739 	device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY,
    740 	    dev_info, DDI_PROP_DONTPASS, "lro_frm_len",
    741 	    XGE_HAL_DEFAULT_LRO_FRM_LEN);
    742 
    743 	/*
    744 	 * Initialize other link layer configuration first
    745 	 */
    746 	xgell_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
    747 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
    748 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
    749 	    XGELL_RX_BUFFER_TOTAL);
    750 	xgell_config->rx_buffer_total += XGELL_RX_BUFFER_RECYCLE_CACHE;
    751 	xgell_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
    752 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
    753 	    device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
    754 	    XGELL_RX_BUFFER_POST_HIWAT);
    755 	xgell_config->rx_buffer_post_hiwat += XGELL_RX_BUFFER_RECYCLE_CACHE;
    756 }
    757 
    758 /*
    759  * xge_alloc_intrs:
    760  *
    761  * Allocate FIXED or MSIX interrupts.
    762  */
    763 static int
    764 xge_alloc_intrs(xgelldev_t *lldev)
    765 {
    766 	dev_info_t *dip = lldev->dev_info;
    767 	int avail, actual, count = 0;
    768 	int i, intr_behavior, ret;
    769 
    770 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX) {
    771 		intr_behavior = DDI_INTR_ALLOC_STRICT;
    772 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
    773 		    DDI_PROP_CANSLEEP, "#msix-request", NULL, 0);
    774 	} else {
    775 		intr_behavior = DDI_INTR_ALLOC_NORMAL;
    776 	}
    777 
    778 	/* Get number of interrupts */
    779 	ret = ddi_intr_get_nintrs(dip, lldev->intr_type, &count);
    780 	if ((ret != DDI_SUCCESS) || (count == 0)) {
    781 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_nintrs() failed, "
    782 		    "ret: %d, count: %d", ret, count);
    783 
    784 		goto _err_exit0;
    785 	}
    786 
    787 	/* Get number of available interrupts */
    788 	ret = ddi_intr_get_navail(dip, lldev->intr_type, &avail);
    789 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
    790 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_navail() failure, "
    791 		    "ret: %d, avail: %d", ret, avail);
    792 
    793 		goto _err_exit0;
    794 	}
    795 
    796 	if (avail < lldev->intr_cnt) {
    797 		xge_debug_osdep(XGE_ERR, "%d interrupts wanted while only "
    798 		    "%d available", lldev->intr_cnt, avail);
    799 		goto _err_exit0;
    800 	}
    801 
    802 	/* Allocate an array of interrupt handles */
    803 	lldev->intr_table_size = lldev->intr_cnt * sizeof (ddi_intr_handle_t);
    804 	lldev->intr_table = kmem_alloc(lldev->intr_table_size, KM_SLEEP);
    805 
    806 	/* Call ddi_intr_alloc() */
    807 	ret = ddi_intr_alloc(dip, lldev->intr_table, lldev->intr_type, 0,
    808 	    lldev->intr_cnt, &actual, intr_behavior);
    809 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
    810 		xge_debug_osdep(XGE_ERR, "ddi_intr_alloc() failed %d", ret);
    811 		goto _err_exit1;
    812 	}
    813 
    814 	xge_debug_osdep(XGE_TRACE, "%s: Requested: %d, Granted: %d",
    815 	    lldev->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X" :
    816 	    "IRQA", count, actual);
    817 
    818 	if (lldev->intr_cnt != actual) {
    819 		xge_debug_osdep(XGE_ERR, "Not enough resources granted");
    820 		goto _err_exit2;
    821 	}
    822 
    823 	/*
    824 	 * Get priority for first msi, assume remaining are all the same
    825 	 */
    826 	if ((ret = ddi_intr_get_pri(lldev->intr_table[0], &lldev->intr_pri)) !=
    827 	    DDI_SUCCESS) {
    828 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_pri() failed %d", ret);
    829 		goto _err_exit2;
    830 	}
    831 
    832 	return (DDI_SUCCESS);
    833 
    834 _err_exit2:
    835 	/* Free already allocated intr */
    836 	for (i = 0; i < actual; i++) {
    837 		(void) ddi_intr_free(lldev->intr_table[i]);
    838 	}
    839 _err_exit1:
    840 	kmem_free(lldev->intr_table, lldev->intr_table_size);
    841 	lldev->intr_table = NULL;
    842 _err_exit0:
    843 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
    844 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
    845 	return (DDI_FAILURE);
    846 }
    847 
    848 /*
    849  * xge_free_intrs:
    850  *
    851  * Free previously allocated interrupts.
    852  */
    853 static void
    854 xge_free_intrs(xgelldev_t *lldev)
    855 {
    856 	int i;
    857 	dev_info_t *dip = lldev->dev_info;
    858 
    859 	/* Free already allocated intr */
    860 	for (i = 0; i < lldev->intr_cnt; i++) {
    861 		(void) ddi_intr_free(lldev->intr_table[i]);
    862 	}
    863 	kmem_free(lldev->intr_table, lldev->intr_table_size);
    864 	lldev->intr_table = NULL;
    865 
    866 	if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
    867 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
    868 }
    869 
    870 /*
    871  * xge_add_intrs:
    872  *
    873  * Register FIXED or MSI interrupts.
    874  */
    875 int
    876 xge_add_intrs(xgelldev_t *lldev)
    877 {
    878 	int i, ret;
    879 	xge_hal_device_t *hldev = lldev->devh;
    880 	xge_hal_device_config_t *hal_conf = &hldev->config;
    881 	xge_hal_ring_config_t *ring_conf = &hal_conf->ring;
    882 	xge_hal_fifo_config_t *fifo_conf = &hal_conf->fifo;
    883 	xge_list_t *item;
    884 	int msix_idx = 1; /* 0 by default is reserved for Alarms. */
    885 	xge_hal_channel_t *assigned[XGELL_RX_RING_NUM_MAX +
    886 	    XGELL_TX_RING_NUM_MAX + 1];
    887 
    888 	xge_assert(lldev->intr_table != NULL);
    889 	switch (lldev->intr_type) {
    890 	case DDI_INTR_TYPE_FIXED:
    891 		ret = ddi_intr_add_handler(lldev->intr_table[0],
    892 		    (ddi_intr_handler_t *)xge_isr,
    893 		    (caddr_t)hldev, 0);
    894 		if (ret != DDI_SUCCESS) {
    895 			xge_debug_osdep(XGE_ERR, "ddi_intr_add_handler(FIXED)"
    896 			    "failed %d", ret);
    897 			return (DDI_FAILURE);
    898 		}
    899 		break;
    900 
    901 	case DDI_INTR_TYPE_MSIX:
    902 		i = 0;
    903 		xge_list_for_each(item, &hldev->free_channels) {
    904 			xge_hal_channel_t *channel = xge_container_of(item,
    905 			    xge_hal_channel_t, item);
    906 			i = channel->post_qid;
    907 			if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
    908 				if (fifo_conf->queue[i].configured) {
    909 					assigned[msix_idx] = channel;
    910 					msix_idx++;
    911 				}
    912 			} else {
    913 				if (ring_conf->queue[i].configured) {
    914 					assigned[msix_idx] = channel;
    915 					msix_idx++;
    916 				}
    917 			}
    918 		}
    919 		for (i = 0; i < lldev->intr_cnt; i++) {
    920 			uint_t (*intr)(caddr_t, caddr_t);
    921 			caddr_t intr_arg;
    922 
    923 			/* partition MSIX vectors */
    924 			if (i == 0) {
    925 				intr = xge_isr;
    926 				intr_arg = (caddr_t)hldev;
    927 				xge_debug_osdep(XGE_TRACE,
    928 				    "Channel-A: using MSI-X #0");
    929 			} else if (assigned[i] && assigned[i]->type ==
    930 			    XGE_HAL_CHANNEL_TYPE_FIFO) {
    931 				intr = xge_fifo_msix_isr;
    932 				intr_arg = (caddr_t)assigned[i];
    933 				xge_debug_osdep(XGE_TRACE, "Channel-Tx%d"
    934 				    "using MSI-X #%d",
    935 				    assigned[i]->post_qid, i);
    936 			} else if (assigned[i] && assigned[i]->type ==
    937 			    XGE_HAL_CHANNEL_TYPE_RING) {
    938 				intr = xge_ring_msix_isr;
    939 				intr_arg = (caddr_t)assigned[i];
    940 				xge_debug_osdep(XGE_TRACE, "Channel-Rx%d: "
    941 				    "using MSI-X #%d",
    942 				    assigned[i]->post_qid, i);
    943 			}
    944 			ret = ddi_intr_add_handler(lldev->intr_table[i], intr,
    945 			    intr_arg, (caddr_t)(uintptr_t)i);
    946 			if (ret != DDI_SUCCESS) {
    947 				int j;
    948 				xge_debug_osdep(XGE_ERR,
    949 				    "ddi_intr_add_handler()"
    950 				    " failed %d", ret);
    951 				for (j = 0; j < i; j++) {
    952 					(void) ddi_intr_remove_handler(
    953 					    lldev->intr_table[j]);
    954 				}
    955 				return (DDI_FAILURE);
    956 			}
    957 		}
    958 
    959 		for (i = 1; i < msix_idx; i++)
    960 			(void) xge_hal_channel_msix_set(assigned[i], i);
    961 		break;
    962 
    963 	default:
    964 		break;
    965 	}
    966 	ret = ddi_intr_get_cap(lldev->intr_table[0], &lldev->intr_cap);
    967 	if (ret != DDI_SUCCESS) {
    968 		xge_debug_osdep(XGE_ERR, "ddi_intr_get_cap() failed %d", ret);
    969 		for (i = 0; i < lldev->intr_cnt; i++) {
    970 			(void) ddi_intr_remove_handler(lldev->intr_table[i]);
    971 		}
    972 		return (DDI_FAILURE);
    973 	}
    974 	return (DDI_SUCCESS);
    975 }
    976 
    977 
    978 /*
    979  * xge_enable_intrs:
    980  *
    981  * Enable FIXED or MSI interrupts
    982  */
    983 int
    984 xge_enable_intrs(xgelldev_t *lldev)
    985 {
    986 	int ret, i;
    987 
    988 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
    989 		/* Call ddi_intr_block_enable() for MSI(X) interrupts */
    990 		if ((ret = ddi_intr_block_enable(lldev->intr_table,
    991 		    lldev->intr_cnt)) != DDI_SUCCESS) {
    992 			xge_debug_osdep(XGE_ERR, "ddi_intr_enable() failed, "
    993 			    "ret 0x%x", ret);
    994 			return (DDI_FAILURE);
    995 		}
    996 	} else {
    997 		/* Call ddi_intr_enable for MSI(X) or FIXED interrupts */
    998 		for (i = 0; i < lldev->intr_cnt; i++) {
    999 			if ((ret = ddi_intr_enable(lldev->intr_table[i]))
   1000 			    != DDI_SUCCESS) {
   1001 				int j;
   1002 
   1003 				xge_debug_osdep(XGE_ERR, "ddi_intr_enable() "
   1004 				    "failed, ret 0x%x", ret);
   1005 
   1006 				/* unwind */
   1007 				for (j = 0; j < i; j++) {
   1008 					(void) ddi_intr_disable(
   1009 					    lldev->intr_table[j]);
   1010 				}
   1011 
   1012 				return (DDI_FAILURE);
   1013 			}
   1014 		}
   1015 	}
   1016 
   1017 	return (DDI_SUCCESS);
   1018 }
   1019 
   1020 /*
   1021  * xge_disable_intrs:
   1022  *
   1023  * Disable FIXED or MSI interrupts
   1024  */
   1025 void
   1026 xge_disable_intrs(xgelldev_t *lldev)
   1027 {
   1028 	int i;
   1029 
   1030 	if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
   1031 		/* Call ddi_intr_block_disable() */
   1032 		(void) ddi_intr_block_disable(lldev->intr_table,
   1033 		    lldev->intr_cnt);
   1034 	} else {
   1035 		for (i = 0; i < lldev->intr_cnt; i++) {
   1036 			(void) ddi_intr_disable(lldev->intr_table[i]);
   1037 		}
   1038 	}
   1039 }
   1040 
   1041 /*
   1042  * xge_rem_intrs:
   1043  *
   1044  * Unregister FIXED or MSI interrupts
   1045  */
   1046 void
   1047 xge_rem_intrs(xgelldev_t *lldev)
   1048 {
   1049 	int i;
   1050 
   1051 	xge_assert(lldev->intr_table != NULL);
   1052 
   1053 	/* Call ddi_intr_remove_handler() */
   1054 	for (i = 0; i < lldev->intr_cnt; i++) {
   1055 		(void) ddi_intr_remove_handler(lldev->intr_table[i]);
   1056 	}
   1057 }
   1058 
   1059 /*
   1060  * xge_attach
   1061  * @dev_info: pointer to dev_info_t structure
   1062  * @cmd: attach command to process
   1063  *
   1064  * This is a solaris standard attach function.  This
   1065  * function initializes the Xframe  identified
   1066  * by the dev_info_t structure and setup the driver
   1067  * data structures corresponding to the Xframe Card.
   1068  * This function also registers the XFRAME device
   1069  * instance with the MAC Layer.
   1070  * If this function returns success then the OS
   1071  * will attach the HBA controller to this
   1072  * driver.
   1073  */
   1074 static int
   1075 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
   1076 {
   1077 	xgelldev_t *ll;
   1078 	xgell_config_t *xgell_config;
   1079 	xge_hal_device_config_t *device_config;
   1080 	xge_hal_device_t *hldev;
   1081 	xge_hal_device_attr_t attr;
   1082 	xge_hal_status_e status;
   1083 	int ret, intr_types, i;
   1084 
   1085 	xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
   1086 
   1087 	switch (cmd) {
   1088 	case DDI_ATTACH:
   1089 		break;
   1090 
   1091 	case DDI_RESUME:
   1092 	case DDI_PM_RESUME:
   1093 		xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
   1094 		ret = DDI_FAILURE;
   1095 		goto _exit0;
   1096 
   1097 	default:
   1098 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
   1099 		ret = DDI_FAILURE;
   1100 		goto _exit0;
   1101 	}
   1102 
   1103 	xgell_config = kmem_zalloc(sizeof (xgell_config_t), KM_SLEEP);
   1104 	device_config = kmem_zalloc(sizeof (xge_hal_device_config_t), KM_SLEEP);
   1105 
   1106 	/*
   1107 	 * Initialize all configurations
   1108 	 */
   1109 	xge_configuration_init(dev_info, device_config, xgell_config);
   1110 
   1111 	/* Determine which types of interrupts supported */
   1112 	ret = ddi_intr_get_supported_types(dev_info, &intr_types);
   1113 	if ((ret != DDI_SUCCESS) || (!(intr_types & DDI_INTR_TYPE_FIXED))) {
   1114 		xge_debug_osdep(XGE_ERR, "%s",
   1115 		    "fixed type interrupt is not supported");
   1116 		goto _exit0a;
   1117 	}
   1118 
   1119 	/* map BAR0 */
   1120 	ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
   1121 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
   1122 	if (ret != DDI_SUCCESS) {
   1123 		xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
   1124 		goto _exit0a;
   1125 	}
   1126 
   1127 	/* map BAR1 */
   1128 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
   1129 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
   1130 	if (ret != DDI_SUCCESS) {
   1131 		xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
   1132 		goto _exit1;
   1133 	}
   1134 
   1135 	/* map BAR2 MSI(X) */
   1136 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar2,
   1137 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh2);
   1138 	if (ret != DDI_SUCCESS) {
   1139 		xge_debug_osdep(XGE_ERR, "unable to map bar2: [%d]", ret);
   1140 		goto _exit1a;
   1141 	}
   1142 
   1143 	/* preallocate memory for new HAL device and private LL part */
   1144 	hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
   1145 
   1146 	/* Get the PCI Configuartion space handle */
   1147 	ret = pci_config_setup(dev_info, &attr.cfgh);
   1148 	if (ret != DDI_SUCCESS) {
   1149 		xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
   1150 		goto _exit2a;
   1151 	}
   1152 
   1153 	attr.pdev = dev_info;
   1154 
   1155 	ret = xgell_device_alloc(hldev, dev_info, &ll);
   1156 	if (ret != DDI_SUCCESS) {
   1157 		xge_debug_osdep(XGE_ERR,
   1158 		    "%s",
   1159 		    "unable to allocate new LL device");
   1160 		goto _exit3;
   1161 	}
   1162 
   1163 	/*
   1164 	 * Init multiple rings configuration
   1165 	 */
   1166 	switch (xgell_config->grouping) {
   1167 	case XGELL_CONF_GROUP_POLICY_VIRT:
   1168 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
   1169 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
   1170 		ll->init_rx_groups = ll->init_rx_rings;
   1171 		break;
   1172 	case XGELL_CONF_GROUP_POLICY_PERF:
   1173 		ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
   1174 		ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
   1175 		ll->init_rx_groups = 1;
   1176 		break;
   1177 	case XGELL_CONF_GROUP_POLICY_BASIC:
   1178 		ll->init_rx_rings = XGELL_RX_RING_NUM_MIN; /* 1 */
   1179 		ll->init_tx_rings = XGELL_TX_RING_NUM_MIN; /* 1 */
   1180 		ll->init_rx_groups = ll->init_rx_rings;
   1181 		break;
   1182 	default:
   1183 		ASSERT(0);
   1184 		break;
   1185 	}
   1186 
   1187 	/*
   1188 	 * Init MSI-X configuration
   1189 	 */
   1190 	if (xgell_config->msix_enable && intr_types & DDI_INTR_TYPE_MSIX) {
   1191 		ll->intr_type = DDI_INTR_TYPE_MSIX;
   1192 		ll->intr_cnt = 1;
   1193 		for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++)
   1194 			if (device_config->fifo.queue[i].configured)
   1195 				ll->intr_cnt++;
   1196 		for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++)
   1197 			if (device_config->ring.queue[i].configured)
   1198 				ll->intr_cnt++;
   1199 	} else {
   1200 		ll->intr_type = DDI_INTR_TYPE_FIXED;
   1201 		ll->intr_cnt = 1;
   1202 	}
   1203 
   1204 	/*
   1205 	 * Allocate interrupt(s)
   1206 	 */
   1207 	while ((ret = xge_alloc_intrs(ll)) != DDI_SUCCESS) {
   1208 		if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
   1209 			xgell_config->msix_enable = 0;
   1210 			ll->intr_type = DDI_INTR_TYPE_FIXED;
   1211 			ll->intr_cnt = 1;
   1212 			device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
   1213 			xge_debug_osdep(XGE_TRACE,
   1214 			    "Unable to allocate MSI-X handlers"
   1215 			    " - defaulting to IRQA");
   1216 			continue;
   1217 		}
   1218 		goto _exit3a;
   1219 	}
   1220 
   1221 	if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
   1222 		device_config->intr_mode = XGE_HAL_INTR_MODE_MSIX;
   1223 		device_config->bimodal_interrupts = 0;
   1224 	} else {
   1225 		device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
   1226 	}
   1227 
   1228 	attr.irqh = ll->intr_pri;
   1229 
   1230 	/* initialize HW */
   1231 	status = xge_hal_device_initialize(hldev, &attr, device_config);
   1232 	if (status != XGE_HAL_OK) {
   1233 		switch (status) {
   1234 		case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
   1235 			xge_debug_osdep(XGE_ERR, "%s",
   1236 			    "driver is not initialized");
   1237 			ret = DDI_FAILURE;
   1238 			goto _exit3b;
   1239 		case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
   1240 			xge_debug_osdep(XGE_ERR, "%s",
   1241 			    "device is not quiescent");
   1242 			ret = DDI_EBUSY;
   1243 			goto _exit3b;
   1244 		case XGE_HAL_ERR_OUT_OF_MEMORY:
   1245 			xge_debug_osdep(XGE_ERR, "%s",
   1246 			    "unable to allocate memory");
   1247 			ret = DDI_ENOMEM;
   1248 			goto _exit3b;
   1249 		default:
   1250 			xge_debug_osdep(XGE_ERR,
   1251 			    "can't initialize the device: %d", status);
   1252 			ret = DDI_FAILURE;
   1253 			goto _exit3b;
   1254 		}
   1255 	}
   1256 
   1257 	/* register interrupt handler for handling xge device interrupts */
   1258 	ret = xge_add_intrs(ll);
   1259 	if (ret != DDI_SUCCESS)
   1260 		goto _exit4;
   1261 
   1262 	/* allocate and register Link Layer */
   1263 	ret = xgell_device_register(ll, xgell_config);
   1264 	if (ret != DDI_SUCCESS) {
   1265 		goto _exit5;
   1266 	}
   1267 
   1268 	/* store ll as a HAL private part */
   1269 	xge_hal_device_private_set(hldev, ll);
   1270 
   1271 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
   1272 	kmem_free(xgell_config, sizeof (xgell_config_t));
   1273 
   1274 	return (DDI_SUCCESS);
   1275 
   1276 _exit5:
   1277 	xge_rem_intrs(ll);
   1278 _exit4:
   1279 	xge_hal_device_terminate(hldev);
   1280 _exit3b:
   1281 	xge_free_intrs(ll);
   1282 _exit3a:
   1283 	xgell_device_free(ll);
   1284 _exit3:
   1285 	pci_config_teardown(&attr.cfgh);
   1286 _exit2a:
   1287 	kmem_free(hldev, sizeof (xge_hal_device_t));
   1288 _exit2:
   1289 	ddi_regs_map_free(&attr.regh2);
   1290 _exit1a:
   1291 	ddi_regs_map_free(&attr.regh1);
   1292 _exit1:
   1293 	ddi_regs_map_free(&attr.regh0);
   1294 _exit0a:
   1295 	kmem_free(device_config, sizeof (xge_hal_device_config_t));
   1296 	kmem_free(xgell_config, sizeof (xgell_config_t));
   1297 _exit0:
   1298 	return (ret);
   1299 }
   1300 
   1301 /*
   1302  * quiesce(9E) entry point.
   1303  *
   1304  * This function is called when the system is single-threaded at high
   1305  * PIL with preemption disabled. Therefore, this function must not be
   1306  * blocked.
   1307  *
   1308  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
   1309  * DDI_FAILURE indicates an error condition and should almost never happen.
   1310  */
   1311 static int
   1312 xge_quiesce(dev_info_t *dev_info)
   1313 {
   1314 	xge_hal_device_t *hldev =
   1315 	    (xge_hal_device_t *)ddi_get_driver_private(dev_info);
   1316 
   1317 	xgelldev_t *lldev = xge_hal_device_private(hldev);
   1318 
   1319 	xge_hal_device_quiesce(hldev, lldev->devh);
   1320 
   1321 	return (DDI_SUCCESS);
   1322 }
   1323 
   1324 /*
   1325  * xge_detach
   1326  * @dev_info: pointer to dev_info_t structure
   1327  * @cmd: attach command to process
   1328  *
   1329  * This function is called by OS when the system is about
   1330  * to shutdown or when the super user tries to unload
   1331  * the driver. This function frees all the memory allocated
   1332  * during xge_attach() and also unregisters the Xframe
   1333  * device instance from the GLD framework.
   1334  */
   1335 static int
   1336 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
   1337 {
   1338 	xge_hal_device_t *hldev;
   1339 	xge_hal_device_attr_t *attr;
   1340 	xgelldev_t *lldev;
   1341 
   1342 	xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
   1343 
   1344 	hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
   1345 	attr = xge_hal_device_attr(hldev);
   1346 	lldev = xge_hal_device_private(hldev);
   1347 
   1348 	switch (cmd) {
   1349 	case DDI_DETACH:
   1350 		break;
   1351 
   1352 	case DDI_PM_SUSPEND:
   1353 		xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
   1354 		return (DDI_FAILURE);
   1355 
   1356 	default:
   1357 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
   1358 		return (DDI_FAILURE);
   1359 	}
   1360 
   1361 	if (lldev->is_initialized) {
   1362 		xge_debug_osdep(XGE_ERR, "%s",
   1363 		    "can not detach: device is not unplumbed");
   1364 		return (DDI_FAILURE);
   1365 	}
   1366 
   1367 	xge_hal_device_terminating(hldev);
   1368 	if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
   1369 		return (DDI_FAILURE);
   1370 	}
   1371 	xge_hal_device_terminate(hldev);
   1372 
   1373 	xge_rem_intrs(lldev);
   1374 	xge_free_intrs(lldev);
   1375 	xgell_device_free(lldev);
   1376 	pci_config_teardown(&attr->cfgh);
   1377 	ddi_regs_map_free(&attr->regh2);
   1378 	ddi_regs_map_free(&attr->regh1);
   1379 	ddi_regs_map_free(&attr->regh0);
   1380 	kmem_free(hldev, sizeof (xge_hal_device_t));
   1381 
   1382 	return (DDI_SUCCESS);
   1383 }
   1384