/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * This file is part of the Chelsio T4 support code. * * Copyright (C) 2011-2013 Chelsio Communications. All rights reserved. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this * release for licensing terms and conditions. */ #include #include #include #include #include #include #include #include /* * NOTE: The "real" NIC driver is in the nexus. This is just a thin wrapper * whose only purpose is to register the mac. */ #include "shared.h" #include "version.h" struct port_info_stub { PORT_INFO_HDR; }; static struct cb_ops cxgbe_cb_ops = { .cb_open = nulldev, .cb_close = nulldev, .cb_strategy = nodev, .cb_print = nodev, .cb_dump = nodev, .cb_read = nodev, .cb_write = nodev, .cb_ioctl = nodev, .cb_devmap = nodev, .cb_mmap = nodev, .cb_segmap = nodev, .cb_chpoll = nochpoll, .cb_prop_op = ddi_prop_op, .cb_flag = D_MP, .cb_rev = CB_REV, .cb_aread = nodev, .cb_awrite = nodev }; static int cxgbe_devo_attach(dev_info_t *, ddi_attach_cmd_t); static int cxgbe_devo_detach(dev_info_t *, ddi_detach_cmd_t); struct dev_ops cxgbe_dev_ops = { .devo_rev = DEVO_REV, .devo_identify = nulldev, .devo_probe = nulldev, .devo_attach = cxgbe_devo_attach, .devo_detach = cxgbe_devo_detach, .devo_reset = nodev, .devo_cb_ops = &cxgbe_cb_ops, }; static struct modldrv modldrv = { .drv_modops = &mod_driverops, .drv_linkinfo = "Chelsio T4 NIC " DRV_VERSION, .drv_dev_ops = &cxgbe_dev_ops }; static struct modlinkage modlinkage = { .ml_rev = MODREV_1, .ml_linkage = {&modldrv, NULL}, }; int _init(void) { int rc; mac_init_ops(&cxgbe_dev_ops, T4_PORT_NAME); rc = mod_install(&modlinkage); if (rc != 0) mac_fini_ops(&cxgbe_dev_ops); return (rc); } int _fini(void) { int rc; rc = mod_remove(&modlinkage); if (rc != 0) return (rc); mac_fini_ops(&cxgbe_dev_ops); return (0); } int _info(struct modinfo *mi) { return (mod_info(&modlinkage, mi)); } static int cxgbe_devo_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct port_info_stub *pi; mac_register_t *mac; mac_handle_t mh; int rc; if (cmd != DDI_ATTACH) return (DDI_FAILURE); pi = ddi_get_parent_data(dip); if (pi == NULL) return (DDI_FAILURE); mac = mac_alloc(MAC_VERSION); if (mac == NULL) { cmn_err(CE_WARN, "%s%d: failed to allocate version %d mac.", ddi_driver_name(pi->dip), ddi_get_instance(pi->dip), MAC_VERSION); return (DDI_FAILURE); } mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; mac->m_driver = pi; mac->m_dip = dip; mac->m_src_addr = pi->hw_addr; mac->m_callbacks = pi->mc; mac->m_max_sdu = pi->mtu; mac->m_priv_props = pi->props; mac->m_margin = 22; /* TODO: mac_register(9s) and onnv code disagree */ rc = mac_register(mac, &mh); mac_free(mac); if (rc != 0) { cmn_err(CE_WARN, "%s%d: failed to register version %d mac.", ddi_driver_name(pi->dip), ddi_get_instance(pi->dip), MAC_VERSION); return (DDI_FAILURE); } pi->mh = mh; /* * Link state from this point onwards to the time interface is plumbed, * should be set to LINK_STATE_UNKNOWN. The mac should be updated about * the link state as either LINK_STATE_UP or LINK_STATE_DOWN based on * the actual link state detection after interface plumb. */ mac_link_update(mh, LINK_STATE_UNKNOWN); ddi_report_dev(dip); return (DDI_SUCCESS); } static int cxgbe_devo_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { struct port_info_stub *pi; mac_handle_t mh; if (cmd != DDI_DETACH) return (DDI_FAILURE); pi = ddi_get_parent_data(dip); if (pi == NULL) return (DDI_FAILURE); mh = pi->mh; pi->mh = NULL; return (mac_unregister(mh)); }