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