Merge git://www.linux-watchdog.org/linux-watchdog
[cascardo/linux.git] / net / ncsi / ncsi-manage.c
index adf5401..5e509e5 100644 (file)
@@ -172,15 +172,15 @@ static void ncsi_channel_monitor(unsigned long data)
        struct ncsi_dev_priv *ndp = np->ndp;
        struct ncsi_cmd_arg nca;
        bool enabled, chained;
-       unsigned int timeout;
+       unsigned int monitor_state;
        unsigned long flags;
        int state, ret;
 
        spin_lock_irqsave(&nc->lock, flags);
        state = nc->state;
        chained = !list_empty(&nc->link);
-       timeout = nc->timeout;
-       enabled = nc->enabled;
+       enabled = nc->monitor.enabled;
+       monitor_state = nc->monitor.state;
        spin_unlock_irqrestore(&nc->lock, flags);
 
        if (!enabled || chained)
@@ -189,7 +189,9 @@ static void ncsi_channel_monitor(unsigned long data)
            state != NCSI_CHANNEL_ACTIVE)
                return;
 
-       if (!(timeout % 2)) {
+       switch (monitor_state) {
+       case NCSI_CHANNEL_MONITOR_START:
+       case NCSI_CHANNEL_MONITOR_RETRY:
                nca.ndp = ndp;
                nca.package = np->id;
                nca.channel = nc->id;
@@ -201,12 +203,16 @@ static void ncsi_channel_monitor(unsigned long data)
                                   ret);
                        return;
                }
-       }
 
-       if (timeout + 1 >= 3) {
+               break;
+       case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
+               break;
+       default:
                if (!(ndp->flags & NCSI_DEV_HWA) &&
-                   state == NCSI_CHANNEL_ACTIVE)
+                   state == NCSI_CHANNEL_ACTIVE) {
                        ncsi_report_link(ndp, true);
+                       ndp->flags |= NCSI_DEV_RESHUFFLE;
+               }
 
                spin_lock_irqsave(&nc->lock, flags);
                nc->state = NCSI_CHANNEL_INVISIBLE;
@@ -221,10 +227,9 @@ static void ncsi_channel_monitor(unsigned long data)
        }
 
        spin_lock_irqsave(&nc->lock, flags);
-       nc->timeout = timeout + 1;
-       nc->enabled = true;
+       nc->monitor.state++;
        spin_unlock_irqrestore(&nc->lock, flags);
-       mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2)));
+       mod_timer(&nc->monitor.timer, jiffies + HZ);
 }
 
 void ncsi_start_channel_monitor(struct ncsi_channel *nc)
@@ -232,12 +237,12 @@ void ncsi_start_channel_monitor(struct ncsi_channel *nc)
        unsigned long flags;
 
        spin_lock_irqsave(&nc->lock, flags);
-       WARN_ON_ONCE(nc->enabled);
-       nc->timeout = 0;
-       nc->enabled = true;
+       WARN_ON_ONCE(nc->monitor.enabled);
+       nc->monitor.enabled = true;
+       nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
        spin_unlock_irqrestore(&nc->lock, flags);
 
-       mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2)));
+       mod_timer(&nc->monitor.timer, jiffies + HZ);
 }
 
 void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
@@ -245,14 +250,14 @@ void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
        unsigned long flags;
 
        spin_lock_irqsave(&nc->lock, flags);
-       if (!nc->enabled) {
+       if (!nc->monitor.enabled) {
                spin_unlock_irqrestore(&nc->lock, flags);
                return;
        }
-       nc->enabled = false;
+       nc->monitor.enabled = false;
        spin_unlock_irqrestore(&nc->lock, flags);
 
-       del_timer_sync(&nc->timer);
+       del_timer_sync(&nc->monitor.timer);
 }
 
 struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
@@ -281,8 +286,9 @@ struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np, unsigned char id)
        nc->id = id;
        nc->package = np;
        nc->state = NCSI_CHANNEL_INACTIVE;
-       nc->enabled = false;
-       setup_timer(&nc->timer, ncsi_channel_monitor, (unsigned long)nc);
+       nc->monitor.enabled = false;
+       setup_timer(&nc->monitor.timer,
+                   ncsi_channel_monitor, (unsigned long)nc);
        spin_lock_init(&nc->lock);
        INIT_LIST_HEAD(&nc->link);
        for (index = 0; index < NCSI_CAP_MAX; index++)
@@ -1181,11 +1187,7 @@ EXPORT_SYMBOL_GPL(ncsi_register_dev);
 int ncsi_start_dev(struct ncsi_dev *nd)
 {
        struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
-       struct ncsi_package *np;
-       struct ncsi_channel *nc;
-       unsigned long flags;
-       bool chained;
-       int old_state, ret;
+       int ret;
 
        if (nd->state != ncsi_dev_state_registered &&
            nd->state != ncsi_dev_state_functional)
@@ -1197,9 +1199,29 @@ int ncsi_start_dev(struct ncsi_dev *nd)
                return 0;
        }
 
-       /* Reset channel's state and start over */
+       if (ndp->flags & NCSI_DEV_HWA)
+               ret = ncsi_enable_hwa(ndp);
+       else
+               ret = ncsi_choose_active_channel(ndp);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ncsi_start_dev);
+
+void ncsi_stop_dev(struct ncsi_dev *nd)
+{
+       struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
+       struct ncsi_package *np;
+       struct ncsi_channel *nc;
+       bool chained;
+       int old_state;
+       unsigned long flags;
+
+       /* Stop the channel monitor and reset channel's state */
        NCSI_FOR_EACH_PACKAGE(ndp, np) {
                NCSI_FOR_EACH_CHANNEL(np, nc) {
+                       ncsi_stop_channel_monitor(nc);
+
                        spin_lock_irqsave(&nc->lock, flags);
                        chained = !list_empty(&nc->link);
                        old_state = nc->state;
@@ -1211,14 +1233,9 @@ int ncsi_start_dev(struct ncsi_dev *nd)
                }
        }
 
-       if (ndp->flags & NCSI_DEV_HWA)
-               ret = ncsi_enable_hwa(ndp);
-       else
-               ret = ncsi_choose_active_channel(ndp);
-
-       return ret;
+       ncsi_report_link(ndp, true);
 }
-EXPORT_SYMBOL_GPL(ncsi_start_dev);
+EXPORT_SYMBOL_GPL(ncsi_stop_dev);
 
 void ncsi_unregister_dev(struct ncsi_dev *nd)
 {