📄 mptlan.c
字号:
/* * linux/drivers/message/fusion/mptlan.c * IP Over Fibre Channel device driver. * 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 * *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* 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"MODULE_LICENSE("GPL");/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * 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 NAA_Hosed { u16 NAA; u8 ieee[FC_ALEN]; struct NAA_Hosed *next;};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 left */ 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 work_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, int priority);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_ioc_reset(MPT_ADAPTER *ioc, int reset_phase);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;#ifdef QLOGIC_NAA_WORKAROUNDstatic struct NAA_Hosed *mpt_bad_naa = NULL;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 * @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 intlan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply){ struct net_device *dev = ioc->netdev; 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!#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? // 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 its 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: /* _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 intmpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase){ struct net_device *dev = ioc->netdev; 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" : ( reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); if (priv->mpt_rxfidx == NULL) return (1); if (reset_phase == MPT_IOC_SETUP_RESET) { ; } else if (reset_phase == MPT_IOC_PRE_RESET) { int i; unsigned long flags; netif_stop_queue(dev); dlprintk ((KERN_INFO "mptlan/ioc_reset: called netif_stop_queue for %s.\n", dev->name)); atomic_set(&priv->buckets_out, 0); /* Reset Rx Free Tail index and re-populate the queue. */ spin_lock_irqsave(&priv->rxfidx_lock, flags); priv->mpt_rxfidx_tail = -1; for (i = 0; i < priv->max_buckets_out; i++) priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); } else { mpt_lan_post_receive_buckets(dev); netif_wake_queue(dev); } return 1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static intmpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply){ dlprintk((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 intmpt_lan_open(struct net_device *dev){ struct mpt_lan_priv *priv = netdev_priv(dev); int i; if (mpt_lan_reset(dev) != 0) { MPT_ADAPTER *mpt_dev = priv->mpt_dev; printk (KERN_WARNING MYNAM "/lan_open: lan_reset failed."); if (mpt_dev->active) printk ("The ioc is active. Perhaps it needs to be" " reset?\n"); else printk ("The ioc in inactive, most likely in the " "process of being reset. Please try again in " "a moment.\n"); } 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++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -