patch-2.4.10 linux/drivers/message/fusion/mptlan.c
Next file: linux/drivers/message/fusion/mptlan.h
Previous file: linux/drivers/message/fusion/mptctl.c
Back to the patch index
Back to the overall index
- Lines: 363
- Date:
Fri Sep 7 09:28:38 2001
- Orig file:
v2.4.9/linux/drivers/message/fusion/mptlan.c
- Orig date:
Wed Jul 25 17:10:20 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/message/fusion/mptlan.c linux/drivers/message/fusion/mptlan.c
@@ -26,7 +26,7 @@
* Copyright (c) 2000-2001 LSI Logic Corporation
* Originally By: Noah Romer
*
- * $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $
+ * $Id: mptlan.c,v 1.32.2.2 2001/07/12 19:43:33 nromer Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -93,6 +93,12 @@
* Fusion MPT LAN private structures
*/
+struct NAA_Hosed {
+ u16 NAA;
+ u8 ieee[FC_ALEN];
+ struct NAA_Hosed *next;
+};
+
struct BufferControl {
struct sk_buff *skb;
dma_addr_t dma;
@@ -153,6 +159,7 @@
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);
@@ -168,6 +175,9 @@
static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
+static struct NAA_Hosed *mpt_bad_naa = NULL;
+rwlock_t bad_naa_lock;
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Fusion MPT LAN external data
@@ -318,6 +328,41 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int
+mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+ struct net_device *dev = mpt_landev[ioc->id];
+ struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
+
+ dprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+ if (priv->mpt_rxfidx == NULL)
+ return (1);
+
+ if (reset_phase == MPT_IOC_PRE_RESET) {
+ int i;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ atomic_set(&priv->buckets_out, 0);
+
+ /* Reset Rx Free Tail index and re-populate the queue. */
+ spin_lock_irqsave(&priv->rxfidx_lock, flags);
+ priv->mpt_rxfidx_tail = -1;
+ for (i = 0; i < priv->max_buckets_out; i++)
+ priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
+ spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
+ } else {
+ mpt_lan_post_receive_buckets(dev);
+ netif_wake_queue(dev);
+ }
+
+ return 1;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static int
mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n"));
@@ -356,7 +401,19 @@
struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
int i;
- mpt_lan_reset(dev);
+ 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)
@@ -402,7 +459,10 @@
IOC_AND_NETDEV_NAMES_s_s(dev));
if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) {
- /* FIXME! */
+ 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);
@@ -422,6 +482,8 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* 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)
{
@@ -660,6 +722,8 @@
dma_addr_t dma;
unsigned long flags;
int ctx;
+ struct NAA_Hosed *nh;
+ u16 cur_naa = 0x1000;
dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
__FUNCTION__, skb));
@@ -707,8 +771,10 @@
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;
@@ -725,7 +791,26 @@
// IOC_AND_NETDEV_NAMES_s_s(dev),
// ctx, skb, skb->data));
- pTrans->TransactionDetails[0] = cpu_to_le32((0x1000 << 16) |
+ /* Munge the NAA for Tx packets to QLogic boards, which don't follow
+ RFC 2625. The longer I look at this, the more my opinion of Qlogic
+ drops. */
+ read_lock_irq(&bad_naa_lock);
+ for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) {
+ if ((nh->ieee[0] == skb->mac.raw[0]) &&
+ (nh->ieee[1] == skb->mac.raw[1]) &&
+ (nh->ieee[2] == skb->mac.raw[2]) &&
+ (nh->ieee[3] == skb->mac.raw[3]) &&
+ (nh->ieee[4] == skb->mac.raw[4]) &&
+ (nh->ieee[5] == skb->mac.raw[5])) {
+ cur_naa = nh->NAA;
+ dprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
+ "= %04x.\n", cur_naa));
+ break;
+ }
+ }
+ read_unlock_irq(&bad_naa_lock);
+
+ pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) |
(skb->mac.raw[0] << 8) |
(skb->mac.raw[1] << 0));
pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
@@ -735,9 +820,15 @@
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_END_OF_BUFFER |
+ ((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);
@@ -1252,12 +1343,12 @@
priv->total_posted = 0;
priv->total_received = 0;
priv->max_buckets_out = max_buckets_out;
- if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out)
- priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets;
+ if (mpt_dev->pfacts[0].MaxLanBuckets < max_buckets_out)
+ priv->max_buckets_out = mpt_dev->pfacts[0].MaxLanBuckets;
dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n",
__LINE__,
- mpt_dev->pfacts0.MaxLanBuckets,
+ mpt_dev->pfacts[0].MaxLanBuckets,
max_buckets_out,
priv->max_buckets_out));
@@ -1316,7 +1407,11 @@
show_mptmod_ver(LANAME, LANVER);
- if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) {
+ /* Init the global r/w lock for the bad_naa list. We want to do this
+ before any boards are initialized and may be used. */
+ rwlock_init(&bad_naa_lock);
+
+ if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
return -EBUSY;
}
@@ -1326,6 +1421,15 @@
dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
+ if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) {
+ dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
+ } else {
+ 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;
+ }
+
for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
mpt_landev[j] = NULL;
}
@@ -1333,14 +1437,14 @@
curadapter = mpt_adapter_find_first();
while (curadapter != NULL) {
- for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) {
+ for (i = 0; i < curadapter->facts.NumberOfPorts; i++) {
printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
curadapter->name,
- curadapter->pfacts0.PortNumber,
- curadapter->pfacts0.ProtocolFlags,
- MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags));
+ curadapter->pfacts[i].PortNumber,
+ curadapter->pfacts[i].ProtocolFlags,
+ MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts[i].ProtocolFlags));
- if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ if (curadapter->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
dev = mpt_register_lan_device (curadapter, i);
if (dev != NULL) {
printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
@@ -1361,7 +1465,7 @@
} else {
printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
curadapter->name,
- curadapter->pfacts0.PortNumber);
+ curadapter->pfacts[i].PortNumber);
}
} else {
printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
@@ -1379,6 +1483,8 @@
{
int i;
+ mpt_reset_deregister(LanCtx);
+
for (i = 0; mpt_landev[i] != NULL; i++) {
struct net_device *dev = mpt_landev[i];
@@ -1411,6 +1517,7 @@
{
struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
struct fcllc *fcllc;
+ u16 source_naa = fch->stype, found = 0;
skb->mac.raw = skb->data;
skb_pull(skb, sizeof(struct mpt_lan_ohdr));
@@ -1444,11 +1551,80 @@
}
}
+ fcllc = (struct fcllc *)skb->data;
+
+ /* Workaround for QLogic not following RFC 2625 in regards to the NAA
+ value. */
+
+ if ((source_naa & 0xF000) == 0)
+ source_naa = swab16(source_naa);
+
+ if (fcllc->ethertype == htons(ETH_P_ARP))
+ dprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of "
+ "%04x.\n", source_naa));
+
+ if ((fcllc->ethertype == htons(ETH_P_ARP)) &&
+ ((source_naa >> 12) != MPT_LAN_NAA_RFC2625)){
+ struct NAA_Hosed *nh, *prevnh;
+ int i;
+
+ dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from "
+ "system with non-RFC 2625 NAA value (%04x).\n",
+ source_naa));
+
+ write_lock_irq(&bad_naa_lock);
+ for (prevnh = nh = mpt_bad_naa; nh != NULL;
+ prevnh=nh, nh=nh->next) {
+ if ((nh->ieee[0] == fch->saddr[0]) &&
+ (nh->ieee[1] == fch->saddr[1]) &&
+ (nh->ieee[2] == fch->saddr[2]) &&
+ (nh->ieee[3] == fch->saddr[3]) &&
+ (nh->ieee[4] == fch->saddr[4]) &&
+ (nh->ieee[5] == fch->saddr[5])) {
+ found = 1;
+ dprintk ((KERN_INFO "mptlan/type_trans: ARP Re"
+ "q/Rep w/ bad NAA from system already"
+ " in DB.\n"));
+ break;
+ }
+ }
+
+ if ((!found) && (nh == NULL)) {
+
+ nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL);
+ dprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/"
+ " bad NAA from system not yet in DB.\n"));
+
+ if (nh != NULL) {
+ nh->next = NULL;
+ if (!mpt_bad_naa)
+ mpt_bad_naa = nh;
+ if (prevnh)
+ prevnh->next = nh;
+
+ nh->NAA = source_naa; /* Set the S_NAA value. */
+ for (i = 0; i < FC_ALEN; i++)
+ nh->ieee[i] = fch->saddr[i];
+ dprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:"
+ "%02x:%02x with non-compliant S_NAA value.\n",
+ fch->saddr[0], fch->saddr[1], fch->saddr[2],
+ fch->saddr[3], fch->saddr[4],fch->saddr[5]));
+ } else {
+ printk (KERN_ERR "mptlan/type_trans: Unable to"
+ " kmalloc a NAA_Hosed struct.\n");
+ }
+ } else if (!found) {
+ printk (KERN_ERR "mptlan/type_trans: found not"
+ " set, but nh isn't null. Evil "
+ "funkiness abounds.\n");
+ }
+ write_unlock_irq(&bad_naa_lock);
+ }
+
+
/* Strip the SNAP header from ARP packets since we don't
* pass them through to the 802.2/SNAP layers.
*/
- fcllc = (struct fcllc *)skb->data;
-
if (fcllc->dsap == EXTENDED_SAP &&
(fcllc->ethertype == htons(ETH_P_IP) ||
fcllc->ethertype == htons(ETH_P_ARP))) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)