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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * The Ethernet Over Infiniband driver
28 */
29
30#include <sys/types.h>
31#include <sys/conf.h>
32#include <sys/devops.h>
33#include <sys/kmem.h>
34#include <sys/ksynch.h>
35#include <sys/modctl.h>
36#include <sys/stat.h>
37#include <sys/ddi.h>
38#include <sys/sunddi.h>
39
40#include <sys/mac_provider.h>
41#include <sys/mac_ether.h>
42
43#include <sys/ib/clients/eoib/eib_impl.h>
44
45/*
46 * Driver entry point declarations
47 */
48static int eib_attach(dev_info_t *, ddi_attach_cmd_t);
49static int eib_detach(dev_info_t *, ddi_detach_cmd_t);
50
51/*
52 * MAC callbacks
53 */
54static int eib_m_stat(void *, uint_t, uint64_t *);
55static int eib_m_start(void *);
56static void eib_m_stop(void *);
57static int eib_m_promisc(void *, boolean_t);
58static int eib_m_multicast(void *, boolean_t, const uint8_t *);
59static int eib_m_unicast(void *, const uint8_t *);
60static mblk_t *eib_m_tx(void *, mblk_t *);
61static boolean_t eib_m_getcapab(void *, mac_capab_t, void *);
62static int eib_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
63    const void *);
64static int eib_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
65static void eib_m_propinfo(void *, const char *, mac_prop_id_t,
66    mac_prop_info_handle_t);
67
68/*
69 * Devops definition
70 */
71DDI_DEFINE_STREAM_OPS(eib_ops, nulldev, nulldev, eib_attach, eib_detach,
72    nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
73
74/*
75 * Module Driver Info
76 */
77static struct modldrv eib_modldrv = {
78	&mod_driverops,		/* Driver module */
79	"EoIB Driver",		/* Driver name and version */
80	&eib_ops,		/* Driver ops */
81};
82
83/*
84 * Module Linkage
85 */
86static struct modlinkage eib_modlinkage = {
87	MODREV_1, (void *)&eib_modldrv, NULL
88};
89
90/*
91 * GLDv3 entry points
92 */
93#define	EIB_M_CALLBACK_FLAGS	\
94	(MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
95static mac_callbacks_t eib_m_callbacks = {
96	EIB_M_CALLBACK_FLAGS,
97	eib_m_stat,
98	eib_m_start,
99	eib_m_stop,
100	eib_m_promisc,
101	eib_m_multicast,
102	eib_m_unicast,
103	eib_m_tx,
104	NULL,
105	NULL,
106	eib_m_getcapab,
107	NULL,
108	NULL,
109	eib_m_setprop,
110	eib_m_getprop,
111	eib_m_propinfo
112};
113
114/*
115 * Async handler callback for ibt events
116 */
117static ibt_clnt_modinfo_t eib_clnt_modinfo = {
118	IBTI_V_CURR,
119	IBT_NETWORK,
120	eib_ibt_async_handler,
121	NULL,
122	EIB_DRV_NAME
123};
124
125/*
126 * Driver State Pointer
127 */
128void *eib_state;
129
130/*
131 * Declarations private to this file
132 */
133static int eib_state_init(eib_t *);
134static int eib_add_event_callbacks(eib_t *);
135static int eib_register_with_mac(eib_t *, dev_info_t *);
136static void eib_rb_attach(eib_t *, uint_t);
137static void eib_rb_state_init(eib_t *);
138static void eib_rb_add_event_callbacks(eib_t *);
139static void eib_rb_register_with_mac(eib_t *);
140
141/*
142 * Definitions private to this file
143 */
144#define	EIB_ATTACH_STATE_ALLOCD		0x01
145#define	EIB_ATTACH_PROPS_PARSED		0x02
146#define	EIB_ATTACH_STATE_INIT_DONE	0x04
147#define	EIB_ATTACH_IBT_ATT_DONE		0x08
148#define	EIB_ATTACH_EV_CBS_ADDED		0x10
149#define	EIB_ATTACH_REGISTER_MAC_DONE	0x20
150
151int
152_init()
153{
154	int ret;
155
156	if (ddi_name_to_major(EIB_DRV_NAME) == (major_t)-1)
157		return (ENODEV);
158
159	if ((ret = ddi_soft_state_init(&eib_state, sizeof (eib_t), 0)) != 0)
160		return (ret);
161
162	mac_init_ops(&eib_ops, EIB_DRV_NAME);
163	if ((ret = mod_install(&eib_modlinkage)) != 0) {
164		mac_fini_ops(&eib_ops);
165		ddi_soft_state_fini(&eib_state);
166		return (ret);
167	}
168
169	eib_debug_init();
170
171	return (ret);
172}
173
174int
175_info(struct modinfo *modinfop)
176{
177	return (mod_info(&eib_modlinkage, modinfop));
178}
179
180int
181_fini()
182{
183	int ret;
184
185	if ((ret = mod_remove(&eib_modlinkage)) != 0)
186		return (ret);
187
188	eib_debug_fini();
189
190	mac_fini_ops(&eib_ops);
191	ddi_soft_state_fini(&eib_state);
192
193	return (ret);
194}
195
196static int
197eib_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
198{
199	eib_t *ss;
200	ibt_status_t ret;
201	int instance;
202	uint_t progress = 0;
203
204	if (cmd != DDI_ATTACH)
205		return (DDI_FAILURE);
206
207	/*
208	 * Allocate softstate for this instance
209	 */
210	instance = ddi_get_instance(dip);
211	if (ddi_soft_state_zalloc(eib_state, instance) == DDI_FAILURE)
212		goto attach_fail;
213
214	progress |= EIB_ATTACH_STATE_ALLOCD;
215
216	ss = ddi_get_soft_state(eib_state, instance);
217	ss->ei_dip = dip;
218	ss->ei_instance = (uint_t)instance;
219
220	/*
221	 * Parse the node properties and get the gateway parameters
222	 * for this instance
223	 */
224	if (eib_get_props(ss) != EIB_E_SUCCESS) {
225		EIB_DPRINTF_ERR(ss->ei_instance,
226		    "eib_attach: eib_get_props() failed");
227		goto attach_fail;
228	}
229	progress |= EIB_ATTACH_PROPS_PARSED;
230
231	/*
232	 * Do per-state initialization
233	 */
234	if (eib_state_init(ss) != EIB_E_SUCCESS) {
235		EIB_DPRINTF_ERR(ss->ei_instance,
236		    "eib_attach: eib_state_init() failed");
237		goto attach_fail;
238	}
239	progress |= EIB_ATTACH_STATE_INIT_DONE;
240
241	/*
242	 * Attach to IBTL
243	 */
244	if ((ret = ibt_attach(&eib_clnt_modinfo, ss->ei_dip, ss,
245	    &ss->ei_ibt_hdl)) != IBT_SUCCESS) {
246		EIB_DPRINTF_ERR(ss->ei_instance,
247		    "eib_attach: ibt_attach() failed, ret=%d", ret);
248		goto attach_fail;
249	}
250	progress |= EIB_ATTACH_IBT_ATT_DONE;
251
252	/*
253	 * Register NDI event callbacks with EoIB nexus
254	 */
255	if (eib_add_event_callbacks(ss) != EIB_E_SUCCESS) {
256		EIB_DPRINTF_ERR(ss->ei_instance,
257		    "eib_attach: eib_add_event_callbacks() failed");
258		goto attach_fail;
259	}
260	progress |= EIB_ATTACH_EV_CBS_ADDED;
261
262	/*
263	 * Register with mac layer
264	 */
265	if (eib_register_with_mac(ss, dip) != EIB_E_SUCCESS) {
266		EIB_DPRINTF_ERR(ss->ei_instance,
267		    "eib_attach: eib_register_with_mac() failed");
268		goto attach_fail;
269	}
270	progress |= EIB_ATTACH_REGISTER_MAC_DONE;
271
272	return (DDI_SUCCESS);
273
274attach_fail:
275	eib_rb_attach(ss, progress);
276	return (DDI_FAILURE);
277}
278
279static int
280eib_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
281{
282	eib_t *ss;
283	int instance;
284
285	if (cmd != DDI_DETACH)
286		return (DDI_FAILURE);
287
288	instance = ddi_get_instance(dip);
289	ss = ddi_get_soft_state(eib_state, instance);
290
291	/*
292	 * If we had not cleaned up rx buffers (and hca resources) during
293	 * unplumb because they were stuck with the nw layer at the time,
294	 * we can try to clean them up now before doing the detach.
295	 */
296	eib_mac_set_nic_state(ss, EIB_NIC_STOPPING);
297
298	eib_rb_rsrc_setup_bufs(ss, B_FALSE);
299	if (ss->ei_tx || ss->ei_rx || ss->ei_lso) {
300		EIB_DPRINTF_WARN(ss->ei_instance,
301		    "eib_detach: buffers still not returned "
302		    "(tx=0x%llx, rx=0x%llx, lso=0x%llx), could "
303		    "not detach", ss->ei_tx, ss->ei_rx, ss->ei_lso);
304		eib_mac_clr_nic_state(ss, EIB_NIC_STOPPING);
305		return (DDI_FAILURE);
306	}
307	if (ss->ei_hca_hdl) {
308		eib_rb_ibt_hca_init(ss, ~0);
309	}
310	eib_mac_clr_nic_state(ss, EIB_NIC_STOPPING);
311
312	eib_rb_attach(ss, ~0);
313
314	return (DDI_SUCCESS);
315}
316
317static int
318eib_m_stat(void *arg, uint_t stat, uint64_t *val)
319{
320	eib_t *ss = arg;
321	eib_stats_t *stats = ss->ei_stats;
322
323	switch (stat) {
324	case MAC_STAT_IFSPEED:
325		*val = ss->ei_props->ep_ifspeed;
326		break;
327
328	case MAC_STAT_OBYTES:
329		*val = stats->st_obytes;
330		break;
331
332	case MAC_STAT_OPACKETS:
333		*val = stats->st_opkts;
334		break;
335
336	case MAC_STAT_BRDCSTXMT:
337		*val = stats->st_brdcstxmit;
338		break;
339
340	case MAC_STAT_MULTIXMT:
341		*val = stats->st_multixmit;
342		break;
343
344	case MAC_STAT_OERRORS:
345		*val = stats->st_oerrors;
346		break;
347
348	case MAC_STAT_NOXMTBUF:
349		*val = stats->st_noxmitbuf;
350		break;
351
352	case MAC_STAT_RBYTES:
353		*val = stats->st_rbytes;
354		break;
355
356	case MAC_STAT_IPACKETS:
357		*val = stats->st_ipkts;
358		break;
359
360	case MAC_STAT_BRDCSTRCV:
361		*val = stats->st_brdcstrcv;
362		break;
363
364	case MAC_STAT_MULTIRCV:
365		*val = stats->st_multircv;
366		break;
367
368	case MAC_STAT_IERRORS:
369		*val = stats->st_ierrors;
370		break;
371
372	case MAC_STAT_NORCVBUF:
373		*val = stats->st_norcvbuf;
374		break;
375
376	case ETHER_STAT_LINK_DUPLEX:
377		*val = LINK_DUPLEX_FULL;
378		break;
379
380	default:
381		return (ENOTSUP);
382	}
383
384	return (0);
385}
386
387static int
388eib_m_start(void *arg)
389{
390	eib_t *ss = arg;
391	int ret = -1;
392
393	eib_mac_set_nic_state(ss, EIB_NIC_STARTING);
394
395	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) == 0)
396		ret = eib_mac_start(ss);
397
398	if (ret == 0)
399		eib_mac_upd_nic_state(ss, EIB_NIC_STARTING, EIB_NIC_STARTED);
400	else
401		eib_mac_clr_nic_state(ss, EIB_NIC_STARTING);
402
403	return (ret);
404}
405
406static void
407eib_m_stop(void *arg)
408{
409	eib_t *ss = arg;
410
411	eib_mac_set_nic_state(ss, EIB_NIC_STOPPING);
412
413	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) != 0)
414		eib_mac_stop(ss);
415
416	eib_mac_clr_nic_state(ss, EIB_NIC_STARTED|EIB_NIC_STOPPING);
417}
418
419static int
420eib_m_promisc(void *arg, boolean_t flag)
421{
422	eib_t *ss = arg;
423
424	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) == 0)
425		return (0);
426
427	return (eib_mac_promisc(ss, flag));
428}
429
430static int
431eib_m_multicast(void *arg, boolean_t add, const uint8_t *mcast_mac)
432{
433	eib_t *ss = arg;
434
435	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) == 0)
436		return (0);
437
438	/*
439	 * We don't have any knowledge which of the vnics built on top of
440	 * the physlink is this multicast group relevant for.  We'll join
441	 * it for vnic0 for now.
442	 *
443	 * Since the tx routine in EoIB currently piggy backs all multicast
444	 * traffic over the broadcast channel, and all vnics are joined to
445	 * the broadcast address when they're created, everyone should receive
446	 * all multicast traffic anyway.
447	 *
448	 * On the rx side, we'll check if the incoming multicast address is
449	 * either on the vnic's list of mcgs joined to (which will only be the
450	 * broadcast address) or on vnic0's list of mcgs.  If we find a match,
451	 * we let the packet come through.
452	 *
453	 * This isn't perfect, but it's the best we can do given that we don't
454	 * have any vlan information corresponding to this multicast address.
455	 *
456	 * Also, for now we'll use the synchronous multicast joins and
457	 * leaves instead of the asynchronous mechanism provided by
458	 * ibt_join_mcg() since that involves additional complexity for failed
459	 * joins and removals.
460	 */
461	return (eib_mac_multicast(ss, add, (uint8_t *)mcast_mac));
462}
463
464static int
465eib_m_unicast(void *arg, const uint8_t *macaddr)
466{
467	eib_t *ss = arg;
468	eib_vnic_t *vnic;
469
470	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) == 0)
471		return (0);
472
473	mutex_enter(&ss->ei_vnic_lock);
474
475	vnic = ss->ei_vnic[0];
476	if (bcmp(macaddr, vnic->vn_login_data.ld_assigned_mac,
477	    ETHERADDRL) == 0) {
478		mutex_exit(&ss->ei_vnic_lock);
479		return (0);
480	}
481
482	mutex_exit(&ss->ei_vnic_lock);
483
484	return (EINVAL);
485}
486
487static mblk_t *
488eib_m_tx(void *arg, mblk_t *mp)
489{
490	eib_t *ss = arg;
491	mblk_t *next;
492
493	/*
494	 * If the nic hasn't been started, drop the message(s)
495	 */
496	if ((ss->ei_node_state->ns_nic_state & EIB_NIC_STARTED) == 0) {
497		freemsgchain(mp);
498		return (NULL);
499	}
500
501	for (; mp != NULL; mp = next) {
502		/*
503		 * Detach this message from the message chain
504		 */
505		next = mp->b_next;
506		mp->b_next = NULL;
507
508		/*
509		 * Attempt to send the message; if we fail (likely due
510		 * to lack of resources), reattach this message to the
511		 * chain and return the unsent chain back.  When we're
512		 * ready to send again, we'll issue a mac_tx_update().
513		 */
514		if (eib_mac_tx(ss, mp) != EIB_E_SUCCESS) {
515			mp->b_next = next;
516			break;
517		}
518	}
519
520	return (mp);
521}
522
523static boolean_t
524eib_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
525{
526	eib_t *ss = arg;
527	eib_caps_t *caps = ss->ei_caps;
528	eib_caps_t s_caps;
529	ibt_hca_attr_t hca_attrs;
530	ibt_status_t ret;
531
532	/*
533	 * If we haven't been plumbed yet, try getting the hca attributes
534	 * and figure out the capabilities now
535	 */
536	if (caps == NULL) {
537		ASSERT(ss->ei_props != NULL);
538
539		ret = ibt_query_hca_byguid(ss->ei_props->ep_hca_guid,
540		    &hca_attrs);
541		if (ret == IBT_SUCCESS) {
542			eib_ibt_record_capab(ss, &hca_attrs, &s_caps);
543			caps = &s_caps;
544		}
545	}
546
547	if ((caps != NULL) && (cap == MAC_CAPAB_HCKSUM)) {
548		uint32_t *tx_flags = cap_data;
549
550		if (caps->cp_cksum_flags == 0) {
551			EIB_DPRINTF_VERBOSE(ss->ei_instance,
552			    "eib_m_getcapab: hw cksum disabled, cksum_flags=0");
553			return (B_FALSE);
554		}
555
556		*tx_flags = caps->cp_cksum_flags;
557
558		return (B_TRUE);
559
560	} else if ((caps != NULL) && (cap == MAC_CAPAB_LSO)) {
561		mac_capab_lso_t *cap_lso = cap_data;
562
563		/*
564		 * If the HCA supports LSO, it will advertise a non-zero
565		 * "max lso size" parameter. Also, LSO relies on hw
566		 * checksum being available.  Finally, if the HCA
567		 * doesn't provide the reserved-lkey capability, LSO
568		 * will adversely affect the performance.  So, we'll
569		 * enable LSO only if we have a non-zero max lso size,
570		 * support checksum offload and provide reserved lkey.
571		 */
572		if (caps->cp_lso_maxlen == 0 ||
573		    caps->cp_cksum_flags == 0 ||
574		    caps->cp_resv_lkey_capab == 0) {
575			EIB_DPRINTF_VERBOSE(ss->ei_instance, "eib_m_getcapab: "
576			    "LSO disabled, lso_maxlen=0x%lx, "
577			    "cksum_flags=0x%lx, resv_lkey_capab=%d",
578			    caps->cp_lso_maxlen,
579			    caps->cp_cksum_flags,
580			    caps->cp_resv_lkey_capab);
581			return (B_FALSE);
582		}
583
584		cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
585		cap_lso->lso_basic_tcp_ipv4.lso_max = caps->cp_lso_maxlen - 1;
586
587		return (B_TRUE);
588	}
589
590	return (B_FALSE);
591}
592
593/*ARGSUSED*/
594static int
595eib_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
596    uint_t pr_valsize, const void *pr_val)
597{
598	return (ENOTSUP);
599}
600
601static int
602eib_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
603    uint_t pr_valsize, void *pr_val)
604{
605	eib_t *ss = arg;
606	link_duplex_t duplex = LINK_DUPLEX_FULL;
607	uint64_t speed = ss->ei_props->ep_ifspeed;
608	int err = 0;
609
610	switch (pr_num) {
611	case MAC_PROP_DUPLEX:
612		ASSERT(pr_valsize >= sizeof (link_duplex_t));
613		bcopy(&duplex, pr_val, sizeof (link_duplex_t));
614		break;
615
616	case MAC_PROP_SPEED:
617		ASSERT(pr_valsize >= sizeof (uint64_t));
618		bcopy(&speed, pr_val, sizeof (speed));
619		break;
620
621	case MAC_PROP_PRIVATE:
622		if (strcmp(pr_name, EIB_DLPROP_GW_EPORT_STATE) == 0) {
623			if (ss->ei_gw_eport_state == FIP_EPORT_UP) {
624				(void) snprintf(pr_val, pr_valsize,
625				    "%s", "up");
626			} else {
627				(void) snprintf(pr_val, pr_valsize,
628				    "%s", "down");
629			}
630		} else if (strcmp(pr_name, EIB_DLPROP_HCA_GUID) == 0) {
631			(void) snprintf(pr_val, pr_valsize, "%llX",
632			    (u_longlong_t)ss->ei_props->ep_hca_guid);
633
634		} else if (strcmp(pr_name, EIB_DLPROP_PORT_GUID) == 0) {
635			(void) snprintf(pr_val, pr_valsize, "%llX",
636			    (u_longlong_t)((ss->ei_props->ep_sgid).gid_guid));
637		}
638		break;
639
640	default:
641		err = ENOTSUP;
642		break;
643	}
644
645	return (err);
646}
647
648/*ARGSUSED*/
649static void
650eib_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
651    mac_prop_info_handle_t prh)
652{
653	switch (pr_num) {
654	case MAC_PROP_DUPLEX:
655	case MAC_PROP_SPEED:
656		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
657		break;
658
659	case MAC_PROP_MTU:
660		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
661		mac_prop_info_set_range_uint32(prh, ETHERMTU, ETHERMTU);
662		break;
663
664	case MAC_PROP_PRIVATE:
665		if (strcmp(pr_name, EIB_DLPROP_GW_EPORT_STATE) == 0) {
666			mac_prop_info_set_default_str(prh, "up ");
667			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
668		} else if (strcmp(pr_name, EIB_DLPROP_HCA_GUID) == 0) {
669			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
670		} else if (strcmp(pr_name, EIB_DLPROP_PORT_GUID) == 0) {
671			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
672		}
673		break;
674	}
675}
676
677static int
678eib_state_init(eib_t *ss)
679{
680	kthread_t *kt;
681
682	/*
683	 * Initialize synchronization primitives
684	 */
685	mutex_init(&ss->ei_vnic_lock, NULL, MUTEX_DRIVER, NULL);
686	mutex_init(&ss->ei_av_lock, NULL, MUTEX_DRIVER, NULL);
687	mutex_init(&ss->ei_ev_lock, NULL, MUTEX_DRIVER, NULL);
688	mutex_init(&ss->ei_rxpost_lock, NULL, MUTEX_DRIVER, NULL);
689	mutex_init(&ss->ei_vnic_req_lock, NULL, MUTEX_DRIVER, NULL);
690	mutex_init(&ss->ei_ka_vnics_lock, NULL, MUTEX_DRIVER, NULL);
691	cv_init(&ss->ei_vnic_cv, NULL, CV_DEFAULT, NULL);
692	cv_init(&ss->ei_ev_cv, NULL, CV_DEFAULT, NULL);
693	cv_init(&ss->ei_rxpost_cv, NULL, CV_DEFAULT, NULL);
694	cv_init(&ss->ei_vnic_req_cv, NULL, CV_DEFAULT, NULL);
695	cv_init(&ss->ei_ka_vnics_cv, NULL, CV_DEFAULT, NULL);
696
697	/*
698	 * Create a node state structure and initialize
699	 */
700	ss->ei_node_state = kmem_zalloc(sizeof (eib_node_state_t), KM_SLEEP);
701	ss->ei_node_state->ns_link_state = LINK_STATE_UNKNOWN;
702	mutex_init(&ss->ei_node_state->ns_lock, NULL, MUTEX_DRIVER, NULL);
703	cv_init(&ss->ei_node_state->ns_cv, NULL, CV_DEFAULT, NULL);
704
705	/*
706	 * Allocate for gathering statistics
707	 */
708	ss->ei_stats = kmem_zalloc(sizeof (eib_stats_t), KM_SLEEP);
709
710	/*
711	 * Start up service threads
712	 */
713	kt = thread_create(NULL, 0, eib_events_handler, ss, 0,
714	    &p0, TS_RUN, minclsyspri);
715	ss->ei_events_handler = kt->t_did;
716
717	kt = thread_create(NULL, 0, eib_refill_rwqes, ss, 0,
718	    &p0, TS_RUN, minclsyspri);
719	ss->ei_rwqes_refiller = kt->t_did;
720
721	kt = thread_create(NULL, 0, eib_vnic_creator, ss, 0,
722	    &p0, TS_RUN, minclsyspri);
723	ss->ei_vnic_creator = kt->t_did;
724
725	kt = thread_create(NULL, 0, eib_manage_keepalives, ss, 0,
726	    &p0, TS_RUN, minclsyspri);
727	ss->ei_keepalives_manager = kt->t_did;
728
729	/*
730	 * Set default state of gw eport
731	 */
732	ss->ei_gw_eport_state = FIP_EPORT_UP;
733
734	/*
735	 * Do static initializations of common structures
736	 */
737	eib_reserved_gid.gid_prefix = 0;
738	eib_reserved_gid.gid_guid = 0;
739
740	return (EIB_E_SUCCESS);
741}
742
743static int
744eib_add_event_callbacks(eib_t *ss)
745{
746	int ret;
747	ddi_eventcookie_t login_ack_evc;
748	ddi_eventcookie_t gw_alive_evc;
749	ddi_eventcookie_t gw_info_evc;
750
751	/*
752	 * Add callback for receiving vnic login acks from the gateway
753	 */
754	if ((ret = ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_LOGIN_ACK,
755	    &login_ack_evc)) != DDI_SUCCESS) {
756		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
757		    "ddi_get_eventcookie(LOGIN_ACK) failed, ret=%d", ret);
758		return (EIB_E_FAILURE);
759	}
760	if ((ret = ddi_add_event_handler(ss->ei_dip, login_ack_evc,
761	    eib_login_ack_cb, ss, &ss->ei_login_ack_cb)) != DDI_SUCCESS) {
762		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
763		    "ddi_add_event_handler(LOGIN_ACK) failed, ret=%d", ret);
764		return (EIB_E_FAILURE);
765	}
766
767	/*
768	 * Add callback for receiving status on gateway transitioning from
769	 * not-available to available
770	 */
771	if ((ret = ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_GW_AVAILABLE,
772	    &gw_alive_evc)) != DDI_SUCCESS) {
773		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
774		    "ddi_get_eventcookie(GW_AVAILABLE) failed, ret=%d", ret);
775		(void) ddi_remove_event_handler(ss->ei_login_ack_cb);
776		return (EIB_E_FAILURE);
777	}
778	if ((ret = ddi_add_event_handler(ss->ei_dip, gw_alive_evc,
779	    eib_gw_alive_cb, ss, &ss->ei_gw_alive_cb)) != DDI_SUCCESS) {
780		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
781		    "ddi_add_event_handler(GW_AVAILABLE) failed, ret=%d", ret);
782		(void) ddi_remove_event_handler(ss->ei_login_ack_cb);
783		return (EIB_E_FAILURE);
784	}
785
786	/*
787	 * Add callback for receiving gateway info update
788	 */
789	if ((ret = ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_GW_INFO_UPDATE,
790	    &gw_info_evc)) != DDI_SUCCESS) {
791		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
792		    "ddi_get_eventcookie(GW_INFO_UPDATE) failed, ret=%d", ret);
793		(void) ddi_remove_event_handler(ss->ei_gw_alive_cb);
794		(void) ddi_remove_event_handler(ss->ei_login_ack_cb);
795		return (EIB_E_FAILURE);
796	}
797	if ((ret = ddi_add_event_handler(ss->ei_dip, gw_info_evc,
798	    eib_gw_info_cb, ss, &ss->ei_gw_info_cb)) != DDI_SUCCESS) {
799		EIB_DPRINTF_ERR(ss->ei_instance, "eib_add_event_callbacks: "
800		    "ddi_add_event_handler(GW_INFO) failed, ret=%d", ret);
801		(void) ddi_remove_event_handler(ss->ei_gw_alive_cb);
802		(void) ddi_remove_event_handler(ss->ei_login_ack_cb);
803		return (EIB_E_FAILURE);
804	}
805
806	return (EIB_E_SUCCESS);
807}
808
809static int
810eib_register_with_mac(eib_t *ss, dev_info_t *dip)
811{
812	mac_register_t *macp;
813	int ret;
814
815	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
816		EIB_DPRINTF_ERR(ss->ei_instance, "eib_register_with_mac: "
817		    "mac_alloc(MAC_VERSION=%d) failed", MAC_VERSION);
818		return (EIB_E_FAILURE);
819	}
820
821	/*
822	 * Note that when we register with mac during attach, we don't
823	 * have the mac address yet (we'll get that after we login into
824	 * the gateway) so we'll simply register a zero macaddr that
825	 * we'll overwrite later during plumb, in eib_m_start(). Likewise,
826	 * we'll also update the max-sdu with the correct MTU after we
827	 * figure it out when we login to the gateway during plumb.
828	 */
829	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
830	macp->m_driver = ss;
831	macp->m_dip = dip;
832	macp->m_src_addr = eib_zero_mac;
833	macp->m_callbacks = &eib_m_callbacks;
834	macp->m_min_sdu = 0;
835	macp->m_max_sdu = ETHERMTU;
836	macp->m_margin = VLAN_TAGSZ;
837	macp->m_priv_props = eib_pvt_props;
838
839	ret = mac_register(macp, &ss->ei_mac_hdl);
840	mac_free(macp);
841
842	if (ret != 0) {
843		EIB_DPRINTF_ERR(ss->ei_instance, "eib_register_with_mac: "
844		    "mac_register() failed, ret=%d", ret);
845		return (EIB_E_FAILURE);
846	}
847
848	return (EIB_E_SUCCESS);
849}
850
851static void
852eib_rb_attach(eib_t *ss, uint_t progress)
853{
854	ibt_status_t ret;
855	int instance;
856
857	if (progress & EIB_ATTACH_REGISTER_MAC_DONE)
858		eib_rb_register_with_mac(ss);
859
860	if (progress & EIB_ATTACH_EV_CBS_ADDED)
861		eib_rb_add_event_callbacks(ss);
862
863	if (progress & EIB_ATTACH_IBT_ATT_DONE) {
864		ret = ibt_detach(ss->ei_ibt_hdl);
865		if (ret != IBT_SUCCESS) {
866			EIB_DPRINTF_WARN(ss->ei_instance, "eib_rb_attach: "
867			    "ibt_detach() failed, ret=%d", ret);
868		}
869		ss->ei_ibt_hdl = NULL;
870	}
871
872	if (progress & EIB_ATTACH_STATE_INIT_DONE)
873		eib_rb_state_init(ss);
874
875	if (progress & EIB_ATTACH_PROPS_PARSED)
876		eib_rb_get_props(ss);
877
878	if (progress & EIB_ATTACH_STATE_ALLOCD) {
879		instance = ddi_get_instance(ss->ei_dip);
880		ddi_soft_state_free(eib_state, instance);
881	}
882}
883
884static void
885eib_rb_state_init(eib_t *ss)
886{
887	/*
888	 * Terminate service threads
889	 */
890	if (ss->ei_keepalives_manager) {
891		eib_stop_manage_keepalives(ss);
892		ss->ei_keepalives_manager = 0;
893	}
894	if (ss->ei_vnic_creator) {
895		eib_stop_vnic_creator(ss);
896		ss->ei_vnic_creator = 0;
897	}
898	if (ss->ei_rwqes_refiller) {
899		eib_stop_refill_rwqes(ss);
900		ss->ei_rwqes_refiller = 0;
901	}
902	if (ss->ei_events_handler) {
903		eib_stop_events_handler(ss);
904		ss->ei_events_handler = 0;
905	}
906
907	/*
908	 * Remove space allocated for gathering statistics
909	 */
910	if (ss->ei_stats) {
911		kmem_free(ss->ei_stats, sizeof (eib_stats_t));
912		ss->ei_stats = NULL;
913	}
914
915	/*
916	 * Remove space allocated for keeping node state
917	 */
918	if (ss->ei_node_state) {
919		cv_destroy(&ss->ei_node_state->ns_cv);
920		mutex_destroy(&ss->ei_node_state->ns_lock);
921		kmem_free(ss->ei_node_state, sizeof (eib_node_state_t));
922		ss->ei_node_state = NULL;
923	}
924
925	/*
926	 * Finally, destroy all synchronization resources
927	 */
928	cv_destroy(&ss->ei_ka_vnics_cv);
929	cv_destroy(&ss->ei_vnic_req_cv);
930	cv_destroy(&ss->ei_rxpost_cv);
931	cv_destroy(&ss->ei_ev_cv);
932	cv_destroy(&ss->ei_vnic_cv);
933	mutex_destroy(&ss->ei_ka_vnics_lock);
934	mutex_destroy(&ss->ei_vnic_req_lock);
935	mutex_destroy(&ss->ei_rxpost_lock);
936	mutex_destroy(&ss->ei_ev_lock);
937	mutex_destroy(&ss->ei_av_lock);
938	mutex_destroy(&ss->ei_vnic_lock);
939}
940
941static void
942eib_rb_add_event_callbacks(eib_t *ss)
943{
944	ddi_eventcookie_t evc;
945
946	if (ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_GW_INFO_UPDATE,
947	    &evc) == DDI_SUCCESS) {
948		(void) ddi_remove_event_handler(ss->ei_gw_info_cb);
949		ss->ei_gw_info_cb = NULL;
950	}
951
952	if (ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_GW_AVAILABLE,
953	    &evc) == DDI_SUCCESS) {
954		(void) ddi_remove_event_handler(ss->ei_gw_alive_cb);
955		ss->ei_gw_alive_cb = NULL;
956	}
957
958	if (ddi_get_eventcookie(ss->ei_dip, EIB_NDI_EVENT_LOGIN_ACK,
959	    &evc) == DDI_SUCCESS) {
960		(void) ddi_remove_event_handler(ss->ei_login_ack_cb);
961		ss->ei_login_ack_cb = NULL;
962	}
963}
964
965static void
966eib_rb_register_with_mac(eib_t *ss)
967{
968	int ret;
969
970	if ((ret = mac_unregister(ss->ei_mac_hdl)) != 0) {
971		EIB_DPRINTF_WARN(ss->ei_instance,
972		    "eib_rb_register_with_mac: "
973		    "mac_unregister() failed, ret=%d", ret);
974	}
975
976	ss->ei_mac_hdl = NULL;
977}
978