/* * attach(9E) -- Attach a device to the system * * Called once for each board successfully probed. */ static int SMCG_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) { gld_mac_info_t *macinfo; Adapter_Struc *pAd; smcg_t *smcg; int rc; ddi_acc_handle_t pcihandle; #ifdef DEBUG if (SMCG_debug & SMCGDDI) cmn_err(CE_CONT, SMCG_NAME "_attach(0x%p)", (void *)devinfo); #endif if (cmd != DDI_ATTACH) return (DDI_FAILURE); /* * Allocate gld_mac_info_t and Lower MAC Adapter_Struc structures */ if ((macinfo = gld_mac_alloc(devinfo)) == NULL) return (DDI_FAILURE); if ((pAd = kmem_zalloc(sizeof (Adapter_Struc), KM_NOSLEEP)) == NULL) { gld_mac_free(macinfo); return (DDI_FAILURE); } if ((smcg = kmem_zalloc(sizeof (smcg_t), KM_NOSLEEP)) == NULL) { gld_mac_free(macinfo); kmem_free(pAd, sizeof (Adapter_Struc)); return (DDI_FAILURE); } pAd->pc_bus = SMCG_PCI_BUS; /* create pci handle for UM_PCI_Service */ if (pci_config_setup(devinfo, (ddi_acc_handle_t *)&pcihandle) != DDI_SUCCESS) { goto attach_fail_cleanup; } /* * Query the LMAC for the device information */ pAd->pcihandle = (void *) pcihandle; rc = LM_GetCnfg(pAd); pci_config_teardown((ddi_acc_handle_t *)&pcihandle); pAd->pcihandle = NULL; if (rc != ADAPTER_AND_CONFIG) { cmn_err(CE_WARN, SMCG_NAME "_attach: LM_GetCnfg failed (0x%x)", rc); goto attach_fail_cleanup; } /* * Initialize pointers to device specific functions which will be * used by the generic layer. */ macinfo->gldm_reset = SMCG_reset; macinfo->gldm_start = SMCG_start_board; macinfo->gldm_stop = SMCG_stop_board; macinfo->gldm_set_mac_addr = SMCG_set_mac_addr; macinfo->gldm_set_multicast = SMCG_set_multicast; macinfo->gldm_set_promiscuous = SMCG_set_promiscuous; macinfo->gldm_get_stats = SMCG_get_stats; macinfo->gldm_send = SMCG_send; macinfo->gldm_intr = SMCG_intr; macinfo->gldm_ioctl = NULL; /* * Initialize board characteristics needed by the generic layer. */ macinfo->gldm_ident = SMCG_IDENT; macinfo->gldm_type = DL_ETHER; macinfo->gldm_minpkt = 0; /* assumes we pad ourselves */ macinfo->gldm_maxpkt = SMCGMAXPKT; macinfo->gldm_addrlen = ETHERADDRL; macinfo->gldm_saplen = -2; macinfo->gldm_ppa = ddi_get_instance(devinfo); pAd->receive_mask = ACCEPT_BROADCAST; pAd->max_packet_size = SMMAXPKT; macinfo->gldm_broadcast_addr = SMCG_broadcastaddr; /* Get the board's vendor-assigned hardware network address. */ LM_Get_Addr(pAd); macinfo->gldm_vendor_addr = (unsigned char *)pAd->node_address; /* Link macinfo, smcg, and LMAC Adapter Structs */ macinfo->gldm_private = (caddr_t)smcg; pAd->sm_private = (void *)smcg; smcg->smcg_pAd = pAd; smcg->smcg_macinfo = macinfo; pAd->ptr_rx_CRC_errors = &smcg->rx_CRC_errors; pAd->ptr_rx_too_big = &smcg->rx_too_big; pAd->ptr_rx_lost_pkts = &smcg->rx_lost_pkts; pAd->ptr_rx_align_errors = &smcg->rx_align_errors; pAd->ptr_rx_overruns = &smcg->rx_overruns; pAd->ptr_tx_deferred = &smcg->tx_deferred; pAd->ptr_tx_total_collisions = &smcg->tx_total_collisions; pAd->ptr_tx_max_collisions = &smcg->tx_max_collisions; pAd->ptr_tx_one_collision = &smcg->tx_one_collision; pAd->ptr_tx_mult_collisions = &smcg->tx_mult_collisions; pAd->ptr_tx_ow_collision = &smcg->tx_ow_collision; pAd->ptr_tx_CD_heartbeat = &smcg->tx_CD_heartbeat; pAd->ptr_tx_carrier_lost = &smcg->tx_carrier_lost; pAd->ptr_tx_underruns = &smcg->tx_underruns; pAd->ptr_ring_OVW = &smcg->ring_OVW; macinfo->gldm_devinfo = smcg->smcg_devinfo = devinfo; pAd->num_of_tx_buffs = ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, "num-tx-bufs", SMTRANSMIT_BUFS); if (pAd->num_of_tx_buffs > SMCG_MAX_TXDESCS) { pAd->num_of_tx_buffs = SMCG_MAX_TXDESCS; cmn_err(CE_WARN, SMCG_NAME "Max number_of_tx_buffs is %d", SMCG_MAX_TXDESCS); } if (pAd->num_of_tx_buffs < 2) { pAd->num_of_tx_buffs = 2; } pAd->num_of_rx_buffs = ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS, "num-rx-bufs", SMRECEIVE_BUFS); if (pAd->num_of_rx_buffs > SMCG_MAX_RXDESCS) { pAd->num_of_rx_buffs = SMCG_MAX_RXDESCS; cmn_err(CE_WARN, SMCG_NAME "Max number_of_rx_buffs is %d", SMCG_MAX_RXDESCS); } if (pAd->num_of_rx_buffs < 2) { pAd->num_of_rx_buffs = 2; } if (ddi_get_iblock_cookie(devinfo, 0, &macinfo->gldm_cookie) != DDI_SUCCESS) goto attach_fail_cleanup; /* * rbuf_lock Protects receive data structures * txbuf_lock Protects transmit data structures * lm_lock Protects all calls to LMAC layer * rlist_lock Protects receive buffer list * Note: Locks should be acquired in the above order. */ mutex_init(&smcg->rbuf_lock, NULL, MUTEX_DRIVER, NULL); mutex_init(&smcg->txbuf_lock, NULL, MUTEX_DRIVER, NULL); mutex_init(&smcg->lm_lock, NULL, MUTEX_DRIVER, NULL); mutex_init(&smcg->rlist_lock, NULL, MUTEX_DRIVER, NULL); /* * SMCG_dma_alloc is called before it is possible to get * any interrupts, send or receive packets... Therefore I'm * not going to take rlist_lock for it. */ if (SMCG_dma_alloc(smcg) != DDI_SUCCESS) goto attach_fail_cleanup1; #ifdef SAFE LM_Reset_Adapter(pAd); #endif /* Add the interrupt handler */ if (ddi_add_intr(devinfo, 0, NULL, NULL, gld_intr, (caddr_t)macinfo) != DDI_SUCCESS) { SMCG_dma_unalloc(smcg); goto attach_fail_cleanup1; } /* * Register ourselves with the GLD interface * * gld_register will: * link us with the GLD system; * create the minor node. */ if (gld_register(devinfo, SMCG_NAME, macinfo) != DDI_SUCCESS) { ddi_remove_intr(devinfo, 0, macinfo->gldm_cookie); SMCG_dma_unalloc(smcg); goto attach_fail_cleanup1; } return (DDI_SUCCESS); attach_fail_cleanup1: mutex_destroy(&smcg->rbuf_lock); mutex_destroy(&smcg->txbuf_lock); mutex_destroy(&smcg->lm_lock); mutex_destroy(&smcg->rlist_lock); attach_fail_cleanup: kmem_free(pAd, sizeof (Adapter_Struc)); kmem_free(smcg, sizeof (smcg_t)); gld_mac_free(macinfo); return (DDI_FAILURE); }
/** * Attach entry point, to attach a device to the system or resume it. * * @param pDip The module structure instance. * @param enmCmd Operation type (attach/resume). * * @returns corresponding solaris error code. */ static int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd) { LogFunc((DEVICE_NAME ":VBoxNetAdpSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd)); int rc = -1; switch (enmCmd) { case DDI_ATTACH: { gld_mac_info_t *pMacInfo = gld_mac_alloc(pDip); if (pMacInfo) { vboxnetadp_state_t *pState = RTMemAllocZ(sizeof(vboxnetadp_state_t)); if (pState) { pState->pDip = pDip; /* * Setup GLD MAC layer registration info. */ pMacInfo->gldm_reset = vboxNetAdpSolarisStub; pMacInfo->gldm_start = vboxNetAdpSolarisStub; pMacInfo->gldm_stop = vboxNetAdpSolarisStub; pMacInfo->gldm_set_mac_addr = vboxNetAdpSolarisSetMacAddress; pMacInfo->gldm_set_multicast = vboxNetAdpSolarisSetMulticast; pMacInfo->gldm_set_promiscuous = vboxNetAdpSolarisSetPromisc; pMacInfo->gldm_send = vboxNetAdpSolarisSend; pMacInfo->gldm_intr = NULL; pMacInfo->gldm_get_stats = vboxNetAdpSolarisGetStats; pMacInfo->gldm_ioctl = NULL; pMacInfo->gldm_ident = DEVICE_NAME; pMacInfo->gldm_type = DL_ETHER; pMacInfo->gldm_minpkt = 0; pMacInfo->gldm_maxpkt = VBOXNETADP_MTU; pMacInfo->gldm_capabilities = GLD_CAP_LINKSTATE; AssertCompile(sizeof(RTMAC) == ETHERADDRL); pMacInfo->gldm_addrlen = ETHERADDRL; pMacInfo->gldm_saplen = -2; pMacInfo->gldm_broadcast_addr = achBroadcastAddr; pMacInfo->gldm_ppa = ddi_get_instance(pState->pDip); pMacInfo->gldm_devinfo = pState->pDip; pMacInfo->gldm_private = (caddr_t)pState; /* * We use a semi-random MAC addresses similar to a guest NIC's MAC address * as the default factory address of the interface. */ rc = vboxNetAdpSolarisGenerateMac(&pState->FactoryMac); if (RT_SUCCESS(rc)) { bcopy(&pState->FactoryMac, &pState->CurrentMac, sizeof(RTMAC)); pMacInfo->gldm_vendor_addr = (unsigned char *)&pState->FactoryMac; /* * Now try registering our GLD with the MAC layer. * Registration can fail on some S10 versions when the MTU size is more than 1500. * When we implement jumbo frames we should probably retry with MTU 1500 for S10. */ rc = gld_register(pDip, (char *)ddi_driver_name(pDip), pMacInfo); if (rc == DDI_SUCCESS) { ddi_report_dev(pDip); gld_linkstate(pMacInfo, GLD_LINKSTATE_UP); return DDI_SUCCESS; } else LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to register GLD. rc=%d\n", rc)); } else LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to generate mac address.rc=%d\n")); RTMemFree(pState); } else LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc state.\n")); gld_mac_free(pMacInfo); } else LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc mac structure.\n")); return DDI_FAILURE; } case DDI_RESUME: { /* Nothing to do here... */ return DDI_SUCCESS; } /* case DDI_PM_RESUME: */ default: return DDI_FAILURE; } }