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