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