/*
* 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))
/*
* 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:
// diopri
|