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 2010 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Source file containing the implementation of the driver entry points
29  * and related helper functions
30  */
31 
32 #include <oce_impl.h>
33 #include <oce_stat.h>
34 #include <oce_ioctl.h>
35 
36 #define	ATTACH_DEV_INIT 	0x1
37 #define	ATTACH_FM_INIT		0x2
38 #define	ATTACH_LOCK_INIT	0x4
39 #define	ATTACH_PCI_INIT 	0x8
40 #define	ATTACH_HW_INIT		0x10
41 #define	ATTACH_SETUP_TXRX 	0x20
42 #define	ATTACH_SETUP_ADAP	0x40
43 #define	ATTACH_STAT_INIT	0x100
44 #define	ATTACH_MAC_REG		0x200
45 
46 /* ---[ globals and externs ]-------------------------------------------- */
47 const char oce_ident_string[] = OCE_IDENT_STRING;
48 const char oce_mod_name[] = OCE_MOD_NAME;
49 
50 char oce_version[] = OCE_REVISION;
51 
52 /* driver properties */
53 static const char mtu_prop_name[] = "oce_default_mtu";
54 static const char tx_ring_size_name[] = "oce_tx_ring_size";
55 static const char tx_bcopy_limit_name[] = "oce_tx_bcopy_limit";
56 static const char rx_bcopy_limit_name[] = "oce_rx_bcopy_limit";
57 static const char fm_cap_name[] = "oce_fm_capability";
58 static const char log_level_name[] = "oce_log_level";
59 static const char lso_capable_name[] = "oce_lso_capable";
60 
61 /* --[ static function prototypes here ]------------------------------- */
62 static int oce_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
63 static int oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
64 static int oce_quiesce(dev_info_t *dip);
65 static int oce_suspend(dev_info_t *dip);
66 static int oce_resume(dev_info_t *dip);
67 static void oce_unconfigure(struct oce_dev *dev);
68 static void oce_init_locks(struct oce_dev *dev);
69 static void oce_destroy_locks(struct oce_dev *dev);
70 static void oce_get_params(struct oce_dev *dev);
71 
72 static struct cb_ops oce_cb_ops = {
73 	nulldev,		/* cb_open */
74 	nulldev,		/* cb_close */
75 	nodev,			/* cb_strategy */
76 	nodev,			/* cb_print */
77 	nodev,			/* cb_dump */
78 	nodev,			/* cb_read */
79 	nodev,			/* cb_write */
80 	nodev,			/* cb_ioctl */
81 	nodev,			/* cb_devmap */
82 	nodev,			/* cb_mmap */
83 	nodev,			/* cb_segmap */
84 	nochpoll,		/* cb_chpoll */
85 	ddi_prop_op,	/* cb_prop_op */
86 	NULL,			/* cb_stream */
87 	D_MP,			/* cb_flag */
88 	CB_REV,			/* cb_rev */
89 	nodev,			/* cb_aread */
90 	nodev			/* cb_awrite */
91 };
92 
93 static struct dev_ops oce_dev_ops = {
94 	DEVO_REV,	/* devo_rev */
95 	0,		/* devo_refcnt */
96 	NULL,		/* devo_getinfo */
97 	NULL,		/* devo_identify */
98 	nulldev,	/* devo_probe */
99 	oce_attach,	/* devo_attach */
100 	oce_detach,	/* devo_detach */
101 	nodev,		/* devo_reset */
102 	&oce_cb_ops,	/* devo_cb_ops */
103 	NULL,		/* devo_bus_ops */
104 	nodev,		/* devo_power */
105 	oce_quiesce	/* devo_quiesce */
106 };
107 
108 static struct modldrv oce_drv = {
109 	&mod_driverops,	/* Type of module.  This one is a driver */
110 	(char *)oce_ident_string, /* Description string */
111 	&oce_dev_ops,	/* driver ops */
112 };
113 
114 static struct modlinkage oce_mod_linkage = {
115 	MODREV_1, &oce_drv, NULL
116 };
117 
118 #define	OCE_M_CB_FLAGS	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | \
119     MC_PROPINFO)
120 static mac_callbacks_t oce_mac_cb = {
121 	OCE_M_CB_FLAGS,		/* mc_callbacks */
122 	oce_m_stat,		/* mc_getstat */
123 	oce_m_start,		/* mc_start */
124 	oce_m_stop,		/* mc_stop */
125 	oce_m_promiscuous,	/* mc_setpromisc */
126 	oce_m_multicast,	/* mc_multicast */
127 	oce_m_unicast,		/* mc_unicast */
128 	oce_m_send,		/* mc_tx */
129 	NULL,			/* mc_reserve */
130 	oce_m_ioctl,		/* mc_ioctl */
131 	oce_m_getcap,		/* mc_getcapab */
132 	NULL,			/* open */
133 	NULL,			/* close */
134 	oce_m_setprop,		/* set properties */
135 	oce_m_getprop,		/* get properties */
136 	oce_m_propinfo		/* properties info */
137 };
138 
139 extern char *oce_priv_props[];
140 
141 /* Module Init */
142 int
143 _info(struct modinfo *modinfop)
144 {
145 	return (mod_info(&oce_mod_linkage, modinfop));
146 } /* _info */
147 
148 int
149 _init(void)
150 {
151 	int ret = 0;
152 
153 	/* install the module */
154 	mac_init_ops(&oce_dev_ops, "oce");
155 
156 	ret = mod_install(&oce_mod_linkage);
157 	if (ret) {
158 		cmn_err(CE_WARN, "mod_install failed  rval=%x", ret);
159 	}
160 
161 	return (ret);
162 } /* _init */
163 
164 
165 int
166 _fini(void)
167 {
168 	int ret = 0;
169 	/* remove the module */
170 	ret = mod_remove(&oce_mod_linkage);
171 	if (ret != 0) {
172 		return (ret);
173 	}
174 
175 	mac_fini_ops(&oce_dev_ops);
176 
177 	return (ret);
178 } /* _fini */
179 
180 
181 static int
182 oce_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
183 {
184 	int ret = 0;
185 	struct oce_dev *dev = NULL;
186 	mac_register_t *mac;
187 
188 	switch (cmd) {
189 	case DDI_RESUME:
190 		return (oce_resume(dip));
191 	default:
192 		return (DDI_FAILURE);
193 
194 	case DDI_ATTACH:
195 		break;
196 	}
197 
198 	/* allocate dev */
199 	dev = kmem_zalloc(sizeof (struct oce_dev), KM_NOSLEEP);
200 	if (dev == NULL) {
201 		return (DDI_FAILURE);
202 	}
203 
204 	/* populate the dev structure */
205 	dev->dip = dip;
206 	dev->dev_id = ddi_get_instance(dip);
207 	dev->suspended = B_FALSE;
208 
209 	/* get the parameters */
210 	oce_get_params(dev);
211 
212 	/*
213 	 * set the ddi driver private data pointer. This is
214 	 * sent to all mac callback entry points
215 	 */
216 	ddi_set_driver_private(dip, dev);
217 
218 	dev->attach_state |= ATTACH_DEV_INIT;
219 
220 	oce_fm_init(dev);
221 	dev->attach_state |= ATTACH_FM_INIT;
222 	ret = oce_setup_intr(dev);
223 	if (ret != DDI_SUCCESS) {
224 		oce_log(dev, CE_WARN, MOD_CONFIG,
225 		    "Interrupt setup failed with %d", ret);
226 		goto attach_fail;
227 
228 	}
229 
230 	/* initialize locks */
231 	oce_init_locks(dev);
232 	dev->attach_state |= ATTACH_LOCK_INIT;
233 
234 	/* setup PCI bars */
235 	ret = oce_pci_init(dev);
236 	if (ret != DDI_SUCCESS) {
237 		oce_log(dev, CE_WARN, MOD_CONFIG,
238 		    "PCI initialization failed with %d", ret);
239 		goto attach_fail;
240 	}
241 	dev->attach_state |= ATTACH_PCI_INIT;
242 
243 	/* HW init */
244 	ret = oce_hw_init(dev);
245 	if (ret != DDI_SUCCESS) {
246 		oce_log(dev, CE_WARN, MOD_CONFIG,
247 		    "HW initialization failed with %d", ret);
248 		goto attach_fail;
249 	}
250 	dev->attach_state |= ATTACH_HW_INIT;
251 
252 	ret = oce_init_txrx(dev);
253 	if (ret  != DDI_SUCCESS) {
254 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
255 		    "Failed to init rings");
256 		goto attach_fail;
257 	}
258 	dev->attach_state |= ATTACH_SETUP_TXRX;
259 
260 	ret = oce_setup_adapter(dev);
261 	if (ret != DDI_SUCCESS) {
262 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
263 		    "Failed to setup adapter");
264 		goto attach_fail;
265 	}
266 	dev->attach_state |=  ATTACH_SETUP_ADAP;
267 
268 
269 	ret = oce_stat_init(dev);
270 	if (ret != DDI_SUCCESS) {
271 		oce_log(dev, CE_WARN, MOD_CONFIG,
272 		    "kstat setup Failed with %d", ret);
273 		goto attach_fail;
274 	}
275 	dev->attach_state |= ATTACH_STAT_INIT;
276 
277 	/* mac_register_t */
278 	oce_log(dev, CE_NOTE, MOD_CONFIG,
279 	    "MAC_VERSION = 0x%x", MAC_VERSION);
280 	mac = mac_alloc(MAC_VERSION);
281 	if (mac == NULL) {
282 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
283 		    "MAC allocation Failed");
284 		goto attach_fail;
285 	}
286 	/*
287 	 * fill the mac structure before calling mac_register
288 	 */
289 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
290 	mac->m_driver = dev;
291 	mac->m_dip = dip;
292 	mac->m_src_addr = dev->mac_addr;
293 	mac->m_callbacks = &oce_mac_cb;
294 	mac->m_min_sdu = 0;
295 	mac->m_max_sdu = dev->mtu;
296 	mac->m_margin = VLAN_TAGSZ;
297 	mac->m_priv_props = oce_priv_props;
298 
299 	oce_log(dev, CE_NOTE, MOD_CONFIG,
300 	    "Driver Private structure = 0x%p", (void *)dev);
301 
302 	/* now register with GLDv3 */
303 	ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle);
304 	/* regardless of the status, free mac_register */
305 	mac_free(mac);
306 	mac = NULL;
307 	if (ret != DDI_SUCCESS) {
308 		oce_log(dev, CE_WARN, MOD_CONFIG,
309 		    "MAC registration failed :0x%x", ret);
310 		goto attach_fail;
311 
312 	}
313 
314 	/* correct link status only after start */
315 	mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN);
316 
317 	dev->attach_state |= ATTACH_MAC_REG;
318 	dev->state |= STATE_INIT;
319 
320 	oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
321 	    "ATTACH SUCCESS");
322 
323 	return (DDI_SUCCESS);
324 
325 attach_fail:
326 	oce_unconfigure(dev);
327 	return (DDI_FAILURE);
328 } /* oce_attach */
329 
330 static int
331 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
332 {
333 	struct oce_dev *dev;
334 	int pcnt = 0;
335 
336 	dev = ddi_get_driver_private(dip);
337 	if (dev == NULL) {
338 		return (DDI_FAILURE);
339 	}
340 	oce_log(dev, CE_NOTE, MOD_CONFIG,
341 	    "Detaching driver: cmd = 0x%x", cmd);
342 
343 	switch (cmd) {
344 	default:
345 		return (DDI_FAILURE);
346 	case DDI_SUSPEND:
347 		return (oce_suspend(dip));
348 	case DDI_DETACH:
349 		break;
350 	} /* switch cmd */
351 
352 	/* Fail detach if MAC unregister is unsuccessfule */
353 	if (mac_unregister(dev->mac_handle) != 0) {
354 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
355 		    "Failed to unregister MAC ");
356 		return (DDI_FAILURE);
357 	}
358 	dev->attach_state &= ~ATTACH_MAC_REG;
359 
360 	/* check if the detach is called with out stopping */
361 	DEV_LOCK(dev);
362 	if (dev->state & STATE_MAC_STARTED) {
363 		dev->state &= ~STATE_MAC_STARTED;
364 		oce_stop(dev);
365 		DEV_UNLOCK(dev);
366 	} else
367 		DEV_UNLOCK(dev);
368 
369 	/*
370 	 * Wait for Packets sent up to be freed
371 	 */
372 	if ((pcnt = oce_rx_pending(dev)) != 0) {
373 		oce_log(dev, CE_WARN, MOD_CONFIG,
374 		    "%d Pending Buffers Detach failed", pcnt);
375 		return (DDI_FAILURE);
376 	}
377 	oce_unconfigure(dev);
378 
379 	return (DDI_SUCCESS);
380 } /* oce_detach */
381 
382 static int
383 oce_quiesce(dev_info_t *dip)
384 {
385 	int ret = DDI_SUCCESS;
386 	struct oce_dev *dev = ddi_get_driver_private(dip);
387 
388 	if (dev == NULL) {
389 		return (DDI_FAILURE);
390 	}
391 	if (dev->suspended) {
392 		return (DDI_SUCCESS);
393 	}
394 
395 	oce_chip_di(dev);
396 
397 	ret = oce_reset_fun(dev);
398 
399 	return (ret);
400 }
401 
402 static int
403 oce_suspend(dev_info_t *dip)
404 {
405 	struct oce_dev *dev = ddi_get_driver_private(dip);
406 
407 	mutex_enter(&dev->dev_lock);
408 	/* Suspend the card */
409 	dev->suspended = B_TRUE;
410 	/* stop the adapter */
411 	if (dev->state & STATE_MAC_STARTED) {
412 		oce_stop(dev);
413 		oce_unsetup_adapter(dev);
414 	}
415 	dev->state &= ~STATE_MAC_STARTED;
416 	mutex_exit(&dev->dev_lock);
417 	return (DDI_SUCCESS);
418 } /* oce_suspend */
419 
420 static int
421 oce_resume(dev_info_t *dip)
422 {
423 	struct oce_dev *dev;
424 	int ret;
425 
426 	/* get the dev pointer from dip */
427 	dev = ddi_get_driver_private(dip);
428 	mutex_enter(&dev->dev_lock);
429 	if (!dev->suspended) {
430 		mutex_exit(&dev->dev_lock);
431 		return (DDI_SUCCESS);
432 	}
433 	if (dev->state & STATE_MAC_STARTED) {
434 		ret = oce_setup_adapter(dev);
435 		if (ret != DDI_SUCCESS) {
436 			mutex_exit(&dev->dev_lock);
437 			return (DDI_FAILURE);
438 		}
439 		ret = oce_start(dev);
440 		if (ret != DDI_SUCCESS) {
441 			mutex_exit(&dev->dev_lock);
442 			return (DDI_FAILURE);
443 		}
444 	}
445 	dev->suspended = B_FALSE;
446 	dev->state |= STATE_MAC_STARTED;
447 	mutex_exit(&dev->dev_lock);
448 	return (ret);
449 } /* oce_resume */
450 
451 static void
452 oce_init_locks(struct oce_dev *dev)
453 {
454 	/* initialize locks */
455 	mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER,
456 	    DDI_INTR_PRI(dev->intr_pri));
457 	mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER,
458 	    DDI_INTR_PRI(dev->intr_pri));
459 } /* oce_init_locks */
460 
461 static void
462 oce_destroy_locks(struct oce_dev *dev)
463 {
464 	mutex_destroy(&dev->dev_lock);
465 	mutex_destroy(&dev->bmbx_lock);
466 } /* oce_destroy_locks */
467 
468 static void
469 oce_unconfigure(struct oce_dev *dev)
470 {
471 	uint32_t state = dev->attach_state;
472 
473 	if (state & ATTACH_MAC_REG) {
474 		(void) mac_unregister(dev->mac_handle);
475 	}
476 	if (state & ATTACH_STAT_INIT) {
477 		oce_stat_fini(dev);
478 	}
479 	if (state & ATTACH_SETUP_ADAP) {
480 		oce_unsetup_adapter(dev);
481 	}
482 
483 	if (state & ATTACH_SETUP_TXRX) {
484 		oce_fini_txrx(dev);
485 	}
486 
487 	if (state & ATTACH_HW_INIT) {
488 		oce_hw_fini(dev);
489 	}
490 	if (state & ATTACH_PCI_INIT) {
491 		oce_pci_fini(dev);
492 	}
493 	if (state & ATTACH_LOCK_INIT) {
494 		oce_destroy_locks(dev);
495 	}
496 	if (state & ATTACH_FM_INIT) {
497 		oce_fm_fini(dev);
498 	}
499 	if (state & ATTACH_DEV_INIT) {
500 		ddi_set_driver_private(dev->dip, NULL);
501 		kmem_free(dev, sizeof (struct oce_dev));
502 	}
503 } /* oce_unconfigure */
504 
505 static void
506 oce_get_params(struct oce_dev *dev)
507 {
508 	uint32_t log_level;
509 	uint16_t mod_mask;
510 	uint16_t severity;
511 
512 	/* non tunables  */
513 	dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE;
514 	dev->flow_control = OCE_DEFAULT_FLOW_CONTROL;
515 
516 	/* configurable parameters */
517 
518 	/* restrict MTU to 1500 and 9000 only */
519 	dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
520 	    DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU);
521 	if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU)
522 		dev->mtu = OCE_MIN_MTU;
523 
524 	dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
525 	    DDI_PROP_DONTPASS, (char *)tx_ring_size_name,
526 	    OCE_DEFAULT_TX_RING_SIZE);
527 
528 	dev->tx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
529 	    DDI_PROP_DONTPASS, (char *)tx_bcopy_limit_name,
530 	    OCE_DEFAULT_TX_BCOPY_LIMIT);
531 	dev->rx_bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
532 	    DDI_PROP_DONTPASS, (char *)rx_bcopy_limit_name,
533 	    OCE_DEFAULT_RX_BCOPY_LIMIT);
534 
535 	dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
536 	    DDI_PROP_DONTPASS, (char *)lso_capable_name, 1);
537 
538 	dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
539 	    DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY);
540 
541 	log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
542 	    DDI_PROP_DONTPASS, (char *)log_level_name,
543 	    OCE_DEFAULT_LOG_SETTINGS);
544 	severity = (uint16_t)(log_level & 0xffff);
545 	mod_mask = (uint16_t)(log_level >> 16);
546 	if (mod_mask > MOD_ISR) {
547 		mod_mask = 0;
548 	}
549 	if (severity > CE_IGNORE) {
550 		severity = 0;
551 	}
552 
553 	dev->mod_mask = mod_mask;
554 	dev->severity = severity;
555 } /* oce_get_params */
556