xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xge.c (revision a07094369b21309434206d9b3601d162693466fc)
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 (__hal_channel_dtr_count(lldev->fifo_channel)
83 			    >= XGELL_TX_LEVEL_HIGH) {
84 				mac_tx_update(lldev->macp);
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 
249 	/*
250 	 * We prefer HAL could provide all default values to these tunables,
251 	 * so this level could care little the configurations need by HAL.
252 	 * Leave a const here is definitely not good idea.
253 	 */
254 	device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
255 	    dev_info, DDI_PROP_DONTPASS, "default_mtu",
256 	    XGE_HAL_DEFAULT_INITIAL_MTU);
257 	device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
258 	    dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
259 	    XGE_HAL_DEFAULT_ISR_POLLING_CNT);
260 	device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
261 	    dev_info, DDI_PROP_DONTPASS, "latency_timer",
262 	    XGE_HAL_DEFAULT_LATENCY_TIMER);
263 	device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
264 	    dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
265 	    XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
266 	device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
267 	    dev_info, DDI_PROP_DONTPASS, "mmrb_count",
268 	    XGE_HAL_DEFAULT_MMRB_COUNT);
269 	device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
270 	    dev_info, DDI_PROP_DONTPASS, "shared_splits",
271 	    XGE_HAL_DEFAULT_SHARED_SPLITS);
272 	device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
273 	    dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
274 	    XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
275 	device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
276 	    dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
277 	    XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
278 	/*
279 	 * Query PCI bus freqency from parent nexus driver.
280 	 * Note this property is only provided on SPARC platforms.
281 	 */
282 	device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
283 	    dev_info, 0, "clock-frequency",
284 	    XGE_HAL_PCI_FREQ_MHERZ_DEFAULT * 1000000) / 1000000;
285 
286 	/*
287 	 * Initialize ring properties
288 	 */
289 	device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
290 	    dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
291 	    XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
292 	device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
293 
294 #if defined(__sparc)
295 	device_config->ring.queue[XGELL_RING_MAIN_QID].no_snoop_bits = 1;
296 #endif
297 	device_config->ring.queue[XGELL_RING_MAIN_QID].max =
298 	    ddi_prop_get_int(DDI_DEV_T_ANY,
299 		dev_info, DDI_PROP_DONTPASS, "ring_main_max",
300 		XGE_HAL_DEFAULT_USE_HARDCODE);
301 	device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
302 	    ddi_prop_get_int(DDI_DEV_T_ANY,
303 		dev_info, DDI_PROP_DONTPASS, "ring_main_initial",
304 		XGE_HAL_DEFAULT_USE_HARDCODE);
305 	if (device_config->ring.queue[XGELL_RING_MAIN_QID].initial ==
306 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
307 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
308 			device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
309 			    device_config->ring.queue[XGELL_RING_MAIN_QID].max =
310 			    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS_J;
311 		} else {
312 			device_config->ring.queue[XGELL_RING_MAIN_QID].initial =
313 			    device_config->ring.queue[XGELL_RING_MAIN_QID].max =
314 			    XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS_N;
315 		}
316 	}
317 	device_config->ring.queue[XGELL_RING_MAIN_QID].buffer_mode =
318 	    ddi_prop_get_int(DDI_DEV_T_ANY,
319 		dev_info, DDI_PROP_DONTPASS, "ring_main_buffer_mode",
320 		XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
321 	device_config->ring.queue[XGELL_RING_MAIN_QID].dram_size_mb =
322 	    ddi_prop_get_int(DDI_DEV_T_ANY,
323 		dev_info, DDI_PROP_DONTPASS, "ring_main_dram_size_mb",
324 		XGE_HAL_DEFAULT_USE_HARDCODE);
325 	device_config->ring.queue[XGELL_RING_MAIN_QID].backoff_interval_us =
326 	    ddi_prop_get_int(DDI_DEV_T_ANY,
327 		dev_info, DDI_PROP_DONTPASS, "ring_main_backoff_interval_us",
328 		XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
329 	device_config->ring.queue[XGELL_RING_MAIN_QID].max_frm_len =
330 	    ddi_prop_get_int(DDI_DEV_T_ANY,
331 		dev_info, DDI_PROP_DONTPASS, "ring_main_max_frm_len",
332 		XGE_HAL_RING_USE_MTU);
333 	device_config->ring.queue[XGELL_RING_MAIN_QID].priority =
334 	    ddi_prop_get_int(DDI_DEV_T_ANY,
335 		dev_info, DDI_PROP_DONTPASS, "ring_main_priority",
336 		XGE_HAL_DEFAULT_RING_PRIORITY);
337 	device_config->ring.queue[XGELL_RING_MAIN_QID].configured =
338 	    ddi_prop_get_int(DDI_DEV_T_ANY,
339 		dev_info, DDI_PROP_DONTPASS, "ring_main_configured",
340 		1); /* HAL never provide a good named macro */
341 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_a =
342 	    ddi_prop_get_int(DDI_DEV_T_ANY,
343 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_a",
344 		XGE_HAL_DEFAULT_RX_URANGE_A);
345 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_a =
346 	    ddi_prop_get_int(DDI_DEV_T_ANY,
347 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_a",
348 		XGE_HAL_DEFAULT_RX_UFC_A);
349 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_b =
350 	    ddi_prop_get_int(DDI_DEV_T_ANY,
351 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_b",
352 		XGE_HAL_DEFAULT_RX_URANGE_B);
353 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_b =
354 	    ddi_prop_get_int(DDI_DEV_T_ANY,
355 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_b",
356 		XGE_HAL_DEFAULT_RX_UFC_B);
357 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.urange_c =
358 	    ddi_prop_get_int(DDI_DEV_T_ANY,
359 		dev_info, DDI_PROP_DONTPASS, "ring_main_urange_c",
360 		XGE_HAL_DEFAULT_RX_URANGE_C);
361 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_c =
362 	    ddi_prop_get_int(DDI_DEV_T_ANY,
363 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_c",
364 		XGE_HAL_DEFAULT_RX_UFC_C);
365 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.ufc_d =
366 	    ddi_prop_get_int(DDI_DEV_T_ANY,
367 		dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_d",
368 		XGE_HAL_DEFAULT_RX_UFC_D);
369 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.timer_val_us =
370 	    ddi_prop_get_int(DDI_DEV_T_ANY,
371 		dev_info, DDI_PROP_DONTPASS, "ring_main_timer_val",
372 		XGE_HAL_DEFAULT_RX_TIMER_VAL);
373 	device_config->ring.queue[XGELL_RING_MAIN_QID].rti.timer_ac_en =
374 	    ddi_prop_get_int(DDI_DEV_T_ANY,
375 		dev_info, DDI_PROP_DONTPASS, "ring_main_timer_ac_en",
376 		XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
377 	device_config->ring.queue[XGELL_RING_MAIN_QID].indicate_max_pkts =
378 	    ddi_prop_get_int(DDI_DEV_T_ANY,
379 		dev_info, DDI_PROP_DONTPASS, "ring_main_indicate_max_pkts",
380 		XGE_HAL_DEFAULT_INDICATE_MAX_PKTS);
381 
382 	/* adaptive rx coalesing */
383 	device_config->sched_timer_us = ddi_prop_get_int(DDI_DEV_T_ANY,
384 	    dev_info, DDI_PROP_DONTPASS, "ring_main_ufc_a_timer",
385 	    0);
386 	device_config->rxufca_intr_thres = ddi_prop_get_int(DDI_DEV_T_ANY,
387 	    dev_info, DDI_PROP_DONTPASS, "rxufca_intr_thres",
388 	    35);
389 	device_config->rxufca_lo_lim = ddi_prop_get_int(DDI_DEV_T_ANY,
390 	    dev_info, DDI_PROP_DONTPASS, "rxufca_lo_lim",
391 	    1);
392 	device_config->rxufca_hi_lim = ddi_prop_get_int(DDI_DEV_T_ANY,
393 	    dev_info, DDI_PROP_DONTPASS, "rxufca_hi_lim",
394 	    16);
395 	device_config->rxufca_lbolt_period = ddi_prop_get_int(DDI_DEV_T_ANY,
396 	    dev_info, DDI_PROP_DONTPASS, "rxufca_lbolt_period",
397 	    1);
398 
399 	/*
400 	 * Initialize mac properties
401 	 */
402 	device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
403 	    dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
404 	    XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
405 	device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
406 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
407 	    XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
408 	device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
409 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
410 	    1); /* HAL never provide a good named macro */
411 	device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
412 	    dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
413 	    XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
414 	device_config->mac.mc_pause_threshold_q0q3 =
415 	    ddi_prop_get_int(DDI_DEV_T_ANY,
416 		dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
417 		XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
418 	device_config->mac.mc_pause_threshold_q4q7 =
419 	    ddi_prop_get_int(DDI_DEV_T_ANY,
420 		dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
421 		XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
422 
423 	/*
424 	 * Initialize fifo properties
425 	 */
426 	device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
427 	    dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
428 	    XGE_HAL_DEFAULT_FIFO_FRAGS);
429 	if (device_config->fifo.max_frags == XGE_HAL_DEFAULT_USE_HARDCODE)
430 	    device_config->fifo.max_frags = XGE_HAL_DEFAULT_FIFO_FRAGS;
431 	device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
432 	    dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
433 	    XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
434 	device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
435 	    dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
436 	    XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
437 #ifdef XGE_HAL_ALIGN_XMIT
438 	device_config->fifo.alignment_size =
439 	    XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE;
440 	device_config->fifo.max_aligned_frags =
441 	    XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS;
442 #endif
443 #if defined(__sparc)
444 	device_config->fifo.queue[0].no_snoop_bits = 1;
445 #endif
446 	device_config->fifo.queue[0].max = ddi_prop_get_int(DDI_DEV_T_ANY,
447 	    dev_info, DDI_PROP_DONTPASS, "fifo0_max",
448 	    XGE_HAL_DEFAULT_USE_HARDCODE);
449 	device_config->fifo.queue[0].initial = ddi_prop_get_int(DDI_DEV_T_ANY,
450 	    dev_info, DDI_PROP_DONTPASS, "fifo0_initial",
451 	    XGE_HAL_DEFAULT_USE_HARDCODE);
452 	if (device_config->fifo.queue[0].initial ==
453 	    XGE_HAL_DEFAULT_USE_HARDCODE) {
454 		if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
455 			device_config->fifo.queue[0].initial =
456 			    device_config->fifo.queue[0].max =
457 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
458 		} else {
459 			device_config->fifo.queue[0].initial =
460 			    device_config->fifo.queue[0].max =
461 			    XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
462 		}
463 	}
464 	device_config->fifo.queue[0].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
465 	    dev_info, DDI_PROP_DONTPASS, "fifo0_intr",
466 	    XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
467 	device_config->fifo.queue[0].configured =
468 	    ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
469 		"fifo0_configured", 1);
470 
471 	/*
472 	 * Initialize tti properties
473 	 */
474 	device_config->tti.enabled = ddi_prop_get_int(DDI_DEV_T_ANY,
475 	    dev_info, DDI_PROP_DONTPASS, "tti_enabled",
476 	    XGE_HAL_TTI_ENABLE);
477 	device_config->tti.urange_a = ddi_prop_get_int(DDI_DEV_T_ANY,
478 	    dev_info, DDI_PROP_DONTPASS, "tti_urange_a",
479 	    XGE_HAL_DEFAULT_TX_URANGE_A);
480 	device_config->tti.ufc_a = ddi_prop_get_int(DDI_DEV_T_ANY,
481 	    dev_info, DDI_PROP_DONTPASS, "tti_ufc_a",
482 	    XGE_HAL_DEFAULT_TX_UFC_A);
483 	device_config->tti.urange_b = ddi_prop_get_int(DDI_DEV_T_ANY,
484 	    dev_info, DDI_PROP_DONTPASS, "tti_urange_b",
485 	    XGE_HAL_DEFAULT_TX_URANGE_B);
486 	device_config->tti.ufc_b = ddi_prop_get_int(DDI_DEV_T_ANY,
487 	    dev_info, DDI_PROP_DONTPASS, "tti_ufc_b",
488 	    XGE_HAL_DEFAULT_TX_UFC_B);
489 	device_config->tti.urange_c = ddi_prop_get_int(DDI_DEV_T_ANY,
490 	    dev_info, DDI_PROP_DONTPASS, "tti_urange_c",
491 	    XGE_HAL_DEFAULT_TX_URANGE_C);
492 	device_config->tti.ufc_c = ddi_prop_get_int(DDI_DEV_T_ANY,
493 	    dev_info, DDI_PROP_DONTPASS, "tti_ufc_c",
494 	    XGE_HAL_DEFAULT_TX_UFC_C);
495 	device_config->tti.ufc_d = ddi_prop_get_int(DDI_DEV_T_ANY,
496 	    dev_info, DDI_PROP_DONTPASS, "tti_ufc_d",
497 	    XGE_HAL_DEFAULT_TX_UFC_D);
498 	device_config->tti.timer_val_us = ddi_prop_get_int(DDI_DEV_T_ANY,
499 	    dev_info, DDI_PROP_DONTPASS, "tti_timer_ac_en",
500 	    XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
501 	device_config->tti.timer_val_us = ddi_prop_get_int(DDI_DEV_T_ANY,
502 	    dev_info, DDI_PROP_DONTPASS, "tti_timer_val",
503 	    XGE_HAL_DEFAULT_TX_TIMER_VAL);
504 	device_config->tti.timer_ci_en = ddi_prop_get_int(DDI_DEV_T_ANY,
505 	    dev_info, DDI_PROP_DONTPASS, "tti_timer_ci_en",
506 	    XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
507 
508 	/*
509 	 * Initialize errors dumping
510 	 */
511 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
512 	    dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
513 	    0);
514 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
515 	    dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
516 	    0);
517 	device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
518 	    dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
519 	    0);
520 
521 	/*
522 	 * Initialize link layer configuration
523 	 */
524 	ll_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
525 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
526 	    XGELL_RX_BUFFER_TOTAL);
527 	ll_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
528 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
529 	    XGELL_RX_BUFFER_POST_HIWAT);
530 	ll_config->rx_buffer_recycle_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
531 	    dev_info, DDI_PROP_DONTPASS, "rx_buffer_recycle_hiwat",
532 	    XGELL_RX_BUFFER_RECYCLE_HIWAT);
533 }
534 
535 /*
536  * xge_attach
537  * @dev_info: pointer to dev_info_t structure
538  * @cmd: attach command to process
539  *
540  * This is a solaris standard attach function.  This
541  * function initializes the Xframe  identified
542  * by the dev_info_t structure and setup the driver
543  * data structures corresponding to the Xframe Card.
544  * This function also registers the XFRAME device
545  * instance with the MAC Layer.
546  * If this function returns success then the OS
547  * will attach the HBA controller to this
548  * driver.
549  */
550 static int
551 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
552 {
553 	xgelldev_t *ll;
554 	xge_hal_device_config_t device_config;
555 	xge_hal_device_t *hldev;
556 	xge_hal_device_attr_t attr;
557 	xge_hal_status_e status;
558 	xgell_config_t ll_config;
559 	int ret;
560 
561 	xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
562 
563 	switch (cmd) {
564 	case DDI_ATTACH:
565 		break;
566 
567 	case DDI_RESUME:
568 	case DDI_PM_RESUME:
569 		xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
570 		ret = DDI_FAILURE;
571 		goto _exit0;
572 
573 	default:
574 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
575 		ret = DDI_FAILURE;
576 		goto _exit0;
577 	}
578 
579 	xge_os_memzero(&device_config, sizeof (xge_hal_device_config_t));
580 
581 	/* Init device_config by lookup up properties from .conf file */
582 	xge_configuration_init(dev_info, &device_config, &ll_config);
583 
584 	/* map BAR0 */
585 	ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
586 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
587 	if (ret != DDI_SUCCESS) {
588 		xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
589 		goto _exit0;
590 	}
591 
592 	/* map BAR1 */
593 	ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
594 	    (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
595 	if (ret != DDI_SUCCESS) {
596 		xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
597 		goto _exit1;
598 	}
599 
600 	/* preallocate memory for new HAL device and private LL part */
601 	hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
602 	if (hldev == NULL) {
603 		xge_debug_osdep(XGE_ERR, "%s", "can not allocate memory");
604 		ret = DDI_ENOMEM;
605 		goto _exit2;
606 	}
607 
608 	/* get the interrupt block cookie associated with the interrupt */
609 	ret = ddi_get_iblock_cookie(dev_info, 0, &attr.irqh);
610 	if (ret != DDI_SUCCESS) {
611 		xge_debug_osdep(XGE_ERR, "%s", "can not get interrupt cookie");
612 		goto _exit2a;
613 	}
614 
615 	/* Get the PCI Configuartion space handle */
616 	ret = pci_config_setup(dev_info, &attr.cfgh);
617 	if (ret != DDI_SUCCESS) {
618 		xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
619 		goto _exit2a;
620 	}
621 
622 	attr.pdev = dev_info;
623 
624 	ret = xgell_device_alloc(hldev, dev_info, &ll);
625 	if (ret != DDI_SUCCESS) {
626 		xge_debug_osdep(XGE_ERR,
627 		    "%s",
628 		    "unable to allocate new LL device");
629 		goto _exit3;
630 	}
631 
632 	/* attach an interrupt handler for handling Xge device interrupts */
633 	ret = ddi_add_intr(dev_info, 0, &attr.irqh, NULL, xge_isr,
634 	    (caddr_t)hldev);
635 	if (ret != DDI_SUCCESS) {
636 		xge_debug_osdep(XGE_ERR, "%s", "unable to register ISR");
637 		goto _exit3a;
638 	}
639 
640 	/* initialize HW */
641 	status = xge_hal_device_initialize(hldev, &attr, &device_config);
642 	if (status != XGE_HAL_OK) {
643 		switch (status) {
644 		case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
645 			xge_debug_osdep(XGE_ERR, "%s",
646 			    "driver is not initialized");
647 			ret = DDI_FAILURE;
648 			goto _exit3b;
649 		case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
650 			xge_debug_osdep(XGE_ERR, "%s",
651 			    "device is not quiescent");
652 			ret = DDI_EBUSY;
653 			goto _exit3b;
654 		case XGE_HAL_ERR_OUT_OF_MEMORY:
655 			xge_debug_osdep(XGE_ERR, "%s",
656 			    "unable to allocate memory");
657 			ret = DDI_ENOMEM;
658 			goto _exit3b;
659 		default:
660 			xge_debug_osdep(XGE_ERR,
661 			    "can't initialize the device: %d", status);
662 			ret = DDI_FAILURE;
663 			goto _exit3b;
664 		}
665 	}
666 
667 	/* allocate and register Link Layer */
668 	ret = xgell_device_register(ll, &ll_config);
669 	if (ret != DDI_SUCCESS) {
670 		goto _exit4;
671 	}
672 
673 	/* store ll as a HAL private part */
674 	xge_hal_device_private_set(hldev, ll);
675 
676 	return (DDI_SUCCESS);
677 
678 _exit4:
679 	xge_hal_device_terminate(hldev);
680 _exit3b:
681 	ddi_remove_intr(attr.pdev, 0, hldev->irqh);
682 _exit3a:
683 	xgell_device_free(ll);
684 _exit3:
685 	pci_config_teardown(&attr.cfgh);
686 _exit2a:
687 	kmem_free(hldev, sizeof (xge_hal_device_t));
688 _exit2:
689 	ddi_regs_map_free(&attr.regh1);
690 _exit1:
691 	ddi_regs_map_free(&attr.regh0);
692 _exit0:
693 	return (ret);
694 }
695 
696 /*
697  * xge_detach
698  * @dev_info: pointer to dev_info_t structure
699  * @cmd: attach command to process
700  *
701  * This function is called by OS when the system is about
702  * to shutdown or when the super user tries to unload
703  * the driver. This function frees all the memory allocated
704  * during xge_attch() and also unregisters the Xframe
705  * device instance from the GLD framework.
706  */
707 static int
708 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
709 {
710 	xge_hal_device_t *hldev;
711 	xge_hal_device_attr_t *attr;
712 	xgelldev_t *lldev;
713 
714 	xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
715 
716 	hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
717 	attr = xge_hal_device_attr(hldev);
718 	lldev = xge_hal_device_private(hldev);
719 
720 	switch (cmd) {
721 	case DDI_DETACH:
722 		break;
723 
724 	case DDI_PM_SUSPEND:
725 		xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
726 		return (DDI_FAILURE);
727 
728 	default:
729 		xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
730 		return (DDI_FAILURE);
731 	}
732 
733 	if (lldev->is_initialized) {
734 		xge_debug_osdep(XGE_ERR, "%s",
735 		    "can not detach: device is not unplumbed");
736 		return (DDI_FAILURE);
737 	}
738 
739 	xge_hal_device_terminating(hldev);
740 	if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
741 		return (DDI_FAILURE);
742 	}
743 	xge_hal_device_terminate(hldev);
744 
745 	ddi_remove_intr(attr->pdev, 0, attr->irqh);
746 	xgell_device_free(lldev);
747 	pci_config_teardown(&attr->cfgh);
748 	ddi_regs_map_free(&attr->regh1);
749 	ddi_regs_map_free(&attr->regh0);
750 	kmem_free(hldev, sizeof (xge_hal_device_t));
751 
752 	return (DDI_SUCCESS);
753 }
754