/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 QLogic Corporation. All rights reserved. */ #include #include #include #include #include #include #include /* * GLDv3 functions prototypes */ static int ql_m_getstat(void *, uint_t, uint64_t *); static int ql_m_start(void *); static void ql_m_stop(void *); static int ql_m_setpromiscuous(void *, boolean_t); static int ql_m_multicst(void *, boolean_t, const uint8_t *); static int ql_m_unicst(void *, const uint8_t *); static mblk_t *ql_m_tx(void *, mblk_t *); static void ql_m_ioctl(void *, queue_t *, mblk_t *); static boolean_t ql_m_getcapab(void *, mac_capab_t, void *); static int ql_m_setprop(void *, const char *, mac_prop_id_t, uint_t, const void *); static int ql_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *); static void ql_m_propinfo(void *, const char *, mac_prop_id_t, mac_prop_info_handle_t); #define QL_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | \ MC_GETPROP | MC_PROPINFO) static mac_callbacks_t ql_m_callbacks = { QL_M_CALLBACK_FLAGS, ql_m_getstat, ql_m_start, ql_m_stop, ql_m_setpromiscuous, ql_m_multicst, NULL, NULL, NULL, ql_m_ioctl, ql_m_getcapab, NULL, NULL, ql_m_setprop, ql_m_getprop, ql_m_propinfo }; char *qlge_priv_prop[] = { "_adv_pause_mode", "_fm_enable", NULL }; /* * This function starts the driver */ static int ql_m_start(void *arg) { qlge_t *qlge = (qlge_t *)arg; /* * reset chip, re-initialize everything but do not * re-allocate memory */ mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } mutex_enter(&qlge->hw_mutex); qlge->mac_flags = QL_MAC_INIT; /* * Write default ethernet address to chip register Mac * Address slot 0 and Enable Primary Mac Function. */ (void) ql_unicst_set(qlge, (uint8_t *)qlge->unicst_addr[0].addr.ether_addr_octet, 0); qlge->stats.rpackets = 0; qlge->stats.rbytes = 0; qlge->stats.opackets = 0; qlge->stats.obytes = 0; mutex_exit(&qlge->hw_mutex); (void) ql_do_start(qlge); mutex_exit(&qlge->gen_mutex); mutex_enter(&qlge->mbx_mutex); (void) ql_get_firmware_version(qlge, NULL); mutex_exit(&qlge->mbx_mutex); return (0); } /* * This function stops the driver */ static void ql_m_stop(void *arg) { qlge_t *qlge = (qlge_t *)arg; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return; } (void) ql_do_stop(qlge); mutex_exit(&qlge->gen_mutex); qlge->mac_flags = QL_MAC_STOPPED; } /* * Add or remove a multicast address */ static int ql_m_multicst(void *arg, boolean_t add, const uint8_t *ep) { qlge_t *qlge = (qlge_t *)arg; int ret = DDI_SUCCESS; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } if (qlge->mac_flags == QL_MAC_DETACH) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } if (add) { QL_DUMP(DBG_GLD, "add to multicast list:\n", (uint8_t *)ep, 8, ETHERADDRL); ret = ql_add_to_multicast_list(qlge, (uint8_t *)ep); } else { QL_DUMP(DBG_GLD, "remove from multicast list:\n", (uint8_t *)ep, 8, ETHERADDRL); ret = ql_remove_from_multicast_list(qlge, (uint8_t *)ep); } mutex_exit(&qlge->gen_mutex); if (ret != DDI_SUCCESS) { ret = EIO; if (qlge->fm_enable) { ddi_fm_service_impact(qlge->dip, DDI_SERVICE_DEGRADED); } } else { ret = 0; } return (ret); } /* * Enable or disable promiscuous mode */ static int ql_m_setpromiscuous(void* arg, boolean_t on) { qlge_t *qlge = (qlge_t *)arg; int mode; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } /* enable reception of all packets on the medium, */ if (on) { mode = 1; QL_PRINT(DBG_GLD, ("%s(%d) enable promiscuous mode\n", __func__, qlge->instance)); } else { mode = 0; QL_PRINT(DBG_GLD, ("%s(%d) disable promiscuous mode\n", __func__, qlge->instance)); } mutex_enter(&qlge->hw_mutex); ql_set_promiscuous(qlge, mode); mutex_exit(&qlge->hw_mutex); mutex_exit(&qlge->gen_mutex); return (DDI_SUCCESS); } static int ql_m_getstat(void *arg, uint_t stat, uint64_t *valp) { qlge_t *qlge = (qlge_t *)arg; struct ql_stats *cur_stats; uint64_t val = 0; int i; uint32_t val32; struct rx_ring *rx_ring; struct tx_ring *tx_ring; ASSERT(qlge != NULL); mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } cur_stats = &qlge->stats; /* these stats are maintained in software */ switch (stat) { case MAC_STAT_IFSPEED /* 1000 */ : if (CFG_IST(qlge, CFG_CHIP_8100) != 0) { qlge->speed = SPEED_10G; } val = qlge->speed * 1000000ull; break; case MAC_STAT_MULTIRCV: val = cur_stats->multircv; break; case MAC_STAT_BRDCSTRCV: val = cur_stats->brdcstrcv; break; case MAC_STAT_MULTIXMT: cur_stats->multixmt = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->multixmt += tx_ring->multixmt; } val = cur_stats->multixmt; break; case MAC_STAT_BRDCSTXMT: cur_stats->brdcstxmt = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->brdcstxmt += tx_ring->brdcstxmt; } val = cur_stats->brdcstxmt; break; case MAC_STAT_NORCVBUF: val = cur_stats->norcvbuf; break; case MAC_STAT_IERRORS: val = cur_stats->errrcv; break; case MAC_STAT_OBYTES: cur_stats->obytes = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->obytes += tx_ring->obytes; } val = cur_stats->obytes; break; case MAC_STAT_OPACKETS: cur_stats->opackets = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->opackets += tx_ring->opackets; } val = cur_stats->opackets; break; case ETHER_STAT_DEFER_XMTS: cur_stats->defer = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->defer += (tx_ring->defer); } val = cur_stats->defer; break; case MAC_STAT_OERRORS: cur_stats->errxmt = 0; for (i = 0; i < qlge->tx_ring_count; i++) { tx_ring = &qlge->tx_ring[i]; cur_stats->errxmt += tx_ring->errxmt; } val = cur_stats->errxmt; break; case MAC_STAT_RBYTES: cur_stats->rbytes = 0; for (i = 0; i < qlge->rx_ring_count; i++) { rx_ring = &qlge->rx_ring[i]; cur_stats->rbytes += rx_ring->rx_bytes; } val = cur_stats->rbytes; break; case MAC_STAT_IPACKETS: cur_stats->rpackets = 0; for (i = 0; i < qlge->rx_ring_count; i++) { rx_ring = &qlge->rx_ring[i]; cur_stats->rpackets += rx_ring->rx_packets; } val = cur_stats->rpackets; break; case ETHER_STAT_FCS_ERRORS: cur_stats->crc = 0; for (i = 0; i < qlge->rx_ring_count; i++) { rx_ring = &qlge->rx_ring[i]; cur_stats->crc += rx_ring->fcs_err; } val = cur_stats->crc; break; case ETHER_STAT_TOOLONG_ERRORS: cur_stats->frame_too_long = 0; for (i = 0; i < qlge->rx_ring_count; i++) { rx_ring = &qlge->rx_ring[i]; cur_stats->frame_too_long += rx_ring->frame_too_long; } val = cur_stats->frame_too_long; break; case ETHER_STAT_XCVR_INUSE: val = XCVR_1000X; break; case ETHER_STAT_JABBER_ERRORS: if (ql_sem_spinlock(qlge, qlge->xgmac_sem_mask) != DDI_SUCCESS) { break; } (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_JABBER_PKTS, &val32); val = val32; ql_sem_unlock(qlge, qlge->xgmac_sem_mask); QL_PRINT(DBG_STATS, ("%s(%d) MAC_STAT_JABBER_ERRORS " "status %d\n", __func__, qlge->instance, val)); break; case ETHER_STAT_LINK_DUPLEX: if (qlge->duplex == 1) val = LINK_DUPLEX_FULL; else val = LINK_DUPLEX_HALF; break; /* statics saved in hw */ case ETHER_STAT_MACRCV_ERRORS: val = 0; if (ql_sem_spinlock(qlge, qlge->xgmac_sem_mask) != DDI_SUCCESS) { break; } (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_ALIGN_ERR, &val32); val += val32; (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_FCS_ERR, &val32); val += val32; (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_JABBER_PKTS, &val32); val += val32; (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_SYM_ERR, &val32); val += val32; (void) ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_INT_ERR, &val32); val += val32; ql_sem_unlock(qlge, qlge->xgmac_sem_mask); break; default: mutex_exit(&qlge->gen_mutex); return (ENOTSUP); } *valp = val; mutex_exit(&qlge->gen_mutex); return (0); } /* * Set the physical network address */ int ql_unicst_set(qlge_t *qlge, const uint8_t *macaddr, int slot) { int ret; ret = ql_sem_spinlock(qlge, SEM_MAC_ADDR_MASK); if (ret != DDI_SUCCESS) goto exit; ret = ql_set_mac_addr_reg(qlge, (uint8_t *)macaddr, MAC_ADDR_TYPE_CAM_MAC, (uint16_t)(qlge->func_number * MAX_CQ + slot)); ql_sem_unlock(qlge, SEM_MAC_ADDR_MASK); exit: if (ret != DDI_SUCCESS) { ret = EIO; if (qlge->fm_enable) { ddi_fm_service_impact(qlge->dip, DDI_SERVICE_DEGRADED); } } else { ret = 0; } return (ret); } /* * Set default MAC address * Each function has a total of 128 mac address, function0: 0~127, * function1 128~254 etc or func_number *128 + n (0~127), but * we only support one MAC address, so its address is * func_number*128+0 */ static int ql_m_unicst(void *arg, const uint8_t *mac) { qlge_t *qlge = (qlge_t *)arg; int status; ASSERT(qlge->mac_flags != QL_MAC_DETACH); mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } mutex_enter(&qlge->hw_mutex); bcopy(mac, qlge->unicst_addr[0].addr.ether_addr_octet, ETHERADDRL); /* Set Mac Address to slot 0 and Enable Primary Mac Function */ status = ql_unicst_set(qlge, mac, 0); mutex_exit(&qlge->hw_mutex); mutex_exit(&qlge->gen_mutex); return (status); } /* * ql_m_tx is used only for sending data packets into ethernet wire. */ static mblk_t * ql_m_tx(void *arg, mblk_t *mp) { qlge_t *qlge = (qlge_t *)arg; struct tx_ring *tx_ring; mblk_t *next; int rval; uint32_t tx_count = 0; caddr_t bp; uint8_t selected_ring = 0; if ((qlge->port_link_state == LS_DOWN) || (qlge->mac_flags != QL_MAC_STARTED)) { cmn_err(CE_WARN, "!%s(%d): exit due to link down", __func__, qlge->instance); freemsgchain(mp); mp = NULL; goto tx_exit; } /* * Calculate which tx ring to send this packet */ bp = (caddr_t)mp->b_rptr; selected_ring = ql_tx_hashing(qlge, bp); tx_ring = &qlge->tx_ring[selected_ring]; mutex_enter(&tx_ring->tx_lock); if (tx_ring->mac_flags != QL_MAC_STARTED) { mutex_exit(&tx_ring->tx_lock); goto tx_exit; } /* we must try to send all */ while (mp != NULL) { /* * if number of available slots is less than a threshold, * then quit */ if (tx_ring->tx_free_count <= TX_STOP_THRESHOLD) { tx_ring->queue_stopped = 1; rval = DDI_FAILURE; /* * If we return the buffer back we are expected to * call mac_tx_ring_update() when * resources are available */ tx_ring->defer++; break; } next = mp->b_next; mp->b_next = NULL; rval = ql_send_common(tx_ring, mp); if (rval != DDI_SUCCESS) { mp->b_next = next; break; } tx_count++; mp = next; } /* * After all msg blocks are mapped or copied to tx buffer, * trigger the hardware to send the msg! */ if (tx_count > 0) { ql_write_doorbell_reg(tx_ring->qlge, tx_ring->prod_idx_db_reg, tx_ring->prod_idx); } mutex_exit(&tx_ring->tx_lock); tx_exit: return (mp); } static void ql_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) { qlge_t *qlge = (qlge_t *)arg; struct iocblk *iocp; boolean_t need_privilege = B_TRUE; int err, cmd; enum ioc_reply status; /* * Validate the command before bothering with the mutex... */ iocp = (struct iocblk *)(void *)mp->b_rptr; iocp->ioc_error = 0; cmd = iocp->ioc_cmd; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); miocnak(wq, mp, 0, EINVAL); return; } switch (cmd) { default: QL_PRINT(DBG_GLD, ("unknown ioctl cmd \n")); miocnak(wq, mp, 0, EINVAL); mutex_exit(&qlge->gen_mutex); return; case QLA_PCI_STATUS: case QLA_WRITE_REG: case QLA_READ_PCI_REG: case QLA_WRITE_PCI_REG: case QLA_GET_DBGLEAVEL: case QLA_SET_DBGLEAVEL: case QLA_READ_CONTRL_REGISTERS: case QLA_MANUAL_READ_FLASH: case QLA_MANUAL_WRITE_FLASH: case QLA_GET_BINARY_CORE_DUMP: case QLA_SUPPORTED_DUMP_TYPES: case QLA_TRIGGER_SYS_ERROR_EVENT: case QLA_READ_FLASH: case QLA_WRITE_FLASH: case QLA_READ_VPD: case QLA_GET_PROP: case QLA_SHOW_REGION: case QLA_LIST_ADAPTER_INFO: case QLA_READ_FW_IMAGE: case QLA_WRITE_FW_IMAGE_HEADERS: case QLA_CONTINUE_COPY_IN: case QLA_CONTINUE_COPY_OUT: case QLA_SOFT_RESET: break; case LB_GET_INFO_SIZE: case LB_GET_INFO: case LB_GET_MODE: need_privilege = B_FALSE; /* FALLTHRU */ case LB_SET_MODE: break; } if (need_privilege) { /* * Check for specific net_config privilege */ err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); if (err != 0) { miocnak(wq, mp, 0, err); mutex_exit(&qlge->gen_mutex); return; } } /* * Implement ioctl */ switch (cmd) { case QLA_PCI_STATUS: case QLA_WRITE_REG: case QLA_READ_PCI_REG: case QLA_WRITE_PCI_REG: case QLA_GET_DBGLEAVEL: case QLA_SET_DBGLEAVEL: case QLA_READ_CONTRL_REGISTERS: case QLA_MANUAL_READ_FLASH: case QLA_MANUAL_WRITE_FLASH: case QLA_GET_BINARY_CORE_DUMP: case QLA_SUPPORTED_DUMP_TYPES: case QLA_TRIGGER_SYS_ERROR_EVENT: case QLA_READ_FLASH: case QLA_WRITE_FLASH: case QLA_READ_VPD: case QLA_GET_PROP: case QLA_SHOW_REGION: case QLA_LIST_ADAPTER_INFO: case QLA_READ_FW_IMAGE: case QLA_WRITE_FW_IMAGE_HEADERS: case QLA_CONTINUE_COPY_IN: case QLA_CONTINUE_COPY_OUT: case QLA_SOFT_RESET: status = ql_chip_ioctl(qlge, wq, mp); break; case LB_GET_INFO_SIZE: case LB_GET_INFO: case LB_GET_MODE: case LB_SET_MODE: status = ql_loop_ioctl(qlge, wq, mp, iocp); break; default: status = IOC_INVAL; break; } /* * Decide how to reply */ switch (status) { default: case IOC_INVAL: /* * Error, reply with a NAK and EINVAL or the specified error */ miocnak(wq, mp, 0, iocp->ioc_error == 0 ? EINVAL : iocp->ioc_error); break; case IOC_DONE: /* * OK, reply already sent */ break; case IOC_ACK: /* * OK, reply with an ACK */ miocack(wq, mp, 0, 0); break; case IOC_REPLY: /* * OK, send prepared reply as ACK or NAK */ mp->b_datap->db_type = (uint8_t)(iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK); qreply(wq, mp); break; } mutex_exit(&qlge->gen_mutex); } /* ARGSUSED */ static int qlge_set_priv_prop(qlge_t *qlge, const char *pr_name, uint_t pr_valsize, const void *pr_val) { int err = 0; long result; if (strcmp(pr_name, "_adv_pause_mode") == 0) { (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); if (result > PAUSE_MODE_PER_PRIORITY || result < PAUSE_MODE_DISABLED) { err = EINVAL; } else if (qlge->pause != (uint32_t)result) { qlge->pause = (uint32_t)result; if (qlge->flags & INTERRUPTS_ENABLED) { mutex_enter(&qlge->mbx_mutex); if (ql_set_pause_mode(qlge) == DDI_FAILURE) err = EINVAL; mutex_exit(&qlge->mbx_mutex); } } return (err); } else if (strcmp(pr_name, "_fm_enable") == 0) { (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); if ((result != 0) && (result != 1)) { err = EINVAL; } else if (qlge->fm_enable != (boolean_t)result) { qlge->fm_enable = (boolean_t)result; } return (err); } return (ENOTSUP); } /* * callback functions for set/get of properties */ /* ARGSUSED */ static int ql_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, uint_t pr_valsize, const void *pr_val) { qlge_t *qlge = barg; int err = 0; uint32_t cur_mtu, new_mtu; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { mutex_exit(&qlge->gen_mutex); return (ECANCELED); } switch (pr_num) { case MAC_PROP_MTU: cur_mtu = qlge->mtu; bcopy(pr_val, &new_mtu, sizeof (new_mtu)); QL_PRINT(DBG_GLD, ("%s(%d) new mtu %d \n", __func__, qlge->instance, new_mtu)); if (new_mtu == cur_mtu) { err = 0; break; } if ((new_mtu != ETHERMTU) && (new_mtu != JUMBO_MTU)) { err = EINVAL; break; } /* * do not change on the fly, allow only before * driver is started or stopped */ if ((qlge->mac_flags == QL_MAC_STARTED) || (qlge->mac_flags == QL_MAC_DETACH)) { err = EBUSY; cmn_err(CE_WARN, "%s(%d) new mtu %d ignored, " "driver busy, mac_flags %d", __func__, qlge->instance, new_mtu, qlge->mac_flags); break; } qlge->mtu = new_mtu; err = mac_maxsdu_update(qlge->mh, qlge->mtu); if (err == 0) { /* EMPTY */ QL_PRINT(DBG_GLD, ("%s(%d) new mtu %d set success\n", __func__, qlge->instance, new_mtu)); } break; case MAC_PROP_PRIVATE: mutex_exit(&qlge->gen_mutex); err = qlge_set_priv_prop(qlge, pr_name, pr_valsize, pr_val); mutex_enter(&qlge->gen_mutex); break; default: err = ENOTSUP; break; } mutex_exit(&qlge->gen_mutex); return (err); } static int qlge_get_priv_prop(qlge_t *qlge, const char *pr_name, uint_t pr_valsize, void *pr_val) { int err = ENOTSUP; uint32_t value; if (strcmp(pr_name, "_adv_pause_mode") == 0) { value = qlge->pause; err = 0; } else if (strcmp(pr_name, "_fm_enable") == 0) { value = qlge->fm_enable; err = 0; } if (err == 0) { (void) snprintf(pr_val, pr_valsize, "%d", value); } return (err); } /* ARGSUSED */ static int ql_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, uint_t pr_valsize, void *pr_val) { qlge_t *qlge = barg; uint64_t speed; link_state_t link_state; link_duplex_t link_duplex; int err = 0; mutex_enter(&qlge->gen_mutex); if (qlge->mac_flags == QL_MAC_SUSPENDED) { err = ECANCELED; goto out; } switch (pr_num) { case MAC_PROP_DUPLEX: ASSERT(pr_valsize >= sizeof (link_duplex_t)); if (qlge->duplex) link_duplex = LINK_DUPLEX_FULL; else link_duplex = LINK_DUPLEX_HALF; bcopy(&link_duplex, pr_val, sizeof (link_duplex_t)); break; case MAC_PROP_SPEED: ASSERT(pr_valsize >= sizeof (speed)); speed = qlge->speed * 1000000ull; bcopy(&speed, pr_val, sizeof (speed)); break; case MAC_PROP_STATUS: ASSERT(pr_valsize >= sizeof (link_state_t)); if (qlge->port_link_state == LS_DOWN) link_state = LINK_STATE_DOWN; else link_state = LINK_STATE_UP; bcopy(&link_state, pr_val, sizeof (link_state_t)); break; case MAC_PROP_PRIVATE: err = qlge_get_priv_prop(qlge, pr_name, pr_valsize, pr_val); break; default: err = ENOTSUP; } out: mutex_exit(&qlge->gen_mutex); return (err); } /* ARGSUSED */ static void ql_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num, mac_prop_info_handle_t prh) { _NOTE(ARGUNUSED(barg)); switch (pr_num) { case MAC_PROP_DUPLEX: case MAC_PROP_SPEED: case MAC_PROP_STATUS: mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); break; case MAC_PROP_PRIVATE: { char val_str[64]; int default_val; if (strcmp(pr_name, "_adv_pause_mode") == 0) default_val = 2; else if (strcmp(pr_name, "_fm_enable") == 0) default_val = 1; else return; (void) snprintf(val_str, sizeof (val_str), "%d", default_val); mac_prop_info_set_default_str(prh, val_str); break; } } } /* ARGSUSED */ static boolean_t ql_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) { int ret = B_FALSE; uint32_t cksum = 0; qlge_t *qlge = (qlge_t *)arg; switch (cap) { case MAC_CAPAB_HCKSUM: if ((qlge->cfg_flags & CFG_CKSUM_FULL_IPv4) != 0) { cksum |= HCKSUM_INET_FULL_V4; } if ((qlge->cfg_flags & CFG_CKSUM_FULL_IPv6) != 0) { cksum |= HCKSUM_INET_FULL_V6; } if ((qlge->cfg_flags & CFG_CKSUM_HEADER_IPv4) != 0) { cksum |= HCKSUM_IPHDRCKSUM; } if ((qlge->cfg_flags & CFG_CKSUM_PARTIAL) != 0) { cksum |= HCKSUM_INET_PARTIAL; } qlge->chksum_cap = cksum; *(uint32_t *)cap_data = cksum; ret = B_TRUE; break; case MAC_CAPAB_LSO: { mac_capab_lso_t *cap_lso = (mac_capab_lso_t *)cap_data; uint32_t page_size; uint32_t lso_max; if ((qlge->cfg_flags & CFG_LSO)&& (qlge->cfg_flags & CFG_SUPPORT_SCATTER_GATHER)) { cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; page_size = ddi_ptob(qlge->dip, (ulong_t)1); lso_max = page_size * (QL_MAX_TX_DMA_HANDLES-1); cap_lso->lso_basic_tcp_ipv4.lso_max = min(lso_max, QL_LSO_MAX); ret = B_TRUE; } break; } default: return (B_FALSE); } return (ret); } void ql_gld3_init(qlge_t *qlge, mac_register_t *macp) { macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; macp->m_driver = qlge; macp->m_dip = qlge->dip; /* This is the mac address from flash to be used by the port */ macp->m_src_addr = qlge->dev_addr.ether_addr_octet; macp->m_min_sdu = 0; macp->m_max_sdu = qlge->mtu; macp->m_margin = VLAN_TAGSZ; macp->m_priv_props = qlge_priv_prop; macp->m_v12n = 0; ql_m_callbacks.mc_unicst = ql_m_unicst; ql_m_callbacks.mc_tx = ql_m_tx; macp->m_callbacks = &ql_m_callbacks; }