162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/message/fusion/mptlan.c 362306a36Sopenharmony_ci * IP Over Fibre Channel device driver. 462306a36Sopenharmony_ci * For use with LSI Fibre Channel PCI chip/adapters 562306a36Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2000-2008 LSI Corporation 862306a36Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 1462306a36Sopenharmony_ci it under the terms of the GNU General Public License as published by 1562306a36Sopenharmony_ci the Free Software Foundation; version 2 of the License. 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci This program is distributed in the hope that it will be useful, 1862306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1962306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2062306a36Sopenharmony_ci GNU General Public License for more details. 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci NO WARRANTY 2362306a36Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2462306a36Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2562306a36Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2662306a36Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2762306a36Sopenharmony_ci solely responsible for determining the appropriateness of using and 2862306a36Sopenharmony_ci distributing the Program and assumes all risks associated with its 2962306a36Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 3062306a36Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 3162306a36Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci DISCLAIMER OF LIABILITY 3462306a36Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3562306a36Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3662306a36Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3762306a36Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3862306a36Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3962306a36Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 4062306a36Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci You should have received a copy of the GNU General Public License 4362306a36Sopenharmony_ci along with this program; if not, write to the Free Software 4462306a36Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4562306a36Sopenharmony_ci*/ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * Define statements used for debugging 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci//#define MPT_LAN_IO_DEBUG 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include "mptlan.h" 5662306a36Sopenharmony_ci#include <linux/init.h> 5762306a36Sopenharmony_ci#include <linux/module.h> 5862306a36Sopenharmony_ci#include <linux/fs.h> 5962306a36Sopenharmony_ci#include <linux/sched.h> 6062306a36Sopenharmony_ci#include <linux/slab.h> 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 6362306a36Sopenharmony_ci#define MYNAM "mptlan" 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6662306a36Sopenharmony_ciMODULE_VERSION(my_VERSION); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * MPT LAN message sizes without variable part. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \ 7362306a36Sopenharmony_ci (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION)) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Fusion MPT LAN private structures 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct BufferControl { 8062306a36Sopenharmony_ci struct sk_buff *skb; 8162306a36Sopenharmony_ci dma_addr_t dma; 8262306a36Sopenharmony_ci unsigned int len; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct mpt_lan_priv { 8662306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev; 8762306a36Sopenharmony_ci u8 pnum; /* Port number in the IOC. This is not a Unix network port! */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci atomic_t buckets_out; /* number of unused buckets on IOC */ 9062306a36Sopenharmony_ci int bucketthresh; /* Send more when this many left */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci int *mpt_txfidx; /* Free Tx Context list */ 9362306a36Sopenharmony_ci int mpt_txfidx_tail; 9462306a36Sopenharmony_ci spinlock_t txfidx_lock; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci int *mpt_rxfidx; /* Free Rx Context list */ 9762306a36Sopenharmony_ci int mpt_rxfidx_tail; 9862306a36Sopenharmony_ci spinlock_t rxfidx_lock; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci struct BufferControl *RcvCtl; /* Receive BufferControl structs */ 10162306a36Sopenharmony_ci struct BufferControl *SendCtl; /* Send BufferControl structs */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci int max_buckets_out; /* Max buckets to send to IOC */ 10462306a36Sopenharmony_ci int tx_max_out; /* IOC's Tx queue len */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci u32 total_posted; 10762306a36Sopenharmony_ci u32 total_received; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci struct delayed_work post_buckets_task; 11062306a36Sopenharmony_ci struct net_device *dev; 11162306a36Sopenharmony_ci unsigned long post_buckets_active; 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct mpt_lan_ohdr { 11562306a36Sopenharmony_ci u16 dtype; 11662306a36Sopenharmony_ci u8 daddr[FC_ALEN]; 11762306a36Sopenharmony_ci u16 stype; 11862306a36Sopenharmony_ci u8 saddr[FC_ALEN]; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Forward protos... 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, 12762306a36Sopenharmony_ci MPT_FRAME_HDR *reply); 12862306a36Sopenharmony_cistatic int mpt_lan_open(struct net_device *dev); 12962306a36Sopenharmony_cistatic int mpt_lan_reset(struct net_device *dev); 13062306a36Sopenharmony_cistatic int mpt_lan_close(struct net_device *dev); 13162306a36Sopenharmony_cistatic void mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv); 13262306a36Sopenharmony_cistatic void mpt_lan_wake_post_buckets_task(struct net_device *dev, 13362306a36Sopenharmony_ci int priority); 13462306a36Sopenharmony_cistatic int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); 13562306a36Sopenharmony_cistatic int mpt_lan_receive_post_reply(struct net_device *dev, 13662306a36Sopenharmony_ci LANReceivePostReply_t *pRecvRep); 13762306a36Sopenharmony_cistatic int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg); 13862306a36Sopenharmony_cistatic int mpt_lan_send_reply(struct net_device *dev, 13962306a36Sopenharmony_ci LANSendReply_t *pSendRep); 14062306a36Sopenharmony_cistatic int mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase); 14162306a36Sopenharmony_cistatic int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); 14262306a36Sopenharmony_cistatic unsigned short mpt_lan_type_trans(struct sk_buff *skb, 14362306a36Sopenharmony_ci struct net_device *dev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Fusion MPT LAN private data 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic u32 max_buckets_out = 127; 15262306a36Sopenharmony_cistatic u32 tx_max_out_p = 127 - 16; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * lan_reply - Handle all data sent from the hardware. 15762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 15862306a36Sopenharmony_ci * @mf: Pointer to original MPT request frame (NULL if TurboReply) 15962306a36Sopenharmony_ci * @reply: Pointer to MPT reply frame 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Returns 1 indicating original alloc'd request frame ptr 16262306a36Sopenharmony_ci * should be freed, or 0 if it shouldn't. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic int 16562306a36Sopenharmony_cilan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct net_device *dev = ioc->netdev; 16862306a36Sopenharmony_ci int FreeReqFrame = 0; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", 17162306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev))); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n", 17462306a36Sopenharmony_ci// mf, reply)); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (mf == NULL) { 17762306a36Sopenharmony_ci u32 tmsg = CAST_PTR_TO_U32(reply); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n", 18062306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 18162306a36Sopenharmony_ci tmsg)); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci switch (GET_LAN_FORM(tmsg)) { 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci // NOTE! (Optimization) First case here is now caught in 18662306a36Sopenharmony_ci // mptbase.c::mpt_interrupt() routine and callcack here 18762306a36Sopenharmony_ci // is now skipped for this case! 18862306a36Sopenharmony_ci#if 0 18962306a36Sopenharmony_ci case LAN_REPLY_FORM_MESSAGE_CONTEXT: 19062306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM "/lan_reply: " 19162306a36Sopenharmony_ci// "MessageContext turbo reply received\n")); 19262306a36Sopenharmony_ci FreeReqFrame = 1; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci#endif 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci case LAN_REPLY_FORM_SEND_SINGLE: 19762306a36Sopenharmony_ci// dioprintk((MYNAM "/lan_reply: " 19862306a36Sopenharmony_ci// "calling mpt_lan_send_reply (turbo)\n")); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci // Potential BUG here? 20162306a36Sopenharmony_ci // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg); 20262306a36Sopenharmony_ci // If/when mpt_lan_send_turbo would return 1 here, 20362306a36Sopenharmony_ci // calling routine (mptbase.c|mpt_interrupt) 20462306a36Sopenharmony_ci // would Oops because mf has already been set 20562306a36Sopenharmony_ci // to NULL. So after return from this func, 20662306a36Sopenharmony_ci // mpt_interrupt() will attempt to put (NULL) mf ptr 20762306a36Sopenharmony_ci // item back onto its adapter FreeQ - Oops!:-( 20862306a36Sopenharmony_ci // It's Ok, since mpt_lan_send_turbo() *currently* 20962306a36Sopenharmony_ci // always returns 0, but..., just in case: 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci (void) mpt_lan_send_turbo(dev, tmsg); 21262306a36Sopenharmony_ci FreeReqFrame = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci case LAN_REPLY_FORM_RECEIVE_SINGLE: 21762306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM "@lan_reply: " 21862306a36Sopenharmony_ci// "rcv-Turbo = %08x\n", tmsg)); 21962306a36Sopenharmony_ci mpt_lan_receive_post_turbo(dev, tmsg); 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply " 22462306a36Sopenharmony_ci "that I don't know what to do with\n"); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return FreeReqFrame; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci// msg = (u32 *) reply; 23562306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n", 23662306a36Sopenharmony_ci// le32_to_cpu(msg[0]), le32_to_cpu(msg[1]), 23762306a36Sopenharmony_ci// le32_to_cpu(msg[2]), le32_to_cpu(msg[3]))); 23862306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n", 23962306a36Sopenharmony_ci// reply->u.hdr.Function)); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci switch (reply->u.hdr.Function) { 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci case MPI_FUNCTION_LAN_SEND: 24462306a36Sopenharmony_ci { 24562306a36Sopenharmony_ci LANSendReply_t *pSendRep; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci pSendRep = (LANSendReply_t *) reply; 24862306a36Sopenharmony_ci FreeReqFrame = mpt_lan_send_reply(dev, pSendRep); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci case MPI_FUNCTION_LAN_RECEIVE: 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci LANReceivePostReply_t *pRecvRep; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci pRecvRep = (LANReceivePostReply_t *) reply; 25762306a36Sopenharmony_ci if (pRecvRep->NumberOfContexts) { 25862306a36Sopenharmony_ci mpt_lan_receive_post_reply(dev, pRecvRep); 25962306a36Sopenharmony_ci if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) 26062306a36Sopenharmony_ci FreeReqFrame = 1; 26162306a36Sopenharmony_ci } else 26262306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM "@lan_reply: zero context " 26362306a36Sopenharmony_ci "ReceivePostReply received.\n")); 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci case MPI_FUNCTION_LAN_RESET: 26862306a36Sopenharmony_ci /* Just a default reply. Might want to check it to 26962306a36Sopenharmony_ci * make sure that everything went ok. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci FreeReqFrame = 1; 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci case MPI_FUNCTION_EVENT_NOTIFICATION: 27562306a36Sopenharmony_ci case MPI_FUNCTION_EVENT_ACK: 27662306a36Sopenharmony_ci /* _EVENT_NOTIFICATION should NOT come down this path any more. 27762306a36Sopenharmony_ci * Should be routed to mpt_lan_event_process(), but just in case... 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci FreeReqFrame = 1; 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci default: 28362306a36Sopenharmony_ci printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo " 28462306a36Sopenharmony_ci "reply that I don't know what to do with\n"); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ 28762306a36Sopenharmony_ci FreeReqFrame = 1; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return FreeReqFrame; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 29662306a36Sopenharmony_cistatic int 29762306a36Sopenharmony_cimpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct net_device *dev = ioc->netdev; 30062306a36Sopenharmony_ci struct mpt_lan_priv *priv; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (dev == NULL) 30362306a36Sopenharmony_ci return(1); 30462306a36Sopenharmony_ci else 30562306a36Sopenharmony_ci priv = netdev_priv(dev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", 30862306a36Sopenharmony_ci reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( 30962306a36Sopenharmony_ci reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (priv->mpt_rxfidx == NULL) 31262306a36Sopenharmony_ci return (1); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (reset_phase == MPT_IOC_SETUP_RESET) { 31562306a36Sopenharmony_ci ; 31662306a36Sopenharmony_ci } else if (reset_phase == MPT_IOC_PRE_RESET) { 31762306a36Sopenharmony_ci int i; 31862306a36Sopenharmony_ci unsigned long flags; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci netif_stop_queue(dev); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci dlprintk ((KERN_INFO "mptlan/ioc_reset: called netif_stop_queue for %s.\n", dev->name)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci atomic_set(&priv->buckets_out, 0); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Reset Rx Free Tail index and re-populate the queue. */ 32762306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 32862306a36Sopenharmony_ci priv->mpt_rxfidx_tail = -1; 32962306a36Sopenharmony_ci for (i = 0; i < priv->max_buckets_out; i++) 33062306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; 33162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci mpt_lan_post_receive_buckets(priv); 33462306a36Sopenharmony_ci netif_wake_queue(dev); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return 1; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 34162306a36Sopenharmony_cistatic int 34262306a36Sopenharmony_cimpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n")); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci switch (le32_to_cpu(pEvReply->Event)) { 34762306a36Sopenharmony_ci case MPI_EVENT_NONE: /* 00 */ 34862306a36Sopenharmony_ci case MPI_EVENT_LOG_DATA: /* 01 */ 34962306a36Sopenharmony_ci case MPI_EVENT_STATE_CHANGE: /* 02 */ 35062306a36Sopenharmony_ci case MPI_EVENT_UNIT_ATTENTION: /* 03 */ 35162306a36Sopenharmony_ci case MPI_EVENT_IOC_BUS_RESET: /* 04 */ 35262306a36Sopenharmony_ci case MPI_EVENT_EXT_BUS_RESET: /* 05 */ 35362306a36Sopenharmony_ci case MPI_EVENT_RESCAN: /* 06 */ 35462306a36Sopenharmony_ci /* Ok, do we need to do anything here? As far as 35562306a36Sopenharmony_ci I can tell, this is when a new device gets added 35662306a36Sopenharmony_ci to the loop. */ 35762306a36Sopenharmony_ci case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ 35862306a36Sopenharmony_ci case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ 35962306a36Sopenharmony_ci case MPI_EVENT_LOGOUT: /* 09 */ 36062306a36Sopenharmony_ci case MPI_EVENT_EVENT_CHANGE: /* 0A */ 36162306a36Sopenharmony_ci default: 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * NOTE: pEvent->AckRequired handling now done in mptbase.c; 36762306a36Sopenharmony_ci * Do NOT do it here now! 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 1; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 37462306a36Sopenharmony_cistatic int 37562306a36Sopenharmony_cimpt_lan_open(struct net_device *dev) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 37862306a36Sopenharmony_ci int i; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (mpt_lan_reset(dev) != 0) { 38162306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci printk (KERN_WARNING MYNAM "/lan_open: lan_reset failed."); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (mpt_dev->active) 38662306a36Sopenharmony_ci printk ("The ioc is active. Perhaps it needs to be" 38762306a36Sopenharmony_ci " reset?\n"); 38862306a36Sopenharmony_ci else 38962306a36Sopenharmony_ci printk ("The ioc in inactive, most likely in the " 39062306a36Sopenharmony_ci "process of being reset. Please try again in " 39162306a36Sopenharmony_ci "a moment.\n"); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci priv->mpt_txfidx = kmalloc_array(priv->tx_max_out, sizeof(int), 39562306a36Sopenharmony_ci GFP_KERNEL); 39662306a36Sopenharmony_ci if (priv->mpt_txfidx == NULL) 39762306a36Sopenharmony_ci goto out; 39862306a36Sopenharmony_ci priv->mpt_txfidx_tail = -1; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci priv->SendCtl = kcalloc(priv->tx_max_out, sizeof(struct BufferControl), 40162306a36Sopenharmony_ci GFP_KERNEL); 40262306a36Sopenharmony_ci if (priv->SendCtl == NULL) 40362306a36Sopenharmony_ci goto out_mpt_txfidx; 40462306a36Sopenharmony_ci for (i = 0; i < priv->tx_max_out; i++) 40562306a36Sopenharmony_ci priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci priv->mpt_rxfidx = kmalloc_array(priv->max_buckets_out, sizeof(int), 41062306a36Sopenharmony_ci GFP_KERNEL); 41162306a36Sopenharmony_ci if (priv->mpt_rxfidx == NULL) 41262306a36Sopenharmony_ci goto out_SendCtl; 41362306a36Sopenharmony_ci priv->mpt_rxfidx_tail = -1; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci priv->RcvCtl = kcalloc(priv->max_buckets_out, 41662306a36Sopenharmony_ci sizeof(struct BufferControl), 41762306a36Sopenharmony_ci GFP_KERNEL); 41862306a36Sopenharmony_ci if (priv->RcvCtl == NULL) 41962306a36Sopenharmony_ci goto out_mpt_rxfidx; 42062306a36Sopenharmony_ci for (i = 0; i < priv->max_buckets_out; i++) 42162306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/**/ dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - ")); 42462306a36Sopenharmony_ci/**/ for (i = 0; i < priv->tx_max_out; i++) 42562306a36Sopenharmony_ci/**/ dlprintk((" %xh", priv->mpt_txfidx[i])); 42662306a36Sopenharmony_ci/**/ dlprintk(("\n")); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci mpt_lan_post_receive_buckets(priv); 43162306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", 43262306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) { 43562306a36Sopenharmony_ci printk (KERN_WARNING MYNAM "/lo: Unable to register for Event" 43662306a36Sopenharmony_ci " Notifications. This is a bad thing! We're not going " 43762306a36Sopenharmony_ci "to go ahead, but I'd be leery of system stability at " 43862306a36Sopenharmony_ci "this point.\n"); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci netif_start_queue(dev); 44262306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM "/lo: Done.\n")); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ciout_mpt_rxfidx: 44662306a36Sopenharmony_ci kfree(priv->mpt_rxfidx); 44762306a36Sopenharmony_ci priv->mpt_rxfidx = NULL; 44862306a36Sopenharmony_ciout_SendCtl: 44962306a36Sopenharmony_ci kfree(priv->SendCtl); 45062306a36Sopenharmony_ci priv->SendCtl = NULL; 45162306a36Sopenharmony_ciout_mpt_txfidx: 45262306a36Sopenharmony_ci kfree(priv->mpt_txfidx); 45362306a36Sopenharmony_ci priv->mpt_txfidx = NULL; 45462306a36Sopenharmony_ciout: return -ENOMEM; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 45862306a36Sopenharmony_ci/* Send a LanReset message to the FW. This should result in the FW returning 45962306a36Sopenharmony_ci any buckets it still has. */ 46062306a36Sopenharmony_cistatic int 46162306a36Sopenharmony_cimpt_lan_reset(struct net_device *dev) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 46462306a36Sopenharmony_ci LANResetRequest_t *pResetReq; 46562306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (mf == NULL) { 47062306a36Sopenharmony_ci/* dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! " 47162306a36Sopenharmony_ci "Unable to allocate a request frame.\n")); 47262306a36Sopenharmony_ci*/ 47362306a36Sopenharmony_ci return -1; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci pResetReq = (LANResetRequest_t *) mf; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci pResetReq->Function = MPI_FUNCTION_LAN_RESET; 47962306a36Sopenharmony_ci pResetReq->ChainOffset = 0; 48062306a36Sopenharmony_ci pResetReq->Reserved = 0; 48162306a36Sopenharmony_ci pResetReq->PortNumber = priv->pnum; 48262306a36Sopenharmony_ci pResetReq->MsgFlags = 0; 48362306a36Sopenharmony_ci pResetReq->Reserved2 = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci mpt_put_msg_frame(LanCtx, priv->mpt_dev, mf); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return 0; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 49162306a36Sopenharmony_cistatic int 49262306a36Sopenharmony_cimpt_lan_close(struct net_device *dev) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 49562306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 49662306a36Sopenharmony_ci unsigned long timeout; 49762306a36Sopenharmony_ci int i; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci mpt_event_deregister(LanCtx); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets " 50462306a36Sopenharmony_ci "since driver was loaded, %d still out\n", 50562306a36Sopenharmony_ci priv->total_posted,atomic_read(&priv->buckets_out))); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci netif_stop_queue(dev); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci mpt_lan_reset(dev); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci timeout = jiffies + 2 * HZ; 51262306a36Sopenharmony_ci while (atomic_read(&priv->buckets_out) && time_before(jiffies, timeout)) 51362306a36Sopenharmony_ci schedule_timeout_interruptible(1); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for (i = 0; i < priv->max_buckets_out; i++) { 51662306a36Sopenharmony_ci if (priv->RcvCtl[i].skb != NULL) { 51762306a36Sopenharmony_ci/**/ dlprintk((KERN_INFO MYNAM "/lan_close: bucket %05x " 51862306a36Sopenharmony_ci/**/ "is still out\n", i)); 51962306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, 52062306a36Sopenharmony_ci priv->RcvCtl[i].dma, 52162306a36Sopenharmony_ci priv->RcvCtl[i].len, DMA_FROM_DEVICE); 52262306a36Sopenharmony_ci dev_kfree_skb(priv->RcvCtl[i].skb); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci kfree(priv->RcvCtl); 52762306a36Sopenharmony_ci kfree(priv->mpt_rxfidx); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci for (i = 0; i < priv->tx_max_out; i++) { 53062306a36Sopenharmony_ci if (priv->SendCtl[i].skb != NULL) { 53162306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, 53262306a36Sopenharmony_ci priv->SendCtl[i].dma, 53362306a36Sopenharmony_ci priv->SendCtl[i].len, DMA_TO_DEVICE); 53462306a36Sopenharmony_ci dev_kfree_skb(priv->SendCtl[i].skb); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci kfree(priv->SendCtl); 53962306a36Sopenharmony_ci kfree(priv->mpt_txfidx); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci atomic_set(&priv->buckets_out, 0); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n", 54462306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev)); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 55062306a36Sopenharmony_ci/* Tx timeout handler. */ 55162306a36Sopenharmony_cistatic void 55262306a36Sopenharmony_cimpt_lan_tx_timeout(struct net_device *dev, unsigned int txqueue) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 55562306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (mpt_dev->active) { 55862306a36Sopenharmony_ci dlprintk (("mptlan/tx_timeout: calling netif_wake_queue for %s.\n", dev->name)); 55962306a36Sopenharmony_ci netif_wake_queue(dev); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 56462306a36Sopenharmony_ci//static inline int 56562306a36Sopenharmony_cistatic int 56662306a36Sopenharmony_cimpt_lan_send_turbo(struct net_device *dev, u32 tmsg) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 56962306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 57062306a36Sopenharmony_ci struct sk_buff *sent; 57162306a36Sopenharmony_ci unsigned long flags; 57262306a36Sopenharmony_ci u32 ctx; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci ctx = GET_LAN_BUFFER_CONTEXT(tmsg); 57562306a36Sopenharmony_ci sent = priv->SendCtl[ctx].skb; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci dev->stats.tx_packets++; 57862306a36Sopenharmony_ci dev->stats.tx_bytes += sent->len; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", 58162306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 58262306a36Sopenharmony_ci __func__, sent)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci priv->SendCtl[ctx].skb = NULL; 58562306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, priv->SendCtl[ctx].dma, 58662306a36Sopenharmony_ci priv->SendCtl[ctx].len, DMA_TO_DEVICE); 58762306a36Sopenharmony_ci dev_kfree_skb_irq(sent); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci spin_lock_irqsave(&priv->txfidx_lock, flags); 59062306a36Sopenharmony_ci priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; 59162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->txfidx_lock, flags); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci netif_wake_queue(dev); 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 59862306a36Sopenharmony_cistatic int 59962306a36Sopenharmony_cimpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 60262306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 60362306a36Sopenharmony_ci struct sk_buff *sent; 60462306a36Sopenharmony_ci unsigned long flags; 60562306a36Sopenharmony_ci int FreeReqFrame = 0; 60662306a36Sopenharmony_ci u32 *pContext; 60762306a36Sopenharmony_ci u32 ctx; 60862306a36Sopenharmony_ci u8 count; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci count = pSendRep->NumberOfContexts; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n", 61362306a36Sopenharmony_ci le16_to_cpu(pSendRep->IOCStatus))); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* Add check for Loginfo Flag in IOCStatus */ 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) { 61862306a36Sopenharmony_ci case MPI_IOCSTATUS_SUCCESS: 61962306a36Sopenharmony_ci dev->stats.tx_packets += count; 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_CANCELED: 62362306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci case MPI_IOCSTATUS_INVALID_SGL: 62762306a36Sopenharmony_ci dev->stats.tx_errors += count; 62862306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", 62962306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev)); 63062306a36Sopenharmony_ci goto out; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci default: 63362306a36Sopenharmony_ci dev->stats.tx_errors += count; 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci pContext = &pSendRep->BufferContext; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci spin_lock_irqsave(&priv->txfidx_lock, flags); 64062306a36Sopenharmony_ci while (count > 0) { 64162306a36Sopenharmony_ci ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci sent = priv->SendCtl[ctx].skb; 64462306a36Sopenharmony_ci dev->stats.tx_bytes += sent->len; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", 64762306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 64862306a36Sopenharmony_ci __func__, sent)); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci priv->SendCtl[ctx].skb = NULL; 65162306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, 65262306a36Sopenharmony_ci priv->SendCtl[ctx].dma, 65362306a36Sopenharmony_ci priv->SendCtl[ctx].len, DMA_TO_DEVICE); 65462306a36Sopenharmony_ci dev_kfree_skb_irq(sent); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci pContext++; 65962306a36Sopenharmony_ci count--; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->txfidx_lock, flags); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ciout: 66462306a36Sopenharmony_ci if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) 66562306a36Sopenharmony_ci FreeReqFrame = 1; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci netif_wake_queue(dev); 66862306a36Sopenharmony_ci return FreeReqFrame; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 67262306a36Sopenharmony_cistatic netdev_tx_t 67362306a36Sopenharmony_cimpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 67662306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 67762306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 67862306a36Sopenharmony_ci LANSendRequest_t *pSendReq; 67962306a36Sopenharmony_ci SGETransaction32_t *pTrans; 68062306a36Sopenharmony_ci SGESimple64_t *pSimple; 68162306a36Sopenharmony_ci const unsigned char *mac; 68262306a36Sopenharmony_ci dma_addr_t dma; 68362306a36Sopenharmony_ci unsigned long flags; 68462306a36Sopenharmony_ci int ctx; 68562306a36Sopenharmony_ci u16 cur_naa = 0x1000; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", 68862306a36Sopenharmony_ci __func__, skb)); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci spin_lock_irqsave(&priv->txfidx_lock, flags); 69162306a36Sopenharmony_ci if (priv->mpt_txfidx_tail < 0) { 69262306a36Sopenharmony_ci netif_stop_queue(dev); 69362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->txfidx_lock, flags); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci printk (KERN_ERR "%s: no tx context available: %u\n", 69662306a36Sopenharmony_ci __func__, priv->mpt_txfidx_tail); 69762306a36Sopenharmony_ci return NETDEV_TX_BUSY; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci mf = mpt_get_msg_frame(LanCtx, mpt_dev); 70162306a36Sopenharmony_ci if (mf == NULL) { 70262306a36Sopenharmony_ci netif_stop_queue(dev); 70362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->txfidx_lock, flags); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci printk (KERN_ERR "%s: Unable to alloc request frame\n", 70662306a36Sopenharmony_ci __func__); 70762306a36Sopenharmony_ci return NETDEV_TX_BUSY; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; 71162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->txfidx_lock, flags); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n", 71462306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev))); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci pSendReq = (LANSendRequest_t *) mf; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* Set the mac.raw pointer, since this apparently isn't getting 71962306a36Sopenharmony_ci * done before we get the skb. Pull the data pointer past the mac data. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci skb_reset_mac_header(skb); 72262306a36Sopenharmony_ci skb_pull(skb, 12); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci dma = dma_map_single(&mpt_dev->pcidev->dev, skb->data, skb->len, 72562306a36Sopenharmony_ci DMA_TO_DEVICE); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci priv->SendCtl[ctx].skb = skb; 72862306a36Sopenharmony_ci priv->SendCtl[ctx].dma = dma; 72962306a36Sopenharmony_ci priv->SendCtl[ctx].len = skb->len; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Message Header */ 73262306a36Sopenharmony_ci pSendReq->Reserved = 0; 73362306a36Sopenharmony_ci pSendReq->Function = MPI_FUNCTION_LAN_SEND; 73462306a36Sopenharmony_ci pSendReq->ChainOffset = 0; 73562306a36Sopenharmony_ci pSendReq->Reserved2 = 0; 73662306a36Sopenharmony_ci pSendReq->MsgFlags = 0; 73762306a36Sopenharmony_ci pSendReq->PortNumber = priv->pnum; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Transaction Context Element */ 74062306a36Sopenharmony_ci pTrans = (SGETransaction32_t *) pSendReq->SG_List; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */ 74362306a36Sopenharmony_ci pTrans->ContextSize = sizeof(u32); 74462306a36Sopenharmony_ci pTrans->DetailsLength = 2 * sizeof(u32); 74562306a36Sopenharmony_ci pTrans->Flags = 0; 74662306a36Sopenharmony_ci pTrans->TransactionContext = cpu_to_le32(ctx); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n", 74962306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev), 75062306a36Sopenharmony_ci// ctx, skb, skb->data)); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci mac = skb_mac_header(skb); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | 75562306a36Sopenharmony_ci (mac[0] << 8) | 75662306a36Sopenharmony_ci (mac[1] << 0)); 75762306a36Sopenharmony_ci pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) | 75862306a36Sopenharmony_ci (mac[3] << 16) | 75962306a36Sopenharmony_ci (mac[4] << 8) | 76062306a36Sopenharmony_ci (mac[5] << 0)); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* If we ever decide to send more than one Simple SGE per LANSend, then 76562306a36Sopenharmony_ci we will need to make sure that LAST_ELEMENT only gets set on the 76662306a36Sopenharmony_ci last one. Otherwise, bad voodoo and evil funkiness will commence. */ 76762306a36Sopenharmony_ci pSimple->FlagsLength = cpu_to_le32( 76862306a36Sopenharmony_ci ((MPI_SGE_FLAGS_LAST_ELEMENT | 76962306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER | 77062306a36Sopenharmony_ci MPI_SGE_FLAGS_SIMPLE_ELEMENT | 77162306a36Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 77262306a36Sopenharmony_ci MPI_SGE_FLAGS_HOST_TO_IOC | 77362306a36Sopenharmony_ci MPI_SGE_FLAGS_64_BIT_ADDRESSING | 77462306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) | 77562306a36Sopenharmony_ci skb->len); 77662306a36Sopenharmony_ci pSimple->Address.Low = cpu_to_le32((u32) dma); 77762306a36Sopenharmony_ci if (sizeof(dma_addr_t) > sizeof(u32)) 77862306a36Sopenharmony_ci pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32)); 77962306a36Sopenharmony_ci else 78062306a36Sopenharmony_ci pSimple->Address.High = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci mpt_put_msg_frame (LanCtx, mpt_dev, mf); 78362306a36Sopenharmony_ci netif_trans_update(dev); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n", 78662306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 78762306a36Sopenharmony_ci le32_to_cpu(pSimple->FlagsLength))); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return NETDEV_TX_OK; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 79362306a36Sopenharmony_cistatic void 79462306a36Sopenharmony_cimpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) 79562306a36Sopenharmony_ci/* 79662306a36Sopenharmony_ci * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { 80262306a36Sopenharmony_ci if (priority) { 80362306a36Sopenharmony_ci schedule_delayed_work(&priv->post_buckets_task, 0); 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci schedule_delayed_work(&priv->post_buckets_task, 1); 80662306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": post_buckets queued on " 80762306a36Sopenharmony_ci "timer.\n")); 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", 81062306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev) )); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 81562306a36Sopenharmony_cistatic int 81662306a36Sopenharmony_cimpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci skb->protocol = mpt_lan_type_trans(skb, dev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " 82362306a36Sopenharmony_ci "delivered to upper level.\n", 82462306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci dev->stats.rx_bytes += skb->len; 82762306a36Sopenharmony_ci dev->stats.rx_packets++; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci skb->dev = dev; 83062306a36Sopenharmony_ci netif_rx(skb); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci dioprintk((MYNAM "/receive_skb: %d buckets remaining\n", 83362306a36Sopenharmony_ci atomic_read(&priv->buckets_out))); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (atomic_read(&priv->buckets_out) < priv->bucketthresh) 83662306a36Sopenharmony_ci mpt_lan_wake_post_buckets_task(dev, 1); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets " 83962306a36Sopenharmony_ci "remaining, %d received back since sod\n", 84062306a36Sopenharmony_ci atomic_read(&priv->buckets_out), priv->total_received)); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return 0; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 84662306a36Sopenharmony_ci//static inline int 84762306a36Sopenharmony_cistatic int 84862306a36Sopenharmony_cimpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 85162306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 85262306a36Sopenharmony_ci struct sk_buff *skb, *old_skb; 85362306a36Sopenharmony_ci unsigned long flags; 85462306a36Sopenharmony_ci u32 ctx, len; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ctx = GET_LAN_BUCKET_CONTEXT(tmsg); 85762306a36Sopenharmony_ci skb = priv->RcvCtl[ctx].skb; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci len = GET_LAN_PACKET_LENGTH(tmsg); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (len < MPT_LAN_RX_COPYBREAK) { 86262306a36Sopenharmony_ci old_skb = skb; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci skb = (struct sk_buff *)dev_alloc_skb(len); 86562306a36Sopenharmony_ci if (!skb) { 86662306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", 86762306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 86862306a36Sopenharmony_ci __FILE__, __LINE__); 86962306a36Sopenharmony_ci return -ENOMEM; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci dma_sync_single_for_cpu(&mpt_dev->pcidev->dev, 87362306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 87462306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 87562306a36Sopenharmony_ci DMA_FROM_DEVICE); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci dma_sync_single_for_device(&mpt_dev->pcidev->dev, 88062306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 88162306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 88262306a36Sopenharmony_ci DMA_FROM_DEVICE); 88362306a36Sopenharmony_ci goto out; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci skb_put(skb, len); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci priv->RcvCtl[ctx].skb = NULL; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, priv->RcvCtl[ctx].dma, 89162306a36Sopenharmony_ci priv->RcvCtl[ctx].len, DMA_FROM_DEVICE); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ciout: 89462306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 89562306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 89662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci atomic_dec(&priv->buckets_out); 89962306a36Sopenharmony_ci priv->total_received++; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci return mpt_lan_receive_skb(dev, skb); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 90562306a36Sopenharmony_cistatic int 90662306a36Sopenharmony_cimpt_lan_receive_post_free(struct net_device *dev, 90762306a36Sopenharmony_ci LANReceivePostReply_t *pRecvRep) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 91062306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 91162306a36Sopenharmony_ci unsigned long flags; 91262306a36Sopenharmony_ci struct sk_buff *skb; 91362306a36Sopenharmony_ci u32 ctx; 91462306a36Sopenharmony_ci int count; 91562306a36Sopenharmony_ci int i; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci count = pRecvRep->NumberOfContexts; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci/**/ dlprintk((KERN_INFO MYNAM "/receive_post_reply: " 92062306a36Sopenharmony_ci "IOC returned %d buckets, freeing them...\n", count)); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 92362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 92462306a36Sopenharmony_ci ctx = le32_to_cpu(pRecvRep->BucketContext[i]); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci skb = priv->RcvCtl[ctx].skb; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci// dlprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n", 92962306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev))); 93062306a36Sopenharmony_ci// dlprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p", 93162306a36Sopenharmony_ci// priv, &(priv->buckets_out))); 93262306a36Sopenharmony_ci// dlprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n")); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci priv->RcvCtl[ctx].skb = NULL; 93562306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, priv->RcvCtl[ctx].dma, 93662306a36Sopenharmony_ci priv->RcvCtl[ctx].len, DMA_FROM_DEVICE); 93762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci atomic_sub(count, &priv->buckets_out); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci// for (i = 0; i < priv->max_buckets_out; i++) 94662306a36Sopenharmony_ci// if (priv->RcvCtl[i].skb != NULL) 94762306a36Sopenharmony_ci// dlprintk((KERN_INFO MYNAM "@rpr: bucket %03x " 94862306a36Sopenharmony_ci// "is still out\n", i)); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci/* dlprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n", 95162306a36Sopenharmony_ci count)); 95262306a36Sopenharmony_ci*/ 95362306a36Sopenharmony_ci/**/ dlprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets " 95462306a36Sopenharmony_ci/**/ "remaining, %d received back since sod.\n", 95562306a36Sopenharmony_ci/**/ atomic_read(&priv->buckets_out), priv->total_received)); 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 96062306a36Sopenharmony_cistatic int 96162306a36Sopenharmony_cimpt_lan_receive_post_reply(struct net_device *dev, 96262306a36Sopenharmony_ci LANReceivePostReply_t *pRecvRep) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 96562306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 96662306a36Sopenharmony_ci struct sk_buff *skb, *old_skb; 96762306a36Sopenharmony_ci unsigned long flags; 96862306a36Sopenharmony_ci u32 len, ctx, offset; 96962306a36Sopenharmony_ci u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining); 97062306a36Sopenharmony_ci int count; 97162306a36Sopenharmony_ci int i, l; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n")); 97462306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n", 97562306a36Sopenharmony_ci le16_to_cpu(pRecvRep->IOCStatus))); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if ((le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_MASK) == 97862306a36Sopenharmony_ci MPI_IOCSTATUS_LAN_CANCELED) 97962306a36Sopenharmony_ci return mpt_lan_receive_post_free(dev, pRecvRep); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci len = le32_to_cpu(pRecvRep->PacketLength); 98262306a36Sopenharmony_ci if (len == 0) { 98362306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO " 98462306a36Sopenharmony_ci "ReceivePostReply w/ PacketLength zero!\n", 98562306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev)); 98662306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n", 98762306a36Sopenharmony_ci pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus)); 98862306a36Sopenharmony_ci return -1; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci ctx = le32_to_cpu(pRecvRep->BucketContext[0]); 99262306a36Sopenharmony_ci count = pRecvRep->NumberOfContexts; 99362306a36Sopenharmony_ci skb = priv->RcvCtl[ctx].skb; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci offset = le32_to_cpu(pRecvRep->PacketOffset); 99662306a36Sopenharmony_ci// if (offset != 0) { 99762306a36Sopenharmony_ci// printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply " 99862306a36Sopenharmony_ci// "w/ PacketOffset %u\n", 99962306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev), 100062306a36Sopenharmony_ci// offset); 100162306a36Sopenharmony_ci// } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n", 100462306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 100562306a36Sopenharmony_ci offset, len)); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (count > 1) { 100862306a36Sopenharmony_ci int szrem = len; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned " 101162306a36Sopenharmony_ci// "for single packet, concatenating...\n", 101262306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev))); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci skb = (struct sk_buff *)dev_alloc_skb(len); 101562306a36Sopenharmony_ci if (!skb) { 101662306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", 101762306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 101862306a36Sopenharmony_ci __FILE__, __LINE__); 101962306a36Sopenharmony_ci return -ENOMEM; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 102362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci ctx = le32_to_cpu(pRecvRep->BucketContext[i]); 102662306a36Sopenharmony_ci old_skb = priv->RcvCtl[ctx].skb; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci l = priv->RcvCtl[ctx].len; 102962306a36Sopenharmony_ci if (szrem < l) 103062306a36Sopenharmony_ci l = szrem; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci// dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n", 103362306a36Sopenharmony_ci// IOC_AND_NETDEV_NAMES_s_s(dev), 103462306a36Sopenharmony_ci// i, l)); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci dma_sync_single_for_cpu(&mpt_dev->pcidev->dev, 103762306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 103862306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 103962306a36Sopenharmony_ci DMA_FROM_DEVICE); 104062306a36Sopenharmony_ci skb_copy_from_linear_data(old_skb, skb_put(skb, l), l); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci dma_sync_single_for_device(&mpt_dev->pcidev->dev, 104362306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 104462306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 104562306a36Sopenharmony_ci DMA_FROM_DEVICE); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 104862306a36Sopenharmony_ci szrem -= l; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci } else if (len < MPT_LAN_RX_COPYBREAK) { 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci old_skb = skb; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci skb = (struct sk_buff *)dev_alloc_skb(len); 105762306a36Sopenharmony_ci if (!skb) { 105862306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", 105962306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 106062306a36Sopenharmony_ci __FILE__, __LINE__); 106162306a36Sopenharmony_ci return -ENOMEM; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci dma_sync_single_for_cpu(&mpt_dev->pcidev->dev, 106562306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 106662306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 106762306a36Sopenharmony_ci DMA_FROM_DEVICE); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci dma_sync_single_for_device(&mpt_dev->pcidev->dev, 107262306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 107362306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 107462306a36Sopenharmony_ci DMA_FROM_DEVICE); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 107762306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 107862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci } else { 108162306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci priv->RcvCtl[ctx].skb = NULL; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, priv->RcvCtl[ctx].dma, 108662306a36Sopenharmony_ci priv->RcvCtl[ctx].len, DMA_FROM_DEVICE); 108762306a36Sopenharmony_ci priv->RcvCtl[ctx].dma = 0; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 109062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci skb_put(skb,len); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci atomic_sub(count, &priv->buckets_out); 109662306a36Sopenharmony_ci priv->total_received += count; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) { 109962306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, " 110062306a36Sopenharmony_ci "MPT_LAN_MAX_BUCKETS_OUT = %d\n", 110162306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 110262306a36Sopenharmony_ci priv->mpt_rxfidx_tail, 110362306a36Sopenharmony_ci MPT_LAN_MAX_BUCKETS_OUT); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci return -1; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (remaining == 0) 110962306a36Sopenharmony_ci printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! " 111062306a36Sopenharmony_ci "(priv->buckets_out = %d)\n", 111162306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 111262306a36Sopenharmony_ci atomic_read(&priv->buckets_out)); 111362306a36Sopenharmony_ci else if (remaining < 10) 111462306a36Sopenharmony_ci printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. " 111562306a36Sopenharmony_ci "(priv->buckets_out = %d)\n", 111662306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 111762306a36Sopenharmony_ci remaining, atomic_read(&priv->buckets_out)); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if ((remaining < priv->bucketthresh) && 112062306a36Sopenharmony_ci ((atomic_read(&priv->buckets_out) - remaining) > 112162306a36Sopenharmony_ci MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) { 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci printk (KERN_WARNING MYNAM " Mismatch between driver's " 112462306a36Sopenharmony_ci "buckets_out count and fw's BucketsRemaining " 112562306a36Sopenharmony_ci "count has crossed the threshold, issuing a " 112662306a36Sopenharmony_ci "LanReset to clear the fw's hashtable. You may " 112762306a36Sopenharmony_ci "want to check your /var/log/messages for \"CRC " 112862306a36Sopenharmony_ci "error\" event notifications.\n"); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci mpt_lan_reset(dev); 113162306a36Sopenharmony_ci mpt_lan_wake_post_buckets_task(dev, 0); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci return mpt_lan_receive_skb(dev, skb); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 113862306a36Sopenharmony_ci/* Simple SGE's only at the moment */ 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic void 114162306a36Sopenharmony_cimpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct net_device *dev = priv->dev; 114462306a36Sopenharmony_ci MPT_ADAPTER *mpt_dev = priv->mpt_dev; 114562306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 114662306a36Sopenharmony_ci LANReceivePostRequest_t *pRecvReq; 114762306a36Sopenharmony_ci SGETransaction32_t *pTrans; 114862306a36Sopenharmony_ci SGESimple64_t *pSimple; 114962306a36Sopenharmony_ci struct sk_buff *skb; 115062306a36Sopenharmony_ci dma_addr_t dma; 115162306a36Sopenharmony_ci u32 curr, buckets, count, max; 115262306a36Sopenharmony_ci u32 len = (dev->mtu + dev->hard_header_len + 4); 115362306a36Sopenharmony_ci unsigned long flags; 115462306a36Sopenharmony_ci int i; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci curr = atomic_read(&priv->buckets_out); 115762306a36Sopenharmony_ci buckets = (priv->max_buckets_out - curr); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", 116062306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 116162306a36Sopenharmony_ci __func__, buckets, curr)); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / 116462306a36Sopenharmony_ci (sizeof(SGETransaction32_t) + sizeof(SGESimple64_t)); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci while (buckets) { 116762306a36Sopenharmony_ci mf = mpt_get_msg_frame(LanCtx, mpt_dev); 116862306a36Sopenharmony_ci if (mf == NULL) { 116962306a36Sopenharmony_ci printk (KERN_ERR "%s: Unable to alloc request frame\n", 117062306a36Sopenharmony_ci __func__); 117162306a36Sopenharmony_ci dioprintk((KERN_ERR "%s: %u buckets remaining\n", 117262306a36Sopenharmony_ci __func__, buckets)); 117362306a36Sopenharmony_ci goto out; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci pRecvReq = (LANReceivePostRequest_t *) mf; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); 117862306a36Sopenharmony_ci mpt_dev->RequestNB[i] = 0; 117962306a36Sopenharmony_ci count = buckets; 118062306a36Sopenharmony_ci if (count > max) 118162306a36Sopenharmony_ci count = max; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE; 118462306a36Sopenharmony_ci pRecvReq->ChainOffset = 0; 118562306a36Sopenharmony_ci pRecvReq->MsgFlags = 0; 118662306a36Sopenharmony_ci pRecvReq->PortNumber = priv->pnum; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci pTrans = (SGETransaction32_t *) pRecvReq->SG_List; 118962306a36Sopenharmony_ci pSimple = NULL; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 119262306a36Sopenharmony_ci int ctx; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxfidx_lock, flags); 119562306a36Sopenharmony_ci if (priv->mpt_rxfidx_tail < 0) { 119662306a36Sopenharmony_ci printk (KERN_ERR "%s: Can't alloc context\n", 119762306a36Sopenharmony_ci __func__); 119862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, 119962306a36Sopenharmony_ci flags); 120062306a36Sopenharmony_ci break; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--]; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci skb = priv->RcvCtl[ctx].skb; 120662306a36Sopenharmony_ci if (skb && (priv->RcvCtl[ctx].len != len)) { 120762306a36Sopenharmony_ci dma_unmap_single(&mpt_dev->pcidev->dev, 120862306a36Sopenharmony_ci priv->RcvCtl[ctx].dma, 120962306a36Sopenharmony_ci priv->RcvCtl[ctx].len, 121062306a36Sopenharmony_ci DMA_FROM_DEVICE); 121162306a36Sopenharmony_ci dev_kfree_skb(priv->RcvCtl[ctx].skb); 121262306a36Sopenharmony_ci skb = priv->RcvCtl[ctx].skb = NULL; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (skb == NULL) { 121662306a36Sopenharmony_ci skb = dev_alloc_skb(len); 121762306a36Sopenharmony_ci if (skb == NULL) { 121862306a36Sopenharmony_ci printk (KERN_WARNING 121962306a36Sopenharmony_ci MYNAM "/%s: Can't alloc skb\n", 122062306a36Sopenharmony_ci __func__); 122162306a36Sopenharmony_ci priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; 122262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 122362306a36Sopenharmony_ci break; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci dma = dma_map_single(&mpt_dev->pcidev->dev, 122762306a36Sopenharmony_ci skb->data, len, 122862306a36Sopenharmony_ci DMA_FROM_DEVICE); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci priv->RcvCtl[ctx].skb = skb; 123162306a36Sopenharmony_ci priv->RcvCtl[ctx].dma = dma; 123262306a36Sopenharmony_ci priv->RcvCtl[ctx].len = len; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxfidx_lock, flags); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci pTrans->ContextSize = sizeof(u32); 123862306a36Sopenharmony_ci pTrans->DetailsLength = 0; 123962306a36Sopenharmony_ci pTrans->Flags = 0; 124062306a36Sopenharmony_ci pTrans->TransactionContext = cpu_to_le32(ctx); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci pSimple = (SGESimple64_t *) pTrans->TransactionDetails; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci pSimple->FlagsLength = cpu_to_le32( 124562306a36Sopenharmony_ci ((MPI_SGE_FLAGS_END_OF_BUFFER | 124662306a36Sopenharmony_ci MPI_SGE_FLAGS_SIMPLE_ELEMENT | 124762306a36Sopenharmony_ci MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len); 124862306a36Sopenharmony_ci pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma); 124962306a36Sopenharmony_ci if (sizeof(dma_addr_t) > sizeof(u32)) 125062306a36Sopenharmony_ci pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32)); 125162306a36Sopenharmony_ci else 125262306a36Sopenharmony_ci pSimple->Address.High = 0; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci pTrans = (SGETransaction32_t *) (pSimple + 1); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (pSimple == NULL) { 125862306a36Sopenharmony_ci/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", 125962306a36Sopenharmony_ci/**/ __func__); 126062306a36Sopenharmony_ci mpt_free_msg_frame(mpt_dev, mf); 126162306a36Sopenharmony_ci goto out; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci pRecvReq->BucketCount = cpu_to_le32(i); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci/* printk(KERN_INFO MYNAM ": posting buckets\n "); 126962306a36Sopenharmony_ci * for (i = 0; i < j + 2; i ++) 127062306a36Sopenharmony_ci * printk (" %08x", le32_to_cpu(msg[i])); 127162306a36Sopenharmony_ci * printk ("\n"); 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci mpt_put_msg_frame(LanCtx, mpt_dev, mf); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci priv->total_posted += i; 127762306a36Sopenharmony_ci buckets -= i; 127862306a36Sopenharmony_ci atomic_add(i, &priv->buckets_out); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ciout: 128262306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", 128362306a36Sopenharmony_ci __func__, buckets, atomic_read(&priv->buckets_out))); 128462306a36Sopenharmony_ci dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", 128562306a36Sopenharmony_ci __func__, priv->total_posted, priv->total_received)); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci clear_bit(0, &priv->post_buckets_active); 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic void 129162306a36Sopenharmony_cimpt_lan_post_receive_buckets_work(struct work_struct *work) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv, 129462306a36Sopenharmony_ci post_buckets_task.work)); 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic const struct net_device_ops mpt_netdev_ops = { 129862306a36Sopenharmony_ci .ndo_open = mpt_lan_open, 129962306a36Sopenharmony_ci .ndo_stop = mpt_lan_close, 130062306a36Sopenharmony_ci .ndo_start_xmit = mpt_lan_sdu_send, 130162306a36Sopenharmony_ci .ndo_tx_timeout = mpt_lan_tx_timeout, 130262306a36Sopenharmony_ci}; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 130562306a36Sopenharmony_cistatic struct net_device * 130662306a36Sopenharmony_cimpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci struct net_device *dev; 130962306a36Sopenharmony_ci struct mpt_lan_priv *priv; 131062306a36Sopenharmony_ci u8 HWaddr[FC_ALEN], *a; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); 131362306a36Sopenharmony_ci if (!dev) 131462306a36Sopenharmony_ci return NULL; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci dev->mtu = MPT_LAN_MTU; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci priv = netdev_priv(dev); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci priv->dev = dev; 132162306a36Sopenharmony_ci priv->mpt_dev = mpt_dev; 132262306a36Sopenharmony_ci priv->pnum = pnum; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->post_buckets_task, 132562306a36Sopenharmony_ci mpt_lan_post_receive_buckets_work); 132662306a36Sopenharmony_ci priv->post_buckets_active = 0; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", 132962306a36Sopenharmony_ci __LINE__, dev->mtu + dev->hard_header_len + 4)); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci atomic_set(&priv->buckets_out, 0); 133262306a36Sopenharmony_ci priv->total_posted = 0; 133362306a36Sopenharmony_ci priv->total_received = 0; 133462306a36Sopenharmony_ci priv->max_buckets_out = max_buckets_out; 133562306a36Sopenharmony_ci if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out) 133662306a36Sopenharmony_ci priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n", 133962306a36Sopenharmony_ci __LINE__, 134062306a36Sopenharmony_ci mpt_dev->pfacts[0].MaxLanBuckets, 134162306a36Sopenharmony_ci max_buckets_out, 134262306a36Sopenharmony_ci priv->max_buckets_out)); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci priv->bucketthresh = priv->max_buckets_out * 2 / 3; 134562306a36Sopenharmony_ci spin_lock_init(&priv->txfidx_lock); 134662306a36Sopenharmony_ci spin_lock_init(&priv->rxfidx_lock); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* Grab pre-fetched LANPage1 stuff. :-) */ 134962306a36Sopenharmony_ci a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci HWaddr[0] = a[5]; 135262306a36Sopenharmony_ci HWaddr[1] = a[4]; 135362306a36Sopenharmony_ci HWaddr[2] = a[3]; 135462306a36Sopenharmony_ci HWaddr[3] = a[2]; 135562306a36Sopenharmony_ci HWaddr[4] = a[1]; 135662306a36Sopenharmony_ci HWaddr[5] = a[0]; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci dev->addr_len = FC_ALEN; 135962306a36Sopenharmony_ci dev_addr_set(dev, HWaddr); 136062306a36Sopenharmony_ci memset(dev->broadcast, 0xff, FC_ALEN); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* The Tx queue is 127 deep on the 909. 136362306a36Sopenharmony_ci * Give ourselves some breathing room. 136462306a36Sopenharmony_ci */ 136562306a36Sopenharmony_ci priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ? 136662306a36Sopenharmony_ci tx_max_out_p : MPT_TX_MAX_OUT_LIM; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci dev->netdev_ops = &mpt_netdev_ops; 136962306a36Sopenharmony_ci dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* MTU range: 96 - 65280 */ 137262306a36Sopenharmony_ci dev->min_mtu = MPT_LAN_MIN_MTU; 137362306a36Sopenharmony_ci dev->max_mtu = MPT_LAN_MAX_MTU; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": Finished registering dev " 137662306a36Sopenharmony_ci "and setting initial values\n")); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (register_netdev(dev) != 0) { 137962306a36Sopenharmony_ci free_netdev(dev); 138062306a36Sopenharmony_ci dev = NULL; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci return dev; 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic int 138662306a36Sopenharmony_cimptlan_probe(struct pci_dev *pdev) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 138962306a36Sopenharmony_ci struct net_device *dev; 139062306a36Sopenharmony_ci int i; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci for (i = 0; i < ioc->facts.NumberOfPorts; i++) { 139362306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s: PortNum=%x, " 139462306a36Sopenharmony_ci "ProtocolFlags=%02Xh (%c%c%c%c)\n", 139562306a36Sopenharmony_ci ioc->name, ioc->pfacts[i].PortNumber, 139662306a36Sopenharmony_ci ioc->pfacts[i].ProtocolFlags, 139762306a36Sopenharmony_ci MPT_PROTOCOL_FLAGS_c_c_c_c( 139862306a36Sopenharmony_ci ioc->pfacts[i].ProtocolFlags)); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (!(ioc->pfacts[i].ProtocolFlags & 140162306a36Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_LAN)) { 140262306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s: Hmmm... LAN protocol " 140362306a36Sopenharmony_ci "seems to be disabled on this adapter port!\n", 140462306a36Sopenharmony_ci ioc->name); 140562306a36Sopenharmony_ci continue; 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci dev = mpt_register_lan_device(ioc, i); 140962306a36Sopenharmony_ci if (!dev) { 141062306a36Sopenharmony_ci printk(KERN_ERR MYNAM ": %s: Unable to register " 141162306a36Sopenharmony_ci "port%d as a LAN device\n", ioc->name, 141262306a36Sopenharmony_ci ioc->pfacts[i].PortNumber); 141362306a36Sopenharmony_ci continue; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " 141762306a36Sopenharmony_ci "registered as '%s'\n", ioc->name, dev->name); 141862306a36Sopenharmony_ci printk(KERN_INFO MYNAM ": %s/%s: " 141962306a36Sopenharmony_ci "LanAddr = %pM\n", 142062306a36Sopenharmony_ci IOC_AND_NETDEV_NAMES_s_s(dev), 142162306a36Sopenharmony_ci dev->dev_addr); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci ioc->netdev = dev; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci return 0; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci return -ENODEV; 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_cistatic void 143262306a36Sopenharmony_cimptlan_remove(struct pci_dev *pdev) 143362306a36Sopenharmony_ci{ 143462306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 143562306a36Sopenharmony_ci struct net_device *dev = ioc->netdev; 143662306a36Sopenharmony_ci struct mpt_lan_priv *priv = netdev_priv(dev); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci cancel_delayed_work_sync(&priv->post_buckets_task); 143962306a36Sopenharmony_ci if(dev != NULL) { 144062306a36Sopenharmony_ci unregister_netdev(dev); 144162306a36Sopenharmony_ci free_netdev(dev); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic struct mpt_pci_driver mptlan_driver = { 144662306a36Sopenharmony_ci .probe = mptlan_probe, 144762306a36Sopenharmony_ci .remove = mptlan_remove, 144862306a36Sopenharmony_ci}; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic int __init mpt_lan_init (void) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci show_mptmod_ver(LANAME, LANVER); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER, 145562306a36Sopenharmony_ci "lan_reply"); 145662306a36Sopenharmony_ci if (LanCtx <= 0) { 145762306a36Sopenharmony_ci printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); 145862306a36Sopenharmony_ci return -EBUSY; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { 146462306a36Sopenharmony_ci printk(KERN_ERR MYNAM ": Eieee! unable to register a reset " 146562306a36Sopenharmony_ci "handler with mptbase! The world is at an end! " 146662306a36Sopenharmony_ci "Everything is fading to black! Goodbye.\n"); 146762306a36Sopenharmony_ci return -EBUSY; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER); 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cistatic void __exit mpt_lan_exit(void) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci mpt_device_driver_deregister(MPTLAN_DRIVER); 147962306a36Sopenharmony_ci mpt_reset_deregister(LanCtx); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (LanCtx) { 148262306a36Sopenharmony_ci mpt_deregister(LanCtx); 148362306a36Sopenharmony_ci LanCtx = MPT_MAX_PROTOCOL_DRIVERS; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cimodule_init(mpt_lan_init); 148862306a36Sopenharmony_cimodule_exit(mpt_lan_exit); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 149162306a36Sopenharmony_cistatic unsigned short 149262306a36Sopenharmony_cimpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; 149562306a36Sopenharmony_ci struct fcllc *fcllc; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci skb_reset_mac_header(skb); 149862306a36Sopenharmony_ci skb_pull(skb, sizeof(struct mpt_lan_ohdr)); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (fch->dtype == htons(0xffff)) { 150162306a36Sopenharmony_ci u32 *p = (u32 *) fch; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci swab32s(p + 0); 150462306a36Sopenharmony_ci swab32s(p + 1); 150562306a36Sopenharmony_ci swab32s(p + 2); 150662306a36Sopenharmony_ci swab32s(p + 3); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", 150962306a36Sopenharmony_ci NETDEV_PTR_TO_IOC_NAME_s(dev)); 151062306a36Sopenharmony_ci printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n", 151162306a36Sopenharmony_ci fch->saddr); 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (*fch->daddr & 1) { 151562306a36Sopenharmony_ci if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) { 151662306a36Sopenharmony_ci skb->pkt_type = PACKET_BROADCAST; 151762306a36Sopenharmony_ci } else { 151862306a36Sopenharmony_ci skb->pkt_type = PACKET_MULTICAST; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci } else { 152162306a36Sopenharmony_ci if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) { 152262306a36Sopenharmony_ci skb->pkt_type = PACKET_OTHERHOST; 152362306a36Sopenharmony_ci } else { 152462306a36Sopenharmony_ci skb->pkt_type = PACKET_HOST; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci fcllc = (struct fcllc *)skb->data; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* Strip the SNAP header from ARP packets since we don't 153162306a36Sopenharmony_ci * pass them through to the 802.2/SNAP layers. 153262306a36Sopenharmony_ci */ 153362306a36Sopenharmony_ci if (fcllc->dsap == EXTENDED_SAP && 153462306a36Sopenharmony_ci (fcllc->ethertype == htons(ETH_P_IP) || 153562306a36Sopenharmony_ci fcllc->ethertype == htons(ETH_P_ARP))) { 153662306a36Sopenharmony_ci skb_pull(skb, sizeof(struct fcllc)); 153762306a36Sopenharmony_ci return fcllc->ethertype; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return htons(ETH_P_802_2); 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1544