[SCSI] mptsas: Fix oops for insmod during kexec
[safe/jmp/linux-2.6] / drivers / message / fusion / mptlan.c
index 7defac7..b691292 100644 (file)
@@ -4,7 +4,8 @@
  *      For use with LSI Logic Fibre Channel PCI chip/adapters
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 2000-2005 LSI Logic Corporation
+ *  Copyright (c) 2000-2007 LSI Logic Corporation
+ *  (mailto:mpt_linux_developer@lsi.com)
  *
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #include <linux/module.h>
 #include <linux/fs.h>
 
+#define my_VERSION     MPT_LINUX_VERSION_COMMON
 #define MYNAM          "mptlan"
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -111,7 +114,8 @@ struct mpt_lan_priv {
        u32 total_received;
        struct net_device_stats stats;  /* Per device statistics */
 
-       struct work_struct post_buckets_task;
+       struct delayed_work post_buckets_task;
+       struct net_device *dev;
        unsigned long post_buckets_active;
 };
 
@@ -132,7 +136,7 @@ static int  lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
 static int  mpt_lan_open(struct net_device *dev);
 static int  mpt_lan_reset(struct net_device *dev);
 static int  mpt_lan_close(struct net_device *dev);
-static void mpt_lan_post_receive_buckets(void *dev_id);
+static void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv);
 static void mpt_lan_wake_post_buckets_task(struct net_device *dev,
                                           int priority);
 static int  mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
@@ -312,7 +316,12 @@ static int
 mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
        struct net_device *dev = ioc->netdev;
-       struct mpt_lan_priv *priv = netdev_priv(dev);
+       struct mpt_lan_priv *priv;
+
+       if (dev == NULL)
+               return(1);
+       else
+               priv = netdev_priv(dev);
 
        dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
                        reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
@@ -340,7 +349,7 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                        priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
                spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
        } else {
-               mpt_lan_post_receive_buckets(dev);
+               mpt_lan_post_receive_buckets(priv);
                netif_wake_queue(dev);
        }
 
@@ -406,14 +415,12 @@ mpt_lan_open(struct net_device *dev)
                goto out;
        priv->mpt_txfidx_tail = -1;
 
-       priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+       priv->SendCtl = kcalloc(priv->tx_max_out, sizeof(struct BufferControl),
                                GFP_KERNEL);
        if (priv->SendCtl == NULL)
                goto out_mpt_txfidx;
-       for (i = 0; i < priv->tx_max_out; i++) {
-               memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+       for (i = 0; i < priv->tx_max_out; i++)
                priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
-       }
 
        dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
 
@@ -423,15 +430,13 @@ mpt_lan_open(struct net_device *dev)
                goto out_SendCtl;
        priv->mpt_rxfidx_tail = -1;
 
-       priv->RcvCtl = kmalloc(priv->max_buckets_out *
-                                               sizeof(struct BufferControl),
+       priv->RcvCtl = kcalloc(priv->max_buckets_out,
+                              sizeof(struct BufferControl),
                               GFP_KERNEL);
        if (priv->RcvCtl == NULL)
                goto out_mpt_rxfidx;
-       for (i = 0; i < priv->max_buckets_out; i++) {
-               memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+       for (i = 0; i < priv->max_buckets_out; i++)
                priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
-       }
 
 /**/   dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
 /**/   for (i = 0; i < priv->tx_max_out; i++)
@@ -440,7 +445,7 @@ mpt_lan_open(struct net_device *dev)
 
        dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
 
-       mpt_lan_post_receive_buckets(dev);
+       mpt_lan_post_receive_buckets(priv);
        printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
                        IOC_AND_NETDEV_NAMES_s_s(dev));
 
@@ -506,7 +511,7 @@ mpt_lan_close(struct net_device *dev)
 {
        struct mpt_lan_priv *priv = netdev_priv(dev);
        MPT_ADAPTER *mpt_dev = priv->mpt_dev;
-       unsigned int timeout;
+       unsigned long timeout;
        int i;
 
        dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
@@ -521,11 +526,9 @@ mpt_lan_close(struct net_device *dev)
 
        mpt_lan_reset(dev);
 
-       timeout = 2 * HZ;
-       while (atomic_read(&priv->buckets_out) && --timeout) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(1);
-       }
+       timeout = jiffies + 2 * HZ;
+       while (atomic_read(&priv->buckets_out) && time_before(jiffies, timeout))
+               schedule_timeout_interruptible(1);
 
        for (i = 0; i < priv->max_buckets_out; i++) {
                if (priv->RcvCtl[i].skb != NULL) {
@@ -538,8 +541,8 @@ mpt_lan_close(struct net_device *dev)
                }
        }
 
-       kfree (priv->RcvCtl);
-       kfree (priv->mpt_rxfidx);
+       kfree(priv->RcvCtl);
+       kfree(priv->mpt_rxfidx);
 
        for (i = 0; i < priv->tx_max_out; i++) {
                if (priv->SendCtl[i].skb != NULL) {
@@ -845,7 +848,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline void
+static void
 mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
 /*
  * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
@@ -855,7 +858,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
        
        if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
                if (priority) {
-                       schedule_work(&priv->post_buckets_task);
+                       schedule_delayed_work(&priv->post_buckets_task, 0);
                } else {
                        schedule_delayed_work(&priv->post_buckets_task, 1);
                        dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
@@ -867,7 +870,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline int
+static int
 mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
 {
        struct mpt_lan_priv *priv = dev->priv;
@@ -1153,10 +1156,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                priv->mpt_rxfidx_tail,
                                MPT_LAN_MAX_BUCKETS_OUT);
 
-               panic("Damn it Jim! I'm a doctor, not a programmer! "
-                               "Oh, wait a sec, I am a programmer. "
-                               "And, who's Jim?!?!\n"
-                               "Arrgghh! We've done it again!\n");
+               return -1;
        }
 
        if (remaining == 0)
@@ -1192,10 +1192,9 @@ mpt_lan_receive_post_reply(struct net_device *dev,
 /* Simple SGE's only at the moment */
 
 static void
-mpt_lan_post_receive_buckets(void *dev_id)
+mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 {
-       struct net_device *dev = dev_id;
-       struct mpt_lan_priv *priv = dev->priv;
+       struct net_device *dev = priv->dev;
        MPT_ADAPTER *mpt_dev = priv->mpt_dev;
        MPT_FRAME_HDR *mf;
        LANReceivePostRequest_t *pRecvReq;
@@ -1339,6 +1338,13 @@ out:
        clear_bit(0, &priv->post_buckets_active);
 }
 
+static void
+mpt_lan_post_receive_buckets_work(struct work_struct *work)
+{
+       mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv,
+                                                 post_buckets_task.work));
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static struct net_device *
 mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
@@ -1354,11 +1360,13 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
 
        priv = netdev_priv(dev);
 
+       priv->dev = dev;
        priv->mpt_dev = mpt_dev;
        priv->pnum = pnum;
 
-       memset(&priv->post_buckets_task, 0, sizeof(struct work_struct));
-       INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
+       memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
+       INIT_DELAYED_WORK(&priv->post_buckets_task,
+                         mpt_lan_post_receive_buckets_work);
        priv->post_buckets_active = 0;
 
        dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",