patch-2.4.7 linux/drivers/message/fusion/mptlan.c
Next file: linux/drivers/message/fusion/mptlan.h
Previous file: linux/drivers/message/fusion/mptctl.c
Back to the patch index
Back to the overall index
- Lines: 1463
- Date:
Fri Jul 6 17:03:11 2001
- Orig file:
v2.4.6/linux/drivers/message/fusion/mptlan.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptlan.c linux/drivers/message/fusion/mptlan.c
@@ -0,0 +1,1462 @@
+/*
+ * 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.
+ *
+ * Credits:
+ * This driver would not exist if not for Alan Cox's development
+ * of the linux i2o driver.
+ *
+ * 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-2001 LSI Logic Corporation
+ * Originally By: Noah Romer
+ *
+ * $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Define statements used for debugging
+ */
+//#define MPT_LAN_IO_DEBUG
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#include "mptlan.h"
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#define MYNAM "mptlan"
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * MPT LAN message sizes without variable part.
+ */
+#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \
+ (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION))
+
+#define MPT_LAN_TRANSACTION32_SIZE \
+ (sizeof(SGETransaction32_t) - sizeof(u32))
+
+/*
+ * Fusion MPT LAN private structures
+ */
+
+struct BufferControl {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned int len;
+};
+
+struct mpt_lan_priv {
+ MPT_ADAPTER *mpt_dev;
+ u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
+
+ atomic_t buckets_out; /* number of unused buckets on IOC */
+ int bucketthresh; /* Send more when this many used */
+
+ int *mpt_txfidx; /* Free Tx Context list */
+ int mpt_txfidx_tail;
+ spinlock_t txfidx_lock;
+
+ int *mpt_rxfidx; /* Free Rx Context list */
+ int mpt_rxfidx_tail;
+ spinlock_t rxfidx_lock;
+
+ struct BufferControl *RcvCtl; /* Receive BufferControl structs */
+ struct BufferControl *SendCtl; /* Send BufferControl structs */
+
+ int max_buckets_out; /* Max buckets to send to IOC */
+ int tx_max_out; /* IOC's Tx queue len */
+
+ u32 total_posted;
+ u32 total_received;
+ struct net_device_stats stats; /* Per device statistics */
+
+ struct tq_struct post_buckets_task;
+ unsigned long post_buckets_active;
+};
+
+struct mpt_lan_ohdr {
+ u16 dtype;
+ u8 daddr[FC_ALEN];
+ u16 stype;
+ u8 saddr[FC_ALEN];
+};
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*
+ * Forward protos...
+ */
+static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
+ MPT_FRAME_HDR *reply);
+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_wake_post_buckets_task(struct net_device *dev);
+static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
+static int mpt_lan_receive_post_reply(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep);
+static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg);
+static int mpt_lan_send_reply(struct net_device *dev,
+ LANSendReply_t *pSendRep);
+static int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
+static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
+ struct net_device *dev);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Fusion MPT LAN private data
+ */
+static int LanCtx = -1;
+
+static u32 max_buckets_out = 127;
+static u32 tx_max_out_p = 127 - 16;
+
+static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * 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
+ * @mf: Pointer to original MPT request frame (NULL if TurboReply)
+ * @reply: Pointer to MPT reply frame
+ *
+ * Returns 1 indicating original alloc'd request frame ptr
+ * should be freed, or 0 if it shouldn't.
+ */
+static int
+lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
+{
+ struct net_device *dev = mpt_landev[ioc->id];
+ int FreeReqFrame = 0;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+// dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n",
+// mf, reply));
+
+ if (mf == NULL) {
+ u32 tmsg = CAST_PTR_TO_U32(reply);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ tmsg));
+
+ switch (GET_LAN_FORM(tmsg)) {
+
+ // 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
+#if 0
+ case LAN_REPLY_FORM_MESSAGE_CONTEXT:
+// dioprintk((KERN_INFO MYNAM "/lan_reply: "
+// "MessageContext turbo reply received\n"));
+ FreeReqFrame = 1;
+ break;
+#endif
+
+ case LAN_REPLY_FORM_SEND_SINGLE:
+// dioprintk((MYNAM "/lan_reply: "
+// "calling mpt_lan_send_reply (turbo)\n"));
+
+ // Potential BUG here? -sralston
+ // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg);
+ // If/when mpt_lan_send_turbo would return 1 here,
+ // calling routine (mptbase.c|mpt_interrupt)
+ // would Oops because mf has already been set
+ // to NULL. So after return from this func,
+ // mpt_interrupt() will attempt to put (NULL) mf ptr
+ // item back onto it's adapter FreeQ - Oops!:-(
+ // It's Ok, since mpt_lan_send_turbo() *currently*
+ // always returns 0, but..., just in case:
+
+ (void) mpt_lan_send_turbo(dev, tmsg);
+ FreeReqFrame = 0;
+
+ break;
+
+ case LAN_REPLY_FORM_RECEIVE_SINGLE:
+// dioprintk((KERN_INFO MYNAM "@lan_reply: "
+// "rcv-Turbo = %08x\n", tmsg));
+ mpt_lan_receive_post_turbo(dev, tmsg);
+ break;
+
+ default:
+ printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply "
+ "that I don't know what to do with\n");
+
+ /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */
+
+ break;
+ }
+
+ return FreeReqFrame;
+ }
+
+// msg = (u32 *) reply;
+// dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n",
+// le32_to_cpu(msg[0]), le32_to_cpu(msg[1]),
+// le32_to_cpu(msg[2]), le32_to_cpu(msg[3])));
+// dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n",
+// reply->u.hdr.Function));
+
+ switch (reply->u.hdr.Function) {
+
+ case MPI_FUNCTION_LAN_SEND:
+ {
+ LANSendReply_t *pSendRep;
+
+ pSendRep = (LANSendReply_t *) reply;
+ FreeReqFrame = mpt_lan_send_reply(dev, pSendRep);
+ break;
+ }
+
+ case MPI_FUNCTION_LAN_RECEIVE:
+ {
+ LANReceivePostReply_t *pRecvRep;
+
+ pRecvRep = (LANReceivePostReply_t *) reply;
+ if (pRecvRep->NumberOfContexts) {
+ mpt_lan_receive_post_reply(dev, pRecvRep);
+ if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+ FreeReqFrame = 1;
+ } else
+ dioprintk((KERN_INFO MYNAM "@lan_reply: zero context "
+ "ReceivePostReply received.\n"));
+ break;
+ }
+
+ case MPI_FUNCTION_LAN_RESET:
+ /* Just a default reply. Might want to check it to
+ * make sure that everything went ok.
+ */
+ FreeReqFrame = 1;
+ break;
+
+ case MPI_FUNCTION_EVENT_NOTIFICATION:
+ case MPI_FUNCTION_EVENT_ACK:
+ /* UPDATE! 20010120 -sralston
+ * _EVENT_NOTIFICATION should NOT come down this path any more.
+ * Should be routed to mpt_lan_event_process(), but just in case...
+ */
+ FreeReqFrame = 1;
+ break;
+
+ default:
+ printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo "
+ "reply that I don't know what to do with\n");
+
+ /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */
+ FreeReqFrame = 1;
+
+ break;
+ }
+
+ return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
+{
+ dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
+
+ switch (le32_to_cpu(pEvReply->Event)) {
+ case MPI_EVENT_NONE: /* 00 */
+ case MPI_EVENT_LOG_DATA: /* 01 */
+ case MPI_EVENT_STATE_CHANGE: /* 02 */
+ case MPI_EVENT_UNIT_ATTENTION: /* 03 */
+ case MPI_EVENT_IOC_BUS_RESET: /* 04 */
+ case MPI_EVENT_EXT_BUS_RESET: /* 05 */
+ case MPI_EVENT_RESCAN: /* 06 */
+ /* Ok, do we need to do anything here? As far as
+ I can tell, this is when a new device gets added
+ to the loop. */
+ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
+ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
+ case MPI_EVENT_LOGOUT: /* 09 */
+ case MPI_EVENT_EVENT_CHANGE: /* 0A */
+ default:
+ break;
+ }
+
+ /*
+ * NOTE: pEvent->AckRequired handling now done in mptbase.c;
+ * Do NOT do it here now!
+ */
+
+ return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_open(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ int i;
+
+ mpt_lan_reset(dev);
+
+ priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL);
+ if (priv->mpt_txfidx == NULL)
+ goto out;
+ priv->mpt_txfidx_tail = -1;
+
+ priv->SendCtl = kmalloc(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));
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
+ }
+
+ dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
+
+ priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
+ GFP_KERNEL);
+ if (priv->mpt_rxfidx == NULL)
+ goto out_SendCtl;
+ priv->mpt_rxfidx_tail = -1;
+
+ priv->RcvCtl = kmalloc(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));
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
+ }
+
+/**/ dprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
+/**/ for (i = 0; i < priv->tx_max_out; i++)
+/**/ dprintk((" %xh", priv->mpt_txfidx[i]));
+/**/ dprintk(("\n"));
+
+ dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
+
+ mpt_lan_post_receive_buckets(dev);
+ printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+
+ if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
+ /* FIXME! */
+ }
+
+ netif_start_queue(dev);
+ dprintk((KERN_INFO MYNAM "/lo: Done.\n"));
+
+ return 0;
+out_mpt_rxfidx:
+ kfree(priv->mpt_rxfidx);
+ priv->mpt_rxfidx = NULL;
+out_SendCtl:
+ kfree(priv->SendCtl);
+ priv->SendCtl = NULL;
+out_mpt_txfidx:
+ kfree(priv->mpt_txfidx);
+ priv->mpt_txfidx = NULL;
+out: return -ENOMEM;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_reset(struct net_device *dev)
+{
+ MPT_FRAME_HDR *mf;
+ LANResetRequest_t *pResetReq;
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+ mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
+
+ if (mf == NULL) {
+/* dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
+ "Unable to allocate a request frame.\n"));
+*/
+ return -1;
+ }
+
+ pResetReq = (LANResetRequest_t *) mf;
+
+ pResetReq->Function = MPI_FUNCTION_LAN_RESET;
+ pResetReq->ChainOffset = 0;
+ pResetReq->Reserved = 0;
+ pResetReq->PortNumber = priv->pnum;
+ pResetReq->MsgFlags = 0;
+ pResetReq->Reserved2 = 0;
+
+ mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf);
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_close(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ unsigned int timeout;
+ int i;
+
+ dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
+
+ mpt_event_deregister(LanCtx);
+
+ dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
+ "since driver was loaded, %d still out\n",
+ priv->total_posted,atomic_read(&priv->buckets_out)));
+
+ netif_stop_queue(dev);
+
+ mpt_lan_reset(dev);
+
+ timeout = 2 * HZ;
+ while (atomic_read(&priv->buckets_out) && --timeout) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+
+ for (i = 0; i < priv->max_buckets_out; i++) {
+ if (priv->RcvCtl[i].skb != NULL) {
+/**/ dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
+/**/ "is still out\n", i));
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
+ priv->RcvCtl[i].len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->RcvCtl[i].skb);
+ }
+ }
+
+ kfree (priv->RcvCtl);
+ kfree (priv->mpt_rxfidx);
+
+ for (i = 0; i < priv->tx_max_out; i++) {
+ if (priv->SendCtl[i].skb != NULL) {
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
+ priv->SendCtl[i].len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb(priv->SendCtl[i].skb);
+ }
+ }
+
+ kfree(priv->SendCtl);
+ kfree(priv->mpt_txfidx);
+
+ atomic_set(&priv->buckets_out, 0);
+
+ printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct net_device_stats *
+mpt_lan_get_stats(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv;
+
+ return (struct net_device_stats *) &priv->stats;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Tx timeout handler. */
+static void
+mpt_lan_tx_timeout(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *sent;
+ unsigned long flags;
+ u32 ctx;
+
+ ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
+ sent = priv->SendCtl[ctx].skb;
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += sent->len;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+ priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sent);
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ netif_wake_queue(dev);
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *sent;
+ unsigned long flags;
+ int FreeReqFrame = 0;
+ u32 *pContext;
+ u32 ctx;
+ u8 count;
+
+ count = pSendRep->NumberOfContexts;
+
+ dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n",
+ le16_to_cpu(pSendRep->IOCStatus)));
+
+ /* Add check for Loginfo Flag in IOCStatus */
+
+ switch (le16_to_cpu(pSendRep->IOCStatus)) {
+ case MPI_IOCSTATUS_SUCCESS:
+ priv->stats.tx_packets += count;
+ break;
+
+ case MPI_IOCSTATUS_LAN_CANCELED:
+ case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED:
+ break;
+
+ case MPI_IOCSTATUS_INVALID_SGL:
+ priv->stats.tx_errors += count;
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ goto out;
+
+ default:
+ priv->stats.tx_errors += count;
+ break;
+ }
+
+ pContext = &pSendRep->BufferContext;
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ while (count > 0) {
+ ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
+
+ sent = priv->SendCtl[ctx].skb;
+ priv->stats.tx_bytes += sent->len;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, sent));
+
+ priv->SendCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
+ priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(sent);
+
+ priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
+
+ pContext++;
+ count--;
+ }
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+out:
+ if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
+ FreeReqFrame = 1;
+
+ netif_wake_queue(dev);
+ return FreeReqFrame;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ MPT_FRAME_HDR *mf;
+ LANSendRequest_t *pSendReq;
+ SGETransaction32_t *pTrans;
+ SGESimple64_t *pSimple;
+ dma_addr_t dma;
+ unsigned long flags;
+ int ctx;
+
+ dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
+ __FUNCTION__, skb));
+
+ spin_lock_irqsave(&priv->txfidx_lock, flags);
+ if (priv->mpt_txfidx_tail < 0) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: no tx context available: %u\n",
+ __FUNCTION__, priv->mpt_txfidx_tail);
+ return 1;
+ }
+
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ if (mf == NULL) {
+ netif_stop_queue(dev);
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+ __FUNCTION__);
+ return 1;
+ }
+
+ ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
+ spin_unlock_irqrestore(&priv->txfidx_lock, flags);
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+ pSendReq = (LANSendRequest_t *) mf;
+
+ /* 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_pull(skb, 12);
+
+ dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ priv->SendCtl[ctx].skb = skb;
+ priv->SendCtl[ctx].dma = dma;
+ priv->SendCtl[ctx].len = skb->len;
+
+ /* Message Header */
+ pSendReq->Function = MPI_FUNCTION_LAN_SEND;
+ pSendReq->ChainOffset = 0;
+ pSendReq->MsgFlags = 0;
+ pSendReq->PortNumber = priv->pnum;
+
+ /* Transaction Context Element */
+ pTrans = (SGETransaction32_t *) pSendReq->SG_List;
+
+ /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */
+ pTrans->ContextSize = sizeof(u32);
+ pTrans->DetailsLength = 2 * sizeof(u32);
+ pTrans->Flags = 0;
+ pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// ctx, skb, skb->data));
+
+ pTrans->TransactionDetails[0] = cpu_to_le32((0x1000 << 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));
+
+ pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
+
+ pSimple->FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_64_BIT_ADDRESSING |
+ MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
+ skb->len);
+ pSimple->Address.Low = cpu_to_le32((u32) dma);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
+ else
+ pSimple->Address.High = 0;
+
+ mpt_put_msg_frame (LanCtx, mpt_dev->id, mf);
+ dev->trans_start = jiffies;
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ le32_to_cpu(pSimple->FlagsLength)));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline void
+mpt_lan_wake_post_buckets_task(struct net_device *dev)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+
+ if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
+ queue_task(&priv->post_buckets_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev) ));
+ }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static inline int
+mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+
+ skb->protocol = mpt_lan_type_trans(skb, dev);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) "
+ "delivered to upper level.\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
+
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ skb->dev = dev;
+ netif_rx(skb);
+
+ dioprintk((MYNAM "/receive_skb: %d buckets remaining\n",
+ atomic_read(&priv->buckets_out)));
+
+ if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
+ mpt_lan_wake_post_buckets_task(dev);
+
+ dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
+ "remaining, %d received back since sod\n",
+ atomic_read(&priv->buckets_out), priv->total_received));
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+//static inline int
+static int
+mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *skb, *old_skb;
+ unsigned long flags;
+ u32 ctx, len;
+
+ ctx = GET_LAN_BUCKET_CONTEXT(tmsg);
+ skb = priv->RcvCtl[ctx].skb;
+
+ len = GET_LAN_PACKET_LENGTH(tmsg);
+
+ if (len < MPT_LAN_RX_COPYBREAK) {
+ old_skb = skb;
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+ memcpy(skb_put(skb, len), old_skb->data, len);
+
+ goto out;
+ }
+
+ skb_put(skb, len);
+
+ priv->RcvCtl[ctx].skb = NULL;
+
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+out:
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ atomic_dec(&priv->buckets_out);
+ priv->total_received++;
+
+ return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_free(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ unsigned long flags;
+ struct sk_buff *skb;
+ u32 ctx;
+ u8 count;
+ int i;
+
+ count = pRecvRep->NumberOfContexts;
+
+/**/ dprintk((KERN_INFO MYNAM "/receive_post_reply: "
+ "IOC returned %d buckets, freeing them...\n", count));
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ for (i = 0; i < count; i++) {
+ ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+
+ skb = priv->RcvCtl[ctx].skb;
+
+// dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+// dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
+// priv, &(priv->buckets_out)));
+// dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
+
+ priv->RcvCtl[ctx].skb = NULL;
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ }
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ atomic_sub(count, &priv->buckets_out);
+
+// for (i = 0; i < priv->max_buckets_out; i++)
+// if (priv->RcvCtl[i].skb != NULL)
+// dprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
+// "is still out\n", i));
+
+/* dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
+ count));
+*/
+/**/ dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
+/**/ "remaining, %d received back since sod.\n",
+/**/ atomic_read(&priv->buckets_out), priv->total_received));
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
+mpt_lan_receive_post_reply(struct net_device *dev,
+ LANReceivePostReply_t *pRecvRep)
+{
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ struct sk_buff *skb, *old_skb;
+ unsigned long flags;
+ u32 len, ctx;
+ u32 offset;
+ u8 count;
+ int i, l;
+
+ dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
+ dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
+ le16_to_cpu(pRecvRep->IOCStatus)));
+
+ if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED)
+ return mpt_lan_receive_post_free(dev, pRecvRep);
+
+ len = le32_to_cpu(pRecvRep->PacketLength);
+ if (len == 0) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO "
+ "ReceivePostReply w/ PacketLength zero!\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n",
+ pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus));
+ return -1;
+ }
+
+ ctx = le32_to_cpu(pRecvRep->BucketContext[0]);
+ count = pRecvRep->NumberOfContexts;
+ skb = priv->RcvCtl[ctx].skb;
+
+ offset = le32_to_cpu(pRecvRep->PacketOffset);
+// if (offset != 0) {
+// printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply "
+// "w/ PacketOffset %u\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// offset);
+// }
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ offset, len));
+
+ if (count > 1) {
+ int szrem = len;
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned "
+// "for single packet, concatenating...\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev)));
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ for (i = 0; i < count; i++) {
+
+ ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
+ old_skb = priv->RcvCtl[ctx].skb;
+
+ l = priv->RcvCtl[ctx].len;
+ if (szrem < l)
+ l = szrem;
+
+// dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// i, l));
+
+ pci_dma_sync_single(mpt_dev->pcidev,
+ priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb_put(skb, l), old_skb->data, l);
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ szrem -= l;
+ }
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ } else if (len < MPT_LAN_RX_COPYBREAK) {
+
+ old_skb = skb;
+
+ skb = (struct sk_buff *)dev_alloc_skb(len);
+ if (!skb) {
+ printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FILE__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+
+ memcpy(skb_put(skb, len), old_skb->data, len);
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ } else {
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+
+ priv->RcvCtl[ctx].skb = NULL;
+
+ pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
+ priv->RcvCtl[ctx].dma = 0;
+
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ skb_put(skb,len);
+ }
+
+ atomic_sub(count, &priv->buckets_out);
+ priv->total_received += count;
+
+ if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) {
+ printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, "
+ "MPT_LAN_MAX_BUCKETS_OUT = %d\n",
+ IOC_AND_NETDEV_NAMES_s_s(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");
+ }
+
+#if 0
+ {
+ u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
+ if (remaining < priv->bucketthresh)
+ mpt_lan_wake_post_buckets_task(dev);
+
+ if (remaining == 0)
+ printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
+ "(priv->buckets_out = %d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ atomic_read(&priv->buckets_out));
+ else
+ printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
+ "(priv->buckets_out = %d)\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ remaining, atomic_read(&priv->buckets_out));
+ }
+#endif
+
+ return mpt_lan_receive_skb(dev, skb);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Simple SGE's only at the moment */
+
+static void
+mpt_lan_post_receive_buckets(void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpt_lan_priv *priv = dev->priv;
+ MPT_ADAPTER *mpt_dev = priv->mpt_dev;
+ MPT_FRAME_HDR *mf;
+ LANReceivePostRequest_t *pRecvReq;
+ SGETransaction32_t *pTrans;
+ SGESimple64_t *pSimple;
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ u32 curr, buckets, count, max;
+ u32 len = (dev->mtu + dev->hard_header_len + 4);
+ unsigned long flags;
+ int i;
+
+ curr = atomic_read(&priv->buckets_out);
+ buckets = (priv->max_buckets_out - curr);
+
+ dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ __FUNCTION__, buckets, curr));
+
+ max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
+ (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
+
+ while (buckets) {
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ if (mf == NULL) {
+ printk (KERN_ERR "%s: Unable to alloc request frame\n",
+ __FUNCTION__);
+ dioprintk((KERN_ERR "%s: %u buckets remaining\n",
+ __FUNCTION__, buckets));
+ goto out;
+ }
+ pRecvReq = (LANReceivePostRequest_t *) mf;
+
+ count = buckets;
+ if (count > max)
+ count = max;
+
+ pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE;
+ pRecvReq->ChainOffset = 0;
+ pRecvReq->MsgFlags = 0;
+ pRecvReq->PortNumber = priv->pnum;
+
+ pTrans = (SGETransaction32_t *) pRecvReq->SG_List;
+ pSimple = NULL;
+
+ for (i = 0; i < count; i++) {
+ int ctx;
+
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ if (priv->mpt_rxfidx_tail < 0) {
+ printk (KERN_ERR "%s: Can't alloc context\n",
+ __FUNCTION__);
+ spin_unlock_irqrestore(&priv->rxfidx_lock,
+ flags);
+ break;
+ }
+
+ ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--];
+
+ skb = priv->RcvCtl[ctx].skb;
+ if (skb && (priv->RcvCtl[ctx].len != len)) {
+ pci_unmap_single(mpt_dev->pcidev,
+ priv->RcvCtl[ctx].dma,
+ priv->RcvCtl[ctx].len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(priv->RcvCtl[ctx].skb);
+ skb = priv->RcvCtl[ctx].skb = NULL;
+ }
+
+ if (skb == NULL) {
+ skb = dev_alloc_skb(len);
+ if (skb == NULL) {
+/**/ printk (KERN_WARNING
+/**/ MYNAM "/%s: Can't alloc skb\n",
+/**/ __FUNCTION__);
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+ break;
+ }
+
+ dma = pci_map_single(mpt_dev->pcidev, skb->data,
+ len, PCI_DMA_FROMDEVICE);
+
+ priv->RcvCtl[ctx].skb = skb;
+ priv->RcvCtl[ctx].dma = dma;
+ priv->RcvCtl[ctx].len = len;
+ }
+
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+
+ pTrans->ContextSize = sizeof(u32);
+ pTrans->DetailsLength = 0;
+ pTrans->Flags = 0;
+ pTrans->TransactionContext[0] = cpu_to_le32(ctx);
+
+ pSimple = (SGESimple64_t *) pTrans->TransactionDetails;
+
+ pSimple->FlagsLength = cpu_to_le32(
+ ((MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
+ pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
+ else
+ pSimple->Address.High = 0;
+
+ pTrans = (SGETransaction32_t *) (pSimple + 1);
+ }
+
+ if (pSimple == NULL) {
+/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
+/**/ __FUNCTION__);
+ mpt_free_msg_frame(LanCtx, mpt_dev->id, mf);
+ goto out;
+ }
+
+ pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT);
+
+ pRecvReq->BucketCount = cpu_to_le32(i);
+
+/* printk(KERN_INFO MYNAM ": posting buckets\n ");
+ * for (i = 0; i < j + 2; i ++)
+ * printk (" %08x", le32_to_cpu(msg[i]));
+ * printk ("\n");
+ */
+
+ mpt_put_msg_frame(LanCtx, mpt_dev->id, mf);
+
+ priv->total_posted += i;
+ buckets -= i;
+ atomic_add(i, &priv->buckets_out);
+ }
+
+out:
+ dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
+ __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+ dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
+ __FUNCTION__, priv->total_posted, priv->total_received));
+
+ clear_bit(0, &priv->post_buckets_active);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+struct net_device *
+mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
+{
+ struct net_device *dev = NULL;
+ struct mpt_lan_priv *priv = NULL;
+ u8 HWaddr[FC_ALEN], *a;
+
+ dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv));
+ if (!dev)
+ return (NULL);
+ dev->mtu = MPT_LAN_MTU;
+
+ priv = (struct mpt_lan_priv *) dev->priv;
+
+ priv->mpt_dev = mpt_dev;
+ priv->pnum = pnum;
+
+ memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct));
+ priv->post_buckets_task.routine = mpt_lan_post_receive_buckets;
+ priv->post_buckets_task.data = dev;
+ priv->post_buckets_active = 0;
+
+ dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
+ __LINE__, dev->mtu + dev->hard_header_len + 4));
+
+ atomic_set(&priv->buckets_out, 0);
+ priv->total_posted = 0;
+ priv->total_received = 0;
+ priv->max_buckets_out = max_buckets_out;
+ if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out)
+ priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets;
+
+ dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
+ __LINE__,
+ mpt_dev->pfacts0.MaxLanBuckets,
+ max_buckets_out,
+ priv->max_buckets_out));
+
+ priv->bucketthresh = priv->max_buckets_out * 2 / 3;
+ priv->txfidx_lock = SPIN_LOCK_UNLOCKED;
+ priv->rxfidx_lock = SPIN_LOCK_UNLOCKED;
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+
+ /* Grab pre-fetched LANPage1 stuff. :-) */
+ a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
+
+ HWaddr[0] = a[5];
+ HWaddr[1] = a[4];
+ HWaddr[2] = a[3];
+ HWaddr[3] = a[2];
+ HWaddr[4] = a[1];
+ HWaddr[5] = a[0];
+
+ dev->addr_len = FC_ALEN;
+ memcpy(dev->dev_addr, HWaddr, FC_ALEN);
+ memset(dev->broadcast, 0xff, FC_ALEN);
+
+ /* The Tx queue is 127 deep on the 909.
+ * Give ourselves some breathing room.
+ */
+ priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
+ tx_max_out_p : MPT_TX_MAX_OUT_LIM;
+
+ dev->open = mpt_lan_open;
+ dev->stop = mpt_lan_close;
+ dev->get_stats = mpt_lan_get_stats;
+ dev->set_multicast_list = NULL;
+ dev->change_mtu = mpt_lan_change_mtu;
+ dev->hard_start_xmit = mpt_lan_sdu_send;
+
+/* Not in 2.3.42. Need 2.3.45+ */
+ dev->tx_timeout = mpt_lan_tx_timeout;
+ dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
+
+ dprintk((KERN_INFO MYNAM ": Finished registering dev "
+ "and setting initial values\n"));
+
+ SET_MODULE_OWNER(dev);
+
+ return dev;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+int __init
+mpt_lan_init (void)
+{
+ struct net_device *dev;
+ MPT_ADAPTER *curadapter;
+ int i = 0, j;
+
+ show_mptmod_ver(LANAME, LANVER);
+
+ if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) {
+ printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
+ return -EBUSY;
+ }
+
+ /* Set the callback index to be used by driver core for turbo replies */
+ mpt_lan_index = LanCtx;
+
+ dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+
+ for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
+ mpt_landev[j] = NULL;
+ }
+ j = 0;
+
+ curadapter = mpt_adapter_find_first();
+ while (curadapter != NULL) {
+ for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) {
+ printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
+ curadapter->name,
+ curadapter->pfacts0.PortNumber,
+ curadapter->pfacts0.ProtocolFlags,
+ MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags));
+
+ if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ dev = mpt_register_lan_device (curadapter, i);
+ if (dev != NULL) {
+ printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
+ curadapter->name, dev->name);
+ printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev),
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
+// IOC_AND_NETDEV_NAMES_s_s(dev),
+// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
+ mpt_landev[j] = dev;
+ dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
+ dev, j, mpt_landev[j]));
+
+ j++;
+ } else {
+ printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
+ curadapter->name,
+ curadapter->pfacts0.PortNumber);
+ }
+ } else {
+ printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
+ curadapter->name);
+ }
+ }
+ curadapter = mpt_adapter_find_next(curadapter);
+ }
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+void __init mpt_lan_exit(void)
+{
+ int i;
+
+ for (i = 0; mpt_landev[i] != NULL; i++) {
+ struct net_device *dev = mpt_landev[i];
+
+ printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n",
+ IOC_AND_NETDEV_NAMES_s_s(dev));
+ unregister_fcdev(dev);
+ mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+ }
+
+ if (LanCtx >= 0) {
+ mpt_deregister(LanCtx);
+ LanCtx = -1;
+ mpt_lan_index = 0;
+ }
+
+ /* deregister any send/receive handler structs. I2Oism? */
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+MODULE_PARM(tx_max_out_p, "i");
+MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
+
+module_init(mpt_lan_init);
+module_exit(mpt_lan_exit);
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static unsigned short
+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_pull(skb, sizeof(struct mpt_lan_ohdr));
+
+ if (fch->dtype == htons(0xffff)) {
+ u32 *p = (u32 *) fch;
+
+ swab32s(p + 0);
+ swab32s(p + 1);
+ swab32s(p + 2);
+ swab32s(p + 3);
+
+ printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
+ NETDEV_PTR_TO_IOC_NAME_s(dev));
+ printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ fch->saddr[0], fch->saddr[1], fch->saddr[2],
+ fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+ }
+
+ if (*fch->daddr & 1) {
+ if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) {
+ skb->pkt_type = PACKET_BROADCAST;
+ } else {
+ skb->pkt_type = PACKET_MULTICAST;
+ }
+ } else {
+ if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) {
+ skb->pkt_type = PACKET_OTHERHOST;
+ } else {
+ skb->pkt_type = PACKET_HOST;
+ }
+ }
+
+ /* Strip the SNAP header from ARP packets since we don't
+ * pass them through to the 802.2/SNAP layers.
+ */
+ fcllc = (struct fcllc *)skb->data;
+
+ if (fcllc->dsap == EXTENDED_SAP &&
+ (fcllc->ethertype == htons(ETH_P_IP) ||
+ fcllc->ethertype == htons(ETH_P_ARP))) {
+ skb_pull(skb, sizeof(struct fcllc));
+ return fcllc->ethertype;
+ }
+
+ return htons(ETH_P_802_2);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)