/*
* linux/drivers/message/fusion/mptlan.c
* IP Over Fibre Channel device driver.
- * For use with PCI chip/adapter(s):
- * LSIFC9xx/LSI409xx Fibre Channel
+ * For use with LSI Logic Fibre Channel PCI chip/adapters
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
- * Credits:
- * This driver would not exist if not for Alan Cox's development
- * of the linux i2o driver.
+ * Copyright (c) 2000-2005 LSI Logic Corporation
*
- * Special thanks goes to the I2O LAN driver people at the
- * University of Helsinki, who, unbeknownst to them, provided
- * the inspiration and initial structure for this driver.
- *
- * A huge debt of gratitude is owed to David S. Miller (DaveM)
- * for fixing much of the stupid and broken stuff in the early
- * driver while porting to sparc64 platform. THANK YOU!
- *
- * A really huge debt of gratitude is owed to Eddie C. Dost
- * for gobs of hard work fixing and optimizing LAN code.
- * THANK YOU!
- *
- * (see also mptbase.c)
- *
- * Copyright (c) 2000-2004 LSI Logic Corporation
- * Originally By: Noah Romer
- * (mailto:mpt_linux_developer@lsil.com)
- *
- * $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
u32 total_received;
struct net_device_stats stats; /* Per device statistics */
- struct mpt_work_struct post_buckets_task;
+ struct work_struct post_buckets_task;
unsigned long post_buckets_active;
};
static u32 max_buckets_out = 127;
static u32 tx_max_out_p = 127 - 16;
-static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1];
-
#ifdef QLOGIC_NAA_WORKAROUND
static struct NAA_Hosed *mpt_bad_naa = NULL;
-rwlock_t bad_naa_lock;
+DEFINE_RWLOCK(bad_naa_lock);
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int
lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
{
- struct net_device *dev = mpt_landev[ioc->id];
+ struct net_device *dev = ioc->netdev;
int FreeReqFrame = 0;
dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n",
// NOTE! (Optimization) First case here is now caught in
// mptbase.c::mpt_interrupt() routine and callcack here
- // is now skipped for this case! 20001218 -sralston
+ // is now skipped for this case!
#if 0
case LAN_REPLY_FORM_MESSAGE_CONTEXT:
// dioprintk((KERN_INFO MYNAM "/lan_reply: "
// dioprintk((MYNAM "/lan_reply: "
// "calling mpt_lan_send_reply (turbo)\n"));
- // Potential BUG here? -sralston
+ // 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)
case MPI_FUNCTION_EVENT_NOTIFICATION:
case MPI_FUNCTION_EVENT_ACK:
- /* UPDATE! 20010120 -sralston
- * _EVENT_NOTIFICATION should NOT come down this path any more.
+ /* _EVENT_NOTIFICATION should NOT come down this path any more.
* Should be routed to mpt_lan_event_process(), but just in case...
*/
FreeReqFrame = 1;
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 = netdev_priv(dev);
+ 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" : (
goto out;
priv->mpt_txfidx_tail = -1;
- priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+ 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++) {
- memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+ 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"));
goto out_SendCtl;
priv->mpt_rxfidx_tail = -1;
- priv->RcvCtl = kmalloc(priv->max_buckets_out *
- sizeof(struct BufferControl),
+ 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++) {
- memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+ 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++)
LANResetRequest_t *pResetReq;
struct mpt_lan_priv *priv = netdev_priv(dev);
- mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id);
+ mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev);
if (mf == NULL) {
/* dlprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! "
pResetReq->MsgFlags = 0;
pResetReq->Reserved2 = 0;
- mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf);
+ mpt_put_msg_frame(LanCtx, priv->mpt_dev, mf);
return 0;
}
{
struct mpt_lan_priv *priv = netdev_priv(dev);
MPT_ADAPTER *mpt_dev = priv->mpt_dev;
- unsigned int timeout;
+ unsigned long timeout;
int i;
dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n"));
mpt_lan_reset(dev);
- timeout = 2 * HZ;
- while (atomic_read(&priv->buckets_out) && --timeout) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
- }
+ 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) {
}
}
- kfree (priv->RcvCtl);
- kfree (priv->mpt_rxfidx);
+ kfree(priv->RcvCtl);
+ kfree(priv->mpt_rxfidx);
for (i = 0; i < priv->tx_max_out; i++) {
if (priv->SendCtl[i].skb != NULL) {
return 1;
}
- mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev);
if (mf == NULL) {
netif_stop_queue(dev);
spin_unlock_irqrestore(&priv->txfidx_lock, flags);
else
pSimple->Address.High = 0;
- mpt_put_msg_frame (LanCtx, mpt_dev->id, mf);
+ mpt_put_msg_frame (LanCtx, mpt_dev, mf);
dev->trans_start = jiffies;
dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n",
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline void
+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
if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
if (priority) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
schedule_work(&priv->post_buckets_task);
-#else
- queue_task(&priv->post_buckets_task, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-#endif
} else {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
schedule_delayed_work(&priv->post_buckets_task, 1);
-#else
- queue_task(&priv->post_buckets_task, &tq_timer);
-#endif
dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
"timer.\n"));
}
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline int
+static int
mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
{
struct mpt_lan_priv *priv = dev->priv;
(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
while (buckets) {
- mf = mpt_get_msg_frame(LanCtx, mpt_dev->id);
+ mf = mpt_get_msg_frame(LanCtx, mpt_dev);
if (mf == NULL) {
printk (KERN_ERR "%s: Unable to alloc request frame\n",
__FUNCTION__);
if (pSimple == NULL) {
/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
/**/ __FUNCTION__);
- mpt_free_msg_frame(LanCtx, mpt_dev->id, mf);
+ mpt_free_msg_frame(mpt_dev, mf);
goto out;
}
* printk ("\n");
*/
- mpt_put_msg_frame(LanCtx, mpt_dev->id, mf);
+ mpt_put_msg_frame(LanCtx, mpt_dev, mf);
priv->total_posted += i;
buckets -= i;
priv->mpt_dev = mpt_dev;
priv->pnum = pnum;
- memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct));
- MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
+ memset(&priv->post_buckets_task, 0, sizeof(struct work_struct));
+ INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
priv->post_buckets_active = 0;
dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
priv->max_buckets_out));
priv->bucketthresh = priv->max_buckets_out * 2 / 3;
- priv->txfidx_lock = SPIN_LOCK_UNLOCKED;
- priv->rxfidx_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&priv->txfidx_lock);
+ spin_lock_init(&priv->rxfidx_lock);
memset(&priv->stats, 0, sizeof(priv->stats));
return dev;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int __init mpt_lan_init (void)
+static int
+mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct net_device *dev;
- MPT_ADAPTER *p;
- int i, j;
+ 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;
+ }
- show_mptmod_ver(LANAME, LANVER);
+ 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 = %02X:%02X:%02X:%02X:%02X:%02X\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]);
+
+ ioc->netdev = dev;
-#ifdef QLOGIC_NAA_WORKAROUND
- /* 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);
-#endif
+ 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);
if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
- if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) {
- dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
- } else {
+ 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;
}
- for (j = 0; j < MPT_MAX_ADAPTERS; j++) {
- mpt_landev[j] = NULL;
- }
-
- for (p = mpt_adapter_find_first(); p; p = mpt_adapter_find_next(p)) {
- for (i = 0; i < p->facts.NumberOfPorts; i++) {
- printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n",
- p->name,
- p->pfacts[i].PortNumber,
- p->pfacts[i].ProtocolFlags,
- MPT_PROTOCOL_FLAGS_c_c_c_c(p->pfacts[i].ProtocolFlags));
-
- if (!(p->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
- printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n",
- p->name);
- continue;
- }
-
- dev = mpt_register_lan_device (p, i);
- if (!dev) {
- printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n",
- p->name,
- p->pfacts[i].PortNumber);
- }
- printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n",
- p->name, dev->name);
- printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\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]);
-// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n",
-// IOC_AND_NETDEV_NAMES_s_s(dev),
-// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out);
- j = p->id;
- mpt_landev[j] = dev;
- dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n",
- dev, j, mpt_landev[j]));
-
- }
- }
-
+ 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"));
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void __exit mpt_lan_exit(void)
{
- int i;
-
+ mpt_device_driver_deregister(MPTLAN_DRIVER);
mpt_reset_deregister(LanCtx);
- for (i = 0; mpt_landev[i] != NULL; i++) {
- struct net_device *dev = mpt_landev[i];
-
- printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n",
- IOC_AND_NETDEV_NAMES_s_s(dev));
- unregister_netdev(dev);
- free_netdev(dev);
- mpt_landev[i] = NULL;
- }
-
if (LanCtx >= 0) {
mpt_deregister(LanCtx);
LanCtx = -1;
mpt_lan_index = 0;
}
-
- /* deregister any send/receive handler structs. I2Oism? */
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
-MODULE_PARM(tx_max_out_p, "i");
-MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
-#endif
-
module_init(mpt_lan_init);
module_exit(mpt_lan_exit);