Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6.git] / drivers / message / fusion / mptlan.c
index ef2713b..7950fc6 100644 (file)
@@ -1,33 +1,12 @@
 /*
  *  linux/drivers/message/fusion/mptlan.c
  *      IP Over Fibre Channel device driver.
- *      For use with PCI chip/adapter(s):
- *          LSIFC9xx/LSI409xx Fibre Channel
- *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ *      For use with LSI Fibre Channel PCI chip/adapters
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
  *
- *  Credits:
- *      This driver would not exist if not for Alan Cox's development
- *      of the linux i2o driver.
+ *  Copyright (c) 2000-2007 LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
- *      Special thanks goes to the I2O LAN driver people at the
- *      University of Helsinki, who, unbeknownst to them, provided
- *      the inspiration and initial structure for this driver.
- *
- *      A huge debt of gratitude is owed to David S. Miller (DaveM)
- *      for fixing much of the stupid and broken stuff in the early
- *      driver while porting to sparc64 platform.  THANK YOU!
- *
- *      A really huge debt of gratitude is owed to Eddie C. Dost
- *      for gobs of hard work fixing and optimizing LAN code.
- *      THANK YOU!
- *
- *      (see also mptbase.c)
- *
- *  Copyright (c) 2000-2004 LSI Logic Corporation
- *  Originally By: Noah Romer
- *  (mailto:mpt_linux_developer@lsil.com)
- *
- *  $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
 #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);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -133,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;
 };
 
@@ -154,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);
@@ -172,7 +154,7 @@ static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
 /*
  *  Fusion MPT LAN private data
  */
-static int LanCtx = -1;
+static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
 static u32 max_buckets_out = 127;
 static u32 tx_max_out_p = 127 - 16;
@@ -183,12 +165,6 @@ DEFINE_RWLOCK(bad_naa_lock);
 #endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Fusion MPT LAN external data
- */
-extern int mpt_lan_index;
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     lan_reply - Handle all data sent from the hardware.
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -221,7 +197,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 
                // NOTE!  (Optimization) First case here is now caught in
                //  mptbase.c::mpt_interrupt() routine and callcack here
-               //  is now skipped for this case!  20001218 -sralston
+               //  is now skipped for this case!
 #if 0
                case LAN_REPLY_FORM_MESSAGE_CONTEXT:
 //                     dioprintk((KERN_INFO MYNAM "/lan_reply: "
@@ -234,7 +210,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 //                     dioprintk((MYNAM "/lan_reply: "
 //                               "calling mpt_lan_send_reply (turbo)\n"));
 
-                       // Potential BUG here?  -sralston
+                       // Potential BUG here?
                        //      FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
                        //  If/when mpt_lan_send_turbo would return 1 here,
                        //  calling routine (mptbase.c|mpt_interrupt)
@@ -310,8 +286,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
 
        case MPI_FUNCTION_EVENT_NOTIFICATION:
        case MPI_FUNCTION_EVENT_ACK:
-               /* UPDATE!  20010120 -sralston
-                *  _EVENT_NOTIFICATION should NOT come down this path any more.
+               /*  _EVENT_NOTIFICATION should NOT come down this path any more.
                 *  Should be routed to mpt_lan_event_process(), but just in case...
                 */
                FreeReqFrame = 1;
@@ -335,7 +310,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" : (
@@ -363,7 +343,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);
        }
 
@@ -429,14 +409,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"));
 
@@ -446,15 +424,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++)
@@ -463,7 +439,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));
 
@@ -529,7 +505,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"));
@@ -544,11 +520,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) {
@@ -561,8 +535,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) {
@@ -734,6 +708,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        LANSendRequest_t *pSendReq;
        SGETransaction32_t *pTrans;
        SGESimple64_t *pSimple;
+       const unsigned char *mac;
        dma_addr_t dma;
        unsigned long flags;
        int ctx;
@@ -773,7 +748,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
        /* Set the mac.raw pointer, since this apparently isn't getting
         * done before we get the skb. Pull the data pointer past the mac data.
         */
-       skb->mac.raw = skb->data;
+       skb_reset_mac_header(skb);
        skb_pull(skb, 12);
 
         dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
@@ -804,6 +779,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 //                     IOC_AND_NETDEV_NAMES_s_s(dev),
 //                     ctx, skb, skb->data));
 
+       mac = skb_mac_header(skb);
 #ifdef QLOGIC_NAA_WORKAROUND
 {
        struct NAA_Hosed *nh;
@@ -813,12 +789,12 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
           drops. */
        read_lock_irq(&bad_naa_lock);
        for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) {
-               if ((nh->ieee[0] == skb->mac.raw[0]) &&
-                   (nh->ieee[1] == skb->mac.raw[1]) &&
-                   (nh->ieee[2] == skb->mac.raw[2]) &&
-                   (nh->ieee[3] == skb->mac.raw[3]) &&
-                   (nh->ieee[4] == skb->mac.raw[4]) &&
-                   (nh->ieee[5] == skb->mac.raw[5])) {
+               if ((nh->ieee[0] == mac[0]) &&
+                   (nh->ieee[1] == mac[1]) &&
+                   (nh->ieee[2] == mac[2]) &&
+                   (nh->ieee[3] == mac[3]) &&
+                   (nh->ieee[4] == mac[4]) &&
+                   (nh->ieee[5] == mac[5])) {
                        cur_naa = nh->NAA;
                        dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
                                  "= %04x.\n", cur_naa));
@@ -830,12 +806,12 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 #endif
 
        pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
-                                                   (skb->mac.raw[0] <<  8) |
-                                                   (skb->mac.raw[1] <<  0));
-       pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
-                                                   (skb->mac.raw[3] << 16) |
-                                                   (skb->mac.raw[4] <<  8) |
-                                                   (skb->mac.raw[5] <<  0));
+                                                   (mac[0] <<  8) |
+                                                   (mac[1] <<  0));
+       pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) |
+                                                   (mac[3] << 16) |
+                                                   (mac[4] <<  8) |
+                                                   (mac[5] <<  0));
 
        pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
 
@@ -868,7 +844,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
@@ -878,7 +854,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 "
@@ -890,7 +866,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;
@@ -950,7 +926,7 @@ mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
                pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
                                            priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
 
-               memcpy(skb_put(skb, len), old_skb->data, len);
+               skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
 
                pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
                                               priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
@@ -1111,7 +1087,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                                    priv->RcvCtl[ctx].dma,
                                                    priv->RcvCtl[ctx].len,
                                                    PCI_DMA_FROMDEVICE);
-                       memcpy(skb_put(skb, l), old_skb->data, l);
+                       skb_copy_from_linear_data(old_skb, skb_put(skb, l), l);
 
                        pci_dma_sync_single_for_device(mpt_dev->pcidev,
                                                       priv->RcvCtl[ctx].dma,
@@ -1140,7 +1116,7 @@ mpt_lan_receive_post_reply(struct net_device *dev,
                                            priv->RcvCtl[ctx].len,
                                            PCI_DMA_FROMDEVICE);
 
-               memcpy(skb_put(skb, len), old_skb->data, len);
+               skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
 
                pci_dma_sync_single_for_device(mpt_dev->pcidev,
                                               priv->RcvCtl[ctx].dma,
@@ -1176,10 +1152,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)
@@ -1215,10 +1188,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;
@@ -1252,6 +1224,8 @@ mpt_lan_post_receive_buckets(void *dev_id)
                }
                pRecvReq = (LANReceivePostRequest_t *) mf;
 
+               i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               mpt_dev->RequestNB[i] = 0;
                count = buckets;
                if (count > max)
                        count = max;
@@ -1362,14 +1336,22 @@ 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)
 {
-       struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
-       struct mpt_lan_priv *priv = NULL;
+       struct net_device *dev;
+       struct mpt_lan_priv *priv;
        u8 HWaddr[FC_ALEN], *a;
 
+       dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
        if (!dev)
                return NULL;
 
@@ -1377,11 +1359,12 @@ 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);
+       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",
@@ -1404,8 +1387,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        spin_lock_init(&priv->txfidx_lock);
        spin_lock_init(&priv->rxfidx_lock);
 
-       memset(&priv->stats, 0, sizeof(priv->stats));
-
        /*  Grab pre-fetched LANPage1 stuff. :-) */
        a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
 
@@ -1440,8 +1421,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
        dlprintk((KERN_INFO MYNAM ": Finished registering dev "
                "and setting initial values\n"));
 
-       SET_MODULE_OWNER(dev);
-
        if (register_netdev(dev) != 0) {
                free_netdev(dev);
                dev = NULL;
@@ -1523,9 +1502,6 @@ static int __init mpt_lan_init (void)
                return -EBUSY;
        }
 
-       /* Set the callback index to be used by driver core for turbo replies */
-       mpt_lan_index = LanCtx;
-
        dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
 
        if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
@@ -1537,8 +1513,7 @@ static int __init mpt_lan_init (void)
 
        dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
        
-       if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER))
-               dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n"));
+       mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER);
        return 0;
 }
 
@@ -1547,10 +1522,9 @@ static void __exit mpt_lan_exit(void)
        mpt_device_driver_deregister(MPTLAN_DRIVER);
        mpt_reset_deregister(LanCtx);
 
-       if (LanCtx >= 0) {
+       if (LanCtx) {
                mpt_deregister(LanCtx);
-               LanCtx = -1;
-               mpt_lan_index = 0;
+               LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
        }
 }
 
@@ -1564,7 +1538,7 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
        struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
        struct fcllc *fcllc;
 
-       skb->mac.raw = skb->data;
+       skb_reset_mac_header(skb);
        skb_pull(skb, sizeof(struct mpt_lan_ohdr));
 
        if (fch->dtype == htons(0xffff)) {