156b2bdd1SGireesh Nagabhushana /*
256b2bdd1SGireesh Nagabhushana  * This file and its contents are supplied under the terms of the
356b2bdd1SGireesh Nagabhushana  * Common Development and Distribution License ("CDDL"), version 1.0.
456b2bdd1SGireesh Nagabhushana  * You may only use this file in accordance with the terms of version
556b2bdd1SGireesh Nagabhushana  * 1.0 of the CDDL.
656b2bdd1SGireesh Nagabhushana  *
756b2bdd1SGireesh Nagabhushana  * A full copy of the text of the CDDL should have accompanied this
856b2bdd1SGireesh Nagabhushana  * source. A copy of the CDDL is also available via the Internet at
956b2bdd1SGireesh Nagabhushana  * http://www.illumos.org/license/CDDL.
1056b2bdd1SGireesh Nagabhushana  */
1156b2bdd1SGireesh Nagabhushana 
1256b2bdd1SGireesh Nagabhushana /*
1356b2bdd1SGireesh Nagabhushana  * This file is part of the Chelsio T4 support code.
1456b2bdd1SGireesh Nagabhushana  *
1556b2bdd1SGireesh Nagabhushana  * Copyright (C) 2011-2013 Chelsio Communications.  All rights reserved.
1656b2bdd1SGireesh Nagabhushana  *
1756b2bdd1SGireesh Nagabhushana  * This program is distributed in the hope that it will be useful, but WITHOUT
1856b2bdd1SGireesh Nagabhushana  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1956b2bdd1SGireesh Nagabhushana  * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
2056b2bdd1SGireesh Nagabhushana  * release for licensing terms and conditions.
2156b2bdd1SGireesh Nagabhushana  */
2256b2bdd1SGireesh Nagabhushana 
2356b2bdd1SGireesh Nagabhushana #include <sys/ddi.h>
2456b2bdd1SGireesh Nagabhushana #include <sys/sunddi.h>
2556b2bdd1SGireesh Nagabhushana #include <sys/modctl.h>
2656b2bdd1SGireesh Nagabhushana #include <sys/conf.h>
2756b2bdd1SGireesh Nagabhushana #include <sys/atomic.h>
2856b2bdd1SGireesh Nagabhushana #include <sys/ethernet.h>
2956b2bdd1SGireesh Nagabhushana #include <sys/mac_provider.h>
3056b2bdd1SGireesh Nagabhushana #include <sys/mac_ether.h>
3156b2bdd1SGireesh Nagabhushana 
3256b2bdd1SGireesh Nagabhushana /*
3356b2bdd1SGireesh Nagabhushana  * NOTE:  The "real" NIC driver is in the nexus.  This is just a thin wrapper
3456b2bdd1SGireesh Nagabhushana  * whose only purpose is to register the mac.
3556b2bdd1SGireesh Nagabhushana  */
3656b2bdd1SGireesh Nagabhushana #include "shared.h"
3756b2bdd1SGireesh Nagabhushana #include "version.h"
3856b2bdd1SGireesh Nagabhushana 
3956b2bdd1SGireesh Nagabhushana struct port_info_stub {
4056b2bdd1SGireesh Nagabhushana 	PORT_INFO_HDR;
4156b2bdd1SGireesh Nagabhushana };
4256b2bdd1SGireesh Nagabhushana 
4356b2bdd1SGireesh Nagabhushana static struct cb_ops cxgbe_cb_ops = {
4456b2bdd1SGireesh Nagabhushana 	.cb_open =		nulldev,
4556b2bdd1SGireesh Nagabhushana 	.cb_close =		nulldev,
4656b2bdd1SGireesh Nagabhushana 	.cb_strategy =		nodev,
4756b2bdd1SGireesh Nagabhushana 	.cb_print = 		nodev,
4856b2bdd1SGireesh Nagabhushana 	.cb_dump =		nodev,
4956b2bdd1SGireesh Nagabhushana 	.cb_read =		nodev,
5056b2bdd1SGireesh Nagabhushana 	.cb_write =		nodev,
5156b2bdd1SGireesh Nagabhushana 	.cb_ioctl =		nodev,
5256b2bdd1SGireesh Nagabhushana 	.cb_devmap =		nodev,
5356b2bdd1SGireesh Nagabhushana 	.cb_mmap =		nodev,
5456b2bdd1SGireesh Nagabhushana 	.cb_segmap =		nodev,
5556b2bdd1SGireesh Nagabhushana 	.cb_chpoll =		nochpoll,
5656b2bdd1SGireesh Nagabhushana 	.cb_prop_op =		ddi_prop_op,
5756b2bdd1SGireesh Nagabhushana 	.cb_flag =		D_MP,
5856b2bdd1SGireesh Nagabhushana 	.cb_rev =		CB_REV,
5956b2bdd1SGireesh Nagabhushana 	.cb_aread =		nodev,
6056b2bdd1SGireesh Nagabhushana 	.cb_awrite =		nodev
6156b2bdd1SGireesh Nagabhushana };
6256b2bdd1SGireesh Nagabhushana 
6356b2bdd1SGireesh Nagabhushana static int cxgbe_devo_attach(dev_info_t *, ddi_attach_cmd_t);
6456b2bdd1SGireesh Nagabhushana static int cxgbe_devo_detach(dev_info_t *, ddi_detach_cmd_t);
6556b2bdd1SGireesh Nagabhushana struct dev_ops cxgbe_dev_ops = {
6656b2bdd1SGireesh Nagabhushana 	.devo_rev =		DEVO_REV,
6756b2bdd1SGireesh Nagabhushana 	.devo_identify =	nulldev,
6856b2bdd1SGireesh Nagabhushana 	.devo_probe =		nulldev,
6956b2bdd1SGireesh Nagabhushana 	.devo_attach =		cxgbe_devo_attach,
7056b2bdd1SGireesh Nagabhushana 	.devo_detach =		cxgbe_devo_detach,
7156b2bdd1SGireesh Nagabhushana 	.devo_reset =		nodev,
7256b2bdd1SGireesh Nagabhushana 	.devo_cb_ops =		&cxgbe_cb_ops,
7356b2bdd1SGireesh Nagabhushana };
7456b2bdd1SGireesh Nagabhushana 
7556b2bdd1SGireesh Nagabhushana static struct modldrv modldrv = {
7656b2bdd1SGireesh Nagabhushana 	.drv_modops =		&mod_driverops,
77de483253SVishal Kulkarni 	.drv_linkinfo =		"Chelsio T4/T5 NIC " DRV_VERSION,
7856b2bdd1SGireesh Nagabhushana 	.drv_dev_ops =		&cxgbe_dev_ops
7956b2bdd1SGireesh Nagabhushana };
8056b2bdd1SGireesh Nagabhushana 
8156b2bdd1SGireesh Nagabhushana static struct modlinkage modlinkage = {
8256b2bdd1SGireesh Nagabhushana 	.ml_rev =		MODREV_1,
8356b2bdd1SGireesh Nagabhushana 	.ml_linkage =		{&modldrv, NULL},
8456b2bdd1SGireesh Nagabhushana };
8556b2bdd1SGireesh Nagabhushana 
8656b2bdd1SGireesh Nagabhushana int
_init(void)8756b2bdd1SGireesh Nagabhushana _init(void)
8856b2bdd1SGireesh Nagabhushana {
8956b2bdd1SGireesh Nagabhushana 	int rc;
9056b2bdd1SGireesh Nagabhushana 
9156b2bdd1SGireesh Nagabhushana 	mac_init_ops(&cxgbe_dev_ops, T4_PORT_NAME);
9256b2bdd1SGireesh Nagabhushana 	rc = mod_install(&modlinkage);
9356b2bdd1SGireesh Nagabhushana 	if (rc != 0)
9456b2bdd1SGireesh Nagabhushana 		mac_fini_ops(&cxgbe_dev_ops);
9556b2bdd1SGireesh Nagabhushana 
9656b2bdd1SGireesh Nagabhushana 	return (rc);
9756b2bdd1SGireesh Nagabhushana }
9856b2bdd1SGireesh Nagabhushana 
9956b2bdd1SGireesh Nagabhushana int
_fini(void)10056b2bdd1SGireesh Nagabhushana _fini(void)
10156b2bdd1SGireesh Nagabhushana {
10256b2bdd1SGireesh Nagabhushana 	int rc;
10356b2bdd1SGireesh Nagabhushana 
10456b2bdd1SGireesh Nagabhushana 	rc = mod_remove(&modlinkage);
10556b2bdd1SGireesh Nagabhushana 	if (rc != 0)
10656b2bdd1SGireesh Nagabhushana 		return (rc);
10756b2bdd1SGireesh Nagabhushana 
10856b2bdd1SGireesh Nagabhushana 	mac_fini_ops(&cxgbe_dev_ops);
10956b2bdd1SGireesh Nagabhushana 	return (0);
11056b2bdd1SGireesh Nagabhushana }
11156b2bdd1SGireesh Nagabhushana 
11256b2bdd1SGireesh Nagabhushana int
_info(struct modinfo * mi)11356b2bdd1SGireesh Nagabhushana _info(struct modinfo *mi)
11456b2bdd1SGireesh Nagabhushana {
11556b2bdd1SGireesh Nagabhushana 	return (mod_info(&modlinkage, mi));
11656b2bdd1SGireesh Nagabhushana }
11756b2bdd1SGireesh Nagabhushana 
11856b2bdd1SGireesh Nagabhushana static int
cxgbe_devo_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)11956b2bdd1SGireesh Nagabhushana cxgbe_devo_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
12056b2bdd1SGireesh Nagabhushana {
12156b2bdd1SGireesh Nagabhushana 	struct port_info_stub *pi;
12256b2bdd1SGireesh Nagabhushana 	mac_register_t *mac;
12356b2bdd1SGireesh Nagabhushana 	mac_handle_t mh;
12456b2bdd1SGireesh Nagabhushana 	int rc;
12556b2bdd1SGireesh Nagabhushana 
12656b2bdd1SGireesh Nagabhushana 	if (cmd != DDI_ATTACH)
12756b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
12856b2bdd1SGireesh Nagabhushana 
12956b2bdd1SGireesh Nagabhushana 	pi = ddi_get_parent_data(dip);
13056b2bdd1SGireesh Nagabhushana 	if (pi == NULL)
13156b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
13256b2bdd1SGireesh Nagabhushana 
13356b2bdd1SGireesh Nagabhushana 	mac = mac_alloc(MAC_VERSION);
13456b2bdd1SGireesh Nagabhushana 	if (mac == NULL) {
13556b2bdd1SGireesh Nagabhushana 		cmn_err(CE_WARN, "%s%d: failed to allocate version %d mac.",
13656b2bdd1SGireesh Nagabhushana 		    ddi_driver_name(pi->dip), ddi_get_instance(pi->dip),
13756b2bdd1SGireesh Nagabhushana 		    MAC_VERSION);
13856b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
13956b2bdd1SGireesh Nagabhushana 	}
14056b2bdd1SGireesh Nagabhushana 
14156b2bdd1SGireesh Nagabhushana 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
14256b2bdd1SGireesh Nagabhushana 	mac->m_driver = pi;
14356b2bdd1SGireesh Nagabhushana 	mac->m_dip = dip;
14456b2bdd1SGireesh Nagabhushana 	mac->m_src_addr = pi->hw_addr;
14556b2bdd1SGireesh Nagabhushana 	mac->m_callbacks = pi->mc;
14656b2bdd1SGireesh Nagabhushana 	mac->m_max_sdu = pi->mtu;
14756b2bdd1SGireesh Nagabhushana 	mac->m_priv_props = pi->props;
14856b2bdd1SGireesh Nagabhushana 	mac->m_margin = 22; /* TODO: mac_register(9s) and onnv code disagree */
14956b2bdd1SGireesh Nagabhushana 
150*3dde7c95SVishal Kulkarni 	if (!mac->m_callbacks->mc_unicst) {
151*3dde7c95SVishal Kulkarni 		cmn_err(CE_NOTE, "%s%d: Multiple Rings Enabled",
152*3dde7c95SVishal Kulkarni 			ddi_driver_name(pi->dip), ddi_get_instance(pi->dip));
153*3dde7c95SVishal Kulkarni 		mac->m_v12n = MAC_VIRT_LEVEL1;
154*3dde7c95SVishal Kulkarni 	} else
155*3dde7c95SVishal Kulkarni 		cmn_err(CE_NOTE, "%s%d: Multiple Rings Disbled",
156*3dde7c95SVishal Kulkarni 			ddi_driver_name(pi->dip), ddi_get_instance(pi->dip));
15756b2bdd1SGireesh Nagabhushana 	rc = mac_register(mac, &mh);
15856b2bdd1SGireesh Nagabhushana 	mac_free(mac);
15956b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
16056b2bdd1SGireesh Nagabhushana 		cmn_err(CE_WARN, "%s%d: failed to register version %d mac.",
16156b2bdd1SGireesh Nagabhushana 		    ddi_driver_name(pi->dip), ddi_get_instance(pi->dip),
16256b2bdd1SGireesh Nagabhushana 		    MAC_VERSION);
16356b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
16456b2bdd1SGireesh Nagabhushana 	}
16556b2bdd1SGireesh Nagabhushana 	pi->mh = mh;
16656b2bdd1SGireesh Nagabhushana 
16756b2bdd1SGireesh Nagabhushana 	/*
16856b2bdd1SGireesh Nagabhushana 	 * Link state from this point onwards to the time interface is plumbed,
16956b2bdd1SGireesh Nagabhushana 	 * should be set to LINK_STATE_UNKNOWN. The mac should be updated about
17056b2bdd1SGireesh Nagabhushana 	 * the link state as either LINK_STATE_UP or LINK_STATE_DOWN based on
17156b2bdd1SGireesh Nagabhushana 	 * the actual link state detection after interface plumb.
17256b2bdd1SGireesh Nagabhushana 	 */
17356b2bdd1SGireesh Nagabhushana 	mac_link_update(mh, LINK_STATE_UNKNOWN);
17456b2bdd1SGireesh Nagabhushana 
17556b2bdd1SGireesh Nagabhushana 	ddi_report_dev(dip);
17656b2bdd1SGireesh Nagabhushana 
17756b2bdd1SGireesh Nagabhushana 	return (DDI_SUCCESS);
17856b2bdd1SGireesh Nagabhushana }
17956b2bdd1SGireesh Nagabhushana 
18056b2bdd1SGireesh Nagabhushana static int
cxgbe_devo_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)18156b2bdd1SGireesh Nagabhushana cxgbe_devo_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
18256b2bdd1SGireesh Nagabhushana {
18356b2bdd1SGireesh Nagabhushana 	struct port_info_stub *pi;
18456b2bdd1SGireesh Nagabhushana 	mac_handle_t mh;
18556b2bdd1SGireesh Nagabhushana 
18656b2bdd1SGireesh Nagabhushana 	if (cmd != DDI_DETACH)
18756b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
18856b2bdd1SGireesh Nagabhushana 
18956b2bdd1SGireesh Nagabhushana 	pi = ddi_get_parent_data(dip);
19056b2bdd1SGireesh Nagabhushana 	if (pi == NULL)
19156b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
19256b2bdd1SGireesh Nagabhushana 
19356b2bdd1SGireesh Nagabhushana 	mh = pi->mh;
19456b2bdd1SGireesh Nagabhushana 	pi->mh = NULL;
19556b2bdd1SGireesh Nagabhushana 
19656b2bdd1SGireesh Nagabhushana 	return (mac_unregister(mh));
19756b2bdd1SGireesh Nagabhushana }
198