12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544 |
- /*
- * linux/drivers/message/fusion/mptlan.c
- * IP Over Fibre Channel device driver.
- * For use with LSI Fibre Channel PCI chip/adapters
- * running LSI Fusion MPT (Message Passing Technology) firmware.
- *
- * Copyright (c) 2000-2008 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
- *
- */
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /*
- 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>
- #include <linux/sched.h>
- #include <linux/slab.h>
- #define my_VERSION MPT_LINUX_VERSION_COMMON
- #define MYNAM "mptlan"
- MODULE_LICENSE("GPL");
- MODULE_VERSION(my_VERSION);
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /*
- * MPT LAN message sizes without variable part.
- */
- #define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \
- (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION))
- #define MPT_LAN_TRANSACTION32_SIZE \
- (sizeof(SGETransaction32_t) - sizeof(u32))
- /*
- * Fusion MPT LAN private structures
- */
- struct BufferControl {
- struct sk_buff *skb;
- dma_addr_t dma;
- unsigned int len;
- };
- struct mpt_lan_priv {
- MPT_ADAPTER *mpt_dev;
- u8 pnum; /* Port number in the IOC. This is not a Unix network port! */
- atomic_t buckets_out; /* number of unused buckets on IOC */
- int bucketthresh; /* Send more when this many 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 delayed_work post_buckets_task;
- struct net_device *dev;
- 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(struct mpt_lan_priv *priv);
- static void mpt_lan_wake_post_buckets_task(struct net_device *dev,
- int priority);
- static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
- 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 u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
- static u32 max_buckets_out = 127;
- static u32 tx_max_out_p = 127 - 16;
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /**
- * lan_reply - Handle all data sent from the hardware.
- * @ioc: Pointer to MPT_ADAPTER structure
- * @mf: Pointer to original MPT request frame (NULL if TurboReply)
- * @reply: Pointer to MPT reply frame
- *
- * Returns 1 indicating original alloc'd request frame ptr
- * should be freed, or 0 if it shouldn't.
- */
- static int
- lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
- {
- struct net_device *dev = 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 int
- mpt_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(priv);
- netif_wake_queue(dev);
- }
- return 1;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_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 int
- mpt_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 = kcalloc(priv->tx_max_out, sizeof(struct BufferControl),
- GFP_KERNEL);
- if (priv->SendCtl == NULL)
- goto out_mpt_txfidx;
- for (i = 0; i < priv->tx_max_out; i++)
- priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
- dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
- priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int),
- GFP_KERNEL);
- if (priv->mpt_rxfidx == NULL)
- goto out_SendCtl;
- priv->mpt_rxfidx_tail = -1;
- priv->RcvCtl = kcalloc(priv->max_buckets_out,
- sizeof(struct BufferControl),
- GFP_KERNEL);
- if (priv->RcvCtl == NULL)
- goto out_mpt_rxfidx;
- for (i = 0; i < priv->max_buckets_out; i++)
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
- /**/ dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
- /**/ for (i = 0; i < priv->tx_max_out; i++)
- /**/ dlprintk((" %xh", priv->mpt_txfidx[i]));
- /**/ dlprintk(("\n"));
- dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n"));
- mpt_lan_post_receive_buckets(priv);
- printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n",
- IOC_AND_NETDEV_NAMES_s_s(dev));
- if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
- printk (KERN_WARNING MYNAM "/lo: Unable to register for Event"
- " Notifications. This is a bad thing! We're not going "
- "to go ahead, but I'd be leery of system stability at "
- "this point.\n");
- }
- netif_start_queue(dev);
- dlprintk((KERN_INFO MYNAM "/lo: Done.\n"));
- return 0;
- out_mpt_rxfidx:
- kfree(priv->mpt_rxfidx);
- priv->mpt_rxfidx = NULL;
- out_SendCtl:
- kfree(priv->SendCtl);
- priv->SendCtl = NULL;
- out_mpt_txfidx:
- kfree(priv->mpt_txfidx);
- priv->mpt_txfidx = NULL;
- out: return -ENOMEM;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /* Send a LanReset message to the FW. This should result in the FW returning
- any buckets it still has. */
- static int
- mpt_lan_reset(struct net_device *dev)
- {
- MPT_FRAME_HDR *mf;
- LANResetRequest_t *pResetReq;
- struct mpt_lan_priv *priv = netdev_priv(dev);
- mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev);
- if (mf == NULL) {
- /* dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
- "Unable to allocate a request frame.\n"));
- */
- return -1;
- }
- pResetReq = (LANResetRequest_t *) mf;
- pResetReq->Function = MPI_FUNCTION_LAN_RESET;
- pResetReq->ChainOffset = 0;
- pResetReq->Reserved = 0;
- pResetReq->PortNumber = priv->pnum;
- pResetReq->MsgFlags = 0;
- pResetReq->Reserved2 = 0;
- mpt_put_msg_frame(LanCtx, priv->mpt_dev, mf);
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_close(struct net_device *dev)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- unsigned long timeout;
- int i;
- dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
- mpt_event_deregister(LanCtx);
- dlprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets "
- "since driver was loaded, %d still out\n",
- priv->total_posted,atomic_read(&priv->buckets_out)));
- netif_stop_queue(dev);
- mpt_lan_reset(dev);
- timeout = jiffies + 2 * HZ;
- while (atomic_read(&priv->buckets_out) && time_before(jiffies, timeout))
- schedule_timeout_interruptible(1);
- for (i = 0; i < priv->max_buckets_out; i++) {
- if (priv->RcvCtl[i].skb != NULL) {
- /**/ dlprintk((KERN_INFO MYNAM "/lan_close: bucket %05x "
- /**/ "is still out\n", i));
- pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma,
- priv->RcvCtl[i].len,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(priv->RcvCtl[i].skb);
- }
- }
- kfree(priv->RcvCtl);
- kfree(priv->mpt_rxfidx);
- for (i = 0; i < priv->tx_max_out; i++) {
- if (priv->SendCtl[i].skb != NULL) {
- pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma,
- priv->SendCtl[i].len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(priv->SendCtl[i].skb);
- }
- }
- kfree(priv->SendCtl);
- kfree(priv->mpt_txfidx);
- atomic_set(&priv->buckets_out, 0);
- printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n",
- IOC_AND_NETDEV_NAMES_s_s(dev));
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
- {
- if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /* Tx timeout handler. */
- static void
- mpt_lan_tx_timeout(struct net_device *dev)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- if (mpt_dev->active) {
- dlprintk (("mptlan/tx_timeout: calling netif_wake_queue for %s.\n", dev->name));
- netif_wake_queue(dev);
- }
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- //static inline int
- static int
- mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- struct sk_buff *sent;
- unsigned long flags;
- u32 ctx;
- ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
- sent = priv->SendCtl[ctx].skb;
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += sent->len;
- dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __func__, sent));
- priv->SendCtl[ctx].skb = NULL;
- pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
- priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(sent);
- spin_lock_irqsave(&priv->txfidx_lock, flags);
- priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
- spin_unlock_irqrestore(&priv->txfidx_lock, flags);
- netif_wake_queue(dev);
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- struct sk_buff *sent;
- unsigned long flags;
- int FreeReqFrame = 0;
- u32 *pContext;
- u32 ctx;
- u8 count;
- count = pSendRep->NumberOfContexts;
- dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n",
- le16_to_cpu(pSendRep->IOCStatus)));
- /* Add check for Loginfo Flag in IOCStatus */
- switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) {
- case MPI_IOCSTATUS_SUCCESS:
- dev->stats.tx_packets += count;
- break;
- case MPI_IOCSTATUS_LAN_CANCELED:
- case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED:
- break;
- case MPI_IOCSTATUS_INVALID_SGL:
- dev->stats.tx_errors += count;
- printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
- IOC_AND_NETDEV_NAMES_s_s(dev));
- goto out;
- default:
- dev->stats.tx_errors += count;
- break;
- }
- pContext = &pSendRep->BufferContext;
- spin_lock_irqsave(&priv->txfidx_lock, flags);
- while (count > 0) {
- ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
- sent = priv->SendCtl[ctx].skb;
- dev->stats.tx_bytes += sent->len;
- dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __func__, sent));
- priv->SendCtl[ctx].skb = NULL;
- pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
- priv->SendCtl[ctx].len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(sent);
- priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx;
- pContext++;
- count--;
- }
- spin_unlock_irqrestore(&priv->txfidx_lock, flags);
- out:
- if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY))
- FreeReqFrame = 1;
- netif_wake_queue(dev);
- return FreeReqFrame;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- MPT_FRAME_HDR *mf;
- LANSendRequest_t *pSendReq;
- SGETransaction32_t *pTrans;
- SGESimple64_t *pSimple;
- const unsigned char *mac;
- dma_addr_t dma;
- unsigned long flags;
- int ctx;
- u16 cur_naa = 0x1000;
- dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
- __func__, skb));
- spin_lock_irqsave(&priv->txfidx_lock, flags);
- if (priv->mpt_txfidx_tail < 0) {
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&priv->txfidx_lock, flags);
- printk (KERN_ERR "%s: no tx context available: %u\n",
- __func__, priv->mpt_txfidx_tail);
- return NETDEV_TX_BUSY;
- }
- mf = mpt_get_msg_frame(LanCtx, mpt_dev);
- if (mf == NULL) {
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&priv->txfidx_lock, flags);
- printk (KERN_ERR "%s: Unable to alloc request frame\n",
- __func__);
- return NETDEV_TX_BUSY;
- }
- ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
- spin_unlock_irqrestore(&priv->txfidx_lock, flags);
- // dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev)));
- pSendReq = (LANSendRequest_t *) mf;
- /* Set the mac.raw pointer, since this apparently isn't getting
- * done before we get the skb. Pull the data pointer past the mac data.
- */
- skb_reset_mac_header(skb);
- skb_pull(skb, 12);
- dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- priv->SendCtl[ctx].skb = skb;
- priv->SendCtl[ctx].dma = dma;
- priv->SendCtl[ctx].len = skb->len;
- /* Message Header */
- pSendReq->Reserved = 0;
- pSendReq->Function = MPI_FUNCTION_LAN_SEND;
- pSendReq->ChainOffset = 0;
- pSendReq->Reserved2 = 0;
- pSendReq->MsgFlags = 0;
- pSendReq->PortNumber = priv->pnum;
- /* Transaction Context Element */
- pTrans = (SGETransaction32_t *) pSendReq->SG_List;
- /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */
- pTrans->ContextSize = sizeof(u32);
- pTrans->DetailsLength = 2 * sizeof(u32);
- pTrans->Flags = 0;
- pTrans->TransactionContext[0] = cpu_to_le32(ctx);
- // dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev),
- // ctx, skb, skb->data));
- mac = skb_mac_header(skb);
- pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) |
- (mac[0] << 8) |
- (mac[1] << 0));
- pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) |
- (mac[3] << 16) |
- (mac[4] << 8) |
- (mac[5] << 0));
- pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
- /* If we ever decide to send more than one Simple SGE per LANSend, then
- we will need to make sure that LAST_ELEMENT only gets set on the
- last one. Otherwise, bad voodoo and evil funkiness will commence. */
- pSimple->FlagsLength = cpu_to_le32(
- ((MPI_SGE_FLAGS_LAST_ELEMENT |
- MPI_SGE_FLAGS_END_OF_BUFFER |
- MPI_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI_SGE_FLAGS_SYSTEM_ADDRESS |
- MPI_SGE_FLAGS_HOST_TO_IOC |
- MPI_SGE_FLAGS_64_BIT_ADDRESSING |
- MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) |
- skb->len);
- pSimple->Address.Low = cpu_to_le32((u32) dma);
- if (sizeof(dma_addr_t) > sizeof(u32))
- pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32));
- else
- pSimple->Address.High = 0;
- mpt_put_msg_frame (LanCtx, mpt_dev, mf);
- dev->trans_start = jiffies;
- dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- le32_to_cpu(pSimple->FlagsLength)));
- return NETDEV_TX_OK;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static void
- mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
- /*
- * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
- */
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
-
- if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
- if (priority) {
- schedule_delayed_work(&priv->post_buckets_task, 0);
- } else {
- schedule_delayed_work(&priv->post_buckets_task, 1);
- dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
- "timer.\n"));
- }
- dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n",
- IOC_AND_NETDEV_NAMES_s_s(dev) ));
- }
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- skb->protocol = mpt_lan_type_trans(skb, dev);
- dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) "
- "delivered to upper level.\n",
- IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
- dev->stats.rx_bytes += skb->len;
- dev->stats.rx_packets++;
- skb->dev = dev;
- netif_rx(skb);
- dioprintk((MYNAM "/receive_skb: %d buckets remaining\n",
- atomic_read(&priv->buckets_out)));
- if (atomic_read(&priv->buckets_out) < priv->bucketthresh)
- mpt_lan_wake_post_buckets_task(dev, 1);
- dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets "
- "remaining, %d received back since sod\n",
- atomic_read(&priv->buckets_out), priv->total_received));
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- //static inline int
- static int
- mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- struct sk_buff *skb, *old_skb;
- unsigned long flags;
- u32 ctx, len;
- ctx = GET_LAN_BUCKET_CONTEXT(tmsg);
- skb = priv->RcvCtl[ctx].skb;
- len = GET_LAN_PACKET_LENGTH(tmsg);
- if (len < MPT_LAN_RX_COPYBREAK) {
- old_skb = skb;
- skb = (struct sk_buff *)dev_alloc_skb(len);
- if (!skb) {
- printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __FILE__, __LINE__);
- return -ENOMEM;
- }
- pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
- pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- goto out;
- }
- skb_put(skb, len);
- priv->RcvCtl[ctx].skb = NULL;
- pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- out:
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- atomic_dec(&priv->buckets_out);
- priv->total_received++;
- return mpt_lan_receive_skb(dev, skb);
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_receive_post_free(struct net_device *dev,
- LANReceivePostReply_t *pRecvRep)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- unsigned long flags;
- struct sk_buff *skb;
- u32 ctx;
- int count;
- int i;
- count = pRecvRep->NumberOfContexts;
- /**/ dlprintk((KERN_INFO MYNAM "/receive_post_reply: "
- "IOC returned %d buckets, freeing them...\n", count));
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- for (i = 0; i < count; i++) {
- ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
- skb = priv->RcvCtl[ctx].skb;
- // dlprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev)));
- // dlprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p",
- // priv, &(priv->buckets_out)));
- // dlprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n"));
- priv->RcvCtl[ctx].skb = NULL;
- pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(skb);
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- }
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- atomic_sub(count, &priv->buckets_out);
- // for (i = 0; i < priv->max_buckets_out; i++)
- // if (priv->RcvCtl[i].skb != NULL)
- // dlprintk((KERN_INFO MYNAM "@rpr: bucket %03x "
- // "is still out\n", i));
- /* dlprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n",
- count));
- */
- /**/ dlprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets "
- /**/ "remaining, %d received back since sod.\n",
- /**/ atomic_read(&priv->buckets_out), priv->total_received));
- return 0;
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static int
- mpt_lan_receive_post_reply(struct net_device *dev,
- LANReceivePostReply_t *pRecvRep)
- {
- struct mpt_lan_priv *priv = netdev_priv(dev);
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- struct sk_buff *skb, *old_skb;
- unsigned long flags;
- u32 len, ctx, offset;
- u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining);
- int count;
- int i, l;
- dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n"));
- dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n",
- le16_to_cpu(pRecvRep->IOCStatus)));
- if ((le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_MASK) ==
- MPI_IOCSTATUS_LAN_CANCELED)
- return mpt_lan_receive_post_free(dev, pRecvRep);
- len = le32_to_cpu(pRecvRep->PacketLength);
- if (len == 0) {
- printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO "
- "ReceivePostReply w/ PacketLength zero!\n",
- IOC_AND_NETDEV_NAMES_s_s(dev));
- printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n",
- pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus));
- return -1;
- }
- ctx = le32_to_cpu(pRecvRep->BucketContext[0]);
- count = pRecvRep->NumberOfContexts;
- skb = priv->RcvCtl[ctx].skb;
- offset = le32_to_cpu(pRecvRep->PacketOffset);
- // if (offset != 0) {
- // printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply "
- // "w/ PacketOffset %u\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev),
- // offset);
- // }
- dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- offset, len));
- if (count > 1) {
- int szrem = len;
- // dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned "
- // "for single packet, concatenating...\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev)));
- skb = (struct sk_buff *)dev_alloc_skb(len);
- if (!skb) {
- printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __FILE__, __LINE__);
- return -ENOMEM;
- }
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- for (i = 0; i < count; i++) {
- ctx = le32_to_cpu(pRecvRep->BucketContext[i]);
- old_skb = priv->RcvCtl[ctx].skb;
- l = priv->RcvCtl[ctx].len;
- if (szrem < l)
- l = szrem;
- // dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n",
- // IOC_AND_NETDEV_NAMES_s_s(dev),
- // i, l));
- pci_dma_sync_single_for_cpu(mpt_dev->pcidev,
- priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len,
- PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(old_skb, skb_put(skb, l), l);
- pci_dma_sync_single_for_device(mpt_dev->pcidev,
- priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len,
- PCI_DMA_FROMDEVICE);
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- szrem -= l;
- }
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- } else if (len < MPT_LAN_RX_COPYBREAK) {
- old_skb = skb;
- skb = (struct sk_buff *)dev_alloc_skb(len);
- if (!skb) {
- printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __FILE__, __LINE__);
- return -ENOMEM;
- }
- pci_dma_sync_single_for_cpu(mpt_dev->pcidev,
- priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len,
- PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
- pci_dma_sync_single_for_device(mpt_dev->pcidev,
- priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len,
- PCI_DMA_FROMDEVICE);
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- } else {
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- priv->RcvCtl[ctx].skb = NULL;
- pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- priv->RcvCtl[ctx].dma = 0;
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- skb_put(skb,len);
- }
- atomic_sub(count, &priv->buckets_out);
- priv->total_received += count;
- if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) {
- printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, "
- "MPT_LAN_MAX_BUCKETS_OUT = %d\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- priv->mpt_rxfidx_tail,
- MPT_LAN_MAX_BUCKETS_OUT);
- return -1;
- }
- if (remaining == 0)
- printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! "
- "(priv->buckets_out = %d)\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- atomic_read(&priv->buckets_out));
- else if (remaining < 10)
- printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. "
- "(priv->buckets_out = %d)\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- remaining, atomic_read(&priv->buckets_out));
-
- if ((remaining < priv->bucketthresh) &&
- ((atomic_read(&priv->buckets_out) - remaining) >
- MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) {
-
- printk (KERN_WARNING MYNAM " Mismatch between driver's "
- "buckets_out count and fw's BucketsRemaining "
- "count has crossed the threshold, issuing a "
- "LanReset to clear the fw's hashtable. You may "
- "want to check your /var/log/messages for \"CRC "
- "error\" event notifications.\n");
-
- mpt_lan_reset(dev);
- mpt_lan_wake_post_buckets_task(dev, 0);
- }
-
- return mpt_lan_receive_skb(dev, skb);
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- /* Simple SGE's only at the moment */
- static void
- mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
- {
- struct net_device *dev = priv->dev;
- MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- MPT_FRAME_HDR *mf;
- LANReceivePostRequest_t *pRecvReq;
- SGETransaction32_t *pTrans;
- SGESimple64_t *pSimple;
- struct sk_buff *skb;
- dma_addr_t dma;
- u32 curr, buckets, count, max;
- u32 len = (dev->mtu + dev->hard_header_len + 4);
- unsigned long flags;
- int i;
- curr = atomic_read(&priv->buckets_out);
- buckets = (priv->max_buckets_out - curr);
- dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- __func__, buckets, curr));
- max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
- (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
- while (buckets) {
- mf = mpt_get_msg_frame(LanCtx, mpt_dev);
- if (mf == NULL) {
- printk (KERN_ERR "%s: Unable to alloc request frame\n",
- __func__);
- dioprintk((KERN_ERR "%s: %u buckets remaining\n",
- __func__, buckets));
- goto out;
- }
- pRecvReq = (LANReceivePostRequest_t *) mf;
- i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- mpt_dev->RequestNB[i] = 0;
- count = buckets;
- if (count > max)
- count = max;
- pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE;
- pRecvReq->ChainOffset = 0;
- pRecvReq->MsgFlags = 0;
- pRecvReq->PortNumber = priv->pnum;
- pTrans = (SGETransaction32_t *) pRecvReq->SG_List;
- pSimple = NULL;
- for (i = 0; i < count; i++) {
- int ctx;
- spin_lock_irqsave(&priv->rxfidx_lock, flags);
- if (priv->mpt_rxfidx_tail < 0) {
- printk (KERN_ERR "%s: Can't alloc context\n",
- __func__);
- spin_unlock_irqrestore(&priv->rxfidx_lock,
- flags);
- break;
- }
- ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--];
- skb = priv->RcvCtl[ctx].skb;
- if (skb && (priv->RcvCtl[ctx].len != len)) {
- pci_unmap_single(mpt_dev->pcidev,
- priv->RcvCtl[ctx].dma,
- priv->RcvCtl[ctx].len,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(priv->RcvCtl[ctx].skb);
- skb = priv->RcvCtl[ctx].skb = NULL;
- }
- if (skb == NULL) {
- skb = dev_alloc_skb(len);
- if (skb == NULL) {
- printk (KERN_WARNING
- MYNAM "/%s: Can't alloc skb\n",
- __func__);
- priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- break;
- }
- dma = pci_map_single(mpt_dev->pcidev, skb->data,
- len, PCI_DMA_FROMDEVICE);
- priv->RcvCtl[ctx].skb = skb;
- priv->RcvCtl[ctx].dma = dma;
- priv->RcvCtl[ctx].len = len;
- }
- spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
- pTrans->ContextSize = sizeof(u32);
- pTrans->DetailsLength = 0;
- pTrans->Flags = 0;
- pTrans->TransactionContext[0] = cpu_to_le32(ctx);
- pSimple = (SGESimple64_t *) pTrans->TransactionDetails;
- pSimple->FlagsLength = cpu_to_le32(
- ((MPI_SGE_FLAGS_END_OF_BUFFER |
- MPI_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len);
- pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma);
- if (sizeof(dma_addr_t) > sizeof(u32))
- pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32));
- else
- pSimple->Address.High = 0;
- pTrans = (SGETransaction32_t *) (pSimple + 1);
- }
- if (pSimple == NULL) {
- /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
- /**/ __func__);
- mpt_free_msg_frame(mpt_dev, mf);
- goto out;
- }
- pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT);
- pRecvReq->BucketCount = cpu_to_le32(i);
- /* printk(KERN_INFO MYNAM ": posting buckets\n ");
- * for (i = 0; i < j + 2; i ++)
- * printk (" %08x", le32_to_cpu(msg[i]));
- * printk ("\n");
- */
- mpt_put_msg_frame(LanCtx, mpt_dev, mf);
- priv->total_posted += i;
- buckets -= i;
- atomic_add(i, &priv->buckets_out);
- }
- out:
- dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
- __func__, buckets, atomic_read(&priv->buckets_out)));
- dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
- __func__, priv->total_posted, priv->total_received));
- clear_bit(0, &priv->post_buckets_active);
- }
- static void
- mpt_lan_post_receive_buckets_work(struct work_struct *work)
- {
- mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv,
- post_buckets_task.work));
- }
- static const struct net_device_ops mpt_netdev_ops = {
- .ndo_open = mpt_lan_open,
- .ndo_stop = mpt_lan_close,
- .ndo_start_xmit = mpt_lan_sdu_send,
- .ndo_change_mtu = mpt_lan_change_mtu,
- .ndo_tx_timeout = mpt_lan_tx_timeout,
- };
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static struct net_device *
- mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
- {
- struct net_device *dev;
- struct mpt_lan_priv *priv;
- u8 HWaddr[FC_ALEN], *a;
- dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
- if (!dev)
- return NULL;
- dev->mtu = MPT_LAN_MTU;
- priv = netdev_priv(dev);
- priv->dev = dev;
- priv->mpt_dev = mpt_dev;
- priv->pnum = pnum;
- INIT_DELAYED_WORK(&priv->post_buckets_task,
- mpt_lan_post_receive_buckets_work);
- priv->post_buckets_active = 0;
- dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
- __LINE__, dev->mtu + dev->hard_header_len + 4));
- atomic_set(&priv->buckets_out, 0);
- priv->total_posted = 0;
- priv->total_received = 0;
- priv->max_buckets_out = max_buckets_out;
- if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out)
- priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets;
- dlprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
- __LINE__,
- mpt_dev->pfacts[0].MaxLanBuckets,
- max_buckets_out,
- priv->max_buckets_out));
- priv->bucketthresh = priv->max_buckets_out * 2 / 3;
- spin_lock_init(&priv->txfidx_lock);
- spin_lock_init(&priv->rxfidx_lock);
- /* Grab pre-fetched LANPage1 stuff. :-) */
- a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
- HWaddr[0] = a[5];
- HWaddr[1] = a[4];
- HWaddr[2] = a[3];
- HWaddr[3] = a[2];
- HWaddr[4] = a[1];
- HWaddr[5] = a[0];
- dev->addr_len = FC_ALEN;
- memcpy(dev->dev_addr, HWaddr, FC_ALEN);
- memset(dev->broadcast, 0xff, FC_ALEN);
- /* The Tx queue is 127 deep on the 909.
- * Give ourselves some breathing room.
- */
- priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
- tx_max_out_p : MPT_TX_MAX_OUT_LIM;
- dev->netdev_ops = &mpt_netdev_ops;
- dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
- dlprintk((KERN_INFO MYNAM ": Finished registering dev "
- "and setting initial values\n"));
- if (register_netdev(dev) != 0) {
- free_netdev(dev);
- dev = NULL;
- }
- return dev;
- }
- static int
- mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id)
- {
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct net_device *dev;
- int i;
- for (i = 0; i < ioc->facts.NumberOfPorts; i++) {
- printk(KERN_INFO MYNAM ": %s: PortNum=%x, "
- "ProtocolFlags=%02Xh (%c%c%c%c)\n",
- ioc->name, ioc->pfacts[i].PortNumber,
- ioc->pfacts[i].ProtocolFlags,
- MPT_PROTOCOL_FLAGS_c_c_c_c(
- ioc->pfacts[i].ProtocolFlags));
- if (!(ioc->pfacts[i].ProtocolFlags &
- MPI_PORTFACTS_PROTOCOL_LAN)) {
- printk(KERN_INFO MYNAM ": %s: Hmmm... LAN protocol "
- "seems to be disabled on this adapter port!\n",
- ioc->name);
- continue;
- }
- dev = mpt_register_lan_device(ioc, i);
- if (!dev) {
- printk(KERN_ERR MYNAM ": %s: Unable to register "
- "port%d as a LAN device\n", ioc->name,
- ioc->pfacts[i].PortNumber);
- continue;
- }
-
- printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device "
- "registered as '%s'\n", ioc->name, dev->name);
- printk(KERN_INFO MYNAM ": %s/%s: "
- "LanAddr = %pM\n",
- IOC_AND_NETDEV_NAMES_s_s(dev),
- dev->dev_addr);
-
- ioc->netdev = dev;
- return 0;
- }
- return -ENODEV;
- }
- static void
- mptlan_remove(struct pci_dev *pdev)
- {
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct net_device *dev = ioc->netdev;
- if(dev != NULL) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
- static struct mpt_pci_driver mptlan_driver = {
- .probe = mptlan_probe,
- .remove = mptlan_remove,
- };
- static int __init mpt_lan_init (void)
- {
- show_mptmod_ver(LANAME, LANVER);
- LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER,
- "lan_reply");
- if (LanCtx <= 0) {
- printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
- return -EBUSY;
- }
- dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
- if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
- printk(KERN_ERR MYNAM ": Eieee! unable to register a reset "
- "handler with mptbase! The world is at an end! "
- "Everything is fading to black! Goodbye.\n");
- return -EBUSY;
- }
- dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
-
- mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER);
- return 0;
- }
- static void __exit mpt_lan_exit(void)
- {
- mpt_device_driver_deregister(MPTLAN_DRIVER);
- mpt_reset_deregister(LanCtx);
- if (LanCtx) {
- mpt_deregister(LanCtx);
- LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
- }
- }
- module_init(mpt_lan_init);
- module_exit(mpt_lan_exit);
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
- static unsigned short
- mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev)
- {
- struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
- struct fcllc *fcllc;
- skb_reset_mac_header(skb);
- skb_pull(skb, sizeof(struct mpt_lan_ohdr));
- if (fch->dtype == htons(0xffff)) {
- u32 *p = (u32 *) fch;
- swab32s(p + 0);
- swab32s(p + 1);
- swab32s(p + 2);
- swab32s(p + 3);
- printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n",
- NETDEV_PTR_TO_IOC_NAME_s(dev));
- printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n",
- fch->saddr);
- }
- if (*fch->daddr & 1) {
- if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) {
- skb->pkt_type = PACKET_BROADCAST;
- } else {
- skb->pkt_type = PACKET_MULTICAST;
- }
- } else {
- if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) {
- skb->pkt_type = PACKET_OTHERHOST;
- } else {
- skb->pkt_type = PACKET_HOST;
- }
- }
- fcllc = (struct fcllc *)skb->data;
- /* Strip the SNAP header from ARP packets since we don't
- * pass them through to the 802.2/SNAP layers.
- */
- if (fcllc->dsap == EXTENDED_SAP &&
- (fcllc->ethertype == htons(ETH_P_IP) ||
- fcllc->ethertype == htons(ETH_P_ARP))) {
- skb_pull(skb, sizeof(struct fcllc));
- return fcllc->ethertype;
- }
- return htons(ETH_P_802_2);
- }
- /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|