summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/io/igb/igb.conf6
-rw-r--r--usr/src/uts/common/io/igb/igb_gld.c10
-rw-r--r--usr/src/uts/common/io/igb/igb_main.c159
-rw-r--r--usr/src/uts/common/io/igb/igb_ndd.c19
-rw-r--r--usr/src/uts/common/io/igb/igb_rx.c16
-rw-r--r--usr/src/uts/common/io/igb/igb_stat.c6
-rw-r--r--usr/src/uts/common/io/igb/igb_sw.h4
-rw-r--r--usr/src/uts/common/io/igb/igb_tx.c12
8 files changed, 189 insertions, 43 deletions
diff --git a/usr/src/uts/common/io/igb/igb.conf b/usr/src/uts/common/io/igb/igb.conf
index 93860209f0..8914b31189 100644
--- a/usr/src/uts/common/io/igb/igb.conf
+++ b/usr/src/uts/common/io/igb/igb.conf
@@ -19,9 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+# Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -133,7 +133,7 @@
# mr_enable
# Enable multiple rx queues and tx queues
# Allowed values: 0, 1
-# Default value: 1
+# Default value: 0
#
# rx_group_number
# The number of the receive ring groups
diff --git a/usr/src/uts/common/io/igb/igb_gld.c b/usr/src/uts/common/io/igb/igb_gld.c
index 539b1992cc..9fddd30f61 100644
--- a/usr/src/uts/common/io/igb/igb_gld.c
+++ b/usr/src/uts/common/io/igb/igb_gld.c
@@ -427,8 +427,10 @@ igb_m_stat(void *arg, uint_t stat, uint64_t *val)
mutex_exit(&igb->gen_lock);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (EIO);
+ }
return (0);
}
@@ -454,7 +456,7 @@ igb_m_start(void *arg)
return (EIO);
}
- igb->igb_state |= IGB_STARTED;
+ atomic_or_32(&igb->igb_state, IGB_STARTED);
mutex_exit(&igb->gen_lock);
@@ -482,7 +484,7 @@ igb_m_stop(void *arg)
return;
}
- igb->igb_state &= ~IGB_STARTED;
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
igb_stop(igb);
diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c
index e2137ae44c..5939625e28 100644
--- a/usr/src/uts/common/io/igb/igb_main.c
+++ b/usr/src/uts/common/io/igb/igb_main.c
@@ -29,7 +29,7 @@
#include "igb_sw.h"
static char ident[] = "Intel 1Gb Ethernet";
-static char igb_version[] = "igb 1.1.9";
+static char igb_version[] = "igb 1.1.10";
/*
* Local function protoypes
@@ -67,10 +67,13 @@ static int igb_get_prop(igb_t *, char *, int, int, int);
static boolean_t igb_is_link_up(igb_t *);
static boolean_t igb_link_check(igb_t *);
static void igb_local_timer(void *);
+static void igb_link_timer(void *);
static void igb_arm_watchdog_timer(igb_t *);
static void igb_start_watchdog_timer(igb_t *);
static void igb_restart_watchdog_timer(igb_t *);
static void igb_stop_watchdog_timer(igb_t *);
+static void igb_start_link_timer(igb_t *);
+static void igb_stop_link_timer(igb_t *);
static void igb_disable_adapter_interrupts(igb_t *);
static void igb_enable_adapter_interrupts_82575(igb_t *);
static void igb_enable_adapter_interrupts_82576(igb_t *);
@@ -507,7 +510,7 @@ igb_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
igb->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
igb_log(igb, "%s", igb_version);
- igb->igb_state |= IGB_INITIALIZED;
+ atomic_or_32(&igb->igb_state, IGB_INITIALIZED);
return (DDI_SUCCESS);
@@ -575,7 +578,7 @@ igb_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
*/
mutex_enter(&igb->gen_lock);
if (igb->igb_state & IGB_STARTED) {
- igb->igb_state &= ~IGB_STARTED;
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
igb_stop(igb);
mutex_exit(&igb->gen_lock);
/* Disable and stop the watchdog timer */
@@ -1027,6 +1030,9 @@ igb_init_locks(igb_t *igb)
mutex_init(&igb->watchdog_lock, NULL,
MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
+
+ mutex_init(&igb->link_lock, NULL,
+ MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
}
/*
@@ -1055,6 +1061,7 @@ igb_destroy_locks(igb_t *igb)
mutex_destroy(&igb->gen_lock);
mutex_destroy(&igb->watchdog_lock);
+ mutex_destroy(&igb->link_lock);
}
static int
@@ -1080,7 +1087,7 @@ igb_resume(dev_info_t *devinfo)
igb_enable_watchdog_timer(igb);
}
- igb->igb_state &= ~IGB_SUSPENDED;
+ atomic_and_32(&igb->igb_state, ~IGB_SUSPENDED);
mutex_exit(&igb->gen_lock);
@@ -1098,7 +1105,7 @@ igb_suspend(dev_info_t *devinfo)
mutex_enter(&igb->gen_lock);
- igb->igb_state |= IGB_SUSPENDED;
+ atomic_or_32(&igb->igb_state, IGB_SUSPENDED);
if (!(igb->igb_state & IGB_STARTED)) {
mutex_exit(&igb->gen_lock);
@@ -1149,6 +1156,11 @@ igb_init(igb_t *igb)
for (i = igb->num_rx_rings - 1; i >= 0; i--)
mutex_exit(&igb->rx_rings[i].rx_lock);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
+ return (IGB_FAILURE);
+ }
+
mutex_exit(&igb->gen_lock);
return (IGB_SUCCESS);
@@ -1325,6 +1337,11 @@ igb_init_adapter(igb_t *igb)
}
/*
+ * Start the link setup timer
+ */
+ igb_start_link_timer(igb);
+
+ /*
* Disable wakeup control by default
*/
E1000_WRITE_REG(hw, E1000_WUC, 0);
@@ -1394,6 +1411,9 @@ igb_stop_adapter(igb_t *igb)
ASSERT(mutex_owned(&igb->gen_lock));
+ /* Stop the link setup timer */
+ igb_stop_link_timer(igb);
+
/* Tell firmware driver is no longer in control */
igb_release_driver_control(hw);
@@ -1424,6 +1444,7 @@ igb_reset(igb_t *igb)
mutex_enter(&igb->gen_lock);
ASSERT(igb->igb_state & IGB_STARTED);
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
/*
* Disable the adapter interrupts to stop any rx/tx activities
@@ -1464,6 +1485,8 @@ igb_reset(igb_t *igb)
*/
igb_setup_rings(igb);
+ atomic_and_32(&igb->igb_state, ~(IGB_ERROR | IGB_STALL));
+
/*
* Enable adapter interrupts
* The interrupts must be enabled after the driver state is START
@@ -1481,6 +1504,8 @@ igb_reset(igb_t *igb)
for (i = igb->num_rx_rings - 1; i >= 0; i--)
mutex_exit(&igb->rx_rings[i].rx_lock);
+ atomic_or_32(&igb->igb_state, IGB_STARTED);
+
mutex_exit(&igb->gen_lock);
return (IGB_SUCCESS);
@@ -1840,9 +1865,6 @@ igb_setup_rings(igb_t *igb)
igb_setup_rx(igb);
igb_setup_tx(igb);
-
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
}
static void
@@ -2397,9 +2419,6 @@ igb_init_unicst(igb_t *igb)
igb->unicst_addr[slot].mac.group_index);
}
}
-
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
}
/*
@@ -2982,8 +3001,10 @@ igb_link_check(igb_t *igb)
igb->link_state = LINK_STATE_UP;
igb->link_down_timeout = 0;
link_changed = B_TRUE;
+ if (!igb->link_complete)
+ igb_stop_link_timer(igb);
}
- } else {
+ } else if (igb->link_complete) {
if (igb->link_state != LINK_STATE_DOWN) {
igb->link_speed = 0;
igb->link_duplex = 0;
@@ -3002,8 +3023,10 @@ igb_link_check(igb_t *igb)
}
}
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (B_FALSE);
+ }
return (link_changed);
}
@@ -3020,17 +3043,24 @@ igb_local_timer(void *arg)
igb_t *igb = (igb_t *)arg;
boolean_t link_changed = B_FALSE;
- if (igb_stall_check(igb))
- igb->igb_state |= IGB_STALL;
+ if (igb->igb_state & IGB_ERROR) {
+ igb->reset_count++;
+ if (igb_reset(igb) == IGB_SUCCESS)
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
- if (igb->igb_state & IGB_STALL) {
+ igb_restart_watchdog_timer(igb);
+ return;
+ }
+
+ if (igb_stall_check(igb) || (igb->igb_state & IGB_STALL)) {
igb_fm_ereport(igb, DDI_FM_DEVICE_STALL);
ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
igb->reset_count++;
- igb->igb_state &= ~IGB_STALL;
if (igb_reset(igb) == IGB_SUCCESS)
- ddi_fm_service_impact(igb->dip,
- DDI_SERVICE_RESTORED);
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
+
+ igb_restart_watchdog_timer(igb);
+ return;
}
mutex_enter(&igb->gen_lock);
@@ -3041,13 +3071,30 @@ igb_local_timer(void *arg)
if (link_changed)
mac_link_update(igb->mac_hdl, igb->link_state);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
-
igb_restart_watchdog_timer(igb);
}
/*
+ * igb_link_timer - link setup timer function
+ *
+ * It is called when the timer for link setup is expired, which indicates
+ * the completion of the link setup. The link state will not be updated
+ * until the link setup is completed. And the link state will not be sent
+ * to the upper layer through mac_link_update() in this function. It will
+ * be updated in the local timer routine or the interrupts service routine
+ * after the interface is started (plumbed).
+ */
+static void
+igb_link_timer(void *arg)
+{
+ igb_t *igb = (igb_t *)arg;
+
+ mutex_enter(&igb->link_lock);
+ igb->link_complete = B_TRUE;
+ igb->link_tid = 0;
+ mutex_exit(&igb->link_lock);
+}
+/*
* igb_stall_check - check for transmit stall
*
* This function checks if the adapter is stalled (in transmit).
@@ -3302,6 +3349,50 @@ igb_stop_watchdog_timer(igb_t *igb)
}
/*
+ * igb_start_link_timer - Start the link setup timer
+ */
+static void
+igb_start_link_timer(struct igb *igb)
+{
+ struct e1000_hw *hw = &igb->hw;
+ clock_t link_timeout;
+
+ if (hw->mac.autoneg)
+ link_timeout = PHY_AUTO_NEG_LIMIT *
+ drv_usectohz(100000);
+ else
+ link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000);
+
+ mutex_enter(&igb->link_lock);
+ if (hw->phy.autoneg_wait_to_complete) {
+ igb->link_complete = B_TRUE;
+ } else {
+ igb->link_complete = B_FALSE;
+ igb->link_tid = timeout(igb_link_timer, (void *)igb,
+ link_timeout);
+ }
+ mutex_exit(&igb->link_lock);
+}
+
+/*
+ * igb_stop_link_timer - Stop the link setup timer
+ */
+static void
+igb_stop_link_timer(struct igb *igb)
+{
+ timeout_id_t tid;
+
+ mutex_enter(&igb->link_lock);
+ igb->link_complete = B_TRUE;
+ tid = igb->link_tid;
+ igb->link_tid = 0;
+ mutex_exit(&igb->link_lock);
+
+ if (tid != 0)
+ (void) untimeout(tid);
+}
+
+/*
* igb_disable_adapter_interrupts - Clear/disable all hardware interrupts
*/
static void
@@ -3829,6 +3920,12 @@ igb_intr_legacy(void *arg1, void *arg2)
link_changed = B_FALSE;
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
if (icr & E1000_ICR_INT_ASSERTED) {
/*
* E1000_ICR_INT_ASSERTED bit was set:
@@ -3872,7 +3969,7 @@ igb_intr_legacy(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
result = DDI_INTR_CLAIMED;
@@ -3917,6 +4014,12 @@ igb_intr_msi(void *arg1, void *arg2)
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_CLAIMED);
+ }
+
/* Make sure all interrupt causes cleared */
(void) E1000_READ_REG(&igb->hw, E1000_EICR);
@@ -3941,7 +4044,7 @@ igb_intr_msi(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
return (DDI_INTR_CLAIMED);
@@ -3999,6 +4102,12 @@ igb_intr_tx_other(void *arg1, void *arg2)
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_CLAIMED);
+ }
+
/*
* Look for tx reclaiming work first. Remember, in the
* case of only interrupt sharing, only one tx ring is
@@ -4027,7 +4136,7 @@ igb_intr_tx_other(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
return (DDI_INTR_CLAIMED);
diff --git a/usr/src/uts/common/io/igb/igb_ndd.c b/usr/src/uts/common/io/igb/igb_ndd.c
index 58ce0e77e5..3e00a82c89 100644
--- a/usr/src/uts/common/io/igb/igb_ndd.c
+++ b/usr/src/uts/common/io/igb/igb_ndd.c
@@ -33,7 +33,7 @@ static int igb_nd_get(queue_t *, mblk_t *, caddr_t, cred_t *);
static int igb_nd_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
static int igb_nd_param_load(igb_t *);
static void igb_nd_get_param_val(nd_param_t *);
-static void igb_nd_set_param_val(nd_param_t *, uint32_t);
+static int igb_nd_set_param_val(nd_param_t *, uint32_t);
/*
* Notes:
@@ -146,7 +146,8 @@ igb_nd_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
if (new_value < nd->min || new_value > nd->max)
return (EINVAL);
- igb_nd_set_param_val(nd, new_value);
+ if (igb_nd_set_param_val(nd, new_value) != IGB_SUCCESS)
+ return (EIO);
return (0);
}
@@ -263,16 +264,17 @@ igb_nd_get_param_val(nd_param_t *nd)
/*
* igb_nd_set_param_val
*/
-static void
+static int
igb_nd_set_param_val(nd_param_t *nd, uint32_t value)
{
igb_t *igb = (igb_t *)nd->private;
+ int result = IGB_SUCCESS;
mutex_enter(&igb->gen_lock);
if (nd->val == value) {
mutex_exit(&igb->gen_lock);
- return;
+ return (IGB_SUCCESS);
}
switch (nd->info) {
@@ -284,16 +286,19 @@ igb_nd_set_param_val(nd_param_t *nd, uint32_t value)
case PARAM_ADV_10HDX_CAP:
nd->val = value;
(void) igb_setup_link(igb, B_TRUE);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ result = IGB_FAILURE;
+ }
break;
default:
break;
}
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
-
mutex_exit(&igb->gen_lock);
+
+ return (result);
}
/*
diff --git a/usr/src/uts/common/io/igb/igb_rx.c b/usr/src/uts/common/io/igb/igb_rx.c
index d1f6368a8d..13265e8a28 100644
--- a/usr/src/uts/common/io/igb/igb_rx.c
+++ b/usr/src/uts/common/io/igb/igb_rx.c
@@ -112,6 +112,8 @@ igb_rx_copy(igb_rx_ring_t *rx_ring, uint32_t index, uint32_t pkt_len)
if (igb_check_dma_handle(
current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (NULL);
}
/*
@@ -184,6 +186,9 @@ igb_rx_bind(igb_rx_ring_t *rx_ring, uint32_t index, uint32_t pkt_len)
if (igb_check_dma_handle(
current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ atomic_inc_32(&rx_ring->rcb_free);
+ return (NULL);
}
mp = current_rcb->mp;
@@ -253,8 +258,9 @@ igb_rx_ring_poll(void *arg, int bytes)
ASSERT(bytes >= 0);
- if (bytes == 0)
- return (mp);
+ if ((bytes == 0) || (rx_ring->igb->igb_state & IGB_SUSPENDED) ||
+ !(rx_ring->igb->igb_state & IGB_STARTED))
+ return (NULL);
mutex_enter(&rx_ring->rx_lock);
mp = igb_rx(rx_ring, bytes);
@@ -290,6 +296,9 @@ igb_rx(igb_rx_ring_t *rx_ring, int poll_bytes)
mblk_head = NULL;
mblk_tail = &mblk_head;
+ if (igb->igb_state & IGB_ERROR)
+ return (NULL);
+
/*
* Sync the receive descriptors before
* accepting the packets
@@ -299,6 +308,8 @@ igb_rx(igb_rx_ring_t *rx_ring, int poll_bytes)
if (igb_check_dma_handle(
rx_ring->rbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (NULL);
}
/*
@@ -401,6 +412,7 @@ rx_discard:
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
}
return (mblk_head);
diff --git a/usr/src/uts/common/io/igb/igb_stat.c b/usr/src/uts/common/io/igb/igb_stat.c
index a16d8bec3f..8edc4dbeed 100644
--- a/usr/src/uts/common/io/igb/igb_stat.c
+++ b/usr/src/uts/common/io/igb/igb_stat.c
@@ -136,8 +136,10 @@ igb_update_stats(kstat_t *ks, int rw)
mutex_exit(&igb->gen_lock);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (EIO);
+ }
return (0);
}
diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h
index 5744f148f0..483f3342b2 100644
--- a/usr/src/uts/common/io/igb/igb_sw.h
+++ b/usr/src/uts/common/io/igb/igb_sw.h
@@ -82,6 +82,7 @@ extern "C" {
#define IGB_STARTED 0x02
#define IGB_SUSPENDED 0x04
#define IGB_STALL 0x08
+#define IGB_ERROR 0x80
#define IGB_INTR_NONE 0
#define IGB_INTR_MSIX 1
@@ -662,6 +663,8 @@ typedef struct igb {
uint32_t link_speed;
uint32_t link_duplex;
uint32_t link_down_timeout;
+ boolean_t link_complete;
+ timeout_id_t link_tid;
uint32_t reset_count;
uint32_t attach_progress;
@@ -715,6 +718,7 @@ typedef struct igb {
kmutex_t gen_lock; /* General lock for device access */
kmutex_t watchdog_lock;
+ kmutex_t link_lock;
boolean_t watchdog_enable;
boolean_t watchdog_start;
diff --git a/usr/src/uts/common/io/igb/igb_tx.c b/usr/src/uts/common/io/igb/igb_tx.c
index a24010cd30..54bde3d330 100644
--- a/usr/src/uts/common/io/igb/igb_tx.c
+++ b/usr/src/uts/common/io/igb/igb_tx.c
@@ -56,6 +56,13 @@ igb_tx_ring_send(void *arg, mblk_t *mp)
ASSERT(tx_ring != NULL);
+ if ((tx_ring->igb->igb_state & IGB_SUSPENDED) ||
+ (tx_ring->igb->igb_state & IGB_ERROR) ||
+ !(tx_ring->igb->igb_state & IGB_STARTED)) {
+ freemsg(mp);
+ return (NULL);
+ }
+
return ((igb_tx(tx_ring, mp)) ? NULL : mp);
}
@@ -1013,6 +1020,7 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list,
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
}
return (desc_num);
@@ -1081,6 +1089,8 @@ igb_tx_recycle_legacy(igb_tx_ring_t *tx_ring)
if (igb_check_dma_handle(
tx_ring->tbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (0);
}
LINK_LIST_INIT(&pending_list);
@@ -1227,6 +1237,8 @@ igb_tx_recycle_head_wb(igb_tx_ring_t *tx_ring)
if (igb_check_dma_handle(
tx_ring->tbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (0);
}
LINK_LIST_INIT(&pending_list);