/* * 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
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * 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.
*/ staticint
lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
{ struct net_device *dev = ioc->netdev; int FreeReqFrame = 0;
// 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:
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;
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) {
;
} elseif (reset_phase == MPT_IOC_PRE_RESET) { int i; unsignedlong 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;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ staticint
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!
*/
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");
}
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");
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* Send a LanReset message to the FW. This should result in the FW returning
any buckets it still has. */ staticint
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;
}
/* 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);
/* 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;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ staticvoid
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 (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));
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");
/* 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;
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;
}
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"));
/* 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.