xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_main.c (revision 86ef0a63)
144961713Sgirish /*
244961713Sgirish  * CDDL HEADER START
344961713Sgirish  *
444961713Sgirish  * The contents of this file are subject to the terms of the
544961713Sgirish  * Common Development and Distribution License (the "License").
644961713Sgirish  * You may not use this file except in compliance with the License.
744961713Sgirish  *
844961713Sgirish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944961713Sgirish  * or http://www.opensolaris.org/os/licensing.
1044961713Sgirish  * See the License for the specific language governing permissions
1144961713Sgirish  * and limitations under the License.
1244961713Sgirish  *
1344961713Sgirish  * When distributing Covered Code, include this CDDL HEADER in each
1444961713Sgirish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544961713Sgirish  * If applicable, add the following below this CDDL HEADER, with the
1644961713Sgirish  * fields enclosed by brackets "[]" replaced with your own identifying
1744961713Sgirish  * information: Portions Copyright [yyyy] [name of copyright owner]
1844961713Sgirish  *
1944961713Sgirish  * CDDL HEADER END
2044961713Sgirish  */
2144961713Sgirish /*
229d587972SSantwona Behera  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23238d8f47SDale Ghent  * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
2444961713Sgirish  */
2644961713Sgirish /*
2744961713Sgirish  * SunOs MT STREAMS NIU/Neptune 10Gb Ethernet Device Driver.
2844961713Sgirish  */
2944961713Sgirish #include	<sys/nxge/nxge_impl.h>
30678453a8Sspeer #include	<sys/nxge/nxge_hio.h>
31678453a8Sspeer #include	<sys/nxge/nxge_rxdma.h>
3214ea4bb7Ssd #include	<sys/pcie.h>
34*86ef0a63SRichard Lowe uint32_t	nxge_use_partition = 0;		/* debug partition flag */
35*86ef0a63SRichard Lowe uint32_t	nxge_dma_obp_props_only = 1;	/* use obp published props */
36*86ef0a63SRichard Lowe uint32_t	nxge_use_rdc_intr = 1;		/* debug to assign rdc intr */
3744961713Sgirish /*
38ec090658Sml  * PSARC/2007/453 MSI-X interrupt limit override
3944961713Sgirish  */
40ec090658Sml uint32_t	nxge_msi_enable = 2;
426f157acbSml /*
436f157acbSml  * Software workaround for a Neptune (PCI-E)
446f157acbSml  * hardware interrupt bug which the hardware
456f157acbSml  * may generate spurious interrupts after the
466f157acbSml  * device interrupt handler was removed. If this flag
476f157acbSml  * is enabled, the driver will reset the
486f157acbSml  * hardware when devices are being detached.
496f157acbSml  */
506f157acbSml uint32_t	nxge_peu_reset_enable = 0;
52b4d05839Sml /*
53b4d05839Sml  * Software workaround for the hardware
54b4d05839Sml  * checksum bugs that affect packet transmission
55b4d05839Sml  * and receive:
56b4d05839Sml  *
57b4d05839Sml  * Usage of nxge_cksum_offload:
58b4d05839Sml  *
59b4d05839Sml  *  (1) nxge_cksum_offload = 0 (default):
60b4d05839Sml  *	- transmits packets:
61b4d05839Sml  *	  TCP: uses the hardware checksum feature.
62b4d05839Sml  *	  UDP: driver will compute the software checksum
63b4d05839Sml  *	       based on the partial checksum computed
64b4d05839Sml  *	       by the IP layer.
65b4d05839Sml  *	- receives packets
66b4d05839Sml  *	  TCP: marks packets checksum flags based on hardware result.
67b4d05839Sml  *	  UDP: will not mark checksum flags.
68b4d05839Sml  *
69b4d05839Sml  *  (2) nxge_cksum_offload = 1:
70b4d05839Sml  *	- transmit packets:
71b4d05839Sml  *	  TCP/UDP: uses the hardware checksum feature.
72b4d05839Sml  *	- receives packets
73b4d05839Sml  *	  TCP/UDP: marks packet checksum flags based on hardware result.
74b4d05839Sml  *
75b4d05839Sml  *  (3) nxge_cksum_offload = 2:
76b4d05839Sml  *	- The driver will not register its checksum capability.
77b4d05839Sml  *	  Checksum for both TCP and UDP will be computed
78b4d05839Sml  *	  by the stack.
79b4d05839Sml  *	- The software LSO is not allowed in this case.
80b4d05839Sml  *
81b4d05839Sml  *  (4) nxge_cksum_offload > 2:
82b4d05839Sml  *	- Will be treated as it is set to 2
83b4d05839Sml  *	  (stack will compute the checksum).
84b4d05839Sml  *
85b4d05839Sml  *  (5) If the hardware bug is fixed, this workaround
86b4d05839Sml  *	needs to be updated accordingly to reflect
87b4d05839Sml  *	the new hardware revision.
88b4d05839Sml  */
89b4d05839Sml uint32_t	nxge_cksum_offload = 0;
9144961713Sgirish /*
9244961713Sgirish  * Globals: tunable parameters (/etc/system or adb)
9344961713Sgirish  *
9444961713Sgirish  */
95*86ef0a63SRichard Lowe uint32_t	nxge_rbr_size = NXGE_RBR_RBB_DEFAULT;
96*86ef0a63SRichard Lowe uint32_t	nxge_rbr_spare_size = 0;
97*86ef0a63SRichard Lowe uint32_t	nxge_rcr_size = NXGE_RCR_DEFAULT;
984df55fdeSJanie Lu uint16_t	nxge_rdc_buf_offset = SW_OFFSET_NO_OFFSET;
99*86ef0a63SRichard Lowe uint32_t	nxge_tx_ring_size = NXGE_TX_RING_DEFAULT;
100*86ef0a63SRichard Lowe boolean_t	nxge_no_msg = B_TRUE;		/* control message display */
101*86ef0a63SRichard Lowe uint32_t	nxge_no_link_notify = 0;	/* control DL_NOTIFY */
102*86ef0a63SRichard Lowe uint32_t	nxge_bcopy_thresh = TX_BCOPY_MAX;
103*86ef0a63SRichard Lowe uint32_t	nxge_dvma_thresh = TX_FASTDVMA_MIN;
104*86ef0a63SRichard Lowe uint32_t	nxge_dma_stream_thresh = TX_STREAM_MIN;
10544961713Sgirish uint32_t	nxge_jumbo_mtu	= TX_JUMBO_MTU;
1061f8914d5Sml nxge_tx_mode_t	nxge_tx_scheme = NXGE_USE_SERIAL;
10830ac2e7bSml /* MAX LSO size */
10930ac2e7bSml #define		NXGE_LSO_MAXLEN	65535
11030ac2e7bSml uint32_t	nxge_lso_max = NXGE_LSO_MAXLEN;
11344961713Sgirish /*
11444961713Sgirish  * Add tunable to reduce the amount of time spent in the
11544961713Sgirish  * ISR doing Rx Processing.
11644961713Sgirish  */
11744961713Sgirish uint32_t nxge_max_rx_pkts = 1024;
11944961713Sgirish /*
12044961713Sgirish  * Tunables to manage the receive buffer blocks.
12144961713Sgirish  *
12244961713Sgirish  * nxge_rx_threshold_hi: copy all buffers.
12344961713Sgirish  * nxge_rx_bcopy_size_type: receive buffer block size type.
12444961713Sgirish  * nxge_rx_threshold_lo: copy only up to tunable block size type.
12544961713Sgirish  */
12644961713Sgirish nxge_rxbuf_threshold_t nxge_rx_threshold_hi = NXGE_RX_COPY_6;
12744961713Sgirish nxge_rxbuf_type_t nxge_rx_buf_size_type = RCR_PKTBUFSZ_0;
12844961713Sgirish nxge_rxbuf_threshold_t nxge_rx_threshold_lo = NXGE_RX_COPY_3;
130d00f30bbSspeer uint32_t	nxge_use_kmem_alloc = 1;
13244961713Sgirish rtrace_t npi_rtracebuf;
134d6d3405fSml /*
135d6d3405fSml  * The hardware sometimes fails to allow enough time for the link partner
136d6d3405fSml  * to send an acknowledgement for packets that the hardware sent to it. The
137d6d3405fSml  * hardware resends the packets earlier than it should be in those instances.
138d6d3405fSml  * This behavior caused some switches to acknowledge the wrong packets
139d6d3405fSml  * and it triggered the fatal error.
140d6d3405fSml  * This software workaround is to set the replay timer to a value
141d6d3405fSml  * suggested by the hardware team.
142d6d3405fSml  *
143d6d3405fSml  * PCI config space replay timer register:
144d6d3405fSml  *     The following replay timeout value is 0xc
145d6d3405fSml  *     for bit 14:18.
146d6d3405fSml  */
147d6d3405fSml #define	PCI_REPLAY_TIMEOUT_CFG_OFFSET	0xb8
148d6d3405fSml #define	PCI_REPLAY_TIMEOUT_SHIFT	14
150d6d3405fSml uint32_t	nxge_set_replay_timer = 1;
151d6d3405fSml uint32_t	nxge_replay_timeout = 0xc;
153cf020df9Sml /*
154cf020df9Sml  * The transmit serialization sometimes causes
155cf020df9Sml  * longer sleep before calling the driver transmit
156cf020df9Sml  * function as it sleeps longer than it should.
157cf020df9Sml  * The performace group suggests that a time wait tunable
158cf020df9Sml  * can be used to set the maximum wait time when needed
159cf020df9Sml  * and the default is set to 1 tick.
160cf020df9Sml  */
161cf020df9Sml uint32_t	nxge_tx_serial_maxsleep = 1;
16344961713Sgirish #if	defined(sun4v)
16444961713Sgirish /*
16544961713Sgirish  * Hypervisor N2/NIU services information.
16644961713Sgirish  */
1674df55fdeSJanie Lu /*
1684df55fdeSJanie Lu  * The following is the default API supported:
1694df55fdeSJanie Lu  * major 1 and minor 1.
1704df55fdeSJanie Lu  *
1714df55fdeSJanie Lu  * Please update the MAX_NIU_MAJORS,
1724df55fdeSJanie Lu  * MAX_NIU_MINORS, and minor number supported
1734df55fdeSJanie Lu  * when the newer Hypervior API interfaces
1744df55fdeSJanie Lu  * are added. Also, please update nxge_hsvc_register()
1754df55fdeSJanie Lu  * if needed.
1764df55fdeSJanie Lu  */
17744961713Sgirish static hsvc_info_t niu_hsvc = {
17944961713Sgirish 	NIU_MINOR_VER, "nxge"
18044961713Sgirish };
182678453a8Sspeer static int nxge_hsvc_register(p_nxge_t);
18344961713Sgirish #endif
18544961713Sgirish /*
18644961713Sgirish  * Function Prototypes
18744961713Sgirish  */
18844961713Sgirish static int nxge_attach(dev_info_t *, ddi_attach_cmd_t);
18944961713Sgirish static int nxge_detach(dev_info_t *, ddi_detach_cmd_t);
19044961713Sgirish static void nxge_unattach(p_nxge_t);
19119397407SSherry Moore static int nxge_quiesce(dev_info_t *);
19344961713Sgirish #if NXGE_PROPERTY
19444961713Sgirish static void nxge_remove_hard_properties(p_nxge_t);
19544961713Sgirish #endif
197678453a8Sspeer /*
198678453a8Sspeer  * These two functions are required by nxge_hio.c
199678453a8Sspeer  */
200da14cebeSEric Cheng extern int nxge_m_mmac_remove(void *arg, int slot);
201651ce697SMichael Speer extern void nxge_grp_cleanup(p_nxge_t nxge);
20344961713Sgirish static nxge_status_t nxge_setup_system_dma_pages(p_nxge_t);
20544961713Sgirish static nxge_status_t nxge_setup_mutexes(p_nxge_t);
20644961713Sgirish static void nxge_destroy_mutexes(p_nxge_t);
20844961713Sgirish static nxge_status_t nxge_map_regs(p_nxge_t nxgep);
20944961713Sgirish static void nxge_unmap_regs(p_nxge_t nxgep);
21044961713Sgirish #ifdef	NXGE_DEBUG
21144961713Sgirish static void nxge_test_map_regs(p_nxge_t nxgep);
21244961713Sgirish #endif
21444961713Sgirish static nxge_status_t nxge_add_intrs(p_nxge_t nxgep);
21544961713Sgirish static void nxge_remove_intrs(p_nxge_t nxgep);
21744961713Sgirish static nxge_status_t nxge_add_intrs_adv(p_nxge_t nxgep);
21844961713Sgirish static nxge_status_t nxge_add_intrs_adv_type(p_nxge_t, uint32_t);
21944961713Sgirish static nxge_status_t nxge_add_intrs_adv_type_fix(p_nxge_t, uint32_t);
22044961713Sgirish static void nxge_intrs_enable(p_nxge_t nxgep);
22144961713Sgirish static void nxge_intrs_disable(p_nxge_t nxgep);
22344961713Sgirish static void nxge_suspend(p_nxge_t);
22444961713Sgirish static nxge_status_t nxge_resume(p_nxge_t);
22644961713Sgirish static nxge_status_t nxge_setup_dev(p_nxge_t);
22744961713Sgirish static void nxge_destroy_dev(p_nxge_t);
22944961713Sgirish static nxge_status_t nxge_alloc_mem_pool(p_nxge_t);
23044961713Sgirish static void nxge_free_mem_pool(p_nxge_t);
232678453a8Sspeer nxge_status_t nxge_alloc_rx_mem_pool(p_nxge_t);
23344961713Sgirish static void nxge_free_rx_mem_pool(p_nxge_t);
235678453a8Sspeer nxge_status_t nxge_alloc_tx_mem_pool(p_nxge_t);
23644961713Sgirish static void nxge_free_tx_mem_pool(p_nxge_t);
23844961713Sgirish static nxge_status_t nxge_dma_mem_alloc(p_nxge_t, dma_method_t,
23944961713Sgirish 	struct ddi_dma_attr *,
24044961713Sgirish 	size_t, ddi_device_acc_attr_t *, uint_t,
24144961713Sgirish 	p_nxge_dma_common_t);
24344961713Sgirish static void nxge_dma_mem_free(p_nxge_dma_common_t);
244678453a8Sspeer static void nxge_dma_free_rx_data_buf(p_nxge_dma_common_t);
24644961713Sgirish static nxge_status_t nxge_alloc_rx_buf_dma(p_nxge_t, uint16_t,
24744961713Sgirish 	p_nxge_dma_common_t *, size_t, size_t, uint32_t *);
24844961713Sgirish static void nxge_free_rx_buf_dma(p_nxge_t, p_nxge_dma_common_t, uint32_t);
25044961713Sgirish static nxge_status_t nxge_alloc_rx_cntl_dma(p_nxge_t, uint16_t,
25144961713Sgirish 	p_nxge_dma_common_t *, size_t);
25244961713Sgirish static void nxge_free_rx_cntl_dma(p_nxge_t, p_nxge_dma_common_t);
254678453a8Sspeer extern nxge_status_t nxge_alloc_tx_buf_dma(p_nxge_t, uint16_t,
25544961713Sgirish 	p_nxge_dma_common_t *, size_t, size_t, uint32_t *);
25644961713Sgirish static void nxge_free_tx_buf_dma(p_nxge_t, p_nxge_dma_common_t, uint32_t);
258678453a8Sspeer extern nxge_status_t nxge_alloc_tx_cntl_dma(p_nxge_t, uint16_t,
25944961713Sgirish 	p_nxge_dma_common_t *,
26044961713Sgirish 	size_t);
26144961713Sgirish static void nxge_free_tx_cntl_dma(p_nxge_t, p_nxge_dma_common_t);
26344961713Sgirish static int nxge_init_common_dev(p_nxge_t);
26444961713Sgirish static void nxge_uninit_common_dev(p_nxge_t);
2654045d941Ssowmini extern int nxge_param_set_mac(p_nxge_t, queue_t *, mblk_t *,
2664045d941Ssowmini     char *, caddr_t);
267e759c33aSMichael Speer #if defined(sun4v)
268e759c33aSMichael Speer extern nxge_status_t nxge_hio_rdc_enable(p_nxge_t nxgep);
269e759c33aSMichael Speer extern nxge_status_t nxge_hio_rdc_intr_arm(p_nxge_t nxge, boolean_t arm);
270e759c33aSMichael Speer #endif
27244961713Sgirish /*
27344961713Sgirish  * The next declarations are for the GLDv3 interface.
27444961713Sgirish  */
27544961713Sgirish static int nxge_m_start(void *);
27644961713Sgirish static void nxge_m_stop(void *);
27744961713Sgirish static int nxge_m_multicst(void *, boolean_t, const uint8_t *);
27844961713Sgirish static int nxge_m_promisc(void *, boolean_t);
27944961713Sgirish static void nxge_m_ioctl(void *, queue_t *, mblk_t *);
28063f531d1SSriharsha Basavapatna nxge_status_t nxge_mac_register(p_nxge_t);
281da14cebeSEric Cheng static int nxge_altmac_set(p_nxge_t nxgep, uint8_t *mac_addr,
282da14cebeSEric Cheng 	int slot, int rdctbl, boolean_t usetbl);
283da14cebeSEric Cheng void nxge_mmac_kstat_update(p_nxge_t nxgep, int slot,
28458324dfcSspeer 	boolean_t factory);
285da14cebeSEric Cheng 
286da14cebeSEric Cheng static void nxge_m_getfactaddr(void *, uint_t, uint8_t *);
2871bd6825cSml static	boolean_t nxge_m_getcapab(void *, mac_capab_t, void *);
2881bd6825cSml static int nxge_m_setprop(void *, const char *, mac_prop_id_t,
2891bd6825cSml     uint_t, const void *);
2901bd6825cSml static int nxge_m_getprop(void *, const char *, mac_prop_id_t,
2910dc2366fSVenugopal Iyer     uint_t, void *);
2920dc2366fSVenugopal Iyer static void nxge_m_propinfo(void *, const char *, mac_prop_id_t,
2930dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
2940dc2366fSVenugopal Iyer static void nxge_priv_propinfo(const char *, mac_prop_info_handle_t);
2951bd6825cSml static int nxge_set_priv_prop(nxge_t *, const char *, uint_t,
2961bd6825cSml     const void *);
2970dc2366fSVenugopal Iyer static int nxge_get_priv_prop(nxge_t *, const char *, uint_t, void *);
298da14cebeSEric Cheng static void nxge_fill_ring(void *, mac_ring_type_t, const int, const int,
299da14cebeSEric Cheng     mac_ring_info_t *, mac_ring_handle_t);
300da14cebeSEric Cheng static void nxge_group_add_ring(mac_group_driver_t, mac_ring_driver_t,
301da14cebeSEric Cheng     mac_ring_type_t);
302da14cebeSEric Cheng static void nxge_group_rem_ring(mac_group_driver_t, mac_ring_driver_t,
303da14cebeSEric Cheng     mac_ring_type_t);
3056f157acbSml static void nxge_niu_peu_reset(p_nxge_t nxgep);
306d6d3405fSml static void nxge_set_pci_replay_timeout(nxge_t *);
3080dc2366fSVenugopal Iyer char *nxge_priv_props[] = {
3090dc2366fSVenugopal Iyer 	"_adv_10gfdx_cap",
3100dc2366fSVenugopal Iyer 	"_adv_pause_cap",
3110dc2366fSVenugopal Iyer 	"_function_number",
3120dc2366fSVenugopal Iyer 	"_fw_version",
3130dc2366fSVenugopal Iyer 	"_port_mode",
3140dc2366fSVenugopal Iyer 	"_hot_swap_phy",
3150dc2366fSVenugopal Iyer 	"_rxdma_intr_time",
3160dc2366fSVenugopal Iyer 	"_rxdma_intr_pkts",
3170dc2366fSVenugopal Iyer 	"_class_opt_ipv4_tcp",
3180dc2366fSVenugopal Iyer 	"_class_opt_ipv4_udp",
3190dc2366fSVenugopal Iyer 	"_class_opt_ipv4_ah",
3200dc2366fSVenugopal Iyer 	"_class_opt_ipv4_sctp",
3210dc2366fSVenugopal Iyer 	"_class_opt_ipv6_tcp",
3220dc2366fSVenugopal Iyer 	"_class_opt_ipv6_udp",
3230dc2366fSVenugopal Iyer 	"_class_opt_ipv6_ah",
3240dc2366fSVenugopal Iyer 	"_class_opt_ipv6_sctp",
3250dc2366fSVenugopal Iyer 	"_soft_lso_enable",
3260dc2366fSVenugopal Iyer 	NULL
3274045d941Ssowmini };
32944961713Sgirish #define	NXGE_NEPTUNE_MAGIC	0x4E584745UL
33044961713Sgirish #define	MAX_DUMP_SZ 256
3321bd6825cSml #define	NXGE_M_CALLBACK_FLAGS	\
335678453a8Sspeer mac_callbacks_t nxge_m_callbacks = {
33644961713Sgirish 	NXGE_M_CALLBACK_FLAGS,
33744961713Sgirish 	nxge_m_stat,
33844961713Sgirish 	nxge_m_start,
33944961713Sgirish 	nxge_m_stop,
34044961713Sgirish 	nxge_m_promisc,
34144961713Sgirish 	nxge_m_multicst,
342da14cebeSEric Cheng 	NULL,
343da14cebeSEric Cheng 	NULL,
3440dc2366fSVenugopal Iyer 	NULL,
34544961713Sgirish 	nxge_m_ioctl,
3461bd6825cSml 	nxge_m_getcapab,
3471bd6825cSml 	NULL,
3481bd6825cSml 	NULL,
3491bd6825cSml 	nxge_m_setprop,
3500dc2366fSVenugopal Iyer 	nxge_m_getprop,
3510dc2366fSVenugopal Iyer 	nxge_m_propinfo
35244961713Sgirish };
35444961713Sgirish void
35544961713Sgirish nxge_err_inject(p_nxge_t, queue_t *, mblk_t *);
357ec090658Sml /* PSARC/2007/453 MSI-X interrupt limit override. */
358ec090658Sml #define	NXGE_MSIX_REQUEST_10G	8
359ec090658Sml #define	NXGE_MSIX_REQUEST_1G	2
360ec090658Sml static int nxge_create_msi_property(p_nxge_t);
361ef755e7aStc /*
362ef755e7aStc  * For applications that care about the
363ef755e7aStc  * latency, it was requested by PAE and the
364ef755e7aStc  * customers that the driver has tunables that
365ef755e7aStc  * allow the user to tune it to a higher number
366ef755e7aStc  * interrupts to spread the interrupts among
367ef755e7aStc  * multiple channels. The DDI framework limits
368ef755e7aStc  * the maximum number of MSI-X resources to allocate
369ef755e7aStc  * to 8 (ddi_msix_alloc_limit). If more than 8
370ef755e7aStc  * is set, ddi_msix_alloc_limit must be set accordingly.
371ef755e7aStc  * The default number of MSI interrupts are set to
372ef755e7aStc  * 8 for 10G and 2 for 1G link.
373ef755e7aStc  */
374ef755e7aStc #define	NXGE_MSIX_MAX_ALLOWED	32
375ef755e7aStc uint32_t nxge_msix_10g_intrs = NXGE_MSIX_REQUEST_10G;
376ef755e7aStc uint32_t nxge_msix_1g_intrs = NXGE_MSIX_REQUEST_1G;
37844961713Sgirish /*
37944961713Sgirish  * These global variables control the message
38044961713Sgirish  * output.
38144961713Sgirish  */
38244961713Sgirish out_dbgmsg_t nxge_dbgmsg_out = DBG_CONSOLE | STR_LOG;
383678453a8Sspeer uint64_t nxge_debug_level;
38544961713Sgirish /*
38644961713Sgirish  * This list contains the instance structures for the Neptune
38744961713Sgirish  * devices present in the system. The lock exists to guarantee
38844961713Sgirish  * mutually exclusive access to the list.
38944961713Sgirish  */
390*86ef0a63SRichard Lowe void			*nxge_list = NULL;
39144961713Sgirish void			*nxge_hw_list = NULL;
392*86ef0a63SRichard Lowe nxge_os_mutex_t		nxge_common_lock;
393*86ef0a63SRichard Lowe nxge_os_mutex_t		nxgedebuglock;
395*86ef0a63SRichard Lowe extern uint64_t		npi_debug_level;
39744961713Sgirish extern nxge_status_t	nxge_ldgv_init(p_nxge_t, int *, int *);
39844961713Sgirish extern nxge_status_t	nxge_ldgv_init_n2(p_nxge_t, int *, int *);
39944961713Sgirish extern nxge_status_t	nxge_ldgv_uninit(p_nxge_t);
40044961713Sgirish extern nxge_status_t	nxge_intr_ldgv_init(p_nxge_t);
40144961713Sgirish extern void		nxge_fm_init(p_nxge_t,
40244961713Sgirish 					ddi_device_acc_attr_t *,
40344961713Sgirish 					ddi_dma_attr_t *);
40444961713Sgirish extern void		nxge_fm_fini(p_nxge_t);
40558324dfcSspeer extern npi_status_t	npi_mac_altaddr_disable(npi_handle_t, uint8_t, uint8_t);
40744961713Sgirish /*
40844961713Sgirish  * Count used to maintain the number of buffers being used
40944961713Sgirish  * by Neptune instances and loaned up to the upper layers.
41044961713Sgirish  */
41144961713Sgirish uint32_t nxge_mblks_pending = 0;
41344961713Sgirish /*
41444961713Sgirish  * Device register access attributes for PIO.
41544961713Sgirish  */
41644961713Sgirish static ddi_device_acc_attr_t nxge_dev_reg_acc_attr = {
417837c1ac4SStephen Hanson 	DDI_DEVICE_ATTR_V1,
41844961713Sgirish 	DDI_STRUCTURE_LE_ACC,
41944961713Sgirish 	DDI_STRICTORDER_ACC,
420837c1ac4SStephen Hanson 	DDI_DEFAULT_ACC
42144961713Sgirish };
42344961713Sgirish /*
42444961713Sgirish  * Device descriptor access attributes for DMA.
42544961713Sgirish  */
42644961713Sgirish static ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr = {
42744961713Sgirish 	DDI_DEVICE_ATTR_V0,
42844961713Sgirish 	DDI_STRUCTURE_LE_ACC,
42944961713Sgirish 	DDI_STRICTORDER_ACC
43044961713Sgirish };
43244961713Sgirish /*
43344961713Sgirish  * Device buffer access attributes for DMA.
43444961713Sgirish  */
43544961713Sgirish static ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr = {
43644961713Sgirish 	DDI_DEVICE_ATTR_V0,
43744961713Sgirish 	DDI_STRUCTURE_BE_ACC,
43844961713Sgirish 	DDI_STRICTORDER_ACC
43944961713Sgirish };
44144961713Sgirish ddi_dma_attr_t nxge_desc_dma_attr = {
44244961713Sgirish 	DMA_ATTR_V0,		/* version number. */
44344961713Sgirish 	0,			/* low address */
44444961713Sgirish 	0xffffffffffffffff,	/* high address */
44544961713Sgirish 	0xffffffffffffffff,	/* address counter max */
44644961713Sgirish #ifndef NIU_PA_WORKAROUND
44744961713Sgirish 	0x100000,		/* alignment */
44844961713Sgirish #else
44944961713Sgirish 	0x2000,
45044961713Sgirish #endif
45144961713Sgirish 	0xfc00fc,		/* dlim_burstsizes */
45244961713Sgirish 	0x1,			/* minimum transfer size */
45344961713Sgirish 	0xffffffffffffffff,	/* maximum transfer size */
45444961713Sgirish 	0xffffffffffffffff,	/* maximum segment size */
45544961713Sgirish 	1,			/* scatter/gather list length */
45644961713Sgirish 	(unsigned int) 1,	/* granularity */
45744961713Sgirish 	0			/* attribute flags */
45844961713Sgirish };
46044961713Sgirish ddi_dma_attr_t nxge_tx_dma_attr = {
46144961713Sgirish 	DMA_ATTR_V0,		/* version number. */
46244961713Sgirish 	0,			/* low address */
46344961713Sgirish 	0xffffffffffffffff,	/* high address */
46444961713Sgirish 	0xffffffffffffffff,	/* address counter max */
46544961713Sgirish #if defined(_BIG_ENDIAN)
46644961713Sgirish 	0x2000,			/* alignment */
46744961713Sgirish #else
46844961713Sgirish 	0x1000,			/* alignment */
46944961713Sgirish #endif
47044961713Sgirish 	0xfc00fc,		/* dlim_burstsizes */
47144961713Sgirish 	0x1,			/* minimum transfer size */
47244961713Sgirish 	0xffffffffffffffff,	/* maximum transfer size */
47344961713Sgirish 	0xffffffffffffffff,	/* maximum segment size */
47444961713Sgirish 	5,			/* scatter/gather list length */
47544961713Sgirish 	(unsigned int) 1,	/* granularity */
47644961713Sgirish 	0			/* attribute flags */
47744961713Sgirish };
47944961713Sgirish ddi_dma_attr_t nxge_rx_dma_attr = {
48044961713Sgirish 	DMA_ATTR_V0,		/* version number. */
48144961713Sgirish 	0,			/* low address */
48244961713Sgirish 	0xffffffffffffffff,	/* high address */
48344961713Sgirish 	0xffffffffffffffff,	/* address counter max */
48444961713Sgirish 	0x2000,			/* alignment */
48544961713Sgirish 	0xfc00fc,		/* dlim_burstsizes */
48644961713Sgirish 	0x1,			/* minimum transfer size */
48744961713Sgirish 	0xffffffffffffffff,	/* maximum transfer size */
48844961713Sgirish 	0xffffffffffffffff,	/* maximum segment size */
48944961713Sgirish 	1,			/* scatter/gather list length */
49044961713Sgirish 	(unsigned int) 1,	/* granularity */
4910e2bd521Ssbehera 	DDI_DMA_RELAXED_ORDERING /* attribute flags */
49244961713Sgirish };
49444961713Sgirish ddi_dma_lim_t nxge_dma_limits = {
49544961713Sgirish 	(uint_t)0,		/* dlim_addr_lo */
49644961713Sgirish 	(uint_t)0xffffffff,	/* dlim_addr_hi */
49744961713Sgirish 	(uint_t)0xffffffff,	/* dlim_cntr_max */
49844961713Sgirish 	(uint_t)0xfc00fc,	/* dlim_burstsizes for 32 and 64 bit xfers */
49944961713Sgirish 	0x1,			/* dlim_minxfer */
50044961713Sgirish 	1024			/* dlim_speed */
50144961713Sgirish };
50344961713Sgirish dma_method_t nxge_force_dma = DVMA;
50544961713Sgirish /*
50644961713Sgirish  * dma chunk sizes.
50744961713Sgirish  *
50844961713Sgirish  * Try to allocate the largest possible size
50944961713Sgirish  * so that fewer number of dma chunks would be managed
51044961713Sgirish  */
51144961713Sgirish #ifdef NIU_PA_WORKAROUND
51244961713Sgirish size_t alloc_sizes [] = {0x2000};
51344961713Sgirish #else
51444961713Sgirish size_t alloc_sizes [] = {0x1000, 0x2000, 0x4000, 0x8000,
51544961713Sgirish 		0x10000, 0x20000, 0x40000, 0x80000,
51630ac2e7bSml 		0x100000, 0x200000, 0x400000, 0x800000,
51730ac2e7bSml 		0x1000000, 0x2000000, 0x4000000};
51844961713Sgirish #endif
52044961713Sgirish /*
52144961713Sgirish  * Translate "dev_t" to a pointer to the associated "dev_info_t".
52244961713Sgirish  */
524678453a8Sspeer extern void nxge_get_environs(nxge_t *);
52644961713Sgirish static int
nxge_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)52744961713Sgirish nxge_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
52844961713Sgirish {
52944961713Sgirish 	p_nxge_t	nxgep = NULL;
53044961713Sgirish 	int		instance;
53144961713Sgirish 	int		status = DDI_SUCCESS;
53244961713Sgirish 	uint8_t		portn;
53358324dfcSspeer 	nxge_mmac_t	*mmac_info;
53544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_attach"));
53744961713Sgirish 	/*
53844961713Sgirish 	 * Get the device instance since we'll need to setup
53944961713Sgirish 	 * or retrieve a soft state for this instance.
54044961713Sgirish 	 */
54144961713Sgirish 	instance = ddi_get_instance(dip);
54344961713Sgirish 	switch (cmd) {
54444961713Sgirish 	case DDI_ATTACH:
54544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_ATTACH"));
54644961713Sgirish 		break;
54844961713Sgirish 	case DDI_RESUME:
54944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_RESUME"));
55044961713Sgirish 		nxgep = (p_nxge_t)ddi_get_soft_state(nxge_list, instance);
55144961713Sgirish 		if (nxgep == NULL) {
55244961713Sgirish 			status = DDI_FAILURE;
55344961713Sgirish 			break;
55444961713Sgirish 		}
55544961713Sgirish 		if (nxgep->dip != dip) {
55644961713Sgirish 			status = DDI_FAILURE;
55744961713Sgirish 			break;
55844961713Sgirish 		}
55944961713Sgirish 		if (nxgep->suspended == DDI_PM_SUSPEND) {
56044961713Sgirish 			status = ddi_dev_is_needed(nxgep->dip, 0, 1);
56144961713Sgirish 		} else {
56256d930aeSspeer 			status = nxge_resume(nxgep);
56344961713Sgirish 		}
56444961713Sgirish 		goto nxge_attach_exit;
56644961713Sgirish 	case DDI_PM_RESUME:
56744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_PM_RESUME"));
56844961713Sgirish 		nxgep = (p_nxge_t)ddi_get_soft_state(nxge_list, instance);
56944961713Sgirish 		if (nxgep == NULL) {
57044961713Sgirish 			status = DDI_FAILURE;
57144961713Sgirish 			break;
57244961713Sgirish 		}
57344961713Sgirish 		if (nxgep->dip != dip) {
57444961713Sgirish 			status = DDI_FAILURE;
57544961713Sgirish 			break;
57644961713Sgirish 		}
57756d930aeSspeer 		status = nxge_resume(nxgep);
57844961713Sgirish 		goto nxge_attach_exit;
58044961713Sgirish 	default:
58144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing unknown"));
58244961713Sgirish 		status = DDI_FAILURE;
58344961713Sgirish 		goto nxge_attach_exit;
58444961713Sgirish 	}
58744961713Sgirish 	if (ddi_soft_state_zalloc(nxge_list, instance) == DDI_FAILURE) {
58844961713Sgirish 		status = DDI_FAILURE;
58944961713Sgirish 		goto nxge_attach_exit;
59044961713Sgirish 	}
59244961713Sgirish 	nxgep = ddi_get_soft_state(nxge_list, instance);
59344961713Sgirish 	if (nxgep == NULL) {
5942e59129aSraghus 		status = NXGE_ERROR;
5952e59129aSraghus 		goto nxge_attach_fail2;
59644961713Sgirish 	}
59898ecde52Stm 	nxgep->nxge_magic = NXGE_MAGIC;
60044961713Sgirish 	nxgep->drv_state = 0;
60144961713Sgirish 	nxgep->dip = dip;
60244961713Sgirish 	nxgep->instance = instance;
60344961713Sgirish 	nxgep->p_dip = ddi_get_parent(dip);
60444961713Sgirish 	nxgep->nxge_debug_level = nxge_debug_level;
60544961713Sgirish 	npi_debug_level = nxge_debug_level;
607678453a8Sspeer 	/* Are we a guest running in a Hybrid I/O environment? */
608678453a8Sspeer 	nxge_get_environs(nxgep);
61044961713Sgirish 	status = nxge_map_regs(nxgep);
61244961713Sgirish 	if (status != NXGE_OK) {
61344961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_map_regs failed"));
6142e59129aSraghus 		goto nxge_attach_fail3;
61544961713Sgirish 	}
617837c1ac4SStephen Hanson 	nxge_fm_init(nxgep, &nxge_dev_reg_acc_attr, &nxge_rx_dma_attr);
619678453a8Sspeer 	/* Create & initialize the per-Neptune data structure */
620678453a8Sspeer 	/* (even if we're a guest). */
62144961713Sgirish 	status = nxge_init_common_dev(nxgep);
62244961713Sgirish 	if (status != NXGE_OK) {
62344961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6244045d941Ssowmini 		    "nxge_init_common_dev failed"));
6252e59129aSraghus 		goto nxge_attach_fail4;
62644961713Sgirish 	}
628d6d3405fSml 	/*
629d6d3405fSml 	 * Software workaround: set the replay timer.
630d6d3405fSml 	 */
631d6d3405fSml 	if (nxgep->niu_type != N2_NIU) {
632d6d3405fSml 		nxge_set_pci_replay_timeout(nxgep);
633d6d3405fSml 	}
635678453a8Sspeer #if defined(sun4v)
636678453a8Sspeer 	/* This is required by nxge_hio_init(), which follows. */
637678453a8Sspeer 	if ((status = nxge_hsvc_register(nxgep)) != DDI_SUCCESS)
6389d5b8bc5SMichael Speer 		goto nxge_attach_fail4;
639678453a8Sspeer #endif
641678453a8Sspeer 	if ((status = nxge_hio_init(nxgep)) != NXGE_OK) {
642678453a8Sspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6434045d941Ssowmini 		    "nxge_hio_init failed"));
644678453a8Sspeer 		goto nxge_attach_fail4;
645678453a8Sspeer 	}
64759ac0c16Sdavemq 	if (nxgep->niu_type == NEPTUNE_2_10GF) {
64859ac0c16Sdavemq 		if (nxgep->function_num > 1) {
6494202ea4bSsbehera 			NXGE_DEBUG_MSG((nxgep, DDI_CTL, "Unsupported"
65059ac0c16Sdavemq 			    " function %d. Only functions 0 and 1 are "
65159ac0c16Sdavemq 			    "supported for this card.", nxgep->function_num));
65259ac0c16Sdavemq 			status = NXGE_ERROR;
6532e59129aSraghus 			goto nxge_attach_fail4;
65459ac0c16Sdavemq 		}
65559ac0c16Sdavemq 	}
657678453a8Sspeer 	if (isLDOMguest(nxgep)) {
658678453a8Sspeer 		/*
659678453a8Sspeer 		 * Use the function number here.
660678453a8Sspeer 		 */
661678453a8Sspeer 		nxgep->mac.portnum = nxgep->function_num;
662678453a8Sspeer 		nxgep->mac.porttype = PORT_TYPE_LOGICAL;
664678453a8Sspeer 		/* XXX We'll set the MAC address counts to 1 for now. */
665678453a8Sspeer 		mmac_info = &nxgep->nxge_mmac_info;
666678453a8Sspeer 		mmac_info->num_mmac = 1;
667678453a8Sspeer 		mmac_info->naddrfree = 1;
66858324dfcSspeer 	} else {
669678453a8Sspeer 		portn = NXGE_GET_PORT_NUM(nxgep->function_num);
670678453a8Sspeer 		nxgep->mac.portnum = portn;
671678453a8Sspeer 		if ((portn == 0) || (portn == 1))
672678453a8Sspeer 			nxgep->mac.porttype = PORT_TYPE_XMAC;
673678453a8Sspeer 		else
674678453a8Sspeer 			nxgep->mac.porttype = PORT_TYPE_BMAC;
675678453a8Sspeer 		/*
676678453a8Sspeer 		 * Neptune has 4 ports, the first 2 ports use XMAC (10G MAC)
677678453a8Sspeer 		 * internally, the rest 2 ports use BMAC (1G "Big" MAC).
678678453a8Sspeer 		 * The two types of MACs have different characterizations.
679678453a8Sspeer 		 */
680678453a8Sspeer 		mmac_info = &nxgep->nxge_mmac_info;
681678453a8Sspeer 		if (nxgep->function_num < 2) {
682678453a8Sspeer 			mmac_info->num_mmac = XMAC_MAX_ALT_ADDR_ENTRY;
683678453a8Sspeer 			mmac_info->naddrfree = XMAC_MAX_ALT_ADDR_ENTRY;
684678453a8Sspeer 		} else {
685678453a8Sspeer 			mmac_info->num_mmac = BMAC_MAX_ALT_ADDR_ENTRY;
686678453a8Sspeer 			mmac_info->naddrfree = BMAC_MAX_ALT_ADDR_ENTRY;
687678453a8Sspeer 		}
68858324dfcSspeer 	}
68944961713Sgirish 	/*
69044961713Sgirish 	 * Setup the Ndd parameters for the this instance.
69144961713Sgirish 	 */
69244961713Sgirish 	nxge_init_param(nxgep);
69444961713Sgirish 	/*
69544961713Sgirish 	 * Setup Register Tracing Buffer.
69644961713Sgirish 	 */
69744961713Sgirish 	npi_rtrace_buf_init((rtrace_t *)&npi_rtracebuf);
69944961713Sgirish 	/* init stats ptr */
70044961713Sgirish 	nxge_init_statsp(nxgep);
7022e59129aSraghus 	/*
703678453a8Sspeer 	 * Copy the vpd info from eeprom to a local data
704678453a8Sspeer 	 * structure, and then check its validity.
7052e59129aSraghus 	 */
706678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
707678453a8Sspeer 		int *regp;
708678453a8Sspeer 		uint_t reglen;
709678453a8Sspeer 		int rv;
711678453a8Sspeer 		nxge_vpd_info_get(nxgep);
713678453a8Sspeer 		/* Find the NIU config handle. */
714678453a8Sspeer 		rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY,
715678453a8Sspeer 		    ddi_get_parent(nxgep->dip), DDI_PROP_DONTPASS,
716678453a8Sspeer 		    "reg", &regp, &reglen);
718678453a8Sspeer 		if (rv != DDI_PROP_SUCCESS) {
719678453a8Sspeer 			goto nxge_attach_fail5;
720678453a8Sspeer 		}
721678453a8Sspeer 		/*
722678453a8Sspeer 		 * The address_hi, that is the first int, in the reg
723678453a8Sspeer 		 * property consists of config handle, but need to remove
724678453a8Sspeer 		 * the bits 28-31 which are OBP specific info.
725678453a8Sspeer 		 */
726678453a8Sspeer 		nxgep->niu_cfg_hdl = (*regp) & 0xFFFFFFF;
727678453a8Sspeer 		ddi_prop_free(regp);
72844961713Sgirish 	}
73048056c53SMichael Speer 	/*
73148056c53SMichael Speer 	 * Set the defaults for the MTU size.
73248056c53SMichael Speer 	 */
73348056c53SMichael Speer 	nxge_hw_id_init(nxgep);
73448056c53SMichael Speer 
735678453a8Sspeer 	if (isLDOMguest(nxgep)) {
736678453a8Sspeer 		uchar_t *prop_val;
737678453a8Sspeer 		uint_t prop_len;
7387b1f684aSSriharsha Basavapatna 		uint32_t max_frame_size;
740678453a8Sspeer 		extern void nxge_get_logical_props(p_nxge_t);
742678453a8Sspeer 		nxgep->statsp->mac_stats.xcvr_inuse = LOGICAL_XCVR;
743678453a8Sspeer 		nxgep->mac.portmode = PORT_LOGICAL;
744678453a8Sspeer 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, nxgep->dip,
745678453a8Sspeer 		    "phy-type", "virtual transceiver");
747678453a8Sspeer 		nxgep->nports = 1;
748678453a8Sspeer 		nxgep->board_ver = 0;	/* XXX What? */
750678453a8Sspeer 		/*
751678453a8Sspeer 		 * local-mac-address property gives us info on which
752678453a8Sspeer 		 * specific MAC address the Hybrid resource is associated
753678453a8Sspeer 		 * with.
754678453a8Sspeer 		 */
755678453a8Sspeer 		if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, nxgep->dip, 0,
756678453a8Sspeer 		    "local-mac-address", &prop_val,
757678453a8Sspeer 		    &prop_len) != DDI_PROP_SUCCESS) {
758678453a8Sspeer 			goto nxge_attach_fail5;
759678453a8Sspeer 		}
760*86ef0a63SRichard Lowe 		if (prop_len !=	 ETHERADDRL) {
761678453a8Sspeer 			ddi_prop_free(prop_val);
762678453a8Sspeer 			goto nxge_attach_fail5;
763678453a8Sspeer 		}
764678453a8Sspeer 		ether_copy(prop_val, nxgep->hio_mac_addr);
765678453a8Sspeer 		ddi_prop_free(prop_val);
766678453a8Sspeer 		nxge_get_logical_props(nxgep);
7687b1f684aSSriharsha Basavapatna 		/*
7697b1f684aSSriharsha Basavapatna 		 * Enable Jumbo property based on the "max-frame-size"
7707b1f684aSSriharsha Basavapatna 		 * property value.
7717b1f684aSSriharsha Basavapatna 		 */
7727b1f684aSSriharsha Basavapatna 		max_frame_size = ddi_prop_get_int(DDI_DEV_T_ANY,
7737b1f684aSSriharsha Basavapatna 		    nxgep->dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7747b1f684aSSriharsha Basavapatna 		    "max-frame-size", NXGE_MTU_DEFAULT_MAX);
7757b1f684aSSriharsha Basavapatna 		if ((max_frame_size > NXGE_MTU_DEFAULT_MAX) &&
7767b1f684aSSriharsha Basavapatna 		    (max_frame_size <= TX_JUMBO_MTU)) {
7777b1f684aSSriharsha Basavapatna 			nxgep->mac.is_jumbo = B_TRUE;
7787b1f684aSSriharsha Basavapatna 			nxgep->mac.maxframesize = (uint16_t)max_frame_size;
7797b1f684aSSriharsha Basavapatna 			nxgep->mac.default_mtu = nxgep->mac.maxframesize -
7807b1f684aSSriharsha Basavapatna 			    NXGE_EHEADER_VLAN_CRC;
7817b1f684aSSriharsha Basavapatna 		}
782678453a8Sspeer 	} else {
783678453a8Sspeer 		status = nxge_xcvr_find(nxgep);
785678453a8Sspeer 		if (status != NXGE_OK) {
786678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_attach: "
7874045d941Ssowmini 			    " Couldn't determine card type"
7884045d941Ssowmini 			    " .... exit "));
789678453a8Sspeer 			goto nxge_attach_fail5;
790678453a8Sspeer 		}
792678453a8Sspeer 		status = nxge_get_config_properties(nxgep);
794678453a8Sspeer 		if (status != NXGE_OK) {
795678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
7964045d941Ssowmini 			    "get_hw create failed"));
797678453a8Sspeer 			goto nxge_attach_fail;
798678453a8Sspeer 		}
79944961713Sgirish 	}
80144961713Sgirish 	/*
80244961713Sgirish 	 * Setup the Kstats for the driver.
80344961713Sgirish 	 */
80444961713Sgirish 	nxge_setup_kstats(nxgep);
806678453a8Sspeer 	if (!isLDOMguest(nxgep))
807678453a8Sspeer 		nxge_setup_param(nxgep);
80944961713Sgirish 	status = nxge_setup_system_dma_pages(nxgep);
81044961713Sgirish 	if (status != NXGE_OK) {
81144961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "set dma page failed"));
81244961713Sgirish 		goto nxge_attach_fail;
81344961713Sgirish 	}
816678453a8Sspeer 	if (!isLDOMguest(nxgep))
817678453a8Sspeer 		nxge_hw_init_niu_common(nxgep);
81944961713Sgirish 	status = nxge_setup_mutexes(nxgep);
82044961713Sgirish 	if (status != NXGE_OK) {
82144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "set mutex failed"));
82244961713Sgirish 		goto nxge_attach_fail;
82344961713Sgirish 	}
825678453a8Sspeer #if defined(sun4v)
826678453a8Sspeer 	if (isLDOMguest(nxgep)) {
827678453a8Sspeer 		/* Find our VR & channel sets. */
828678453a8Sspeer 		status = nxge_hio_vr_add(nxgep);
829ef523517SMichael Speer 		if (status != DDI_SUCCESS) {
830ef523517SMichael Speer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
831330cd344SMichael Speer 			    "nxge_hio_vr_add failed"));
832330cd344SMichael Speer 			(void) hsvc_unregister(&nxgep->niu_hsvc);
833330cd344SMichael Speer 			nxgep->niu_hsvc_available = B_FALSE;
834ef523517SMichael Speer 			goto nxge_attach_fail;
835330cd344SMichael Speer 		}
836678453a8Sspeer 		goto nxge_attach_exit;
837678453a8Sspeer 	}
838678453a8Sspeer #endif
84044961713Sgirish 	status = nxge_setup_dev(nxgep);
84144961713Sgirish 	if (status != DDI_SUCCESS) {
84244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "set dev failed"));
84344961713Sgirish 		goto nxge_attach_fail;
84444961713Sgirish 	}
84644961713Sgirish 	status = nxge_add_intrs(nxgep);
84744961713Sgirish 	if (status != DDI_SUCCESS) {
84844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "add_intr failed"));
84944961713Sgirish 		goto nxge_attach_fail;
85044961713Sgirish 	}
851330cd344SMichael Speer 
85200161856Syc 	/* If a guest, register with vio_net instead. */
8532e59129aSraghus 	if ((status = nxge_mac_register(nxgep)) != NXGE_OK) {
85444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL,
855678453a8Sspeer 		    "unable to register to mac layer (%d)", status));
85644961713Sgirish 		goto nxge_attach_fail;
85744961713Sgirish 	}
85944961713Sgirish 	mac_link_update(nxgep->mach, LINK_STATE_UNKNOWN);
861678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, DDI_CTL,
862678453a8Sspeer 	    "registered to mac (instance %d)", instance));
86400161856Syc 	/* nxge_link_monitor calls xcvr.check_link recursively */
86544961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_START);
86744961713Sgirish 	goto nxge_attach_exit;
86944961713Sgirish nxge_attach_fail:
87044961713Sgirish 	nxge_unattach(nxgep);
8712e59129aSraghus 	goto nxge_attach_fail1;
8732e59129aSraghus nxge_attach_fail5:
8742e59129aSraghus 	/*
8752e59129aSraghus 	 * Tear down the ndd parameters setup.
8762e59129aSraghus 	 */
8772e59129aSraghus 	nxge_destroy_param(nxgep);
8792e59129aSraghus 	/*
8802e59129aSraghus 	 * Tear down the kstat setup.
8812e59129aSraghus 	 */
8822e59129aSraghus 	nxge_destroy_kstats(nxgep);
8842e59129aSraghus nxge_attach_fail4:
8852e59129aSraghus 	if (nxgep->nxge_hw_p) {
8862e59129aSraghus 		nxge_uninit_common_dev(nxgep);
8872e59129aSraghus 		nxgep->nxge_hw_p = NULL;
8882e59129aSraghus 	}
8902e59129aSraghus nxge_attach_fail3:
8912e59129aSraghus 	/*
8922e59129aSraghus 	 * Unmap the register setup.
8932e59129aSraghus 	 */
8942e59129aSraghus 	nxge_unmap_regs(nxgep);
8962e59129aSraghus 	nxge_fm_fini(nxgep);
8982e59129aSraghus nxge_attach_fail2:
8992e59129aSraghus 	ddi_soft_state_free(nxge_list, nxgep->instance);
9012e59129aSraghus nxge_attach_fail1:
90256d930aeSspeer 	if (status != NXGE_OK)
90356d930aeSspeer 		status = (NXGE_ERROR | NXGE_DDI_FAILED);
90444961713Sgirish 	nxgep = NULL;
90644961713Sgirish nxge_attach_exit:
90744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_attach status = 0x%08x",
9084045d941Ssowmini 	    status));
91044961713Sgirish 	return (status);
91144961713Sgirish }
91344961713Sgirish static int
nxge_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)91444961713Sgirish nxge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
91544961713Sgirish {
916*86ef0a63SRichard Lowe 	int		status = DDI_SUCCESS;
917*86ef0a63SRichard Lowe 	int		instance;
918*86ef0a63SRichard Lowe 	p_nxge_t	nxgep = NULL;
92044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_detach"));
92144961713Sgirish 	instance = ddi_get_instance(dip);
92244961713Sgirish 	nxgep = ddi_get_soft_state(nxge_list, instance);
92344961713Sgirish 	if (nxgep == NULL) {
92444961713Sgirish 		status = DDI_FAILURE;
92544961713Sgirish 		goto nxge_detach_exit;
92644961713Sgirish 	}
92844961713Sgirish 	switch (cmd) {
92944961713Sgirish 	case DDI_DETACH:
93044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_DETACH"));
93144961713Sgirish 		break;
93344961713Sgirish 	case DDI_PM_SUSPEND:
93444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_PM_SUSPEND"));
93544961713Sgirish 		nxgep->suspended = DDI_PM_SUSPEND;
93644961713Sgirish 		nxge_suspend(nxgep);
93744961713Sgirish 		break;
93944961713Sgirish 	case DDI_SUSPEND:
94044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, DDI_CTL, "doing DDI_SUSPEND"));
94144961713Sgirish 		if (nxgep->suspended != DDI_PM_SUSPEND) {
94244961713Sgirish 			nxgep->suspended = DDI_SUSPEND;
94344961713Sgirish 			nxge_suspend(nxgep);
94444961713Sgirish 		}
94544961713Sgirish 		break;
94744961713Sgirish 	default:
94844961713Sgirish 		status = DDI_FAILURE;
94944961713Sgirish 	}
95144961713Sgirish 	if (cmd != DDI_DETACH)
95244961713Sgirish 		goto nxge_detach_exit;
95444961713Sgirish 	/*
95544961713Sgirish 	 * Stop the xcvr polling.
95644961713Sgirish 	 */
95744961713Sgirish 	nxgep->suspended = cmd;
95944961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
96163f531d1SSriharsha Basavapatna 	if (nxgep->mach && (status = mac_unregister(nxgep->mach)) != 0) {
96244961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
9634045d941Ssowmini 		    "<== nxge_detach status = 0x%08X", status));
96444961713Sgirish 		return (DDI_FAILURE);
96544961713Sgirish 	}
96744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL,
9684045d941Ssowmini 	    "<== nxge_detach (mac_unregister) status = 0x%08X", status));