/*
* linux/drivers/message/fusion/mptlan.c
* IP Over Fibre Channel device driver.
- * For use with LSI Logic Fibre Channel PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI Fibre Channel PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * Copyright (c) 2000-2008 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#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"
* 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;
u32 total_posted;
u32 total_received;
- struct net_device_stats stats; /* Per device statistics */
struct delayed_work post_buckets_task;
struct net_device *dev;
/*
* Fusion MPT LAN private data
*/
-static int LanCtx = -1;
+static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
static u32 max_buckets_out = 127;
static u32 tx_max_out_p = 127 - 16;
-#ifdef QLOGIC_NAA_WORKAROUND
-static struct NAA_Hosed *mpt_bad_naa = NULL;
-DEFINE_RWLOCK(bad_naa_lock);
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Fusion MPT LAN external data
- */
-extern int mpt_lan_index;
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* lan_reply - Handle all data sent from the hardware.
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static struct net_device_stats *
-mpt_lan_get_stats(struct net_device *dev)
-{
- struct mpt_lan_priv *priv = netdev_priv(dev);
-
- return (struct net_device_stats *) &priv->stats;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int
mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
{
ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
sent = priv->SendCtl[ctx].skb;
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += sent->len;
+ 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),
- __FUNCTION__, sent));
+ __func__, sent));
priv->SendCtl[ctx].skb = NULL;
pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) {
case MPI_IOCSTATUS_SUCCESS:
- priv->stats.tx_packets += count;
+ dev->stats.tx_packets += count;
break;
case MPI_IOCSTATUS_LAN_CANCELED:
break;
case MPI_IOCSTATUS_INVALID_SGL:
- priv->stats.tx_errors += count;
+ 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:
- priv->stats.tx_errors += count;
+ dev->stats.tx_errors += count;
break;
}
ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
sent = priv->SendCtl[ctx].skb;
- priv->stats.tx_bytes += sent->len;
+ dev->stats.tx_bytes += sent->len;
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
IOC_AND_NETDEV_NAMES_s_s(dev),
- __FUNCTION__, sent));
+ __func__, sent));
priv->SendCtl[ctx].skb = NULL;
pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
u16 cur_naa = 0x1000;
dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
- __FUNCTION__, skb));
+ __func__, skb));
spin_lock_irqsave(&priv->txfidx_lock, flags);
if (priv->mpt_txfidx_tail < 0) {
spin_unlock_irqrestore(&priv->txfidx_lock, flags);
printk (KERN_ERR "%s: no tx context available: %u\n",
- __FUNCTION__, priv->mpt_txfidx_tail);
- return 1;
+ __func__, priv->mpt_txfidx_tail);
+ return NETDEV_TX_BUSY;
}
mf = mpt_get_msg_frame(LanCtx, mpt_dev);
spin_unlock_irqrestore(&priv->txfidx_lock, flags);
printk (KERN_ERR "%s: Unable to alloc request frame\n",
- __FUNCTION__);
- return 1;
+ __func__);
+ return NETDEV_TX_BUSY;
}
ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--];
// ctx, skb, skb->data));
mac = skb_mac_header(skb);
-#ifdef QLOGIC_NAA_WORKAROUND
-{
- struct NAA_Hosed *nh;
-
- /* 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] == mac[0]) &&
- (nh->ieee[1] == mac[1]) &&
- (nh->ieee[2] == mac[2]) &&
- (nh->ieee[3] == mac[3]) &&
- (nh->ieee[4] == mac[4]) &&
- (nh->ieee[5] == mac[5])) {
- cur_naa = nh->NAA;
- dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
- "= %04x.\n", cur_naa));
- break;
- }
- }
- read_unlock_irq(&bad_naa_lock);
-}
-#endif
pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) |
(mac[0] << 8) |
IOC_AND_NETDEV_NAMES_s_s(dev),
le32_to_cpu(pSimple->FlagsLength)));
- return 0;
+ return NETDEV_TX_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
* @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
*/
{
- struct mpt_lan_priv *priv = dev->priv;
+ struct mpt_lan_priv *priv = netdev_priv(dev);
if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
if (priority) {
static int
mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
{
- struct mpt_lan_priv *priv = dev->priv;
+ struct mpt_lan_priv *priv = netdev_priv(dev);
skb->protocol = mpt_lan_type_trans(skb, dev);
"delivered to upper level.\n",
IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
- priv->stats.rx_bytes += skb->len;
- priv->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
skb->dev = dev;
netif_rx(skb);
static int
mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg)
{
- struct mpt_lan_priv *priv = dev->priv;
+ struct mpt_lan_priv *priv = netdev_priv(dev);
MPT_ADAPTER *mpt_dev = priv->mpt_dev;
struct sk_buff *skb, *old_skb;
unsigned long flags;
pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
- memcpy(skb_put(skb, len), old_skb->data, len);
+ 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);
mpt_lan_receive_post_free(struct net_device *dev,
LANReceivePostReply_t *pRecvRep)
{
- struct mpt_lan_priv *priv = dev->priv;
+ struct mpt_lan_priv *priv = netdev_priv(dev);
MPT_ADAPTER *mpt_dev = priv->mpt_dev;
unsigned long flags;
struct sk_buff *skb;
mpt_lan_receive_post_reply(struct net_device *dev,
LANReceivePostReply_t *pRecvRep)
{
- struct mpt_lan_priv *priv = dev->priv;
+ struct mpt_lan_priv *priv = netdev_priv(dev);
MPT_ADAPTER *mpt_dev = priv->mpt_dev;
struct sk_buff *skb, *old_skb;
unsigned long flags;
priv->RcvCtl[ctx].dma,
priv->RcvCtl[ctx].len,
PCI_DMA_FROMDEVICE);
- memcpy(skb_put(skb, l), old_skb->data, l);
+ 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);
- memcpy(skb_put(skb, len), old_skb->data, len);
+ 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,
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
IOC_AND_NETDEV_NAMES_s_s(dev),
- __FUNCTION__, buckets, curr));
+ __func__, buckets, curr));
max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
mf = mpt_get_msg_frame(LanCtx, mpt_dev);
if (mf == NULL) {
printk (KERN_ERR "%s: Unable to alloc request frame\n",
- __FUNCTION__);
+ __func__);
dioprintk((KERN_ERR "%s: %u buckets remaining\n",
- __FUNCTION__, buckets));
+ __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;
spin_lock_irqsave(&priv->rxfidx_lock, flags);
if (priv->mpt_rxfidx_tail < 0) {
printk (KERN_ERR "%s: Can't alloc context\n",
- __FUNCTION__);
+ __func__);
spin_unlock_irqrestore(&priv->rxfidx_lock,
flags);
break;
if (skb == NULL) {
printk (KERN_WARNING
MYNAM "/%s: Can't alloc skb\n",
- __FUNCTION__);
+ __func__);
priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
break;
if (pSimple == NULL) {
/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
-/**/ __FUNCTION__);
+/**/ __func__);
mpt_free_msg_frame(mpt_dev, mf);
goto out;
}
out:
dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
- __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+ __func__, buckets, atomic_read(&priv->buckets_out)));
dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
- __FUNCTION__, priv->total_posted, priv->total_received));
+ __func__, priv->total_posted, priv->total_received));
clear_bit(0, &priv->post_buckets_active);
}
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 = alloc_fcdev(sizeof(struct mpt_lan_priv));
- struct mpt_lan_priv *priv = NULL;
+ 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;
priv->mpt_dev = mpt_dev;
priv->pnum = pnum;
- memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
INIT_DELAYED_WORK(&priv->post_buckets_task,
mpt_lan_post_receive_buckets_work);
priv->post_buckets_active = 0;
spin_lock_init(&priv->txfidx_lock);
spin_lock_init(&priv->rxfidx_lock);
- memset(&priv->stats, 0, sizeof(priv->stats));
-
/* Grab pre-fetched LANPage1 stuff. :-) */
a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
tx_max_out_p : MPT_TX_MAX_OUT_LIM;
- dev->open = mpt_lan_open;
- dev->stop = mpt_lan_close;
- dev->get_stats = mpt_lan_get_stats;
- dev->set_multicast_list = NULL;
- dev->change_mtu = mpt_lan_change_mtu;
- dev->hard_start_xmit = mpt_lan_sdu_send;
-
-/* Not in 2.3.42. Need 2.3.45+ */
- dev->tx_timeout = mpt_lan_tx_timeout;
+ 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"));
- SET_MODULE_OWNER(dev);
-
if (register_netdev(dev) != 0) {
free_netdev(dev);
dev = NULL;
printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device "
"registered as '%s'\n", ioc->name, dev->name);
printk(KERN_INFO MYNAM ": %s/%s: "
- "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ "LanAddr = %pM\n",
IOC_AND_NETDEV_NAMES_s_s(dev),
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ dev->dev_addr);
ioc->netdev = dev;
return -EBUSY;
}
- /* Set the callback index to be used by driver core for turbo replies */
- mpt_lan_index = LanCtx;
-
dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
- if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER))
- dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n"));
+ mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER);
return 0;
}
mpt_device_driver_deregister(MPTLAN_DRIVER);
mpt_reset_deregister(LanCtx);
- if (LanCtx >= 0) {
+ if (LanCtx) {
mpt_deregister(LanCtx);
- LanCtx = -1;
- mpt_lan_index = 0;
+ LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
}
}
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 = %02x:%02x:%02x:%02x:%02x:%02x\n",
- fch->saddr[0], fch->saddr[1], fch->saddr[2],
- fch->saddr[3], fch->saddr[4], fch->saddr[5]);
+ printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n",
+ fch->saddr);
}
if (*fch->daddr & 1) {
fcllc = (struct fcllc *)skb->data;
-#ifdef QLOGIC_NAA_WORKAROUND
-{
- u16 source_naa = fch->stype, found = 0;
-
- /* 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))
- dlprintk ((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;
-
- dlprintk ((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;
- dlprintk ((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);
- dlprintk ((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];
- dlprintk ((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);
- }
-}
-#endif
-
/* Strip the SNAP header from ARP packets since we don't
* pass them through to the 802.2/SNAP layers.
*/