xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xge.c (revision 8347601bcb0a439f6e50fc36b4039a73d08700e1)
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 2006 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 	xgelldev_t *lldev = item->context;
78 
79 	switch (item->event_type) {
80 	case XGELL_EVENT_RESCHED_NEEDED:
81 		if (lldev->is_initialized) {
82 			if (xge_hal_channel_dtr_count(lldev->fifo_channel)
83 			    >= XGELL_TX_LEVEL_HIGH) {
84 				mac_tx_update(lldev->mh);
85 				xge_debug_osdep(XGE_TRACE,
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_queue_produce context
109  */
110 static void
111 xge_callback_event_queued(xge_hal_device_h devh, int event_type)
112 {
113 	if (event_type == XGELL_EVENT_RESCHED_NEEDED) {
114 		(void) taskq_dispatch(system_taskq, xge_device_poll_now, devh,
115 		    TQ_NOSLEEP);
116 	}
117 }
118 
119 /*
120  * xge_driver_init_hal
121  *
122  * To initialize HAL portion of driver.
123  */
124 static xge_hal_status_e
125 xge_driver_init_hal(void)
126 {
127 	static xge_hal_driver_config_t driver_config;
128 	xge_hal_uld_cbs_t uld_callbacks;
129 
130 	driver_config.queue_size_initial = 1;
131 	driver_config.queue_size_max = 4;
132 
133 	uld_callbacks.link_up = xgell_callback_link_up;
134 	uld_callbacks.link_down = xgell_callback_link_down;
135 	uld_callbacks.crit_err = xge_callback_crit_err;
136 	uld_callbacks.event = xge_event;
137 	uld_callbacks.event_queued = xge_callback_event_queued;
138 	uld_callbacks.before_device_poll = NULL;
139 	uld_callbacks.after_device_poll = NULL;
140 	uld_callbacks.sched_timer = NULL;
141 
142 	return (xge_hal_driver_initialize(&driver_config, &uld_callbacks));
143 
144 }
145 
146 /*
147  * _init
148  *
149  * Solaris standard _init function for a device driver
150  */
151 int
152 _init(void)
153 {
154 	int ret = 0;
155 	xge_hal_status_e status;
156 
157 	status = xge_driver_init_hal();
158 	if (status != XGE_HAL_OK) {
159 		xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)",
160 		    status);
161 		return (EINVAL);
162 	}
163 
164 	xge_hal_driver_debug_module_mask_set(0xffffffff);
165 	xge_hal_driver_debug_level_set(XGE_TRACE);
166 
167 	mac_init_ops(&xge_ops, "xge");
168 	if ((ret = mod_install(&modlinkage)) != 0) {
169 		xge_hal_driver_terminate();
170 		mac_fini_ops(&xge_ops);
171 		xge_debug_osdep(XGE_ERR, "%s",
172 		    "Unable to install the driver");
173 		return (ret);
174 	}
175 
176 	return (0);
177 }
178 
179 /*
180  * _fini
181  *
182  * Solaris standard _fini function for device driver
183  */
184 int
185 _fini(void)
186 {
187 	int ret;
188 
189 	ret = mod_remove(&modlinkage);
190 	if (ret == 0) {
191 		xge_hal_driver_terminate();
192 		mac_fini_ops(&xge_ops);
193 	}
194 
195 	return (ret);
196 }
197 
198 /*
199  * _info
200  *
201  * Solaris standard _info function for device driver
202  */
203 int
204 _info(struct modinfo *pModinfo)
205 {
206 	return (mod_info(&modlinkage, pModinfo));
207 }
208 
209 /*
210  * xge_isr
211  * @arg: pointer to device private strucutre(hldev)
212  *
213  * This is the ISR scheduled by the OS to indicate to the
214  * driver that the receive/transmit operation is completed.
215  */
216 static uint_t
217 xge_isr(caddr_t arg)
218 {
219 	xge_hal_status_e status;
220 	xge_hal_device_t *hldev = (xge_hal_device_t *)arg;
221 	xgelldev_t *lldev = xge_hal_device_private(hldev);
222 
223 	if (!lldev->is_initialized) {
224 		return (DDI_INTR_CLAIMED);
225 	}
226 
227 	status = xge_hal_device_handle_irq(hldev);
228 
229 	return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
230 	    DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
231 }
232 
233 /*
234  * xge_configuration_init
235  * @device_config: pointer to xge_hal_device_config_t
236  *
237  * This function will lookup properties from .conf file to init
238  * the configuration data structure. If a property is not in .conf
239  * file, the default value should be set.
240  */
241 static void
242 xge_configuration_init(dev_info_t *dev_info,
243     xge_hal_device_config_t *device_config, xgell_config_t *ll_config)
244 {
245 	/*
246 	 * Initialize common properties
247 	 */
248 	device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
249 	    dev_info, DDI_PROP_DONTPASS, "default_mtu",
250 	    XGE_HAL_DEFAULT_INITIAL_MTU);
251 	device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
252 	    dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
253 	    XGE_HAL_DEFAULT_ISR_POLLING_CNT);
254 	device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
255 	    dev_info, DDI_PROP_DONTPASS, "latency_timer",
256 	    XGE_HAL_DEFAULT_LATENCY_TIMER);
257 	device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
258 	    dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
259 	    XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
260 	device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
261 	    dev_info, DDI_PROP_DONTPASS, "mmrb_count",
262 	    XGE_HAL_DEFAULT_MMRB_COUNT);
263 	device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
264 	    dev_info, DDI_PROP_DONTPASS, "shared_splits",
265 	    XGE_HAL_DEFAULT_SHARED_SPLITS);
266 	device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
267 	    dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
268 	    XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
269 	device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
270 	    dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
271 	    XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
272 	device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
273 	    dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz",
274 	    XGE_HAL_DEFAULT_USE_HARDCODE);
275 
276 	/*
277 	 * Initialize ring properties
278 	 */
279 	device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
280 	    dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
281 	    XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
282 	device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
283 
284 #if defined(__sparc)
285 	device_config->ring.queue[XGELL_RING_MAIN_QID].no_snoop_bits = 1;
286 #endif
287 	device_config->ring.queue[XGELL_RING_MAIN_QID].max =
288 	    ddi_prop_get_int(DDI_DEV_T_ANY,
289 		dev_info, DDI_PROP_DONTPASS, "ring_main_max",
290 		XGE_HAL_DEFAULT_USE_HARDCODE);
291 	device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
292 	    ddi_prop_get_int(DDI_DEV_T_ANY,
293 		dev_info, DDI_PROP_DONTPASS, "ring_main_initial",
294 		XGE_HAL_DEFAULT_USE_HARDCODE);
295 	if (device_config->ring.queue[XGELL_RING_MAIN_QID].initial ==
296 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
297 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
298 			device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
299 			    device_config->ring.queue[XGELL_RING_MAIN_QID].max =
300 			    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS_J;
301 		} else {
302 			device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
303 			    device_config->ring.queue[XGELL_RING_MAIN_QID].max =
304 			    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS_N;
305 		}
306 	}
307 	device_config->ring.queue[XGELL_RING_MAIN_QID].buffer_mode =
308 	    ddi_prop_get_int(DDI_DEV_T_ANY,
309 		dev_info, DDI_PROP_DONTPASS, "ring_main_buffer_mode",
310 		XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
311 	device_config->ring.queue[XGELL_RING_MAIN_QID].dram_size_mb =
312 	    ddi_prop_get_int(DDI_DEV_T_ANY,
313 		dev_info, DDI_PROP_DONTPASS, "ring_main_dram_size_mb",
314 		XGE_HAL_DEFAULT_USE_HARDCODE);
315 	device_config->ring.queue[XGELL_RING_MAIN_QID].backoff_interval_us =
316 	    ddi_prop_get_int(DDI_DEV_T_ANY,
317 		dev_info, DDI_PROP_DONTPASS, "ring_main_backoff_interval_us",
318 		XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
319 	device_config->ring.queue[XGELL_RING_MAIN_QID].max_frm_len =
320 	    ddi_prop_get_int(DDI_DEV_T_ANY,
321 		dev_info, DDI_PROP_DONTPASS, "ring_main_max_frm_len",
322 		XGE_HAL_RING_USE_MTU);
323 	device_config->ring.queue[XGELL_RING_MAIN_QID].priority =
324 	    ddi_prop_get_int(DDI_DEV_T_ANY,
325 		dev_info, DDI_PROP_DONTPASS, "ring_main_priority",
326 		XGE_HAL_DEFAULT_RING_PRIORITY);
327 	device_config->ring.queue[XGELL_RING_MAIN_QID].configured =
328 	    ddi_prop_get_int(DDI_DEV_T_ANY,
329 		dev_info, DDI_PROP_DONTPASS, "ring_main_configured",
330 		1);
331 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_a =
332 	    ddi_prop_get_int(DDI_DEV_T_ANY,
333 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_a",
334 		XGE_HAL_DEFAULT_RX_URANGE_A);
335 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_a =
336 	    ddi_prop_get_int(DDI_DEV_T_ANY,
337 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_a",
338 		XGE_HAL_DEFAULT_RX_UFC_A);
339 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_b =
340 	    ddi_prop_get_int(DDI_DEV_T_ANY,
341 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_b",
342 		XGE_HAL_DEFAULT_RX_URANGE_B);
343 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_b =
344 	    ddi_prop_get_int(DDI_DEV_T_ANY,
345 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_b",
346 		device_config->mtu > XGE_HAL_DEFAULT_MTU ?
347 			XGE_HAL_DEFAULT_RX_UFC_B_J :
348 			XGE_HAL_DEFAULT_RX_UFC_B_N);
349 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_c =
350 	    ddi_prop_get_int(DDI_DEV_T_ANY,
351 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_c",
352 		XGE_HAL_DEFAULT_RX_URANGE_C);
353 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_c =
354 	    ddi_prop_get_int(DDI_DEV_T_ANY,
355 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_c",
356 		device_config->mtu > XGE_HAL_DEFAULT_MTU ?
357 			XGE_HAL_DEFAULT_RX_UFC_C_J :
358 			XGE_HAL_DEFAULT_RX_UFC_C_N);
359 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_d =
360 	    ddi_prop_get_int(DDI_DEV_T_ANY,
361 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_d",
362 		XGE_HAL_DEFAULT_RX_UFC_D);
363 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.timer_val_us =
364 	    ddi_prop_get_int(DDI_DEV_T_ANY,
365 		dev_info, DDI_PROP_DONTPASS, "ring_main_timer_val",
366 		XGE_HAL_DEFAULT_RX_TIMER_VAL);
367 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.timer_ac_en =
368 	    ddi_prop_get_int(DDI_DEV_T_ANY,
369 		dev_info, DDI_PROP_DONTPASS, "ring_main_timer_ac_en",
370 		XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
371 	device_config->ring.queue[XGELL_RING_MAIN_QID].indicate_max_pkts =
372 	    ddi_prop_get_int(DDI_DEV_T_ANY,
373 		dev_info, DDI_PROP_DONTPASS, "ring_main_indicate_max_pkts",
374 		(device_config->bimodal_interrupts ?
375 			XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B :
376 			XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N));
377 
378 	/*
379 	 * Initialize mac properties
380 	 */
381 	device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
382 	    dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
383 	    XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
384 	device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
385 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
386 	    XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
387 	device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
388 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
389 	    1); /* HAL never provide a good named macro */
390 	device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY,
391 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en",
392 	    XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS);
393 	device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY,
394 	    dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en",
395 	    XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS);
396 	device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
397 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
398 	    XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
399 	device_config->mac.mc_pause_threshold_q0q3 =
400 	    ddi_prop_get_int(DDI_DEV_T_ANY,
401 		dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
402 		XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
403 	device_config->mac.mc_pause_threshold_q4q7 =
404 	    ddi_prop_get_int(DDI_DEV_T_ANY,
405 		dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
406 		XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
407 
408 	/*
409 	 * Initialize fifo properties
410 	 */
411 	device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
412 	    dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
413 	    XGE_HAL_DEFAULT_FIFO_FRAGS);
414 	if (device_config->fifo.max_frags == XGE_HAL_DEFAULT_USE_HARDCODE)
415 	    device_config->fifo.max_frags = XGE_HAL_DEFAULT_FIFO_FRAGS;
416 	device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
417 	    dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
418 	    XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
419 	device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
420 	    dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
421 	    XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
422 #ifdef XGE_HAL_ALIGN_XMIT
423 	device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY,
424 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size",
425 	    XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE);
426 	device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
427 	    dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags",
428 	    XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS);
429 #endif
430 #if defined(__sparc)
431 	device_config->fifo.queue[0].no_snoop_bits = 1;
432 #endif
433 	device_config->fifo.queue[0].max = ddi_prop_get_int(DDI_DEV_T_ANY,
434 	    dev_info, DDI_PROP_DONTPASS, "fifo0_max",
435 	    XGE_HAL_DEFAULT_USE_HARDCODE);
436 	device_config->fifo.queue[0].initial = ddi_prop_get_int(DDI_DEV_T_ANY,
437 	    dev_info, DDI_PROP_DONTPASS, "fifo0_initial",
438 	    XGE_HAL_DEFAULT_USE_HARDCODE);
439 	if (device_config->fifo.queue[0].initial ==
440 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
441 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
442 			device_config->fifo.queue[0].initial =
443 			    device_config->fifo.queue[0].max =
444 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
445 		} else {
446 			device_config->fifo.queue[0].initial =
447 			    device_config->fifo.queue[0].max =
448 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
449 		}
450 	}
451 	device_config->fifo.queue[0].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
452 	    dev_info, DDI_PROP_DONTPASS, "fifo0_intr",
453 	    XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
454 	device_config->fifo.queue[0].configured =
455 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
456 		"fifo0_configured", 1);
457 
458 	/*
459 	 * Bimodal Interrupts - TTI 56 configuration
460 	 */
461 	device_config->bimodal_interrupts = ddi_prop_get_int(
462 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts",
463 	    XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS);
464 	device_config->bimodal_timer_lo_us = ddi_prop_get_int(
465 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us",
466 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US);
467 	device_config->bimodal_timer_hi_us = ddi_prop_get_int(
468 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us",
469 	    XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US);
470 
471 	/*
472 	 * TTI 0 configuration
473 	 */
474 	device_config->fifo.queue[0].tti[0].enabled = ddi_prop_get_int(
475 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_enable", 1);
476 	device_config->fifo.queue[0].tti[0].urange_a = ddi_prop_get_int(
477 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_urange_a",
478 	    XGE_HAL_DEFAULT_TX_URANGE_A);
479 	device_config->fifo.queue[0].tti[0].ufc_a = ddi_prop_get_int(
480 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_ufc_a",
481 	    XGE_HAL_DEFAULT_TX_UFC_A);
482 	device_config->fifo.queue[0].tti[0].urange_b = ddi_prop_get_int(
483 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_urange_b",
484 	    XGE_HAL_DEFAULT_TX_URANGE_B);
485 	device_config->fifo.queue[0].tti[0].ufc_b = ddi_prop_get_int(
486 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_ufc_b",
487 	    XGE_HAL_DEFAULT_TX_UFC_B);
488 	device_config->fifo.queue[0].tti[0].urange_c = ddi_prop_get_int(
489 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_urange_c",
490 	    XGE_HAL_DEFAULT_TX_URANGE_C);
491 	device_config->fifo.queue[0].tti[0].ufc_c = ddi_prop_get_int(
492 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_ufc_c",
493 	    XGE_HAL_DEFAULT_TX_UFC_C);
494 	device_config->fifo.queue[0].tti[0].ufc_d = ddi_prop_get_int(
495 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_ufc_d",
496 	    XGE_HAL_DEFAULT_TX_UFC_D);
497 	device_config->fifo.queue[0].tti[0].timer_ac_en = ddi_prop_get_int(
498 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_timer_ac_en",
499 	    XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
500 	device_config->fifo.queue[0].tti[0].timer_val_us = ddi_prop_get_int(
501 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_timer_val",
502 	    XGE_HAL_DEFAULT_TX_TIMER_VAL);
503 	device_config->fifo.queue[0].tti[0].timer_ci_en = ddi_prop_get_int(
504 	    DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "tti_timer_ci_en",
505 	    XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
506 
507 	/*
508 	 * Initialize errors dumping
509 	 */
510 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
511 	    dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
512 	    0);
513 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
514 	    dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
515 	    0);
516 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
517 	    dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
518 	    0);
519 
520 	/*
521 	 * LRO tunables
522 	 */
523 	device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY,
524 	    dev_info, DDI_PROP_DONTPASS, "lro_sg_size",
525 	    XGE_HAL_DEFAULT_LRO_SG_SIZE);
526 	device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY,
527 	    dev_info, DDI_PROP_DONTPASS, "lro_frm_len",
528 	    XGE_HAL_DEFAULT_LRO_FRM_LEN);
529 
530 	/*
531 	 * Initialize link layer configuration
532 	 */
533 	ll_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
534 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
535 	    device_config->ring.queue[XGELL_RING_MAIN_QID].initial *
536 					XGELL_RX_BUFFER_TOTAL);
537 	ll_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
538 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
539 	    device_config->ring.queue[XGELL_RING_MAIN_QID].initial *
540 					XGELL_RX_BUFFER_POST_HIWAT);
541 	ll_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY,
542 	    dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst",
543 	    XGELL_RX_PKT_BURST);
544 	ll_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
545 	    DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT);
546 	ll_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
547 	    DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT);
548 	ll_config->msi_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
549 	    DDI_PROP_DONTPASS, "msi_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
550 	ll_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
551 	    DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
552 }
553 
554 /*
555  * xge_attach
556  * @dev_info: pointer to dev_info_t structure
557  * @cmd: attach command to process
558  *
559  * This is a solaris standard attach function.  This
560  * function initializes the Xframe  identified
561  * by the dev_info_t structure and setup the driver
562  * data structures corresponding to the Xframe Card.
563  * This function also registers the XFRAME device
564  * instance with the MAC Layer.
565  * If this function returns success then the OS
566  * will attach the HBA controller to this
567  * driver.
568  */
569 static int
570 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
571 {
572 	xgelldev_t *ll;
573 	xge_hal_device_config_t device_config;
574 	xge_hal_device_t *hldev;
575 	xge_hal_device_attr_t attr;
576 	xge_hal_status_e status;
577 	xgell_config_t ll_config;
578 	int ret;
579 
580 	xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
581 
582 	switch (cmd) {
583 	case DDI_ATTACH:
584 		break;
585 
586 	case DDI_RESUME:
587 	case DDI_PM_RESUME:
588 		xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
589 		ret = DDI_FAILURE;
590 		goto _exit0;
591 
592 	default:
593 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
594 		ret = DDI_FAILURE;
595 		goto _exit0;
596 	}
597 
598 	xge_os_memzero(&device_config, sizeof (xge_hal_device_config_t));
599 
600 	/* Init device_config by lookup up properties from .conf file */
601 	xge_configuration_init(dev_info, &device_config, &ll_config);
602 
603 	/* map BAR0 */
604 	ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
605 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
606 	if (ret != DDI_SUCCESS) {
607 		xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
608 		goto _exit0;
609 	}
610 
611 	/* map BAR1 */
612 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
613 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
614 	if (ret != DDI_SUCCESS) {
615 		xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
616 		goto _exit1;
617 	}
618 
619 	/* preallocate memory for new HAL device and private LL part */
620 	hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
621 	if (hldev == NULL) {
622 		xge_debug_osdep(XGE_ERR, "%s", "can not allocate memory");
623 		ret = DDI_ENOMEM;
624 		goto _exit2;
625 	}
626 
627 	/* get the interrupt block cookie associated with the interrupt */
628 	ret = ddi_get_iblock_cookie(dev_info, 0, &attr.irqh);
629 	if (ret != DDI_SUCCESS) {
630 		xge_debug_osdep(XGE_ERR, "%s", "can not get interrupt cookie");
631 		goto _exit2a;
632 	}
633 
634 	/* Get the PCI Configuartion space handle */
635 	ret = pci_config_setup(dev_info, &attr.cfgh);
636 	if (ret != DDI_SUCCESS) {
637 		xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
638 		goto _exit2a;
639 	}
640 
641 	attr.pdev = dev_info;
642 
643 	ret = xgell_device_alloc(hldev, dev_info, &ll);
644 	if (ret != DDI_SUCCESS) {
645 		xge_debug_osdep(XGE_ERR,
646 		    "%s",
647 		    "unable to allocate new LL device");
648 		goto _exit3;
649 	}
650 
651 	/* attach an interrupt handler for handling Xge device interrupts */
652 	ret = ddi_add_intr(dev_info, 0, &attr.irqh, NULL, xge_isr,
653 	    (caddr_t)hldev);
654 	if (ret != DDI_SUCCESS) {
655 		xge_debug_osdep(XGE_ERR, "%s", "unable to register ISR");
656 		goto _exit3a;
657 	}
658 
659 	/* initialize HW */
660 	status = xge_hal_device_initialize(hldev, &attr, &device_config);
661 	if (status != XGE_HAL_OK) {
662 		switch (status) {
663 		case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
664 			xge_debug_osdep(XGE_ERR, "%s",
665 			    "driver is not initialized");
666 			ret = DDI_FAILURE;
667 			goto _exit3b;
668 		case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
669 			xge_debug_osdep(XGE_ERR, "%s",
670 			    "device is not quiescent");
671 			ret = DDI_EBUSY;
672 			goto _exit3b;
673 		case XGE_HAL_ERR_OUT_OF_MEMORY:
674 			xge_debug_osdep(XGE_ERR, "%s",
675 			    "unable to allocate memory");
676 			ret = DDI_ENOMEM;
677 			goto _exit3b;
678 		default:
679 			xge_debug_osdep(XGE_ERR,
680 			    "can't initialize the device: %d", status);
681 			ret = DDI_FAILURE;
682 			goto _exit3b;
683 		}
684 	}
685 
686 	/* allocate and register Link Layer */
687 	ret = xgell_device_register(ll, &ll_config);
688 	if (ret != DDI_SUCCESS) {
689 		goto _exit4;
690 	}
691 
692 	/* store ll as a HAL private part */
693 	xge_hal_device_private_set(hldev, ll);
694 
695 	return (DDI_SUCCESS);
696 
697 _exit4:
698 	xge_hal_device_terminate(hldev);
699 _exit3b:
700 	ddi_remove_intr(attr.pdev, 0, hldev->irqh);
701 _exit3a:
702 	xgell_device_free(ll);
703 _exit3:
704 	pci_config_teardown(&attr.cfgh);
705 _exit2a:
706 	kmem_free(hldev, sizeof (xge_hal_device_t));
707 _exit2:
708 	ddi_regs_map_free(&attr.regh1);
709 _exit1:
710 	ddi_regs_map_free(&attr.regh0);
711 _exit0:
712 	return (ret);
713 }
714 
715 /*
716  * xge_detach
717  * @dev_info: pointer to dev_info_t structure
718  * @cmd: attach command to process
719  *
720  * This function is called by OS when the system is about
721  * to shutdown or when the super user tries to unload
722  * the driver. This function frees all the memory allocated
723  * during xge_attch() and also unregisters the Xframe
724  * device instance from the GLD framework.
725  */
726 static int
727 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
728 {
729 	xge_hal_device_t *hldev;
730 	xge_hal_device_attr_t *attr;
731 	xgelldev_t *lldev;
732 
733 	xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
734 
735 	hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
736 	attr = xge_hal_device_attr(hldev);
737 	lldev = xge_hal_device_private(hldev);
738 
739 	switch (cmd) {
740 	case DDI_DETACH:
741 		break;
742 
743 	case DDI_PM_SUSPEND:
744 		xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
745 		return (DDI_FAILURE);
746 
747 	default:
748 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
749 		return (DDI_FAILURE);
750 	}
751 
752 	if (lldev->is_initialized) {
753 		xge_debug_osdep(XGE_ERR, "%s",
754 		    "can not detach: device is not unplumbed");
755 		return (DDI_FAILURE);
756 	}
757 
758 	xge_hal_device_terminating(hldev);
759 	if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
760 		return (DDI_FAILURE);
761 	}
762 	xge_hal_device_terminate(hldev);
763 
764 	ddi_remove_intr(attr->pdev, 0, attr->irqh);
765 	xgell_device_free(lldev);
766 	pci_config_teardown(&attr->cfgh);
767 	ddi_regs_map_free(&attr->regh1);
768 	ddi_regs_map_free(&attr->regh0);
769 	kmem_free(hldev, sizeof (xge_hal_device_t));
770 
771 	return (DDI_SUCCESS);
772 }
773