xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/oce/oce_main.c (revision 2dea4eed7ad1c66ae4770263aa2911815a8b86eb)
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_SETUP_INTR	0x4
39 #define	ATTACH_LOCK_INIT	0x8
40 #define	ATTACH_PCI_INIT 	0x10
41 #define	ATTACH_BOOTSTRAP_INIT	0x20
42 #define	ATTACH_HW_INIT		0x40
43 #define	ATTACH_ADD_HANDLERS	0x80
44 #define	ATTACH_STAT_INIT	0x100
45 #define	ATTACH_MAC_REG		0x200
46 
47 /* ---[ globals and externs ]-------------------------------------------- */
48 const char oce_ident_string[] = OCE_IDENT_STRING;
49 const char oce_mod_name[] = OCE_MOD_NAME;
50 static const char oce_desc_string[] = OCE_DESC_STRING;
51 
52 char oce_version[] = OCE_REVISION;
53 
54 /* driver properties */
55 static const char mtu_prop_name[] = "oce_default_mtu";
56 static const char tx_ring_size_name[] = "oce_tx_ring_size";
57 static const char bcopy_limit_name[] = "oce_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 int oce_reset_fun(struct oce_dev *dev);
73 
74 static struct cb_ops oce_cb_ops = {
75 	nulldev,		/* cb_open */
76 	nulldev,		/* cb_close */
77 	nodev,			/* cb_strategy */
78 	nodev,			/* cb_print */
79 	nodev,			/* cb_dump */
80 	nodev,			/* cb_read */
81 	nodev,			/* cb_write */
82 	nodev,			/* cb_ioctl */
83 	nodev,			/* cb_devmap */
84 	nodev,			/* cb_mmap */
85 	nodev,			/* cb_segmap */
86 	nochpoll,		/* cb_chpoll */
87 	ddi_prop_op,	/* cb_prop_op */
88 	NULL,			/* cb_stream */
89 	D_MP,			/* cb_flag */
90 	CB_REV,			/* cb_rev */
91 	nodev,			/* cb_aread */
92 	nodev			/* cb_awrite */
93 };
94 
95 static struct dev_ops oce_dev_ops = {
96 	DEVO_REV,	/* devo_rev */
97 	0,		/* devo_refcnt */
98 	NULL,		/* devo_getinfo */
99 	NULL,		/* devo_identify */
100 	nulldev,	/* devo_probe */
101 	oce_attach,	/* devo_attach */
102 	oce_detach,	/* devo_detach */
103 	nodev,		/* devo_reset */
104 	&oce_cb_ops,	/* devo_cb_ops */
105 	NULL,		/* devo_bus_ops */
106 	nodev,		/* devo_power */
107 	oce_quiesce	/* devo_quiesce */
108 };
109 
110 static struct modldrv oce_drv = {
111 	&mod_driverops,	/* Type of module.  This one is a driver */
112 	(char *)oce_ident_string, /* Description string */
113 	&oce_dev_ops,	/* driver ops */
114 };
115 
116 static struct modlinkage oce_mod_linkage = {
117 	MODREV_1, &oce_drv, NULL
118 };
119 
120 #define	OCE_M_CB_FLAGS	(MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
121 static mac_callbacks_t oce_mac_cb = {
122 	OCE_M_CB_FLAGS,		/* mc_callbacks */
123 	oce_m_stat,		/* mc_getstat */
124 	oce_m_start,		/* mc_start */
125 	oce_m_stop,		/* mc_stop */
126 	oce_m_promiscuous,	/* mc_setpromisc */
127 	oce_m_multicast,	/* mc_multicast */
128 	oce_m_unicast,		/* mc_unicast */
129 	oce_m_send,		/* mc_tx */
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 };
137 
138 extern mac_priv_prop_t oce_priv_props[];
139 extern uint32_t oce_num_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 	int intr_types;
186 	struct oce_dev *dev = NULL;
187 	mac_register_t *mac;
188 	struct mac_address_format mac_addr;
189 
190 	switch (cmd) {
191 	case DDI_RESUME:
192 		return (oce_resume(dip));
193 	default:
194 		return (DDI_FAILURE);
195 
196 	case DDI_ATTACH:
197 		break;
198 	}
199 	oce_log(dev, CE_CONT, MOD_CONFIG, "!%s, %s",
200 	    oce_desc_string, oce_version);
201 
202 
203 	/* get supported intr types */
204 	ret = ddi_intr_get_supported_types(dip, &intr_types);
205 	if (ret != DDI_SUCCESS) {
206 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
207 		    "Failed to retrieve intr types ");
208 		return (DDI_FAILURE);
209 	}
210 
211 	/* allocate dev */
212 	dev = kmem_zalloc(sizeof (struct oce_dev), KM_SLEEP);
213 
214 	/* populate the dev structure */
215 	dev->dip = dip;
216 	dev->dev_id = ddi_get_instance(dip);
217 	dev->intr_types = intr_types;
218 	dev->suspended = B_FALSE;
219 
220 	/* get the parameters */
221 	oce_get_params(dev);
222 
223 	/*
224 	 * set the ddi driver private data pointer. This is
225 	 * sent to all mac callback entry points
226 	 */
227 	ddi_set_driver_private(dip, dev);
228 
229 	dev->attach_state |= ATTACH_DEV_INIT;
230 
231 	oce_fm_init(dev);
232 	dev->attach_state |= ATTACH_FM_INIT;
233 
234 	ret = oce_setup_intr(dev);
235 	if (ret != DDI_SUCCESS) {
236 		oce_log(dev, CE_WARN, MOD_CONFIG,
237 		    "Interrupt setup failed with %d", ret);
238 		goto attach_fail;
239 	}
240 	dev->attach_state |= ATTACH_SETUP_INTR;
241 
242 	/* initialize locks */
243 	oce_init_locks(dev);
244 	dev->attach_state |= ATTACH_LOCK_INIT;
245 
246 	/* setup PCI bars */
247 	ret = oce_pci_init(dev);
248 	if (ret != DDI_SUCCESS) {
249 		oce_log(dev, CE_WARN, MOD_CONFIG,
250 		    "PCI initialization failed with %d", ret);
251 		goto attach_fail;
252 	}
253 	dev->attach_state |= ATTACH_PCI_INIT;
254 
255 	/* check if reset if required */
256 	if (oce_is_reset_pci(dev)) {
257 		ret = oce_pci_soft_reset(dev);
258 		if (ret) {
259 			oce_log(dev, CE_WARN, MOD_CONFIG,
260 			    "Device Reset failed: %d", ret);
261 			goto attach_fail;
262 		}
263 	}
264 
265 	/* create bootstrap mailbox */
266 	dev->bmbx = oce_alloc_dma_buffer(dev,
267 	    sizeof (struct oce_bmbx), DDI_DMA_CONSISTENT);
268 	if (dev->bmbx == NULL) {
269 		oce_log(dev, CE_WARN, MOD_CONFIG,
270 		    "Failed to allocate bmbx: size = %u",
271 		    (uint32_t)sizeof (struct oce_bmbx));
272 		goto attach_fail;
273 	}
274 	dev->attach_state |= ATTACH_BOOTSTRAP_INIT;
275 
276 	/* initialize the BMBX */
277 	ret = oce_mbox_init(dev);
278 	if (ret != 0) {
279 		oce_log(dev, CE_WARN, MOD_CONFIG,
280 		    "Mailbox initialization Failed with %d", ret);
281 		goto attach_fail;
282 	}
283 
284 	/* read the firmware version */
285 	ret = oce_get_fw_version(dev);
286 	if (ret != 0) {
287 		oce_log(dev, CE_WARN, MOD_CONFIG,
288 		    "Firmaware version read failed with %d", ret);
289 		goto attach_fail;
290 	}
291 
292 	/* read the fw config */
293 	ret = oce_get_fw_config(dev);
294 	if (ret != 0) {
295 		oce_log(dev, CE_WARN, MOD_CONFIG,
296 		    "Firmware configuration read failed with %d", ret);
297 		goto attach_fail;
298 	}
299 
300 	/* read the MAC address */
301 	ret = oce_read_mac_addr(dev, dev->if_id, 1,
302 	    MAC_ADDRESS_TYPE_NETWORK, &mac_addr);
303 	if (ret != 0) {
304 		oce_log(dev, CE_WARN, MOD_CONFIG,
305 		    "MAC address read failed with %d", ret);
306 		goto attach_fail;
307 	}
308 	bcopy(&mac_addr.mac_addr[0], &dev->mac_addr[0], ETHERADDRL);
309 
310 	ret = oce_stat_init(dev);
311 	if (ret != DDI_SUCCESS) {
312 		oce_log(dev, CE_WARN, MOD_CONFIG,
313 		    "kstat setup Failed with %d", ret);
314 		goto attach_fail;
315 	}
316 	dev->attach_state |= ATTACH_STAT_INIT;
317 
318 	/* mac_register_t */
319 	oce_log(dev, CE_NOTE, MOD_CONFIG,
320 	    "MAC_VERSION = 0x%x", MAC_VERSION);
321 	mac = mac_alloc(MAC_VERSION);
322 	if (mac == NULL) {
323 		oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
324 		    "MAC allocation Failed");
325 		goto attach_fail;
326 	}
327 	/*
328 	 * fill the mac structure before calling mac_register
329 	 */
330 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
331 	mac->m_driver = dev;
332 	mac->m_dip = dip;
333 	mac->m_src_addr = dev->mac_addr;
334 	mac->m_callbacks = &oce_mac_cb;
335 	mac->m_min_sdu = 0;
336 	mac->m_max_sdu = dev->mtu;
337 	mac->m_margin = VLAN_TAGSZ;
338 	mac->m_priv_props = oce_priv_props;
339 	mac->m_priv_prop_count = oce_num_props;
340 
341 	oce_log(dev, CE_NOTE, MOD_CONFIG,
342 	    "Driver Private structure = 0x%p", (void *)dev);
343 
344 	/* now register with GLDv3 */
345 	ret = mac_register(mac, (mac_handle_t *)&dev->mac_handle);
346 	/* regardless of the status, free mac_register */
347 	mac_free(mac);
348 	mac = NULL;
349 	if (ret != DDI_SUCCESS) {
350 		oce_log(dev, CE_WARN, MOD_CONFIG,
351 		    "MAC registration failed :0x%x", ret);
352 		goto attach_fail;
353 
354 	}
355 
356 	/* correct link status only after start */
357 	mac_link_update(dev->mac_handle, LINK_STATE_UNKNOWN);
358 
359 	dev->attach_state |= ATTACH_MAC_REG;
360 	dev->state |= STATE_INIT;
361 	oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
362 	    "ATTACH SUCCESS");
363 
364 	return (DDI_SUCCESS);
365 
366 attach_fail:
367 	oce_unconfigure(dev);
368 	return (DDI_FAILURE);
369 } /* oce_attach */
370 
371 static int
372 oce_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
373 {
374 	struct oce_dev *dev = ddi_get_driver_private(dip);
375 
376 	ASSERT(dev != NULL);
377 
378 	oce_log(dev, CE_NOTE, MOD_CONFIG,
379 	    "Detaching driver: cmd = 0x%x", cmd);
380 
381 	switch (cmd) {
382 	case DDI_DETACH:
383 		oce_unconfigure(dev);
384 		break;
385 
386 	case DDI_SUSPEND:
387 		return (oce_suspend(dip));
388 
389 	default:
390 		return (DDI_FAILURE);
391 	} /* switch cmd */
392 	return (DDI_SUCCESS);
393 } /* oce_detach */
394 
395 static int
396 oce_quiesce(dev_info_t *dip)
397 {
398 	int ret = DDI_SUCCESS;
399 	struct oce_dev *dev = ddi_get_driver_private(dip);
400 
401 	if (dev == NULL) {
402 		return (DDI_FAILURE);
403 	}
404 	if (dev->suspended) {
405 		return (DDI_SUCCESS);
406 	}
407 
408 	oce_di(dev);
409 
410 	ret = oce_reset_fun(dev);
411 
412 	return (ret);
413 }
414 
415 static int
416 oce_suspend(dev_info_t *dip)
417 {
418 	struct oce_dev *dev = ddi_get_driver_private(dip);
419 
420 	mutex_enter(&dev->dev_lock);
421 	/* Suspend the card */
422 	dev->suspended = B_TRUE;
423 	/* stop the adapter */
424 	if (dev->state & STATE_MAC_STARTED) {
425 		oce_stop(dev);
426 	}
427 	dev->state &= ~STATE_MAC_STARTED;
428 	mutex_exit(&dev->dev_lock);
429 	return (DDI_SUCCESS);
430 } /* oce_suspend */
431 
432 static int
433 oce_resume(dev_info_t *dip)
434 {
435 	struct oce_dev *dev;
436 	int ret;
437 
438 	/* get the dev pointer from dip */
439 	dev = ddi_get_driver_private(dip);
440 	mutex_enter(&dev->dev_lock);
441 	if (!dev->suspended) {
442 		mutex_exit(&dev->dev_lock);
443 		return (DDI_SUCCESS);
444 	}
445 	if (dev->state & STATE_MAC_STARTED) {
446 		ret = oce_start(dev);
447 		if (ret != DDI_SUCCESS) {
448 			mutex_exit(&dev->dev_lock);
449 			return (DDI_FAILURE);
450 		}
451 	}
452 	dev->suspended = B_FALSE;
453 	dev->state |= STATE_MAC_STARTED;
454 	mutex_exit(&dev->dev_lock);
455 	return (ret);
456 } /* oce_resume */
457 
458 static void
459 oce_init_locks(struct oce_dev *dev)
460 {
461 	/* initialize locks */
462 	mutex_init(&dev->dev_lock, NULL, MUTEX_DRIVER,
463 	    DDI_INTR_PRI(dev->intr_pri));
464 	mutex_init(&dev->bmbx_lock, NULL, MUTEX_DRIVER,
465 	    DDI_INTR_PRI(dev->intr_pri));
466 } /* oce_init_locks */
467 
468 static void
469 oce_destroy_locks(struct oce_dev *dev)
470 {
471 	mutex_destroy(&dev->dev_lock);
472 	mutex_destroy(&dev->bmbx_lock);
473 } /* oce_destroy_locks */
474 
475 static void
476 oce_unconfigure(struct oce_dev *dev)
477 {
478 	uint32_t state = dev->attach_state;
479 
480 	if (state & ATTACH_MAC_REG) {
481 		(void) mac_unregister(dev->mac_handle);
482 	}
483 	if (state & ATTACH_STAT_INIT) {
484 		oce_stat_fini(dev);
485 	}
486 	if (state & ATTACH_BOOTSTRAP_INIT) {
487 		oce_free_dma_buffer(dev, dev->bmbx);
488 	}
489 	if (state & ATTACH_PCI_INIT) {
490 		oce_pci_fini(dev);
491 	}
492 	if (state & ATTACH_LOCK_INIT) {
493 		oce_destroy_locks(dev);
494 	}
495 	if (state & ATTACH_SETUP_INTR) {
496 		(void) oce_teardown_intr(dev);
497 	}
498 	if (state & ATTACH_FM_INIT) {
499 		oce_fm_fini(dev);
500 	}
501 	if (state & ATTACH_DEV_INIT) {
502 		ddi_set_driver_private(dev->dip, NULL);
503 		kmem_free(dev, sizeof (struct oce_dev));
504 	}
505 } /* oce_unconfigure */
506 
507 static void
508 oce_get_params(struct oce_dev *dev)
509 {
510 	uint32_t log_level;
511 	uint16_t mod_mask;
512 	uint16_t severity;
513 
514 	/* non tunables  */
515 	dev->rx_ring_size = OCE_DEFAULT_RX_RING_SIZE;
516 	dev->flow_control = OCE_DEFAULT_FLOW_CONTROL;
517 
518 	/* configurable parameters */
519 
520 	/* restrict MTU to 1500 and 9000 only */
521 	dev->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
522 	    DDI_PROP_DONTPASS, (char *)mtu_prop_name, OCE_MIN_MTU);
523 	if (dev->mtu != OCE_MIN_MTU && dev->mtu != OCE_MAX_MTU)
524 		dev->mtu = OCE_MIN_MTU;
525 
526 	dev->tx_ring_size = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
527 	    DDI_PROP_DONTPASS, (char *)tx_ring_size_name,
528 	    OCE_DEFAULT_TX_RING_SIZE);
529 
530 	dev->bcopy_limit = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
531 	    DDI_PROP_DONTPASS, (char *)bcopy_limit_name,
532 	    OCE_DEFAULT_BCOPY_LIMIT);
533 
534 	dev->lso_capable = (boolean_t)ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
535 	    DDI_PROP_DONTPASS, (char *)lso_capable_name, 0);
536 
537 	dev->fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
538 	    DDI_PROP_DONTPASS, (char *)fm_cap_name, OCE_FM_CAPABILITY);
539 
540 	log_level = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
541 	    DDI_PROP_DONTPASS, (char *)log_level_name,
542 	    OCE_DEFAULT_LOG_SETTINGS);
543 	severity = (uint16_t)(log_level & 0xffff);
544 	mod_mask = (uint16_t)(log_level >> 16);
545 	if (mod_mask > MOD_ISR) {
546 		mod_mask = 0;
547 	}
548 	if (severity > CE_IGNORE) {
549 		severity = 0;
550 	}
551 
552 	dev->mod_mask = mod_mask;
553 	dev->severity = severity;
554 } /* oce_get_params */
555