/* Internally resume the rings on group basis (Eg IRM) */ int oce_resume_group_rings(oce_group_t *grp) { struct oce_dev *dev = grp->parent; int qidx, pmac_idx, ret = DDI_SUCCESS; if (grp->state & GROUP_MAC_STARTED) { if (grp->grp_num == 0) { if (dev->num_mca > OCE_MAX_MCA) { ret = oce_set_multicast_table(dev, dev->if_id, &dev->multi_cast[0], OCE_MAX_MCA, B_TRUE, MBX_BOOTSTRAP); } else { ret = oce_set_multicast_table(dev, dev->if_id, &dev->multi_cast[0], dev->num_mca, B_FALSE, MBX_BOOTSTRAP); } if (ret != 0) { oce_log(dev, CE_WARN, MOD_CONFIG, "set mcast failed 0x%x", ret); return (ret); } } /* Add the group based MACs */ for (pmac_idx = 0; pmac_idx < grp->num_pmac; pmac_idx++) { if (grp->pmac_ids[pmac_idx] != INVALID_PMAC_ID) { ret = oce_add_mac(dev, grp->if_id, (uint8_t *)&grp->mac_addr[pmac_idx], &grp->pmac_ids[pmac_idx], MBX_BOOTSTRAP); if (ret != DDI_SUCCESS) { oce_log(dev, CE_WARN, MOD_CONFIG, "MAC addition failed grp = %p, " "idx = %d, ret = %x", (void *)grp, pmac_idx, ret); return (ret); } } } for (qidx = 0; qidx < grp->num_rings; qidx++) { mac_ring_intr_set(grp->ring[qidx].rx->handle, dev->htable[grp->ring[qidx].rx->cq->eq->idx]); (void) oce_start_rq(grp->ring[qidx].rx); } grp->state &= ~GROUP_SUSPEND; } return (ret); }
int oce_m_multicast(void *arg, boolean_t add, const uint8_t *mca) { struct oce_dev *dev = (struct oce_dev *)arg; struct ether_addr *mca_drv_list; struct ether_addr mca_hw_list[OCE_MAX_MCA]; uint16_t new_mcnt = dev->num_mca; int ret; int i; /* check the address */ if ((mca[0] & 0x1) == 0) { return (EINVAL); } /* Allocate the local array for holding the addresses temporarily */ bzero(&mca_hw_list, sizeof (&mca_hw_list)); mca_drv_list = &dev->multi_cast[0]; DEV_LOCK(dev); if (add) { /* check if we exceeded hw max supported */ if (new_mcnt < OCE_MAX_MCA) { /* copy entire dev mca to the mbx */ bcopy((void*)mca_drv_list, (void*)mca_hw_list, (dev->num_mca * sizeof (struct ether_addr))); /* Append the new one to local list */ bcopy(mca, &mca_hw_list[dev->num_mca], sizeof (struct ether_addr)); } new_mcnt++; } else { struct ether_addr *hwlistp = &mca_hw_list[0]; for (i = 0; i < dev->num_mca; i++) { /* copy only if it does not match */ if (bcmp((mca_drv_list + i), mca, ETHERADDRL)) { bcopy(mca_drv_list + i, hwlistp, ETHERADDRL); hwlistp++; } else { new_mcnt--; } } } if (dev->suspended) { goto finish; } if (new_mcnt > OCE_MAX_MCA) { ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0], OCE_MAX_MCA, B_TRUE); } else { ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0], new_mcnt, B_FALSE); } if (ret != 0) { oce_log(dev, CE_WARN, MOD_CONFIG, "mcast %s fails", add ? "ADD" : "DEL"); DEV_UNLOCK(dev); return (EIO); } /* * Copy the local structure to dev structure */ finish: if (new_mcnt && new_mcnt <= OCE_MAX_MCA) { bcopy(mca_hw_list, mca_drv_list, new_mcnt * sizeof (struct ether_addr)); dev->num_mca = (uint16_t)new_mcnt; } DEV_UNLOCK(dev); oce_log(dev, CE_NOTE, MOD_CONFIG, "mcast %s, addr=%02x:%02x:%02x:%02x:%02x:%02x, num_mca=%d", add ? "ADD" : "DEL", mca[0], mca[1], mca[2], mca[3], mca[4], mca[5], dev->num_mca); return (0); } /* oce_m_multicast */