patch-2.4.19 linux-2.4.19/drivers/message/fusion/mptbase.c
Next file: linux-2.4.19/drivers/message/fusion/mptbase.h
Previous file: linux-2.4.19/drivers/message/fusion/lsi/mpi_type.h
Back to the patch index
Back to the overall index
- Lines: 5150
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/message/fusion/mptbase.c
- Orig date:
Sun Sep 30 12:26:06 2001
diff -urN linux-2.4.18/drivers/message/fusion/mptbase.c linux-2.4.19/drivers/message/fusion/mptbase.c
@@ -20,6 +20,12 @@
* And to Roger Hickerson (LSI Logic) for tirelessly supporting
* this driver project.
*
+ * A special thanks to Pamela Delaney (LSI Logic) for tons of work
+ * and countless enhancements while adding support for the 1030
+ * chip family. Pam has been instrumental in the development of
+ * of the 2.xx.xx series fusion drivers, and her contributions are
+ * far too numerous to hope to list in one place.
+ *
* All manner of help from Stephen Shirron (LSI Logic):
* low-level FC analysis, debug + various fixes in FCxx firmware,
* initial port to alpha platform, various driver code optimizations,
@@ -38,11 +44,12 @@
* for gobs of hard work fixing and optimizing LAN code.
* THANK YOU!
*
- * Copyright (c) 1999-2001 LSI Logic Corporation
+ * Copyright (c) 1999-2002 LSI Logic Corporation
* Originally By: Steven J. Ralston
- * (mailto:Steve.Ralston@lsil.com)
+ * (mailto:sjralston1@netscape.net)
+ * (mailto:Pam.Delaney@lsil.com)
*
- * $Id: mptbase.c,v 1.53.4.3 2001/09/18 03:54:54 sralston Exp $
+ * $Id: mptbase.c,v 1.110 2002/02/27 18:44:20 sralston Exp $
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -93,11 +100,14 @@
#include <linux/kdev_t.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
-#include <linux/proc_fs.h>
+#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <asm/io.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
+#ifdef __sparc__
+#include <asm/irq.h> /* needed for __irq_itoa() proto */
+#endif
#include "mptbase.h"
@@ -110,27 +120,33 @@
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
-
/*
* cmd line parameters
*/
MODULE_PARM(PortIo, "0-1i");
MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
-MODULE_PARM(HardReset, "0-1i");
-MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset");
static int PortIo = 0;
-static int HardReset = 1;
+
+#ifdef MFCNT
+static int mfcounter = 0;
+#define PRINT_MF_COUNT 20000
+#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Public data...
*/
-int mpt_lan_index = 0;
-int mpt_stm_index = 0;
+int mpt_lan_index = -1;
+int mpt_stm_index = -1;
+
+struct proc_dir_entry *mpt_proc_root_dir;
+
+DmpServices_t *DmpService;
+
+void *mpt_v_ASCQ_TablePtr;
+const char **mpt_ScsiOpcodesPtr;
+int mpt_ASCQ_TableSz;
-void *mpt_v_ASCQ_TablePtr = NULL;
-const char **mpt_ScsiOpcodesPtr = NULL;
-int mpt_ASCQ_TableSz = 0;
#define WHOINIT_UNKNOWN 0xAA
@@ -139,12 +155,12 @@
* Private data...
*/
/* Adapter lookup table */
-static MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS] = {0};
+ MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS];
static MPT_ADAPTER_TRACKER MptAdapters;
/* Callback lookup table */
static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
/* Protocol driver class lookup table */
-static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
+static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
/* Event handler lookup table */
static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
/* Reset handler lookup table */
@@ -152,6 +168,10 @@
static int FusionInitCalled = 0;
static int mpt_base_index = -1;
+static int last_drv_idx = -1;
+static int isense_idx = -1;
+
+static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -160,49 +180,84 @@
static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
-static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason);
-static int mpt_adapter_install(struct pci_dev *pdev);
-static void mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
+static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
+static int mpt_adapter_install(struct pci_dev *pdev);
+static void mpt_detect_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
-static int MakeIocReady(MPT_ADAPTER *ioc, int force);
-static u32 GetIocState(MPT_ADAPTER *ioc, int cooked);
-static int GetIocFacts(MPT_ADAPTER *ioc);
-static int GetPortFacts(MPT_ADAPTER *ioc, int portnum);
-static int SendIocInit(MPT_ADAPTER *ioc);
-static int SendPortEnable(MPT_ADAPTER *ioc, int portnum);
-static int mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore);
-static int KickStart(MPT_ADAPTER *ioc, int ignore);
-static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
+static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
+//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
+static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
+static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
+static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
+static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
+static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
+static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
+static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
static int PrimeIocFifos(MPT_ADAPTER *ioc);
-static int HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait);
-static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong);
-static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong);
-static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong);
+static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
+static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int GetLanConfigPages(MPT_ADAPTER *ioc);
+static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
+static int GetIoUnitPage2(MPT_ADAPTER *ioc);
+static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
+static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
+static int mpt_findImVolumes(MPT_ADAPTER *ioc);
+static void mpt_timer_expired(unsigned long data);
static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
-static int procmpt_create(void);
#ifdef CONFIG_PROC_FS
+static int procmpt_create(void);
static int procmpt_destroy(void);
+static int procmpt_summary_read(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int procmpt_version_read(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
#endif
-static int procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data);
-/*static int procmpt_info(char *buf, char **start, off_t offset, int len);*/
+static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
+//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
-static struct proc_dir_entry *procmpt_root_dir = NULL;
-
int fusion_init(void);
static void fusion_exit(void);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * more Private data...
+ */
+#ifdef CONFIG_PROC_FS
+struct _mpt_proc_list {
+ const char *name;
+ int (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_proc_list[] = {
+ { "summary", procmpt_summary_read},
+ { "version", procmpt_version_read},
+};
+#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0]))
+
+struct _mpt_ioc_proc_list {
+ const char *name;
+ int (*f)(char *, char **, off_t, int, int *, void *);
+} mpt_ioc_proc_list[] = {
+ { "info", procmpt_iocinfo_read},
+ { "summary", procmpt_summary_read},
+};
+#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0]))
+
+#endif
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* 20000207 -sralston
* GRRRRR... IOSpace (port i/o) register access (for the 909) is back!
* 20000517 -sralston
@@ -225,9 +280,18 @@
writel(v, a);
}
+static inline void CHIPREG_PIO_WRITE32(volatile u32 *a, u32 v)
+{
+ outl(v, (unsigned long)a);
+}
+
+static inline u32 CHIPREG_PIO_READ32(volatile u32 *a)
+{
+ return inl((unsigned long)a);
+}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
* @irq: irq number (not used)
* @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
@@ -252,8 +316,7 @@
MPT_FRAME_HDR *mf;
MPT_FRAME_HDR *mr;
u32 pa;
- u32 *m;
- int req_idx;
+ int req_idx = -1;
int cb_idx;
int type;
int freeme;
@@ -262,6 +325,21 @@
ioc = bus_id;
/*
+ * Verify ioc pointer is ok
+ */
+ {
+ MPT_ADAPTER *iocCmp;
+ iocCmp = mpt_adapter_find_first();
+ while ((ioc != iocCmp) && iocCmp)
+ iocCmp = mpt_adapter_find_next(iocCmp);
+
+ if (!iocCmp) {
+ printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n");
+ return;
+ }
+ }
+
+ /*
* Drain the reply FIFO!
*
* NOTES: I've seen up to 10 replies processed in this loop, so far...
@@ -281,25 +359,27 @@
* Check for non-TURBO reply!
*/
if (pa & MPI_ADDRESS_REPLY_A_BIT) {
- dma_addr_t reply_dma_addr;
+ u32 reply_dma_low;
u16 ioc_stat;
/* non-TURBO reply! Hmmm, something may be up...
* Newest turbo reply mechanism; get address
* via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
*/
- reply_dma_addr = (pa = (pa << 1));
- /* Map DMA address of reply header to cpu address. */
- m = (u32 *) ((u8 *)ioc->reply_frames +
- (reply_dma_addr - ioc->reply_frames_dma));
+ /* Map DMA address of reply header to cpu address.
+ * pa is 32 bits - but the dma address may be 32 or 64 bits
+ * get offset based only only the low addresses
+ */
+ reply_dma_low = (pa = (pa << 1));
+ mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
+ (reply_dma_low - ioc->reply_frames_low_dma));
- mr = (MPT_FRAME_HDR *) m;
req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
- dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n",
+ dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n",
ioc->name, mr));
DBG_DUMP_REPLY_FRAME(mr)
@@ -307,7 +387,7 @@
* Check/log IOC log info
*/
ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
- if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+ if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
if ((int)ioc->chip_type <= (int)FC929)
mpt_fc_log_info(ioc, log_info);
@@ -318,7 +398,7 @@
/*
* Process turbo (context) reply...
*/
- dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa));
+ dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%08x)\n", ioc->name, pa));
type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
cb_idx = mpt_stm_index;
@@ -357,6 +437,34 @@
pa = 0; /* No reply flush! */
}
+ if ((int)ioc->chip_type > (int)FC929) {
+ /* Verify mf, mf are reasonable.
+ */
+ if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
+ || (mf < ioc->req_frames)) ) {
+ printk(MYIOC_s_WARN_FMT
+ "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, mf, req_idx);
+ cb_idx = 0;
+ pa = 0;
+ freeme = 0;
+ }
+ if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
+ || (mr < ioc->reply_frames)) ) {
+ printk(MYIOC_s_WARN_FMT
+ "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, mr);
+ cb_idx = 0;
+ pa = 0;
+ freeme = 0;
+ }
+ if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
+ printk(MYIOC_s_WARN_FMT
+ "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
+ cb_idx = 0;
+ pa = 0;
+ freeme = 0;
+ }
+ }
+
/* Check for (valid) IO callback! */
if (cb_idx) {
/* Do the callback! */
@@ -374,15 +482,18 @@
/* Put Request back on FreeQ! */
spin_lock_irqsave(&ioc->FreeQlock, flags);
Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+ ioc->mfcnt--;
+#endif
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
}
count++;
- dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count));
+ dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count));
mb();
if (count >= MPT_MAX_REPLIES_PER_ISR) {
- dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.",
+ dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.",
ioc->name, count));
dirqprintk((" Giving this ISR a break!\n"));
return;
@@ -409,17 +520,17 @@
int freereq = 1;
u8 func;
- dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name));
+ dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
if ((mf == NULL) ||
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
- printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n",
+ printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
ioc->name, mf);
return 1;
}
if (reply == NULL) {
- dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n",
+ dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
ioc->name));
return 1;
}
@@ -430,7 +541,7 @@
}
func = reply->u.hdr.Function;
- dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n",
+ dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
ioc->name, func));
if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -441,30 +552,77 @@
results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
if (results != evHandlers) {
/* CHECKME! Any special handling needed here? */
- dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n",
+ dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
ioc->name, evHandlers, results));
}
/*
- * Hmmm... It seems that EventNotificationReply is an exception
- * to the rule of one reply per request.
+ * Hmmm... It seems that EventNotificationReply is an exception
+ * to the rule of one reply per request.
*/
if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
freereq = 0;
+
#ifdef CONFIG_PROC_FS
// LogEvent(ioc, pEvReply);
#endif
+
} else if (func == MPI_FUNCTION_EVENT_ACK) {
- dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n",
+ dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
ioc->name));
+ } else if (func == MPI_FUNCTION_CONFIG) {
+ CONFIGPARMS *pCfg;
+ unsigned long flags;
+
+ dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+ ioc->name, mf, reply));
+
+ pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
+
+ if (pCfg) {
+ /* disable timer and remove from linked list */
+ del_timer(&pCfg->timer);
+
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ Q_DEL_ITEM(&pCfg->linkage);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+ /*
+ * If IOC Status is SUCCESS, save the header
+ * and set the status code to GOOD.
+ */
+ pCfg->status = MPT_CONFIG_ERROR;
+ if (reply) {
+ ConfigReply_t *pReply = (ConfigReply_t *)reply;
+ u16 status;
+
+ status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ dprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+ status, le32_to_cpu(pReply->IOCLogInfo)));
+
+ pCfg->status = status;
+ if (status == MPI_IOCSTATUS_SUCCESS) {
+ pCfg->hdr->PageVersion = pReply->Header.PageVersion;
+ pCfg->hdr->PageLength = pReply->Header.PageLength;
+ pCfg->hdr->PageNumber = pReply->Header.PageNumber;
+ pCfg->hdr->PageType = pReply->Header.PageType;
+ }
+ }
+
+ /*
+ * Wake up the original calling thread
+ */
+ pCfg->wait_done = 1;
+ wake_up(&mpt_waitq);
+ }
} else {
- printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n",
+ printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
ioc->name, func);
}
/*
- * Conditionally tell caller to free the original
- * EventNotification/EventAck/unexpected request frame!
+ * Conditionally tell caller to free the original
+ * EventNotification/EventAck/unexpected request frame!
*/
return freereq;
}
@@ -480,21 +638,22 @@
* protocol-specific driver must do this before it will be able to
* use any IOC resources, such as obtaining request frames.
*
- * NOTES: The SCSI protocol driver currently calls this routine twice
- * in order to register separate callbacks; one for "normal" SCSI IO
- * and another for MptScsiTaskMgmt requests.
+ * NOTES: The SCSI protocol driver currently calls this routine thrice
+ * in order to register separate callbacks; one for "normal" SCSI IO;
+ * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
*
* Returns a positive integer valued "handle" in the
- * range (and S.O.D. order) {7,6,...,1} if successful.
+ * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
* Any non-positive return value (including zero!) should be considered
* an error by the caller.
*/
int
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
{
- int r = -1;
int i;
+ last_drv_idx = -1;
+
#ifndef MODULE
/*
* Handle possibility of the mptscsih_detect() routine getting
@@ -512,7 +671,7 @@
#endif
/*
- * Search for empty callback slot in this order: {7,6,...,1}
+ * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
* (slot/handle 0 is reserved!)
*/
for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
@@ -520,7 +679,7 @@
MptCallbacks[i] = cbfunc;
MptDriverClass[i] = dclass;
MptEvHandlers[i] = NULL;
- r = i;
+ last_drv_idx = i;
if (cbfunc != mpt_base_reply) {
MOD_INC_USE_COUNT;
}
@@ -528,7 +687,7 @@
}
}
- return r;
+ return last_drv_idx;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -546,6 +705,11 @@
MptCallbacks[cb_idx] = NULL;
MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
MptEvHandlers[cb_idx] = NULL;
+
+ last_drv_idx++;
+ if (isense_idx != -1 && isense_idx <= cb_idx)
+ isense_idx++;
+
if (cb_idx != mpt_base_index) {
MOD_DEC_USE_COUNT;
}
@@ -639,7 +803,8 @@
* @handle: Handle of registered MPT protocol driver
* @iocid: IOC unique identifier (integer)
*
- * Returns pointer to a MPT request frame or %NULL if none are available.
+ * Returns pointer to a MPT request frame or %NULL if none are available
+ * or IOC is not active.
*/
MPT_FRAME_HDR*
mpt_get_msg_frame(int handle, int iocid)
@@ -650,6 +815,16 @@
/* validate handle and ioc identifier */
iocp = mpt_adapters[iocid];
+
+#ifdef MFCNT
+ if (!iocp->active)
+ printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+#endif
+
+ /* If interrupts are not attached, do not return a request frame */
+ if (!iocp->active)
+ return NULL;
+
spin_lock_irqsave(&iocp->FreeQlock, flags);
if (! Q_IS_EMPTY(&iocp->FreeQ)) {
int req_offset;
@@ -662,8 +837,20 @@
mf->u.frame.hwhdr.msgctxu.fld.req_idx =
cpu_to_le16(req_offset / iocp->req_sz);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+#ifdef MFCNT
+ iocp->mfcnt++;
+#endif
}
spin_unlock_irqrestore(&iocp->FreeQlock, flags);
+
+#ifdef MFCNT
+ if (mf == NULL)
+ printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth);
+ mfcounter++;
+ if (mfcounter == PRINT_MF_COUNT)
+ printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth);
+#endif
+
dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
iocp->name, handle, iocid, mf));
return mf;
@@ -687,7 +874,7 @@
iocp = mpt_adapters[iocid];
if (iocp != NULL) {
- dma_addr_t mf_dma_addr;
+ u32 mf_dma_addr;
int req_offset;
/* ensure values are reset properly! */
@@ -700,23 +887,23 @@
#ifdef MPT_DEBUG_MSG_FRAME
{
u32 *m = mf->u.frame.hwhdr.__hdr;
- int i, n;
+ int ii, n;
printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
iocp->name, m);
n = iocp->req_sz/4 - 1;
while (m[n] == 0)
n--;
- for (i=0; i<=n; i++) {
- if (i && ((i%8)==0))
+ for (ii=0; ii<=n; ii++) {
+ if (ii && ((ii%8)==0))
printk("\n" KERN_INFO " ");
- printk(" %08x", le32_to_cpu(m[i]));
+ printk(" %08x", le32_to_cpu(m[ii]));
}
printk("\n");
}
#endif
- mf_dma_addr = iocp->req_frames_dma + req_offset;
+ mf_dma_addr = iocp->req_frames_low_dma + req_offset;
CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr);
}
}
@@ -742,6 +929,9 @@
/* Put Request back on FreeQ! */
spin_lock_irqsave(&iocp->FreeQlock, flags);
Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR);
+#ifdef MFCNT
+ iocp->mfcnt--;
+#endif
spin_unlock_irqrestore(&iocp->FreeQlock, flags);
}
}
@@ -754,8 +944,9 @@
* @iocid: IOC unique identifier (integer)
* @reqBytes: Size of the request in bytes
* @req: Pointer to MPT request frame
+ * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
*
- * This routine is used exclusively by mptscsih to send MptScsiTaskMgmt
+ * This routine is used exclusively to send MptScsiTaskMgmt
* requests since they are required to be sent via doorbell handshake.
*
* NOTE: It is the callers responsibility to byte-swap fields in the
@@ -764,41 +955,30 @@
* Returns 0 for success, non-zero for failure.
*/
int
-mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req)
+mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag)
{
MPT_ADAPTER *iocp;
int r = 0;
iocp = mpt_adapters[iocid];
if (iocp != NULL) {
- u8 *req_as_bytes;
- u32 ioc_raw_state;
- int i;
-
- /* YIKES! We already know something is amiss.
- * Do upfront check on IOC state.
- */
- ioc_raw_state = GetIocState(iocp, 0);
- if ((ioc_raw_state & MPI_DOORBELL_ACTIVE) ||
- ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)) {
- printk(KERN_WARNING MYNAM ": %s: Bad IOC state (%08x) WARNING!\n",
- iocp->name, ioc_raw_state);
- if ((r = mpt_do_ioc_recovery(iocp, MPT_HOSTEVENT_IOC_RECOVER)) != 0) {
- printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
- r, iocp->name);
- return r;
- }
- }
+ u8 *req_as_bytes;
+ int ii;
+
+ /* State is known to be good upon entering
+ * this function so issue the bus reset
+ * request.
+ */
/*
* Emulate what mpt_put_msg_frame() does /wrt to sanity
* setting cb_idx/req_idx. But ONLY if this request
* is in proper (pre-alloc'd) request buffer range...
*/
- i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
- if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
+ ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
+ if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) {
MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
- mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i);
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
}
@@ -810,36 +990,40 @@
((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
/* Wait for IOC doorbell int */
- if ((i = WaitForDoorbellInt(iocp, 2)) < 0) {
- return i;
+ if ((ii = WaitForDoorbellInt(iocp, 2, sleepFlag)) < 0) {
+ return ii;
}
+ /* Read doorbell and check for active bit */
+ if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+ return -5;
+
dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
- iocp->name, i));
+ iocp->name, ii));
CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
- if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+ if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
return -2;
}
/* Send request via doorbell handshake */
req_as_bytes = (u8 *) req;
- for (i = 0; i < reqBytes/4; i++) {
+ for (ii = 0; ii < reqBytes/4; ii++) {
u32 word;
- word = ((req_as_bytes[(i*4) + 0] << 0) |
- (req_as_bytes[(i*4) + 1] << 8) |
- (req_as_bytes[(i*4) + 2] << 16) |
- (req_as_bytes[(i*4) + 3] << 24));
+ word = ((req_as_bytes[(ii*4) + 0] << 0) |
+ (req_as_bytes[(ii*4) + 1] << 8) |
+ (req_as_bytes[(ii*4) + 2] << 16) |
+ (req_as_bytes[(ii*4) + 3] << 24));
CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
- if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
+ if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
r = -3;
break;
}
}
- if ((r = WaitForDoorbellInt(iocp, 2)) >= 0)
+ if ((r = WaitForDoorbellInt(iocp, 10, sleepFlag)) >= 0)
r = 0;
else
r = -4;
@@ -871,8 +1055,8 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * mpt_adapter_find_next - Find next MPT adapter pointer.
- * @prev: Pointer to previous MPT adapter
+ * mpt_adapter_find_next - Find next MPT adapter pointer.
+ * @prev: Pointer to previous MPT adapter
*
* Returns next MPT adapter pointer or %NULL if there are no more.
*/
@@ -888,13 +1072,13 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* mpt_pci_scan - Scan PCI devices for MPT adapters.
*
* Returns count of MPT adapters found, keying off of PCI vendor and
* device_id's.
*/
-int __init
+static int __init
mpt_pci_scan(void)
{
struct pci_dev *pdev;
@@ -906,7 +1090,7 @@
dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n"));
/*
- * NOTE: The 929 (I believe) will appear as 2 separate PCI devices,
+ * NOTE: The 929 and 1030 will appear as 2 separate PCI devices,
* one for each channel.
*/
pci_for_each_dev(pdev) {
@@ -917,9 +1101,9 @@
if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
(pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+ (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
#if 0
/* FIXME! C103x family */
- (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
(pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
(pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) &&
#endif
@@ -929,7 +1113,7 @@
}
/* GRRRRR
- * 929 dual function devices may be presented in Func 1,0 order,
+ * dual function devices (929, 1030) may be presented in Func 1,0 order,
* but we'd really really rather have them in Func 0,1 order.
* Do some kind of look ahead here...
*/
@@ -937,11 +1121,11 @@
pdev2 = pci_peek_next_dev(pdev);
if (pdev2 && (pdev2->vendor == 0x1000) &&
(PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) &&
- (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
+ (pdev2->device == pdev->device) &&
(pdev2->bus->number == pdev->bus->number) &&
!(pdev2->devfn & 1)) {
dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n",
- pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
+ pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device));
found++;
if ((r = mpt_adapter_install(pdev2)) == 0)
count++;
@@ -969,9 +1153,7 @@
}
#ifdef CONFIG_PROC_FS
- if (procmpt_create() != 0)
- printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n",
- MPT_PROCFS_MPTBASEDIR);
+ (void) procmpt_create();
#endif
return count;
@@ -1004,7 +1186,7 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* mpt_adapter_install - Install a PCI intelligent MPT adapter.
* @pdev: Pointer to pci_dev structure
*
@@ -1030,7 +1212,7 @@
unsigned long port;
u32 msize;
u32 psize;
- int i;
+ int ii;
int r = -ENODEV;
int len;
@@ -1040,41 +1222,68 @@
return -ENOMEM;
}
memset(ioc, 0, sizeof(*ioc));
- ioc->req_sz = MPT_REQ_SIZE; /* avoid div by zero! */
ioc->alloc_total = sizeof(MPT_ADAPTER);
+ ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
+ ioc->reply_sz = ioc->req_sz;
ioc->pcidev = pdev;
+ ioc->diagPending = 0;
+ spin_lock_init(&ioc->diagLock);
+
+ /* Initialize the event logging.
+ */
+ ioc->eventTypes = 0; /* None */
+ ioc->eventContext = 0;
+ ioc->eventLogSize = 0;
+ ioc->events = NULL;
+
+#ifdef MFCNT
+ ioc->mfcnt = 0;
+#endif
+
+ /* Initialize the FW and Data image pointers.
+ */
+ ioc->FWImage = NULL;
+ ioc->FWImage_dma = 0;
+
+ /* Initilize SCSI Config Data structure
+ */
+ memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
+
+ /* Initialize the running configQ head.
+ */
+ Q_INIT(&ioc->configQ, Q_ITEM);
/* Find lookup slot. */
- for (i=0; i < MPT_MAX_ADAPTERS; i++) {
- if (mpt_adapters[i] == NULL) {
- ioc->id = i; /* Assign adapter unique id (lookup) */
+ for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) {
+ if (mpt_adapters[ii] == NULL) {
+ ioc->id = ii; /* Assign adapter unique id (lookup) */
break;
}
}
- if (i == MPT_MAX_ADAPTERS) {
- printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i);
+ if (ii == MPT_MAX_ADAPTERS) {
+ printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii);
kfree(ioc);
return -ENFILE;
}
mem_phys = msize = 0;
port = psize = 0;
- for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
- if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
+ for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
+ if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) {
/* Get I/O space! */
- port = pdev->PCI_BASEADDR_START(i);
- psize = PCI_BASEADDR_SIZE(pdev,i);
+ port = pdev->PCI_BASEADDR_START(ii);
+ psize = PCI_BASEADDR_SIZE(pdev,ii);
} else {
/* Get memmap */
- mem_phys = pdev->PCI_BASEADDR_START(i);
- msize = PCI_BASEADDR_SIZE(pdev,i);
+ mem_phys = pdev->PCI_BASEADDR_START(ii);
+ msize = PCI_BASEADDR_SIZE(pdev,ii);
break;
}
}
ioc->mem_size = msize;
- if (i == DEVICE_COUNT_RESOURCE) {
+ if (ii == DEVICE_COUNT_RESOURCE) {
printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
kfree(ioc);
return -EINVAL;
@@ -1098,6 +1307,8 @@
}
dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+ dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+ &ioc->facts, &ioc->pfacts[0]));
if (PortIo) {
u8 *pmem = (u8*)port;
ioc->mem_phys = port;
@@ -1107,6 +1318,13 @@
ioc->chip = (SYSIF_REGS*)mem;
}
+ /* Save Port IO values incase we need to do downloadboot */
+ {
+ u8 *pmem = (u8*)port;
+ ioc->pio_mem_phys = port;
+ ioc->pio_chip = (SYSIF_REGS*)pmem;
+ }
+
ioc->chip_type = FCUNK;
if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
ioc->chip_type = FC909;
@@ -1120,12 +1338,19 @@
ioc->chip_type = FC919;
ioc->prod_name = "LSIFC919";
}
-#if 0
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
ioc->chip_type = C1030;
ioc->prod_name = "LSI53C1030";
+ {
+ /* 1030 Chip Fix. Disable Split transactions
+ * for PCIX. Set bits 4 - 6 to zero.
+ */
+ u16 pcixcmd = 0;
+ pci_read_config_word(pdev, 0x6a, &pcixcmd);
+ pcixcmd &= 0xFF8F;
+ pci_write_config_word(pdev, 0x6a, pcixcmd);
+ }
}
-#endif
myname = "iocN";
len = strlen(myname);
@@ -1145,8 +1370,13 @@
r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
if (r < 0) {
- printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n",
+#ifndef __sparc__
+ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
ioc->name, pdev->irq);
+#else
+ printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
+ ioc->name, __irq_itoa(pdev->irq));
+#endif
iounmap(mem);
kfree(ioc);
return -EBUSY;
@@ -1156,7 +1386,11 @@
pci_set_master(pdev); /* ?? */
+#ifndef __sparc__
dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
+#else
+ dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
+#endif
}
/* tack onto tail of our MPT adapter list */
@@ -1166,12 +1400,12 @@
mpt_adapters[ioc->id] = ioc;
/* NEW! 20010220 -sralston
- * Check for "929 bound ports" to reduce redundant resets.
+ * Check for "bound ports" (929, 1030) to reduce redundant resets.
*/
- if (ioc->chip_type == FC929)
- mpt_detect_929_bound_ports(ioc, pdev);
+ if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030))
+ mpt_detect_bound_ports(ioc, pdev);
- if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) {
+ if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
ioc->name, r);
}
@@ -1180,10 +1414,11 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* mpt_do_ioc_recovery - Initialize or recover MPT adapter.
* @ioc: Pointer to MPT adapter structure
* @reason: Event word / reason
+ * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
*
* This routine performs all the steps necessary to bring the IOC
* to a OPERATIONAL state.
@@ -1191,16 +1426,21 @@
* This routine also pre-fetches the LAN MAC address of a Fibre Channel
* MPT adapter.
*
- * Returns 0 for success.
+ * Returns:
+ * 0 for success
+ * -1 if failed to get board READY
+ * -2 if READY but IOCFacts Failed
+ * -3 if READY but PrimeIOCFifos Failed
+ * -4 if READY but IOCInit Failed
*/
static int
-mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
+mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
{
int hard_reset_done = 0;
int alt_ioc_ready = 0;
int hard;
int r;
- int i;
+ int ii;
int handlers;
printk(KERN_INFO MYNAM ": Initiating %s %s\n",
@@ -1211,156 +1451,106 @@
ioc->active = 0;
/* NOTE: Access to IOC's request FreeQ is now blocked! */
-// FIXME? Cleanup all IOC requests here! (or below?)
-// But watch out for event associated request?
+ if (ioc->alt_ioc) {
+ /* Disable alt-IOC's reply interrupts for a bit ... */
+ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
+ ioc->alt_ioc->active = 0;
+ /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
+ }
- hard = HardReset;
- if (ioc->alt_ioc && (reason == MPT_HOSTEVENT_IOC_BRINGUP))
+ hard = 1;
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
hard = 0;
- if ((hard_reset_done = MakeIocReady(ioc, hard)) < 0) {
+ if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
ioc->name);
return -1;
}
-// NEW!
-#if 0 // Kiss-of-death!?!
- if (ioc->alt_ioc) {
-// Grrr... Hold off any alt-IOC interrupts (and events) while
-// handshaking to <this> IOC, needed because?
- /* Disable alt-IOC's reply interrupts for a bit ... */
- alt_ioc_intmask = CHIPREG_READ32(&ioc->alt_ioc->chip->IntMask);
- CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
- ioc->alt_ioc->active = 0;
- /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
- }
-#endif
-
+ /* hard_reset_done = 0 if a soft reset was performed
+ * and 1 if a hard reset was performed.
+ */
if (hard_reset_done && ioc->alt_ioc) {
- if ((r = MakeIocReady(ioc->alt_ioc, 0)) == 0)
+ if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
alt_ioc_ready = 1;
else
- printk(KERN_WARNING MYNAM ": alt-%s: (%d) Not ready WARNING!\n",
+ printk(KERN_WARNING MYNAM
+ ": alt-%s: (%d) Not ready WARNING!\n",
ioc->alt_ioc->name, r);
}
+ /* Get IOC facts! */
+ if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
+ return -2;
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
- /* Get IOC facts! */
- if ((r = GetIocFacts(ioc)) != 0)
- return -2;
MptDisplayIocCapabilities(ioc);
}
- /*
- * Call each currently registered protocol IOC reset handler
- * with pre-reset indication.
- * NOTE: If we're doing _IOC_BRINGUP, there can be no
- * MptResetHandlers[] registered yet.
- */
- if (hard_reset_done) {
- r = handlers = 0;
- for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
- if (MptResetHandlers[i]) {
- dprintk((KERN_INFO MYNAM ": %s: Calling IOC pre_reset handler #%d\n",
- ioc->name, i));
- r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_PRE_RESET);
- handlers++;
-
- if (alt_ioc_ready) {
- dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC pre_reset handler #%d\n",
- ioc->alt_ioc->name, i));
- r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
- handlers++;
- }
- }
- }
- /* FIXME? Examine results here? */
- }
-
- // May need to check/upload firmware & data here!
-
- if ((r = SendIocInit(ioc)) != 0)
- return -3;
-// NEW!
if (alt_ioc_ready) {
- if ((r = SendIocInit(ioc->alt_ioc)) != 0) {
- alt_ioc_ready = 0;
- printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n",
- ioc->alt_ioc->name, r);
- }
- }
-
- /*
- * Call each currently registered protocol IOC reset handler
- * with post-reset indication.
- * NOTE: If we're doing _IOC_BRINGUP, there can be no
- * MptResetHandlers[] registered yet.
- */
- if (hard_reset_done) {
- r = handlers = 0;
- for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
- if (MptResetHandlers[i]) {
- dprintk((KERN_INFO MYNAM ": %s: Calling IOC post_reset handler #%d\n",
- ioc->name, i));
- r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_POST_RESET);
- handlers++;
-
- if (alt_ioc_ready) {
- dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC post_reset handler #%d\n",
- ioc->alt_ioc->name, i));
- r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
- handlers++;
- }
- }
+ if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0)
+ return -2;
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+ MptDisplayIocCapabilities(ioc->alt_ioc);
}
- /* FIXME? Examine results here? */
}
/*
* Prime reply & request queues!
- * (mucho alloc's)
+ * (mucho alloc's) Must be done prior to
+ * init as upper addresses are needed for init.
*/
if ((r = PrimeIocFifos(ioc)) != 0)
+ return -3;
+
+ // May need to check/upload firmware & data here!
+ if ((r = SendIocInit(ioc, sleepFlag)) != 0)
return -4;
// NEW!
if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
ioc->alt_ioc->name, r);
+ alt_ioc_ready = 0;
}
-// FIXME! Cleanup all IOC (and alt-IOC?) requests here!
+ if (alt_ioc_ready) {
+ if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
+ alt_ioc_ready = 0;
+ printk(KERN_WARNING MYNAM
+ ": alt-%s: (%d) init failure WARNING!\n",
+ ioc->alt_ioc->name, r);
+ }
+ }
- if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
- (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
- /*
- * Pre-fetch the ports LAN MAC address!
- * (LANPage1_t stuff)
- */
- (void) GetLanConfigPages(ioc);
-#ifdef MPT_DEBUG
- {
- u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
- dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
- ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
+ if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+ dprintk((MYIOC_s_INFO_FMT
+ "firmware upload required!\n", ioc->name));
+
+ r = mpt_do_upload(ioc, sleepFlag);
+ if (r != 0)
+ printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+ /* Handle the alt IOC too */
+ if (alt_ioc_ready){
+ r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
+ if (r != 0)
+ printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+ }
}
-#endif
}
+
/* Enable! (reply interrupt) */
CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
ioc->active = 1;
-// NEW!
-#if 0 // Kiss-of-death!?!
- if (alt_ioc_ready && (r==0)) {
+ if (ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt) */
dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
ioc->alt_ioc->active = 1;
}
-#endif
/* NEW! 20010120 -sralston
* Enable MPT base driver management of EventNotification
@@ -1368,19 +1558,95 @@
*/
if (!ioc->facts.EventState)
(void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
-// NEW!
-// FIXME!?!
-// if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) {
-// (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
-// }
+
+ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
+ (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
+
+ /* (Bugzilla:fibrebugs, #513)
+ * Bug fix (part 2)! 20010905 -sralston
+ * Add additional "reason" check before call to GetLanConfigPages
+ * (combined with GetIoUnitPage2 call). This prevents a somewhat
+ * recursive scenario; GetLanConfigPages times out, timer expired
+ * routine calls HardResetHandler, which calls into here again,
+ * and we try GetLanConfigPages again...
+ */
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+ if ((int)ioc->chip_type <= (int)FC929) {
+ /*
+ * Pre-fetch FC port WWN and stuff...
+ * (FCPortPage0_t stuff)
+ */
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ (void) GetFcPortPage0(ioc, ii);
+ }
+
+ if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+ (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
+ /*
+ * Pre-fetch the ports LAN MAC address!
+ * (LANPage1_t stuff)
+ */
+ (void) GetLanConfigPages(ioc);
+#ifdef MPT_DEBUG
+ {
+ u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
+ }
+#endif
+ }
+ } else {
+ /* Get NVRAM and adapter maximums from SPP 0 and 2
+ */
+ mpt_GetScsiPortSettings(ioc, 0);
+
+ /* Get version and length of SDP 1
+ */
+ mpt_readScsiDevicePageHeaders(ioc, 0);
+
+ /* Find IM volumes
+ */
+ if (ioc->facts.MsgVersion >= 0x0102)
+ mpt_findImVolumes(ioc);
+ }
+
+ GetIoUnitPage2(ioc);
+ }
+
+ /*
+ * Call each currently registered protocol IOC reset handler
+ * with post-reset indication.
+ * NOTE: If we're doing _IOC_BRINGUP, there can be no
+ * MptResetHandlers[] registered yet.
+ */
+ if (hard_reset_done) {
+ r = handlers = 0;
+ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ if (MptResetHandlers[ii]) {
+ dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
+ ioc->name, ii));
+ r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
+ handlers++;
+
+ if (alt_ioc_ready) {
+ dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+ ioc->name, ioc->alt_ioc->name, ii));
+ r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+ handlers++;
+ }
+ }
+ }
+ /* FIXME? Examine results here? */
+ }
return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * mpt_detect_929_bound_ports - Search for PCI bus/dev_function
- * which matches PCI bus/dev_function (+/-1) for newly discovered 929.
+ * mpt_detect_bound_ports - Search for PCI bus/dev_function
+ * which matches PCI bus/dev_function (+/-1) for newly discovered 929
+ * or 1030.
* @ioc: Pointer to MPT adapter structure
* @pdev: Pointer to (struct pci_dev) structure
*
@@ -1388,22 +1654,22 @@
* using alt_ioc pointer fields in their %MPT_ADAPTER structures.
*/
static void
-mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
+mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
{
MPT_ADAPTER *ioc_srch = mpt_adapter_find_first();
unsigned int match_lo, match_hi;
match_lo = pdev->devfn-1;
match_hi = pdev->devfn+1;
- dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
+ dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n",
ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi));
while (ioc_srch != NULL) {
struct pci_dev *_pcidev = ioc_srch->pcidev;
- if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) &&
- (_pcidev->bus->number == pdev->bus->number) &&
- (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
+ if ((_pcidev->device == pdev->device) &&
+ (_pcidev->bus->number == pdev->bus->number) &&
+ (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) {
/* Paranoia checks */
if (ioc->alt_ioc != NULL) {
printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
@@ -1418,8 +1684,6 @@
ioc->name, ioc_srch->name));
ioc_srch->alt_ioc = ioc;
ioc->alt_ioc = ioc_srch;
- ioc->sod_reset = ioc->alt_ioc->sod_reset;
- ioc->last_kickstart = ioc->alt_ioc->last_kickstart;
break;
}
ioc_srch = mpt_adapter_find_next(ioc_srch);
@@ -1440,10 +1704,10 @@
u32 state;
/* Disable the FW */
- state = GetIocState(this, 1);
+ state = mpt_GetIocState(this, 1);
if (state == MPI_IOC_STATE_OPERATIONAL) {
- if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) != 0)
- (void) KickStart(this, 1);
+ if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0)
+ (void) KickStart(this, 1, NO_SLEEP);
}
/* Disable adapter interrupts! */
@@ -1475,12 +1739,37 @@
}
if (freeup && this->sense_buf_pool != NULL) {
- sz = (this->req_depth * 256);
+ sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC);
pci_free_consistent(this->pcidev, sz,
this->sense_buf_pool, this->sense_buf_pool_dma);
this->sense_buf_pool = NULL;
this->alloc_total -= sz;
}
+
+ if (freeup && this->events != NULL){
+ sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
+ kfree(this->events);
+ this->events = NULL;
+ this->alloc_total -= sz;
+ }
+
+ if (freeup && this->FWImage != NULL) {
+ sz = this->facts.FWImageSize;
+ pci_free_consistent(this->pcidev, sz,
+ this->FWImage, this->FWImage_dma);
+ this->FWImage = NULL;
+ this->alloc_total -= sz;
+ }
+
+ if (freeup && this->spi_data.nvram != NULL) {
+ kfree(this->spi_data.nvram);
+ this->spi_data.nvram = NULL;
+ }
+
+ if (freeup && this->spi_data.pIocPg3 != NULL) {
+ kfree(this->spi_data.pIocPg3);
+ this->spi_data.pIocPg3 = NULL;
+ }
}
}
@@ -1575,23 +1864,30 @@
/*
* MakeIocReady - Get IOC to a READY state, using KickStart if needed.
* @ioc: Pointer to MPT_ADAPTER structure
- * @kick: Force hard KickStart of IOC
+ * @force: Force hard KickStart of IOC
+ * @sleepFlag: Specifies whether the process can sleep
*
- * Returns 0 for already-READY, 1 for hard reset success,
- * else negative for failure.
+ * Returns:
+ * 1 - DIAG reset and READY
+ * 0 - READY initially OR soft reset and READY
+ * -1 - Any failure on KickStart
+ * -2 - Msg Unit Reset Failed
+ * -3 - IO Unit Reset Failed
+ * -4 - IOC owned by a PEER
*/
static int
-MakeIocReady(MPT_ADAPTER *ioc, int force)
+MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
{
u32 ioc_state;
int statefault = 0;
- int cntdn;
+ int cntdn;
int hard_reset_done = 0;
int r;
- int i;
+ int ii;
+ int whoinit;
/* Get current [raw] IOC state */
- ioc_state = GetIocState(ioc, 0);
+ ioc_state = mpt_GetIocState(ioc, 0);
dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
/*
@@ -1600,7 +1896,7 @@
*/
if (ioc_state & MPI_DOORBELL_ACTIVE) {
statefault = 1;
- printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+ printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
ioc->name);
}
@@ -1613,7 +1909,7 @@
*/
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
statefault = 2;
- printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
ioc->name);
printk(KERN_WARNING " FAULT code = %04xh\n",
ioc_state & MPI_DOORBELL_DATA_MASK);
@@ -1623,28 +1919,49 @@
* Hmmm... Did it get left operational?
*/
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
- statefault = 3;
- dprintk((KERN_WARNING MYNAM ": %s: Hmmm... IOC operational unexpected\n",
+ dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
ioc->name));
+
+ /* Check WhoInit.
+ * If PCI Peer, exit.
+ * Else, if no fault conditions are present, issue a MessageUnitReset
+ * Else, fall through to KickStart case
+ */
+ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
+ dprintk((KERN_WARNING MYNAM
+ ": whoinit 0x%x\n statefault %d force %d\n",
+ whoinit, statefault, force));
+ if (whoinit == MPI_WHOINIT_PCI_PEER)
+ return -4;
+ else {
+ if ((statefault == 0 ) && (force == 0)) {
+ if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+ return 0;
+ }
+ statefault = 3;
+ }
}
- hard_reset_done = KickStart(ioc, statefault||force);
+ hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
if (hard_reset_done < 0)
return -1;
/*
* Loop here waiting for IOC to come READY.
*/
- i = 0;
+ ii = 0;
cntdn = HZ * 15;
- while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+ if (sleepFlag != CAN_SLEEP)
+ cntdn *= 10; /* 1500 iterations @ 1msec per */
+
+ while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
/*
* BIOS or previous driver load left IOC in OP state.
* Reset messaging FIFOs.
*/
- if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
- printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+ if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
+ printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
return -2;
}
} else if (ioc_state == MPI_IOC_STATE_RESET) {
@@ -1652,25 +1969,30 @@
* Something is wrong. Try to get IOC back
* to a known state.
*/
- if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
- printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+ if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
+ printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
return -3;
}
}
- i++; cntdn--;
+ ii++; cntdn--;
if (!cntdn) {
- printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
- ioc->name, (i+5)/HZ);
+ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+ ioc->name, (ii+5)/HZ);
return -ETIME;
}
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ } else {
+ mdelay (1); /* 1 msec delay */
+ }
+
}
if (statefault < 3) {
- printk(KERN_WARNING MYNAM ": %s: Whew! Recovered from %s\n",
+ printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
ioc->name,
statefault==1 ? "stuck handshake" : "IOC FAULT");
}
@@ -1680,21 +2002,21 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * GetIocState - Get the current state of a MPT adapter.
+ * mpt_GetIocState - Get the current state of a MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @cooked: Request raw or cooked IOC state
*
* Returns all IOC Doorbell register bits if cooked==0, else just the
* Doorbell bits in MPI_IOC_STATE_MASK.
*/
-static u32
-GetIocState(MPT_ADAPTER *ioc, int cooked)
+u32
+mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
{
u32 s, sc;
/* Get! */
s = CHIPREG_READ32(&ioc->chip->Doorbell);
- dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s));
+// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
sc = s & MPI_IOC_STATE_MASK;
/* Save! */
@@ -1707,11 +2029,13 @@
/*
* GetIocFacts - Send IOCFacts request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
+ * @sleepFlag: Specifies whether the process can sleep
+ * @reason: If recovery, only update facts.
*
* Returns 0 for success, non-zero for failure.
*/
static int
-GetIocFacts(MPT_ADAPTER *ioc)
+GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
{
IOCFacts_t get_facts;
IOCFactsReply_t *facts;
@@ -1741,14 +2065,13 @@
get_facts.Function = MPI_FUNCTION_IOC_FACTS;
/* Assert: All other get_facts fields are zero! */
- dprintk((KERN_INFO MYNAM ": %s: Sending get IocFacts request\n", ioc->name));
+ dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name));
/* No non-zero fields in the get_facts request are greater than
* 1 byte in size, so we can just fire it off as is.
*/
- r = HandShakeReqAndReply(ioc,
- req_sz, (u32*)&get_facts,
- reply_sz, (u16*)facts, 3);
+ r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
+ reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag);
if (r != 0)
return r;
@@ -1761,14 +2084,17 @@
*/
/* Did we get a valid reply? */
if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
- /*
- * If not been here, done that, save off first WhoInit value
- */
- if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
- ioc->FirstWhoInit = facts->WhoInit;
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+ /*
+ * If not been here, done that, save off first WhoInit value
+ */
+ if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
+ ioc->FirstWhoInit = facts->WhoInit;
+ }
facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
facts->MsgContext = le32_to_cpu(facts->MsgContext);
+ facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
@@ -1776,7 +2102,23 @@
facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
- facts->FWVersion = le16_to_cpu(facts->FWVersion);
+
+ /*
+ * FC f/w version changed between 1.1 and 1.2
+ * Old: u16{Major(4),Minor(4),SubMinor(8)}
+ * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
+ */
+ if (facts->MsgVersion < 0x0102) {
+ /*
+ * Handle old FC f/w style, convert to new...
+ */
+ u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
+ facts->FWVersion.Word =
+ ((oldv<<12) & 0xFF000000) |
+ ((oldv<<8) & 0x000FFF00);
+ } else
+ facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
+
facts->ProductID = le16_to_cpu(facts->ProductID);
facts->CurrentHostMfaHighAddr =
le32_to_cpu(facts->CurrentHostMfaHighAddr);
@@ -1791,52 +2133,42 @@
* Older MPI-1.00.xx struct had 13 dwords, and enlarged
* to 14 in MPI-1.01.0x.
*/
- if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
+ if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
+ facts->MsgVersion > 0x0100) {
facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
- facts->DataImageSize = le32_to_cpu(facts->DataImageSize);
}
- if (facts->RequestFrameSize) {
- /*
- * Set values for this IOC's REQUEST queue size & depth...
- */
- ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
-
- /*
- * Set values for this IOC's REPLY queue size & depth...
- *
- * BUG? FIX? 20000516 -nromer & sralston
- * GRRR... The following did not translate well from MPI v0.09:
- * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4);
- * to 0.10:
- * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4);
- * Was trying to minimally optimize to smallest possible reply size
- * (and greatly reduce kmalloc size). But LAN may need larger reply?
- *
- * So for now, just set reply size to request size. FIXME?
- */
- ioc->reply_sz = ioc->req_sz;
- } else {
+ if (!facts->RequestFrameSize) {
/* Something is wrong! */
- printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n",
+ printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
ioc->name);
- ioc->req_sz = MPT_REQ_SIZE;
- ioc->reply_sz = MPT_REPLY_SIZE;
return -55;
}
- ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits);
- ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth);
- dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n",
+ if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+ /*
+ * Set values for this IOC's request & reply frame sizes,
+ * and request & reply queue depths...
+ */
+ ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
+ ioc->req_depth = MIN(MPT_DEFAULT_REQ_DEPTH, facts->GlobalCredits);
+ ioc->reply_sz = ioc->req_sz;
+ ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
+
+ /* 1030 - should we use a smaller DEFAULT_REPLY_DEPTH?
+ * FIX
+ */
+ dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
ioc->name, ioc->reply_sz, ioc->reply_depth));
- dprintk((KERN_INFO MYNAM ": %s: req_sz =%3d, req_depth =%4d\n",
+ dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
ioc->name, ioc->req_sz, ioc->req_depth));
- /* Get port facts! */
- if ( (r = GetPortFacts(ioc, 0)) != 0 )
- return r;
+ /* Get port facts! */
+ if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
+ return r;
+ }
} else {
- printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
+ printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n",
ioc->name);
return -66;
}
@@ -1849,15 +2181,16 @@
* GetPortFacts - Send PortFacts request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @portnum: Port number
+ * @sleepFlag: Specifies whether the process can sleep
*
* Returns 0 for success, non-zero for failure.
*/
static int
-GetPortFacts(MPT_ADAPTER *ioc, int portnum)
+GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
{
PortFacts_t get_pfacts;
PortFactsReply_t *pfacts;
- int i;
+ int ii;
int req_sz;
int reply_sz;
@@ -1883,16 +2216,16 @@
get_pfacts.PortNumber = portnum;
/* Assert: All other get_pfacts fields are zero! */
- dprintk((KERN_INFO MYNAM ": %s: Sending get PortFacts(%d) request\n",
+ dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
ioc->name, portnum));
/* No non-zero fields in the get_pfacts request are greater than
* 1 byte in size, so we can just fire it off as is.
*/
- i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
- reply_sz, (u16*)pfacts, 3);
- if (i != 0)
- return i;
+ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
+ reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag);
+ if (ii != 0)
+ return ii;
/* Did we get a valid reply? */
@@ -1914,13 +2247,14 @@
/*
* SendIocInit - Send IOCInit request to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
+ * @sleepFlag: Specifies whether the process can sleep
*
* Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
*
* Returns 0 for success, non-zero for failure.
*/
static int
-SendIocInit(MPT_ADAPTER *ioc)
+SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
{
IOCInit_t ioc_init;
MPIDefaultReply_t init_reply;
@@ -1937,20 +2271,35 @@
ioc_init.Function = MPI_FUNCTION_IOC_INIT;
/* ioc_init.Flags = 0; */
- /*ioc_init.MaxDevices = 16;*/
- ioc_init.MaxDevices = 255;
-/* ioc_init.MaxBuses = 16; */
- ioc_init.MaxBuses = 1;
+ if ((int)ioc->chip_type <= (int)FC929) {
+ ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
+ }
+ else {
+ ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
+ }
+ ioc_init.MaxBuses = MPT_MAX_BUS;
/* ioc_init.MsgFlags = 0; */
/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */
ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
- ioc_init.HostMfaHighAddr = cpu_to_le32(0); /* Say we 32-bit! for now */
- dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
+#ifdef __ia64__
+ /* Save the upper 32-bits of the request
+ * (reply) and sense buffers.
+ */
+ ioc_init.HostMfaHighAddr = cpu_to_le32((u32)(ioc->req_frames_dma >> 32));
+ ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)(ioc->sense_buf_pool_dma >> 32));
+#else
+ /* Force 32-bit addressing */
+ ioc_init.HostMfaHighAddr = cpu_to_le32(0);
+ ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
+#endif
- r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
- sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10);
+ dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+ ioc->name, &ioc_init));
+
+ r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
+ sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
if (r != 0)
return r;
@@ -1958,7 +2307,7 @@
* since we don't even look at it's contents.
*/
- if ((r = SendPortEnable(ioc, 0)) != 0)
+ if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
return r;
/* YIKES! SUPER IMPORTANT!!!
@@ -1967,21 +2316,27 @@
*/
count = 0;
cntdn = HZ * 60; /* chg'd from 30 to 60 seconds */
- state = GetIocState(ioc, 1);
+ if (sleepFlag != CAN_SLEEP)
+ cntdn *= 10; /* scale for 1msec delays */
+ state = mpt_GetIocState(ioc, 1);
while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ } else {
+ mdelay(1);
+ }
if (!cntdn) {
- printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n",
+ printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
ioc->name, (count+5)/HZ);
return -9;
}
- state = GetIocState(ioc, 1);
+ state = mpt_GetIocState(ioc, 1);
count++;
}
- dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
return r;
@@ -1992,17 +2347,18 @@
* SendPortEnable - Send PortEnable request to MPT adapter port.
* @ioc: Pointer to MPT_ADAPTER structure
* @portnum: Port number to enable
+ * @sleepFlag: Specifies whether the process can sleep
*
* Send PortEnable to bring IOC to OPERATIONAL state.
*
* Returns 0 for success, non-zero for failure.
*/
static int
-SendPortEnable(MPT_ADAPTER *ioc, int portnum)
+SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
{
PortEnable_t port_enable;
MPIDefaultReply_t reply_buf;
- int i;
+ int ii;
int req_sz;
int reply_sz;
@@ -2019,13 +2375,21 @@
/* port_enable.MsgFlags = 0; */
/* port_enable.MsgContext = 0; */
- dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n",
+ dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
ioc->name, portnum, &port_enable));
- i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
- reply_sz, (u16*)&reply_buf, 65);
- if (i != 0)
- return i;
+ /* RAID FW may take a long time to enable
+ */
+ if ((int)ioc->chip_type <= (int)FC929) {
+ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+ reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
+ } else {
+ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
+ reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+ }
+
+ if (ii != 0)
+ return ii;
/* We do not even look at the reply, so we need not
* swap the multi-byte fields.
@@ -2036,19 +2400,341 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
+ * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sleepFlag: Specifies whether the process can sleep
+ *
+ * Returns 0 for success, >0 for handshake failure
+ * <0 for fw upload failure.
+ *
+ * Remark: If bound IOC and a successful FWUpload was performed
+ * on the bound IOC, the second image is discarded
+ * and memory is free'd. Both channels must upload to prevent
+ * IOC from running in degraded mode.
+ */
+static int
+mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
+{
+ u8 request[sizeof(FWUpload_t) + 24];
+ u8 reply[sizeof(FWUploadReply_t)];
+ FWUpload_t *prequest;
+ FWUploadReply_t *preply;
+ FWUploadTCSGE_t *ptcsge = NULL;
+ MptSge_t *psge;
+ u8 *mem;
+ dma_addr_t dma_addr;
+ int sgeoffset;
+ int i, sz, req_sz, reply_sz;
+ int cmdStatus, freeMem = 0;
+
+ /* If the image size is 0 or if the pointer is
+ * not NULL (error), we are done.
+ */
+ if (((sz = ioc->facts.FWImageSize) == 0) || ioc->FWImage)
+ return 0;
+
+ /* Allocate memory
+ */
+ mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->FWImage_dma);
+ if (mem == NULL)
+ return -1;
+
+ memset(mem, 0, sz);
+ ioc->alloc_total += sz;
+ ioc->FWImage = mem;
+ dprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d bytes\n",
+ mem, (void *)(ulong)ioc->FWImage_dma, sz));
+
+ dma_addr = ioc->FWImage_dma;
+
+ prequest = (FWUpload_t *)&request;
+ preply = (FWUploadReply_t *)&reply;
+
+ /* Destination... */
+ req_sz = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION)
+ + sizeof(FWUploadTCSGE_t) + sizeof(MptSge_t);
+ memset(prequest, 0, req_sz);
+
+ reply_sz = sizeof(reply);
+ memset(preply, 0, reply_sz);
+
+ prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
+ prequest->Function = MPI_FUNCTION_FW_UPLOAD;
+ prequest->MsgContext = 0; /* anything */
+
+ ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
+ ptcsge->Reserved = 0;
+ ptcsge->ContextSize = 0;
+ ptcsge->DetailsLength = 12;
+ ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
+ ptcsge->Reserved1 = 0;
+ ptcsge->ImageOffset = 0;
+ ptcsge->ImageSize = cpu_to_le32(sz);
+
+ sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
+ psge = (MptSge_t *) &request[sgeoffset];
+ psge->FlagsLength = cpu_to_le32(MPT_SGE_FLAGS_SSIMPLE_READ | (u32) sz);
+
+ cpu_to_leXX(dma_addr, psge->Address);
+
+ dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p)\n",
+ ioc->name, prequest));
+
+ i = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)prequest,
+ reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
+
+ cmdStatus = -EFAULT;
+ if (i == 0) {
+ /* Handshake transfer was complete and successful.
+ * Check the Reply Frame.
+ */
+ int status, transfer_sz;
+ status = le16_to_cpu(preply->IOCStatus);
+ if (status == MPI_IOCSTATUS_SUCCESS) {
+ transfer_sz = le32_to_cpu(preply->ActualImageSize);
+ if (transfer_sz == sz)
+ cmdStatus = 0;
+ }
+ }
+ dprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
+ ioc->name, cmdStatus));
+
+ /* Check to see if we have a copy of this image in
+ * host memory already.
+ */
+ if (cmdStatus == 0) {
+ if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
+ freeMem = 1;
+ }
+
+ /* We already have a copy of this image or
+ * we had some type of an error - either the handshake
+ * failed (i != 0) or the command did not complete successfully.
+ */
+ if (cmdStatus || freeMem) {
+ dprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n",
+ ioc->name, cmdStatus ? "incomplete" : "duplicate"));
+
+ pci_free_consistent(ioc->pcidev, sz,
+ ioc->FWImage, ioc->FWImage_dma);
+ ioc->FWImage = NULL;
+ ioc->alloc_total -= sz;
+ }
+
+ return cmdStatus;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_downloadboot - DownloadBoot code
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @flag: Specify which part of IOC memory is to be uploaded.
+ * @sleepFlag: Specifies whether the process can sleep
+ *
+ * FwDownloadBoot requires Programmed IO access.
+ *
+ * Returns 0 for success
+ * -1 FW Image size is 0
+ * -2 No valid FWImage Pointer
+ * <0 for fw upload failure.
+ */
+static int
+mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
+{
+ MpiFwHeader_t *FwHdr = NULL;
+ MpiExtImageHeader_t *ExtHdr;
+ int fw_sz;
+ u32 diag0val;
+#ifdef MPT_DEBUG
+ u32 diag1val = 0;
+#endif
+ int count = 0;
+ u32 *ptru32 = NULL;
+ u32 diagRwData;
+ u32 nextImage;
+
+ dprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n",
+ ioc->name));
+#ifdef MPT_DEBUG
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+#endif
+
+ dprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n",
+ ioc->name, ioc->facts.FWImageSize, ioc->FWImage));
+ if (ioc->alt_ioc)
+ dprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n",
+ ioc->name, ioc->alt_ioc->FWImage));
+
+ /* Get dma_addr and data transfer size.
+ */
+ if ((fw_sz = ioc->facts.FWImageSize) == 0)
+ return -1;
+
+ /* Get the DMA from ioc or ioc->alt_ioc */
+ if (ioc->FWImage)
+ FwHdr = (MpiFwHeader_t *)ioc->FWImage;
+ else if (ioc->alt_ioc && ioc->alt_ioc->FWImage)
+ FwHdr = (MpiFwHeader_t *)ioc->alt_ioc->FWImage;
+
+ dprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n",
+ ioc->name, FwHdr));
+
+ if (!FwHdr)
+ return -2;
+
+ /* Write magic sequence to WriteSequence register
+ * until enter diagnostic mode
+ */
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ while ((diag0val & MPI_DIAG_DRWE) == 0) {
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+ /* wait 100 msec */
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(100 * HZ / 1000);
+ } else {
+ mdelay (100);
+ }
+
+ count++;
+ if (count > 20) {
+ printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+ ioc->name, diag0val);
+ return -EFAULT;
+
+ }
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+#endif
+ dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+ ioc->name, diag0val));
+ }
+
+ /* Set the DiagRwEn and Disable ARM bits */
+ diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+#ifdef MPT_DEBUG
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+#endif
+
+ /* Write the LoadStartAddress to the DiagRw Address Register
+ * using Programmed IO
+ */
+
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress);
+ dprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+ ioc->name, FwHdr->LoadStartAddress));
+
+ nextImage = FwHdr->NextImageHeaderOffset;
+
+ /* round up count to a 32bit alignment */
+ ptru32 = (u32 *) FwHdr;
+ count = (FwHdr->ImageSize + 3)/4;
+
+ dprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n",
+ ioc->name, count, ptru32));
+ while (count-- ) {
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+ ptru32++;
+ }
+
+ dprintk((MYIOC_s_INFO_FMT "FW Image done! \n", ioc->name));
+
+ while (nextImage) {
+
+ /* Set the pointer to the extended image
+ */
+ ExtHdr = (MpiExtImageHeader_t *) ((char *) FwHdr + nextImage);
+
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, ExtHdr->LoadStartAddress);
+
+ count = (ExtHdr->ImageSize + 3 )/4;
+
+ ptru32 = (u32 *) ExtHdr;
+ dprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n",
+ ioc->name, count, ptru32));
+ while (count-- ) {
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32);
+ ptru32++;
+ }
+ nextImage = ExtHdr->NextImageHeaderOffset;
+ }
+
+
+ /* Write the IopResetVectorRegAddr */
+ dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name));
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr);
+
+ /* Write the IopResetVectorValue */
+ dprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name));
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue);
+
+ /* Clear the internal flash bad bit - autoincrementing register,
+ * so must do two writes.
+ */
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+ diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
+ diagRwData |= 0x4000000;
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
+ CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
+
+ /* clear the RW enable and DISARM bits */
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+
+ /* Write 0xFF to reset the sequencer */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
+
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
* KickStart - Perform hard reset of MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
* @force: Force hard reset
+ * @sleepFlag: Specifies whether the process can sleep
*
* This routine places MPT adapter in diagnostic mode via the
* WriteSequence register, and then performs a hard reset of adapter
* via the Diagnostic register.
*
- * Returns 0 for soft reset success, 1 for hard reset success,
- * else a negative value for failure.
+ * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
+ * or NO_SLEEP (interrupt thread, use mdelay)
+ * force - 1 if doorbell active, board fault state
+ * board operational, IOC_RECOVERY or
+ * IOC_BRINGUP and there is an alt_ioc.
+ * 0 else
+ *
+ * Returns:
+ * 1 - hard reset, READY
+ * 0 - no reset due to History bit, READY
+ * -1 - no reset due to History bit but not READY
+ * OR reset but failed to come READY
+ * -2 - no reset, could not enter DIAG mode
+ * -3 - reset but bad FW bit
*/
static int
-KickStart(MPT_ADAPTER *ioc, int force)
+KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
{
int hard_reset_done = 0;
u32 ioc_state;
@@ -2056,183 +2742,295 @@
dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
- hard_reset_done = mpt_fc9x9_reset(ioc, force);
-#if 0
- if (ioc->chip_type == FC909 || ioc->chip-type == FC919) {
- hard_reset_done = mpt_fc9x9_reset(ioc, force);
- } else if (ioc->chip_type == FC929) {
- unsigned long delta;
-
- delta = jiffies - ioc->last_kickstart;
- dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
- ioc->name, ioc->last_kickstart, delta));
- if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
- hard_reset_done = mpt_fc9x9_reset(ioc, ignore);
- else {
- dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
- ioc->name, delta));
- return 0;
- }
- /* TODO! Add C1030!
- } else if (ioc->chip_type == C1030) {
- */
- } else {
- printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n",
- ioc->name, ioc->chip_type);
- return -5;
- }
-#endif
-
+ hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
if (hard_reset_done < 0)
return hard_reset_done;
- dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
+ dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
ioc->name));
for (cnt=0; cnt<HZ*20; cnt++) {
- if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
- dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
+ if ((ioc_state = mpt_GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
+ dprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
ioc->name, cnt));
return hard_reset_done;
}
- /* udelay(10000) ? */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ } else {
+ mdelay (10);
+ }
}
- printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n",
+ printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n",
ioc->name);
return -1;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter.
+ * mpt_diag_reset - Perform hard reset of the adapter.
* @ioc: Pointer to MPT_ADAPTER structure
- *
- * This routine places FC9x9 adapter in diagnostic mode via the
- * WriteSequence register, and then performs a hard reset of adapter
- * via the Diagnostic register.
- *
- * Returns 0 for success, non-zero for failure.
+ * @ignore: Set if to honor and clear to ignore
+ * the reset history bit
+ * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
+ * else set to NO_SLEEP (use mdelay instead)
+ *
+ * This routine places the adapter in diagnostic mode via the
+ * WriteSequence register and then performs a hard reset of adapter
+ * via the Diagnostic register. Adapter should be in ready state
+ * upon successful completion.
+ *
+ * Returns: 1 hard reset successful
+ * 0 no reset performed because reset history bit set
+ * -2 enabling diagnostic mode failed
+ * -3 diagnostic reset failed
*/
static int
-mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore)
+mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
{
u32 diag0val;
+ u32 doorbell;
int hard_reset_done = 0;
+ int count = 0;
+#ifdef MPT_DEBUG
+ u32 diag1val = 0;
+#endif
- /* Use "Diagnostic reset" method! (only thing available!) */
+ /* Clear any existing interrupts */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+ /* Use "Diagnostic reset" method! (only thing available!) */
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
#ifdef MPT_DEBUG
-{
- u32 diag1val = 0;
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((KERN_INFO MYNAM ": %s: DBG1: diag0=%08x, diag1=%08x\n",
+ dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
-}
#endif
- if (diag0val & MPI_DIAG_DRWE) {
- dprintk((KERN_INFO MYNAM ": %s: DiagWriteEn bit already set\n",
- ioc->name));
- } else {
- /* Write magic sequence to WriteSequence register */
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
- CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
- dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#1]\n",
- ioc->name));
- }
- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ /* Do the reset if we are told to ignore the reset history
+ * or if the reset history is 0
+ */
+ if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
+ while ((diag0val & MPI_DIAG_DRWE) == 0) {
+ /* Write magic sequence to WriteSequence register
+ * Loop until in diagnostic mode
+ */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+
+ /* wait 100 msec */
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(100 * HZ / 1000);
+ } else {
+ mdelay (100);
+ }
+
+ count++;
+ if (count > 20) {
+ printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+ ioc->name, diag0val);
+ return -2;
+
+ }
+
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+
+ dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+ ioc->name, diag0val));
+ }
+
#ifdef MPT_DEBUG
-{
- u32 diag1val = 0;
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((KERN_INFO MYNAM ": %s: DbG2: diag0=%08x, diag1=%08x\n",
- ioc->name, diag0val, diag1val));
-}
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
#endif
- if (!ignore && (diag0val & MPI_DIAG_RESET_HISTORY)) {
- dprintk((KERN_INFO MYNAM ": %s: Skipping due to ResetHistory bit set!\n",
- ioc->name));
- } else {
+ /* Write the PreventIocBoot bit */
+ if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+ diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
+ }
+
+ /*
+ * Disable the ARM (Bug fix)
+ *
+ */
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
+ mdelay (1);
+
/*
* Now hit the reset bit in the Diagnostic register
- * (THE BIG HAMMER!)
+ * (THE BIG HAMMER!) (Clears DRWE bit).
*/
- CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
hard_reset_done = 1;
- dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset performed\n",
+ dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
ioc->name));
- /* want udelay(100) */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ /*
+ * Call each currently registered protocol IOC reset handler
+ * with pre-reset indication.
+ * NOTE: If we're doing _IOC_BRINGUP, there can be no
+ * MptResetHandlers[] registered yet.
+ */
+ {
+ int ii;
+ int r = 0;
+
+ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ if (MptResetHandlers[ii]) {
+ dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
+ ioc->name, ii));
+ r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
+ if (ioc->alt_ioc) {
+ dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
+ ioc->name, ioc->alt_ioc->name, ii));
+ r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+ }
+ }
+ }
+ /* FIXME? Examine results here? */
+ }
+
+ if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+ /* If the DownloadBoot operation fails, the
+ * IOC will be left unusable. This is a fatal error
+ * case. _diag_reset will return < 0
+ */
+ for (count = 0; count < 30; count ++) {
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT
+ "DbG2b: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+#endif
+ if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
+ break;
+ }
+
+ /* wait 1 sec */
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ } else {
+ mdelay (1000);
+ }
+ }
+ if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
+ printk(KERN_WARNING MYNAM
+ ": firmware downloadboot failure (%d)!\n", count);
+ }
+
+ } else {
+ /* Wait for FW to reload and for board
+ * to go to the READY state.
+ * Maximum wait is 30 seconds.
+ * If fail, no error will check again
+ * with calling program.
+ */
+ for (count = 0; count < 30; count ++) {
+ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+ doorbell &= MPI_IOC_STATE_MASK;
+
+ if (doorbell == MPI_IOC_STATE_READY) {
+ break;
+ }
+
+ /* wait 1 sec */
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ } else {
+ mdelay (1000);
+ }
+ }
+ }
+ }
- /* Write magic sequence to WriteSequence register */
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+ if (ioc->alt_ioc)
+ diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+ dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+ ioc->name, diag0val, diag1val));
+#endif
+
+ /* Clear RESET_HISTORY bit! Place board in the
+ * diagnostic mode to update the diag register.
+ */
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ count = 0;
+ while ((diag0val & MPI_DIAG_DRWE) == 0) {
+ /* Write magic sequence to WriteSequence register
+ * Loop until in diagnostic mode
+ */
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
- dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#2]\n",
- ioc->name));
- }
- /* Clear RESET_HISTORY bit! */
- CHIPREG_WRITE32(&ioc->chip->Diagnostic, 0x0);
+ /* wait 100 msec */
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(100 * HZ / 1000);
+ } else {
+ mdelay (100);
+ }
+ count++;
+ if (count > 20) {
+ printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
+ ioc->name, diag0val);
+ break;
+ }
+ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ }
+ diag0val &= ~MPI_DIAG_RESET_HISTORY;
+ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
-{
- u32 diag1val = 0;
- if (ioc->alt_ioc)
- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((KERN_INFO MYNAM ": %s: DbG3: diag0=%08x, diag1=%08x\n",
- ioc->name, diag0val, diag1val));
-}
-#endif
if (diag0val & MPI_DIAG_RESET_HISTORY) {
- printk(KERN_WARNING MYNAM ": %s: WARNING - ResetHistory bit failed to clear!\n",
+ printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
ioc->name);
}
+ /* Disable Diagnostic Mode
+ */
+ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
+
+ /* Check FW reload status flags.
+ */
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
+ printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
+ ioc->name, diag0val);
+ return -3;
+ }
+
#ifdef MPT_DEBUG
-{
- u32 diag1val = 0;
if (ioc->alt_ioc)
diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
- dprintk((KERN_INFO MYNAM ": %s: DbG4: diag0=%08x, diag1=%08x\n",
+ dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
ioc->name, diag0val, diag1val));
-}
#endif
- if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
- printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED! (%02xh)\n",
- ioc->name, diag0val);
- return -3;
- }
/*
* Reset flag that says we've enabled event notification
*/
ioc->facts.EventState = 0;
- /* NEW! 20010220 -sralston
- * Try to avoid redundant resets of the 929.
- */
- ioc->sod_reset++;
- ioc->last_kickstart = jiffies;
- if (ioc->alt_ioc) {
- ioc->alt_ioc->sod_reset = ioc->sod_reset;
- ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
- }
+ if (ioc->alt_ioc)
+ ioc->alt_ioc->facts.EventState = 0;
return hard_reset_done;
}
@@ -2249,16 +3047,45 @@
* Returns 0 for success, non-zero for failure.
*/
static int
-SendIocReset(MPT_ADAPTER *ioc, u8 reset_type)
+SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
{
int r;
+ u32 state;
+ int cntdn, count;
dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
ioc->name, reset_type));
CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
- if ((r = WaitForDoorbellAck(ioc, 2)) < 0)
+ if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
return r;
+ /* FW ACK'd request, wait for READY state
+ */
+ cntdn = HZ * 15;
+ count = 0;
+ if (sleepFlag != CAN_SLEEP)
+ cntdn *= 10; /* 1500 iterations @ 1msec per */
+
+ while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+ cntdn--;
+ count++;
+ if (!cntdn) {
+ if (sleepFlag != CAN_SLEEP)
+ count *= 10;
+
+ printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+ ioc->name, (count+5)/HZ);
+ return -ETIME;
+ }
+
+ if (sleepFlag == CAN_SLEEP) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ } else {
+ mdelay (1); /* 1 msec delay */
+ }
+ }
+
/* TODO!
* Cleanup all event stuff for this IOC; re-issue EventNotification
* request if needed.
@@ -2275,7 +3102,8 @@
* @ioc: Pointer to MPT_ADAPTER structure
*
* This routine allocates memory for the MPT reply and request frame
- * pools, and primes the IOC reply FIFO with reply frames.
+ * pools (if necessary), and primes the IOC reply FIFO with
+ * reply frames.
*
* Returns 0 for success, non-zero for failure.
*/
@@ -2284,6 +3112,7 @@
{
MPT_FRAME_HDR *mf;
unsigned long b;
+ unsigned long flags;
dma_addr_t aligned_mem_dma;
u8 *mem, *aligned_mem;
int i, sz;
@@ -2299,8 +3128,8 @@
memset(mem, 0, sz);
ioc->alloc_total += sz;
ioc->reply_alloc = mem;
- dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%08x], sz=%d bytes\n",
- ioc->name, mem, ioc->reply_alloc_dma, sz));
+ dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n",
+ ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, sz));
b = (unsigned long) mem;
b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2308,15 +3137,20 @@
ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem;
ioc->reply_frames_dma =
(ioc->reply_alloc_dma + (aligned_mem - mem));
- aligned_mem_dma = ioc->reply_frames_dma;
- dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n",
- ioc->name, aligned_mem, aligned_mem_dma));
-
- for (i = 0; i < ioc->reply_depth; i++) {
- /* Write each address to the IOC! */
- CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
- aligned_mem_dma += ioc->reply_sz;
- }
+
+ ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF);
+ }
+
+ /* Post Reply frames to FIFO
+ */
+ aligned_mem_dma = ioc->reply_frames_dma;
+ dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n",
+ ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma));
+
+ for (i = 0; i < ioc->reply_depth; i++) {
+ /* Write each address to the IOC! */
+ CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma);
+ aligned_mem_dma += ioc->reply_sz;
}
@@ -2336,8 +3170,8 @@
memset(mem, 0, sz);
ioc->alloc_total += sz;
ioc->req_alloc = mem;
- dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%08x], sz=%d bytes\n",
- ioc->name, mem, ioc->req_alloc_dma, sz));
+ dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n",
+ ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, sz));
b = (unsigned long) mem;
b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -2345,18 +3179,18 @@
ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem;
ioc->req_frames_dma =
(ioc->req_alloc_dma + (aligned_mem - mem));
- aligned_mem_dma = ioc->req_frames_dma;
- dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%08x]\n",
- ioc->name, aligned_mem, aligned_mem_dma));
+ ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF);
- for (i = 0; i < ioc->req_depth; i++) {
- mf = (MPT_FRAME_HDR *) aligned_mem;
-
- /* Queue REQUESTs *internally*! */
- Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
- aligned_mem += ioc->req_sz;
+#ifdef __ia64__
+ /* Check: upper 32-bits of the request and reply frame
+ * physical addresses must be the same.
+ * ia64 check only
+ */
+ if ((ioc->req_frames_dma >> 32) != (ioc->reply_frames_dma >> 32)){
+ goto out_fail;
}
+#endif
#if defined(CONFIG_MTRR) && 0
/*
@@ -2367,20 +3201,38 @@
ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma,
sz,
MTRR_TYPE_WRCOMB, 1);
- dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n",
- ioc->name, ioc->req_alloc_dma,
- sz ));
+ dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+ ioc->name, ioc->req_alloc_dma, sz));
#endif
+ }
+
+ /* Initialize Request frames linked list
+ */
+ aligned_mem_dma = ioc->req_frames_dma;
+ aligned_mem = (u8 *) ioc->req_frames;
+ dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n",
+ ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma));
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
+ for (i = 0; i < ioc->req_depth; i++) {
+ mf = (MPT_FRAME_HDR *) aligned_mem;
+
+ /* Queue REQUESTs *internally*! */
+ Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR);
+ aligned_mem += ioc->req_sz;
}
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
if (ioc->sense_buf_pool == NULL) {
- sz = (ioc->req_depth * 256);
+ sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
ioc->sense_buf_pool =
pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
if (ioc->sense_buf_pool == NULL)
goto out_fail;
+ ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
ioc->alloc_total += sz;
}
@@ -2408,7 +3260,7 @@
#if defined(CONFIG_MTRR) && 0
if (ioc->mtrr_reg > 0) {
mtrr_del(ioc->mtrr_reg, 0, 0);
- dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n",
+ dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n",
ioc->name));
}
#endif
@@ -2417,7 +3269,7 @@
ioc->alloc_total -= sz;
}
if (ioc->sense_buf_pool != NULL) {
- sz = (ioc->req_depth * 256);
+ sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
pci_free_consistent(ioc->pcidev,
sz,
ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
@@ -2427,8 +3279,8 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * HandShakeReqAndReply - Send MPT request to and receive reply from
+/**
+ * mpt_handshake_req_reply_wait - Send MPT request to and receive reply from
* IOC via doorbell handshake method.
* @ioc: Pointer to MPT_ADAPTER structure
* @reqBytes: Size of the request in bytes
@@ -2436,6 +3288,7 @@
* @replyBytes: Expected size of the reply in bytes
* @u16reply: Pointer to area where reply should be written
* @maxwait: Max wait time for a reply (in seconds)
+ * @sleepFlag: Specifies whether the process can sleep
*
* NOTES: It is the callers responsibility to byte-swap fields in the
* request which are greater than 1 byte in size. It is also the
@@ -2444,8 +3297,9 @@
*
* Returns 0 for success, non-zero for failure.
*/
-static int
-HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait)
+int
+mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
+ int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
{
MPIDefaultReply_t *mptReply;
int failcnt = 0;
@@ -2471,57 +3325,61 @@
/*
* Wait for IOC's doorbell handshake int
*/
- if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+ if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
failcnt++;
- dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
+ dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
+ /* Read doorbell and check for active bit */
+ if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
+ return -1;
+
/*
* Clear doorbell int (WRITE 0 to IntStatus reg),
* then wait for IOC to ACKnowledge that it's ready for
* our handshake request.
*/
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
- if (!failcnt && (t = WaitForDoorbellAck(ioc, 2)) < 0)
+ if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
failcnt++;
if (!failcnt) {
- int i;
+ int ii;
u8 *req_as_bytes = (u8 *) req;
/*
* Stuff request words via doorbell handshake,
* with ACK from IOC for each.
*/
- for (i = 0; !failcnt && i < reqBytes/4; i++) {
- u32 word = ((req_as_bytes[(i*4) + 0] << 0) |
- (req_as_bytes[(i*4) + 1] << 8) |
- (req_as_bytes[(i*4) + 2] << 16) |
- (req_as_bytes[(i*4) + 3] << 24));
+ for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
+ u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
+ (req_as_bytes[(ii*4) + 1] << 8) |
+ (req_as_bytes[(ii*4) + 2] << 16) |
+ (req_as_bytes[(ii*4) + 3] << 24));
CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
- if ((t = WaitForDoorbellAck(ioc, 2)) < 0)
+ if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
failcnt++;
}
dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
DBG_DUMP_REQUEST_FRAME_HDR(req)
- dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n",
+ dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
/*
* Wait for completion of doorbell handshake reply from the IOC
*/
- if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait)) < 0)
+ if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
failcnt++;
/*
* Copy out the cached reply...
*/
- for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++)
- u16reply[i] = ioc->hs_reply[i];
+ for (ii=0; ii < MIN(replyBytes/2,mptReply->MsgLength*2); ii++)
+ u16reply[ii] = ioc->hs_reply[ii];
} else {
return -99;
}
@@ -2535,6 +3393,7 @@
* in it's IntStatus register.
* @ioc: Pointer to MPT_ADAPTER structure
* @howlong: How long to wait (in seconds)
+ * @sleepFlag: Specifies whether the process can sleep
*
* This routine waits (up to ~2 seconds max) for IOC doorbell
* handshake ACKnowledge.
@@ -2542,28 +3401,40 @@
* Returns a negative value on failure, else wait loop count.
*/
static int
-WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
{
int cntdn = HZ * howlong;
int count = 0;
u32 intstat;
- while (--cntdn) {
- intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
- if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
- break;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- count++;
+ if (sleepFlag == CAN_SLEEP) {
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+ break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ count++;
+ }
+ } else {
+ cntdn *= 10; /* convert to msec */
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
+ break;
+ mdelay (1);
+ count++;
+ }
+ count /= 10;
}
if (cntdn) {
- dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n",
+ dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n",
ioc->name, count));
return count;
}
- printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n",
+ printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n",
ioc->name, (count+5)/HZ);
return -1;
}
@@ -2574,34 +3445,47 @@
* in it's IntStatus register.
* @ioc: Pointer to MPT_ADAPTER structure
* @howlong: How long to wait (in seconds)
+ * @sleepFlag: Specifies whether the process can sleep
*
* This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
*
* Returns a negative value on failure, else wait loop count.
*/
static int
-WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
{
int cntdn = HZ * howlong;
int count = 0;
u32 intstat;
- while (--cntdn) {
- intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
- if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
- break;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- count++;
+ if (sleepFlag == CAN_SLEEP) {
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+ break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ count++;
+ }
+ } else {
+ cntdn *= 10; /* convert to msec */
+ while (--cntdn) {
+ intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
+ if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
+ break;
+ mdelay(1);
+ count++;
+ }
+ count /= 10;
}
if (cntdn) {
- dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n",
+ dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n",
ioc->name, count));
return count;
}
- printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n",
+ printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n",
ioc->name, (count+5)/HZ);
return -1;
}
@@ -2611,6 +3495,7 @@
* WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
* @ioc: Pointer to MPT_ADAPTER structure
* @howlong: How long to wait (in seconds)
+ * @sleepFlag: Specifies whether the process can sleep
*
* This routine polls the IOC for a handshake reply, 16 bits at a time.
* Reply is cached to IOC private area large enough to hold a maximum
@@ -2619,13 +3504,13 @@
* Returns a negative value on failure, else size of reply in WORDS.
*/
static int
-WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
+WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
{
int u16cnt = 0;
int failcnt = 0;
int t;
u16 *hs_reply = ioc->hs_reply;
- volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
+ volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
u16 hword;
hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
@@ -2634,12 +3519,12 @@
* Get first two u16's so we can look at IOC's intended reply MsgLength
*/
u16cnt=0;
- if ((t = WaitForDoorbellInt(ioc, howlong)) < 0) {
+ if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
failcnt++;
} else {
hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
- if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+ if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
failcnt++;
else {
hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
@@ -2647,7 +3532,7 @@
}
}
- dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
+ dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n",
ioc->name, le32_to_cpu(*(u32 *)hs_reply),
failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
@@ -2656,7 +3541,7 @@
* reply 16 bits at a time.
*/
for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
- if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+ if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
failcnt++;
hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
/* don't overflow our IOC hs_reply[] buffer! */
@@ -2665,12 +3550,12 @@
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
}
- if (!failcnt && (t = WaitForDoorbellInt(ioc, 2)) < 0)
+ if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0)
failcnt++;
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
if (failcnt) {
- printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n",
+ printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
ioc->name);
return -failcnt;
}
@@ -2681,130 +3566,631 @@
else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
return -102;
}
-#endif
+#endif
+
+ dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
+ DBG_DUMP_REPLY_FRAME(mptReply)
+
+ dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n",
+ ioc->name, u16cnt/2));
+ return u16cnt/2;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetLanConfigPages - Fetch LANConfig pages.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Return: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetLanConfigPages(MPT_ADAPTER *ioc)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ LANPage0_t *ppage0_alloc;
+ dma_addr_t page0_dma;
+ LANPage1_t *ppage1_alloc;
+ dma_addr_t page1_dma;
+ int rc = 0;
+ int data_sz;
+ int copy_sz;
+
+ /* Get LAN Page 0 header */
+ hdr.PageVersion = 0;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+ cfg.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = 0;
+ cfg.timeout = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ return rc;
+
+ if (hdr.PageLength > 0) {
+ data_sz = hdr.PageLength * 4;
+ ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+ rc = -ENOMEM;
+ if (ppage0_alloc) {
+ memset((u8 *)ppage0_alloc, 0, data_sz);
+ cfg.physAddr = page0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) == 0) {
+ /* save the data */
+ copy_sz = MIN(sizeof(LANPage0_t), data_sz);
+ memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
+
+ }
+
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+
+ /* FIXME!
+ * Normalize endianness of structure data,
+ * by byte-swapping all > 1 byte fields!
+ */
+
+ }
+
+ if (rc)
+ return rc;
+ }
+
+ /* Get LAN Page 1 header */
+ hdr.PageVersion = 0;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 1;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
+ cfg.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ return rc;
+
+ if (hdr.PageLength == 0)
+ return 0;
+
+ data_sz = hdr.PageLength * 4;
+ rc = -ENOMEM;
+ ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
+ if (ppage1_alloc) {
+ memset((u8 *)ppage1_alloc, 0, data_sz);
+ cfg.physAddr = page1_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) == 0) {
+ /* save the data */
+ copy_sz = MIN(sizeof(LANPage1_t), data_sz);
+ memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
+ }
+
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
+
+ /* FIXME!
+ * Normalize endianness of structure data,
+ * by byte-swapping all > 1 byte fields!
+ */
+
+ }
+
+ return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetFcPortPage0 - Fetch FCPort config Page0.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @portnum: IOC Port number
+ *
+ * Return: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ FCPortPage0_t *ppage0_alloc;
+ FCPortPage0_t *pp0dest;
+ dma_addr_t page0_dma;
+ int data_sz;
+ int copy_sz;
+ int rc;
+
+ /* Get FCPort Page 0 header */
+ hdr.PageVersion = 0;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
+ cfg.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = portnum;
+ cfg.timeout = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ return rc;
+
+ if (hdr.PageLength == 0)
+ return 0;
+
+ data_sz = hdr.PageLength * 4;
+ rc = -ENOMEM;
+ ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+ if (ppage0_alloc) {
+ memset((u8 *)ppage0_alloc, 0, data_sz);
+ cfg.physAddr = page0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) == 0) {
+ /* save the data */
+ pp0dest = &ioc->fc_port_page0[portnum];
+ copy_sz = MIN(sizeof(FCPortPage0_t), data_sz);
+ memcpy(pp0dest, ppage0_alloc, copy_sz);
+
+ /*
+ * Normalize endianness of structure data,
+ * by byte-swapping all > 1 byte fields!
+ */
+ pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
+ pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
+ pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
+ pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
+ pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
+ pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
+ pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
+ pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
+ pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
+ pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
+ pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
+ pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
+ pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
+ pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
+ pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
+ pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
+
+ }
+
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+ }
+
+ return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ * Returns: 0 for success
+ * -ENOMEM if no memory available
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ */
+static int
+GetIoUnitPage2(MPT_ADAPTER *ioc)
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ IOUnitPage2_t *ppage_alloc;
+ dma_addr_t page_dma;
+ int data_sz;
+ int rc;
+
+ /* Get the page header */
+ hdr.PageVersion = 0;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 2;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
+ cfg.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = 0;
+ cfg.timeout = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ return rc;
+
+ if (hdr.PageLength == 0)
+ return 0;
+
+ /* Read the config page */
+ data_sz = hdr.PageLength * 4;
+ rc = -ENOMEM;
+ ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+ if (ppage_alloc) {
+ memset((u8 *)ppage_alloc, 0, data_sz);
+ cfg.physAddr = page_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ /* If Good, save data */
+ if ((rc = mpt_config(ioc, &cfg)) == 0)
+ ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
+
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
+ }
+
+ return rc;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
+ * @ioc: Pointer to a Adapter Strucutre
+ * @portnum: IOC port number
+ *
+ * Return: -EFAULT if read of config page header fails
+ * or if no nvram
+ * If read of SCSI Port Page 0 fails,
+ * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
+ * Adapter settings: async, narrow
+ * Return 1
+ * If read of SCSI Port Page 2 fails,
+ * Adapter settings valid
+ * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
+ * Return 1
+ * Else
+ * Both valid
+ * Return 0
+ * CHECK - what type of locking mechanisms should be used????
+ */
+static int
+mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
+{
+ u8 *pbuf = NULL;
+ dma_addr_t buf_dma;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t header;
+ int ii;
+ int data, rc = 0;
+
+ /* Allocate memory
+ */
+ if (!ioc->spi_data.nvram) {
+ int sz;
+ u8 *mem;
+ sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
+ mem = kmalloc(sz, GFP_KERNEL);
+ if (mem == NULL)
+ return -EFAULT;
+
+ ioc->spi_data.nvram = (int *) mem;
+
+ dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+ ioc->name, ioc->spi_data.nvram, sz));
+ }
+
+ /* Invalidate NVRAM information
+ */
+ for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+ ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
+ }
+
+ /* Read SPP0 header, allocate memory, then read page.
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+ cfg.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = portnum;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = 0; /* use default */
+ if (mpt_config(ioc, &cfg) != 0)
+ return -EFAULT;
+
+ if (header.PageLength > 0) {
+ pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+ if (pbuf) {
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.physAddr = buf_dma;
+ if (mpt_config(ioc, &cfg) != 0) {
+ ioc->spi_data.maxBusWidth = MPT_NARROW;
+ ioc->spi_data.maxSyncOffset = 0;
+ ioc->spi_data.minSyncFactor = MPT_ASYNC;
+ ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
+ rc = 1;
+ } else {
+ /* Save the Port Page 0 data
+ */
+ SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
+ pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
+ pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
+
+ ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
+ data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
+ if (data) {
+ ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
+ data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
+ ioc->spi_data.minSyncFactor = (u8) (data >> 8);
+ } else {
+ ioc->spi_data.maxSyncOffset = 0;
+ ioc->spi_data.minSyncFactor = MPT_ASYNC;
+ }
+
+ ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
+
+ /* Update the minSyncFactor based on bus type.
+ */
+ if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
+ (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
+
+ if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
+ ioc->spi_data.minSyncFactor = MPT_ULTRA;
+ }
+ }
+ if (pbuf) {
+ pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+ pbuf = NULL;
+ }
+ }
+ }
+
+ /* SCSI Port Page 2 - Read the header then the page.
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 2;
+ header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
+ cfg.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = portnum;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ if (mpt_config(ioc, &cfg) != 0)
+ return -EFAULT;
+
+ if (header.PageLength > 0) {
+ /* Allocate memory and read SCSI Port Page 2
+ */
+ pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
+ if (pbuf) {
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
+ cfg.physAddr = buf_dma;
+ if (mpt_config(ioc, &cfg) != 0) {
+ /* Nvram data is left with INVALID mark
+ */
+ rc = 1;
+ } else {
+ SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
+ MpiDeviceInfo_t *pdevice = NULL;
+
+ /* Save the Port Page 2 data
+ * (reformat into a 32bit quantity)
+ */
+ for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+ pdevice = &pPP2->DeviceSettings[ii];
+ data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
+ (pdevice->SyncFactor << 8) | pdevice->Timeout;
+ ioc->spi_data.nvram[ii] = data;
+ }
+ }
+
+ pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
+ pbuf = NULL;
+ }
+ }
- dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name));
- DBG_DUMP_REPLY_FRAME(mptReply)
+ /* Update Adapter limits with those from NVRAM
+ * Comment: Don't need to do this. Target performance
+ * parameters will never exceed the adapters limits.
+ */
- dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n",
- ioc->name, u16cnt/2));
- return u16cnt/2;
+ return rc;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * GetLanConfigPages - Fetch LANConfig pages.
- * @ioc: Pointer to MPT_ADAPTER structure
+/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
+ * @ioc: Pointer to a Adapter Strucutre
+ * @portnum: IOC port number
*
- * Returns 0 for success, non-zero for failure.
+ * Return: -EFAULT if read of config page header fails
+ * or 0 if success.
*/
static int
-GetLanConfigPages(MPT_ADAPTER *ioc)
+mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
{
- Config_t config_req;
- ConfigReply_t config_reply;
- LANPage0_t *page0;
- dma_addr_t page0_dma;
- LANPage1_t *page1;
- dma_addr_t page1_dma;
- int i;
- int req_sz;
- int reply_sz;
- int data_sz;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t header;
-/* LANPage0 */
- /* Immediate destination (reply area)... */
- reply_sz = sizeof(config_reply);
- memset(&config_reply, 0, reply_sz);
-
- /* Ultimate destination... */
- page0 = &ioc->lan_cnfg_page0;
- data_sz = sizeof(*page0);
- memset(page0, 0, data_sz);
-
- /* Request area (config_req on the stack right now!) */
- req_sz = sizeof(config_req);
- memset(&config_req, 0, req_sz);
- config_req.Function = MPI_FUNCTION_CONFIG;
- config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
- /* config_req.Header.PageVersion = 0; */
- /* config_req.Header.PageLength = 0; */
- config_req.Header.PageNumber = 0;
- config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
- /* config_req.PageAddress = 0; */
- config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
- ((MPI_SGE_FLAGS_LAST_ELEMENT |
- MPI_SGE_FLAGS_END_OF_BUFFER |
- MPI_SGE_FLAGS_END_OF_LIST |
- MPI_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI_SGE_FLAGS_SYSTEM_ADDRESS |
- MPI_SGE_FLAGS_32_BIT_ADDRESSING |
- MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
- (u32)data_sz
- );
- page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE);
- config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma);
+ /* Read the SCSI Device Page 1 header
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 1;
+ header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+ cfg.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = portnum;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = 0;
+ if (mpt_config(ioc, &cfg) != 0)
+ return -EFAULT;
+
+ ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
+ ioc->spi_data.sdp1length = cfg.hdr->PageLength;
+
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 0;
+ header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+ if (mpt_config(ioc, &cfg) != 0)
+ return -EFAULT;
- dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n",
- ioc->name));
+ ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
+ ioc->spi_data.sdp0length = cfg.hdr->PageLength;
- i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
- reply_sz, (u16*)&config_reply, 3);
- pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
- if (i != 0)
- return i;
+ return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
+ * @ioc: Pointer to a Adapter Strucutre
+ * @portnum: IOC port number
+ *
+ * Return:
+ * 0 on success
+ * -EFAULT if read of config page header fails or data pointer not NULL
+ * -ENOMEM if pci_alloc failed
+ */
+static int
+mpt_findImVolumes(MPT_ADAPTER *ioc)
+{
+ IOCPage2_t *pIoc2 = NULL;
+ IOCPage3_t *pIoc3 = NULL;
+ ConfigPageIoc2RaidVol_t *pIocRv = NULL;
+ u8 *mem;
+ dma_addr_t ioc2_dma;
+ dma_addr_t ioc3_dma;
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t header;
+ int jj;
+ int rc = 0;
+ int iocpage2sz;
+ int iocpage3sz = 0;
+ u8 nVols, nPhys;
+ u8 vid, vbus, vioc;
+
+ if (ioc->spi_data.pIocPg3)
+ return -EFAULT;
+
+ /* Read IOCP2 header then the page.
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 2;
+ header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+ cfg.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = 0;
+ if (mpt_config(ioc, &cfg) != 0)
+ return -EFAULT;
+
+ if (header.PageLength == 0)
+ return -EFAULT;
+
+ iocpage2sz = header.PageLength * 4;
+ pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
+ if (!pIoc2)
+ return -ENOMEM;
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.physAddr = ioc2_dma;
+ if (mpt_config(ioc, &cfg) != 0)
+ goto done_and_free;
+
+ /* Identify RAID Volume Id's */
+ nVols = pIoc2->NumActiveVolumes;
+ if ( nVols == 0) {
+ /* No RAID Volumes. Done.
+ */
+ } else {
+ /* At least 1 RAID Volume
+ */
+ pIocRv = pIoc2->RaidVolume;
+ ioc->spi_data.isRaid = 0;
+ for (jj = 0; jj < nVols; jj++, pIocRv++) {
+ vid = pIocRv->VolumeID;
+ vbus = pIocRv->VolumeBus;
+ vioc = pIocRv->VolumeIOC;
+
+ /* find the match
+ */
+ if (vbus == 0) {
+ ioc->spi_data.isRaid |= (1 << vid);
+ } else {
+ /* Error! Always bus 0
+ */
+ }
+ }
+ }
- /* Now byte swap the necessary LANPage0 fields */
+ /* Identify Hidden Physical Disk Id's */
+ nPhys = pIoc2->NumActivePhysDisks;
+ if (nPhys == 0) {
+ /* No physical disks. Done.
+ */
+ } else {
+ /* There is at least one physical disk.
+ * Read and save IOC Page 3
+ */
+ header.PageVersion = 0;
+ header.PageLength = 0;
+ header.PageNumber = 3;
+ header.PageType = MPI_CONFIG_PAGETYPE_IOC;
+ cfg.hdr = &header;
+ cfg.physAddr = -1;
+ cfg.pageAddr = 0;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.timeout = 0;
+ if (mpt_config(ioc, &cfg) != 0)
+ goto done_and_free;
-/* LANPage1 */
- /* Immediate destination (reply area)... */
- reply_sz = sizeof(config_reply);
- memset(&config_reply, 0, reply_sz);
-
- /* Ultimate destination... */
- page1 = &ioc->lan_cnfg_page1;
- data_sz = sizeof(*page1);
- memset(page1, 0, data_sz);
-
- /* Request area (config_req on the stack right now!) */
- req_sz = sizeof(config_req);
- memset(&config_req, 0, req_sz);
- config_req.Function = MPI_FUNCTION_CONFIG;
- config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
- /* config_req.Header.PageVersion = 0; */
- /* config_req.Header.PageLength = 0; */
- config_req.Header.PageNumber = 1;
- config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN;
- /* config_req.PageAddress = 0; */
- config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32(
- ((MPI_SGE_FLAGS_LAST_ELEMENT |
- MPI_SGE_FLAGS_END_OF_BUFFER |
- MPI_SGE_FLAGS_END_OF_LIST |
- MPI_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI_SGE_FLAGS_SYSTEM_ADDRESS |
- MPI_SGE_FLAGS_32_BIT_ADDRESSING |
- MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) |
- (u32)data_sz
- );
- page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE);
- config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma);
+ if (header.PageLength == 0)
+ goto done_and_free;
- dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n",
- ioc->name));
+ /* Read Header good, alloc memory
+ */
+ iocpage3sz = header.PageLength * 4;
+ pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
+ if (!pIoc3)
+ goto done_and_free;
- i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
- reply_sz, (u16*)&config_reply, 3);
- pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
- if (i != 0)
- return i;
+ /* Read the Page and save the data
+ * into malloc'd memory.
+ */
+ cfg.physAddr = ioc3_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ if (mpt_config(ioc, &cfg) == 0) {
+ mem = kmalloc(iocpage3sz, GFP_KERNEL);
+ if (mem) {
+ memcpy(mem, (u8 *)pIoc3, iocpage3sz);
+ ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
+ }
+ }
+ }
- /* Now byte swap the necessary LANPage1 fields */
+done_and_free:
+ if (pIoc2) {
+ pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
+ pIoc2 = NULL;
+ }
- return 0;
+ if (pIoc3) {
+ pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
+ pIoc3 = NULL;
+ }
+
+ return rc;
}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* SendEventNotification - Send EventNotification (on or off) request
* to MPT adapter.
* @ioc: Pointer to MPT_ADAPTER structure
@@ -2817,13 +4203,13 @@
evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id);
if (evnp == NULL) {
- dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n",
+ dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
ioc->name));
return 0;
}
memset(evnp, 0, sizeof(*evnp));
- dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch));
+ dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
evnp->ChainOffset = 0;
@@ -2847,13 +4233,13 @@
EventAck_t *pAck;
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
- printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n",
+ printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
ioc->name);
return -1;
}
memset(pAck, 0, sizeof(*pAck));
- dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name));
+ dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
pAck->Function = MPI_FUNCTION_EVENT_ACK;
pAck->ChainOffset = 0;
@@ -2866,25 +4252,212 @@
return 0;
}
-#ifdef CONFIG_PROC_FS /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_config - Generic function to issue config message
+ * @ioc - Pointer to an adapter structure
+ * @cfg - Pointer to a configuration structure. Struct contains
+ * action, page address, direction, physical address
+ * and pointer to a configuration page header
+ * Page header is updated.
+ *
+ * Returns 0 for success
+ * -EPERM if not allowed due to ISR context
+ * -EAGAIN if no msg frames currently available
+ * -EFAULT for non-successful reply or no reply (timeout)
+ */
+int
+mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
+{
+ Config_t *pReq;
+ MPT_FRAME_HDR *mf;
+ MptSge_t *psge;
+ unsigned long flags;
+ int ii, rc;
+ int flagsLength;
+ int in_isr;
+
+ /* (Bugzilla:fibrebugs, #513)
+ * Bug fix (part 1)! 20010905 -sralston
+ * Prevent calling wait_event() (below), if caller happens
+ * to be in ISR context, because that is fatal!
+ */
+ in_isr = in_interrupt();
+ if (in_isr) {
+ dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+ ioc->name));
+ return -EPERM;
+ }
+
+ /* Get and Populate a free Frame
+ */
+ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
+ dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+ ioc->name));
+ return -EAGAIN;
+ }
+ pReq = (Config_t *)mf;
+ pReq->Action = pCfg->action;
+ pReq->Reserved = 0;
+ pReq->ChainOffset = 0;
+ pReq->Function = MPI_FUNCTION_CONFIG;
+ pReq->Reserved1[0] = 0;
+ pReq->Reserved1[1] = 0;
+ pReq->Reserved1[2] = 0;
+ pReq->MsgFlags = 0;
+ for (ii=0; ii < 8; ii++)
+ pReq->Reserved2[ii] = 0;
+
+ pReq->Header.PageVersion = pCfg->hdr->PageVersion;
+ pReq->Header.PageLength = pCfg->hdr->PageLength;
+ pReq->Header.PageNumber = pCfg->hdr->PageNumber;
+ pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
+ pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
+
+ /* Add a SGE to the config request.
+ */
+ flagsLength = ((MPI_SGE_FLAGS_LAST_ELEMENT |
+ MPI_SGE_FLAGS_END_OF_BUFFER |
+ MPI_SGE_FLAGS_END_OF_LIST |
+ MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPT_SGE_ADDRESS_SIZE ) << MPI_SGE_FLAGS_SHIFT) |
+ pCfg->hdr->PageLength * 4;
+
+ if (pCfg->dir)
+ flagsLength |= (MPI_SGE_FLAGS_DIRECTION << MPI_SGE_FLAGS_SHIFT);
+
+ psge = (MptSge_t *) &pReq->PageBufferSGE;
+ psge->FlagsLength = cpu_to_le32(flagsLength);
+ cpu_to_leXX(pCfg->physAddr, psge->Address);
+
+ dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+ ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
+
+ /* Append pCfg pointer to end of mf
+ */
+ *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
+
+ /* Initalize the timer
+ */
+ init_timer(&pCfg->timer);
+ pCfg->timer.data = (unsigned long) ioc;
+ pCfg->timer.function = mpt_timer_expired;
+ pCfg->wait_done = 0;
+
+ /* Set the timer; ensure 10 second minimum */
+ if (pCfg->timeout < 10)
+ pCfg->timer.expires = jiffies + HZ*10;
+ else
+ pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
+
+ /* Add to end of Q, set timer and then issue this command */
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+ add_timer(&pCfg->timer);
+ mpt_put_msg_frame(mpt_base_index, ioc->id, mf);
+ wait_event(mpt_waitq, pCfg->wait_done);
+
+ /* mf has been freed - do not access */
+
+ rc = pCfg->status;
+
+ return rc;
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ * mpt_timer_expired - Call back for timer process.
+ * Used only internal config functionality.
+ * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
+ */
+static void
+mpt_timer_expired(unsigned long data)
+{
+ MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
+
+ dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+
+ /* Perform a FW reload */
+ if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+ printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
+
+ /* No more processing.
+ * Hard reset clean-up will wake up
+ * process and free all resources.
+ */
+ dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+
+ return;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * mpt_ioc_reset - Base cleanup for hard reset
+ * @ioc: Pointer to the adapter structure
+ * @reset_phase: Indicates pre- or post-reset functionality
+ *
+ * Remark: Free's resources with internally generated commands.
*/
+static int
+mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+ CONFIGPARMS *pCfg;
+ unsigned long flags;
+
+ dprintk((KERN_WARNING MYNAM
+ ": IOC %s_reset routed to MPT base driver!\n",
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+
+ if (reset_phase == MPT_IOC_PRE_RESET) {
+ /* If the internal config Q is not empty -
+ * delete timer. MF resources will be freed when
+ * the FIFO's are primed.
+ */
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ if (! Q_IS_EMPTY(&ioc->configQ)){
+ pCfg = (CONFIGPARMS *)ioc->configQ.head;
+ do {
+ del_timer(&pCfg->timer);
+ pCfg = (CONFIGPARMS *) (pCfg->linkage.forw);
+ } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+ }
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
+ } else {
+ CONFIGPARMS *pNext;
+
+ /* Search the configQ for internal commands.
+ * Flush the Q, and wake up all suspended threads.
+ */
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
+ if (! Q_IS_EMPTY(&ioc->configQ)){
+ pCfg = (CONFIGPARMS *)ioc->configQ.head;
+ do {
+ pNext = (CONFIGPARMS *) pCfg->linkage.forw;
-#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \
-{ \
- len -= off; \
- if (len < count) { \
- *eof = 1; \
- if (len <= 0) \
- return 0; \
- } else \
- len = count; \
- *start = page + off; \
- return len; \
+ Q_DEL_ITEM(&pCfg->linkage);
+
+ pCfg->status = MPT_CONFIG_ERROR;
+ pCfg->wait_done = 1;
+ wake_up(&mpt_waitq);
+
+ pCfg = pNext;
+ } while (pCfg != (CONFIGPARMS *)&ioc->configQ);
+ }
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+ }
+
+ return 1; /* currently means nothing really */
}
+
+#ifdef CONFIG_PROC_FS /* { */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
+ */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
@@ -2894,71 +4467,62 @@
static int
procmpt_create(void)
{
- MPT_ADAPTER *ioc;
- struct proc_dir_entry *ent;
- int errcnt = 0;
+ MPT_ADAPTER *ioc;
+ struct proc_dir_entry *ent;
+ int ii;
/*
- * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
- * (single level) to multi level (e.g. "driver/message/fusion")
- * something here needs to change. -sralston
+ * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+ * (single level) to multi level (e.g. "driver/message/fusion")
+ * something here needs to change. -sralston
*/
- procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL);
- if (procmpt_root_dir == NULL)
+ mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
+ if (mpt_proc_root_dir == NULL)
return -ENOTDIR;
- if ((ioc = mpt_adapter_find_first()) != NULL) {
- ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL);
- if (ent == NULL) {
- printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n",
- MPT_PROCFS_SUMMARY_PATHNAME);
- errcnt++;
+ for (ii=0; ii < MPT_PROC_ENTRIES; ii++) {
+ ent = create_proc_entry(mpt_proc_list[ii].name,
+ S_IFREG|S_IRUGO, mpt_proc_root_dir);
+ if (!ent) {
+ printk(KERN_WARNING MYNAM
+ ": WARNING - Could not create /proc/mpt/%s entry\n",
+ mpt_proc_list[ii].name);
+ continue;
}
+ ent->read_proc = mpt_proc_list[ii].f;
+ ent->data = NULL;
}
+ ioc = mpt_adapter_find_first();
while (ioc != NULL) {
- char pname[32];
- int namelen;
+ struct proc_dir_entry *dent;
/*
* Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
*/
- namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
- if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) {
+ if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) {
/*
- * And populate it with: "summary" and "dbg" file entries.
+ * And populate it with mpt_ioc_proc_list[] entries.
*/
- (void) sprintf(pname+namelen, "/summary");
- ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc);
- if (ent == NULL) {
- errcnt++;
- printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
- ioc->name, pname);
- }
-//#ifdef MPT_DEBUG
- /* DEBUG aid! */
- (void) sprintf(pname+namelen, "/dbg");
- ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc);
- if (ent == NULL) {
- errcnt++;
- printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
- ioc->name, pname);
+ for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+ ent = create_proc_entry(mpt_ioc_proc_list[ii].name,
+ S_IFREG|S_IRUGO, dent);
+ if (!ent) {
+ printk(KERN_WARNING MYNAM
+ ": WARNING - Could not create /proc/mpt/%s/%s entry!\n",
+ ioc->name,
+ mpt_ioc_proc_list[ii].name);
+ continue;
+ }
+ ent->read_proc = mpt_ioc_proc_list[ii].f;
+ ent->data = ioc;
}
-//#endif
} else {
- errcnt++;
- printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n",
- ioc->name, pname);
-
+ printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n",
+ ioc->name, mpt_ioc_proc_list[ii].name);
}
-
ioc = mpt_adapter_find_next(ioc);
}
- if (errcnt) {
-// remove_proc_entry("mpt", 0);
- return -ENOTDIR;
- }
-
return 0;
}
@@ -2971,44 +4535,44 @@
static int
procmpt_destroy(void)
{
- MPT_ADAPTER *ioc;
+ MPT_ADAPTER *ioc;
+ int ii;
- if (!procmpt_root_dir)
+ if (!mpt_proc_root_dir)
return 0;
/*
- * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
- * (single level) to multi level (e.g. "driver/message/fusion")
- * something here needs to change. -sralston
+ * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
+ * (single level) to multi level (e.g. "driver/message/fusion")
+ * something here needs to change. -sralston
*/
ioc = mpt_adapter_find_first();
- if (ioc != NULL) {
- remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0);
- }
-
while (ioc != NULL) {
char pname[32];
int namelen;
+
+ namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
+
/*
* Tear down each "/proc/mpt/iocN" subdirectory.
*/
- namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
- (void) sprintf(pname+namelen, "/summary");
- remove_proc_entry(pname, 0);
-//#ifdef MPT_DEBUG
- (void) sprintf(pname+namelen, "/dbg");
- remove_proc_entry(pname, 0);
-//#endif
- (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
- remove_proc_entry(pname, 0);
+ for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) {
+ (void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name);
+ remove_proc_entry(pname, NULL);
+ }
+
+ remove_proc_entry(ioc->name, mpt_proc_root_dir);
ioc = mpt_adapter_find_next(ioc);
}
- if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
- remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
- procmpt_root_dir = NULL;
+ for (ii=0; ii < MPT_PROC_ENTRIES; ii++)
+ remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir);
+
+ if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) {
+ remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
+ mpt_proc_root_dir = NULL;
return 0;
}
@@ -3016,23 +4580,23 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * procmpt_read_summary - Handle read request from /proc/mpt/summary
+/*
+ * procmpt_summary_read - Handle read request from /proc/mpt/summary
* or from /proc/mpt/iocN/summary.
- * @page: Pointer to area to write information
+ * @buf: Pointer to area to write information
* @start: Pointer to start pointer
- * @off: Offset to start writing
- * @count:
+ * @offset: Offset to start writing
+ * @request:
* @eof: Pointer to EOF integer
- * @data: Pointer
+ * @data: Pointer
*
- * Returns numbers of characters written to process performing the read.
+ * Returns number of characters written to process performing the read.
*/
static int
-procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data)
+procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
{
MPT_ADAPTER *ioc;
- char *out = page;
+ char *out = buf;
int len;
if (data == NULL)
@@ -3040,84 +4604,196 @@
else
ioc = data;
-// Too verbose!
-// out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none");
-
while (ioc) {
int more = 0;
-// Too verbose!
-// mpt_print_ioc_facts(ioc, out, &more, 0);
mpt_print_ioc_summary(ioc, out, &more, 0, 1);
out += more;
- if ((out-page) >= count) {
+ if ((out-buf) >= request) {
break;
}
if (data == NULL)
ioc = mpt_adapter_find_next(ioc);
else
- ioc = NULL; /* force exit for iocN */
+ ioc = NULL; /* force exit for iocN */
}
- len = out - page;
+ len = out - buf;
- PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+ MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
}
-// debug aid!
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg.
- * @page: Pointer to area to write information
+/*
+ * procmpt_version_read - Handle read request from /proc/mpt/version.
+ * @buf: Pointer to area to write information
* @start: Pointer to start pointer
- * @off: Offset to start writing
- * @count:
+ * @offset: Offset to start writing
+ * @request:
* @eof: Pointer to EOF integer
- * @data: Pointer
+ * @data: Pointer
*
- * Returns numbers of characters written to process performing the read.
+ * Returns number of characters written to process performing the read.
*/
static int
-procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data)
+procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
{
- MPT_ADAPTER *ioc;
- char *out = page;
- int len;
+ int ii;
+ int scsi, lan, ctl, targ, dmp;
+ char *drvname;
+ int len;
+
+ len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
+ len += sprintf(buf+len, " Fusion MPT base driver\n");
+
+ scsi = lan = ctl = targ = dmp = 0;
+ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ drvname = NULL;
+ if (MptCallbacks[ii]) {
+ switch (MptDriverClass[ii]) {
+ case MPTSCSIH_DRIVER:
+ if (!scsi++) drvname = "SCSI host";
+ break;
+ case MPTLAN_DRIVER:
+ if (!lan++) drvname = "LAN";
+ break;
+ case MPTSTM_DRIVER:
+ if (!targ++) drvname = "SCSI target";
+ break;
+ case MPTCTL_DRIVER:
+ if (!ctl++) drvname = "ioctl";
+ break;
+ case MPTDMP_DRIVER:
+ if (!dmp++) drvname = "DMP";
+ break;
+ }
+
+ if (drvname)
+ len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
+ /*
+ * Handle isense special case, because it
+ * doesn't do a formal mpt_register call.
+ */
+ if (isense_idx == ii)
+ len += sprintf(buf+len, " Fusion MPT isense driver\n");
+ } else
+ break;
+ }
- ioc = data;
+ MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
+}
- while (ioc) {
- int more = 0;
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
+ * @buf: Pointer to area to write information
+ * @start: Pointer to start pointer
+ * @offset: Offset to start writing
+ * @request:
+ * @eof: Pointer to EOF integer
+ * @data: Pointer
+ *
+ * Returns number of characters written to process performing the read.
+ */
+static int
+procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
+{
+ MPT_ADAPTER *ioc = data;
+ int len;
+ char expVer[32];
+ int sz;
+ int p;
- mpt_print_ioc_facts(ioc, out, &more, 0);
+ mpt_get_fw_exp_ver(expVer, ioc);
- out += more;
- if ((out-page) >= count) {
- break;
+ len = sprintf(buf, "%s:", ioc->name);
+ if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
+ len += sprintf(buf+len, " (f/w download boot flag set)");
+// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
+// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
+
+ len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
+ ioc->facts.ProductID,
+ ioc->prod_name);
+ len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
+ if (ioc->facts.FWImageSize)
+ len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
+ len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
+ len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
+ len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
+
+ len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
+ ioc->facts.CurrentHostMfaHighAddr);
+ len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
+ ioc->facts.CurrentSenseBufferHighAddr);
+
+ len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
+ len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+
+ len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
+ ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma);
+ /*
+ * Rounding UP to nearest 4-kB boundary here...
+ */
+ sz = (ioc->req_sz * ioc->req_depth) + 128;
+ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
+ len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
+ ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
+ len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
+ 4*ioc->facts.RequestFrameSize,
+ ioc->facts.GlobalCredits);
+
+ len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n",
+ ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma);
+ sz = (ioc->reply_sz * ioc->reply_depth) + 128;
+ len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
+ ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
+ len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
+ ioc->facts.CurReplyFrameSize,
+ ioc->facts.ReplyQueueDepth);
+
+ len += sprintf(buf+len, " MaxDevices = %d\n",
+ (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
+ len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
+
+ /* per-port info */
+ for (p=0; p < ioc->facts.NumberOfPorts; p++) {
+ len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
+ p+1,
+ ioc->facts.NumberOfPorts);
+ if ((int)ioc->chip_type <= (int)FC929) {
+ if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+ u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+ len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ a[5], a[4], a[3], a[2], a[1], a[0]);
+ }
+ len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
+ ioc->fc_port_page0[p].WWNN.High,
+ ioc->fc_port_page0[p].WWNN.Low,
+ ioc->fc_port_page0[p].WWPN.High,
+ ioc->fc_port_page0[p].WWPN.Low);
}
- ioc = NULL;
}
- len = out - page;
- PROC_MPT_READ_RETURN(page,start,off,count,eof,len);
+ MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
}
+
#endif /* CONFIG_PROC_FS } */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void
mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
{
- if ((ioc->facts.FWVersion & 0xF000) == 0xE000)
+ buf[0] ='\0';
+ if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
sprintf(buf, " (Exp %02d%02d)",
- (ioc->facts.FWVersion & 0x0F00) >> 8, /* Month */
- ioc->facts.FWVersion & 0x001F); /* Day */
- else
- buf[0] ='\0';
+ (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
+ (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
- /* insider hack! */
- if (ioc->facts.FWVersion & 0x0080) {
- strcat(buf, " [MDBG]");
+ /* insider hack! */
+ if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
+ strcat(buf, " [MDBG]");
}
}
@@ -3130,8 +4806,8 @@
* @len: Offset at which to start writing in buffer
* @showlan: Display LAN stuff?
*
- * This routine writes (english readable) ASCII text, which represents
- * a summary of IOC information, to a buffer.
+ * This routine writes (english readable) ASCII text, which represents
+ * a summary of IOC information, to a buffer.
*/
void
mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
@@ -3144,11 +4820,11 @@
/*
* Shorter summary of attached ioc's...
*/
- y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d",
+ y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
ioc->name,
ioc->prod_name,
MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
- ioc->facts.FWVersion,
+ ioc->facts.FWVersion.Word,
expVer,
ioc->facts.NumberOfPorts,
ioc->req_depth);
@@ -3159,8 +4835,11 @@
a[5], a[4], a[3], a[2], a[1], a[0]);
}
- if (ioc->pci_irq < 100)
- y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#ifndef __sparc__
+ y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+#else
+ y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
+#endif
if (!ioc->active)
y += sprintf(buffer+len+y, " (disabled)");
@@ -3171,75 +4850,66 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * Reset Handling
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer.
+ * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
+ * Management call based on input arg values. If TaskMgmt fails,
+ * return associated SCSI request.
* @ioc: Pointer to MPT_ADAPTER structure
- * @buffer: Pointer to buffer where IOC facts should be written
- * @size: Pointer to number of bytes we wrote (set by this routine)
- * @len: Offset at which to start writing in buffer
+ * @sleepFlag: Indicates if sleep or schedule must be called.
+ *
+ * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
+ * or a non-interrupt thread. In the former, must not call schedule().
*
- * This routine writes (english readable) ASCII text, which represents
- * a summary of the IOC facts, to a buffer.
+ * Remark: A return of -1 is a FATAL error case, as it means a
+ * FW reload/initialization failed.
+ *
+ * Returns 0 for SUCCESS or -1 if FAILED.
*/
-void
-mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+int
+mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
{
- char expVer[32];
- char iocName[16];
- int sz;
- int y;
- int p;
-
- mpt_get_fw_exp_ver(expVer, ioc);
+ int rc;
+ unsigned long flags;
- strcpy(iocName, ioc->name);
- y = sprintf(buffer+len, "%s:\n", iocName);
+ dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+#ifdef MFCNT
+ printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
+ printk("MF count 0x%x !\n", ioc->mfcnt);
+#endif
- y += sprintf(buffer+len+y, " ProductID = 0x%04x\n", ioc->facts.ProductID);
- for (p=0; p < ioc->facts.NumberOfPorts; p++) {
- y += sprintf(buffer+len+y, " PortNumber = %d (of %d)\n",
- p+1,
- ioc->facts.NumberOfPorts);
- if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
- u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
- y += sprintf(buffer+len+y, " LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- a[5], a[4], a[3], a[2], a[1], a[0]);
- }
- }
- y += sprintf(buffer+len+y, " FWVersion = 0x%04x%s\n", ioc->facts.FWVersion, expVer);
- y += sprintf(buffer+len+y, " MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
- y += sprintf(buffer+len+y, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
- y += sprintf(buffer+len+y, " EventState = 0x%02x\n", ioc->facts.EventState);
- y += sprintf(buffer+len+y, " CurrentHostMfaHighAddr = 0x%08x\n",
- ioc->facts.CurrentHostMfaHighAddr);
- y += sprintf(buffer+len+y, " CurrentSenseBufferHighAddr = 0x%08x\n",
- ioc->facts.CurrentSenseBufferHighAddr);
- y += sprintf(buffer+len+y, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
- y += sprintf(buffer+len+y, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
+ /* Reset the adapter. Prevent more than 1 call to
+ * mpt_do_ioc_recovery at any instant in time.
+ */
+ spin_lock_irqsave(&ioc->diagLock, flags);
+ if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
+ spin_unlock_irqrestore(&ioc->diagLock, flags);
+ return 0;
+ } else {
+ ioc->diagPending = 1;
+ }
+ spin_unlock_irqrestore(&ioc->diagLock, flags);
- y += sprintf(buffer+len+y, " RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
- ioc->req_alloc, ioc->req_alloc_dma);
- /*
- * Rounding UP to nearest 4-kB boundary here...
+ /* FIXME: If do_ioc_recovery fails, repeat....
*/
- sz = (ioc->req_sz * ioc->req_depth) + 128;
- sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
- y += sprintf(buffer+len+y, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
- ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
- y += sprintf(buffer+len+y, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
- 4*ioc->facts.RequestFrameSize,
- ioc->facts.GlobalCredits);
- y += sprintf(buffer+len+y, " ReplyFrames @ 0x%p (Dma @ 0x%08x)\n",
- ioc->reply_alloc, ioc->reply_alloc_dma);
- sz = (ioc->reply_sz * ioc->reply_depth) + 128;
- y += sprintf(buffer+len+y, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
- ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
- y += sprintf(buffer+len+y, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
- ioc->facts.CurReplyFrameSize,
- ioc->facts.ReplyQueueDepth);
+ if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
+ printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+ rc, ioc->name);
+ }
- *size = y;
+ spin_lock_irqsave(&ioc->diagLock, flags);
+ ioc->diagPending = 0;
+ if (ioc->alt_ioc)
+ ioc->alt_ioc->diagPending = 0;
+ spin_unlock_irqrestore(&ioc->diagLock, flags);
+
+ dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+
+ return rc;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3268,7 +4938,7 @@
ds = "External Bus Reset";
break;
case MPI_EVENT_RESCAN:
- ds = "Bus Rescan Event";
+ ds = "Bus Rescan Event";
/* 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. */
@@ -3296,6 +4966,9 @@
else
ds = "Events(OFF) Change";
break;
+ case MPI_EVENT_INTEGRATED_RAID:
+ ds = "Integrated Raid";
+ break;
/*
* MPT base "custom" events may be added here...
*/
@@ -3307,7 +4980,7 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* ProcessEventNotification - Route a received EventNotificationReply to
* all currently regeistered event handlers.
* @ioc: Pointer to MPT_ADAPTER structure
@@ -3322,7 +4995,7 @@
u16 evDataLen;
u32 evData0 = 0;
// u32 evCtx;
- int i;
+ int ii;
int r = 0;
int handlers = 0;
char *evStr;
@@ -3339,15 +5012,15 @@
}
evStr = EventDescriptionStr(event, evData0);
- dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n",
+ dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
ioc->name,
evStr,
event));
#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
- for (i = 0; i < evDataLen; i++)
- printk(" %08x", le32_to_cpu(pEventReply->Data[i]));
+ for (ii = 0; ii < evDataLen; ii++)
+ printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
printk("\n");
#endif
@@ -3365,6 +5038,8 @@
case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
case MPI_EVENT_LOGOUT: /* 09 */
+ case MPI_EVENT_INTEGRATED_RAID: /* 0B */
+ case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */
default:
break;
case MPI_EVENT_EVENT_CHANGE: /* 0A */
@@ -3382,13 +5057,36 @@
}
/*
+ * Should this event be logged? Events are written sequentially.
+ * When buffer is full, start again at the top.
+ */
+ if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
+ int idx;
+
+ idx = ioc->eventContext % ioc->eventLogSize;
+
+ ioc->events[idx].event = event;
+ ioc->events[idx].eventContext = ioc->eventContext;
+
+ for (ii = 0; ii < 2; ii++) {
+ if (ii < evDataLen)
+ ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
+ else
+ ioc->events[idx].data[ii] = 0;
+ }
+
+ ioc->eventContext++;
+ }
+
+
+ /*
* Call each currently registered protocol event handler.
*/
- for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
- if (MptEvHandlers[i]) {
- dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n",
- ioc->name, i));
- r += (*(MptEvHandlers[i]))(ioc, pEventReply);
+ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ if (MptEvHandlers[ii]) {
+ dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+ ioc->name, ii));
+ r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
handlers++;
}
}
@@ -3398,7 +5096,9 @@
* If needed, send (a single) EventAck.
*/
if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
- if ((i = SendEventAck(ioc, pEventReply)) != 0) {
+ if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
+ printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+ ioc->name, ii);
}
}
@@ -3427,7 +5127,7 @@
switch(log_info) {
/* FCP Initiator */
- case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
+ case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME:
desc = "Received an out of order frame - unsupported";
break;
case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME:
@@ -3483,7 +5183,7 @@
desc = "Not sent because login to remote node not validated";
break;
case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND:
- desc = "Cleared from the outbound after a logout";
+ desc = "Cleared from the outbound queue after a logout";
break;
case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN:
desc = "Cleared waiting for data after a logout";
@@ -3516,7 +5216,7 @@
break;
}
- printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
+ printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}",
ioc->name, log_info, subcl_str[subcl]);
if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET)
printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET);
@@ -3539,7 +5239,7 @@
mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
{
/* FIXME! */
- printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info);
+ printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3553,7 +5253,7 @@
* Specialized driver registration routine for the isense driver.
*/
int
-mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable)
+mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable)
{
int r = 0;
@@ -3562,6 +5262,7 @@
mpt_ASCQ_TableSz = ascqtbl_sz;
mpt_ScsiOpcodesPtr = opsTable;
printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n");
+ isense_idx = last_drv_idx;
r = 1;
}
MOD_INC_USE_COUNT;
@@ -3582,11 +5283,15 @@
mpt_ASCQ_TableSz = 0;
mpt_ScsiOpcodesPtr = NULL;
printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
+ isense_idx = -1;
MOD_DEC_USE_COUNT;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+EXPORT_SYMBOL(mpt_adapters);
+EXPORT_SYMBOL(mpt_proc_root_dir);
+EXPORT_SYMBOL(DmpService);
EXPORT_SYMBOL(mpt_register);
EXPORT_SYMBOL(mpt_deregister);
EXPORT_SYMBOL(mpt_event_register);
@@ -3597,12 +5302,16 @@
EXPORT_SYMBOL(mpt_put_msg_frame);
EXPORT_SYMBOL(mpt_free_msg_frame);
EXPORT_SYMBOL(mpt_send_handshake_request);
+EXPORT_SYMBOL(mpt_handshake_req_reply_wait);
EXPORT_SYMBOL(mpt_adapter_find_first);
EXPORT_SYMBOL(mpt_adapter_find_next);
EXPORT_SYMBOL(mpt_verify_adapter);
+EXPORT_SYMBOL(mpt_GetIocState);
EXPORT_SYMBOL(mpt_print_ioc_summary);
EXPORT_SYMBOL(mpt_lan_index);
EXPORT_SYMBOL(mpt_stm_index);
+EXPORT_SYMBOL(mpt_HardResetHandler);
+EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_register_ascqops_strings);
EXPORT_SYMBOL(mpt_deregister_ascqops_strings);
@@ -3611,12 +5320,13 @@
EXPORT_SYMBOL(mpt_ScsiOpcodesPtr);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* fusion_init - Fusion MPT base driver initialization routine.
*
* Returns 0 for success, non-zero for failure.
*/
-int __init fusion_init(void)
+int __init
+fusion_init(void)
{
int i;
@@ -3636,12 +5346,22 @@
MptResetHandlers[i] = NULL;
}
+ DmpService = NULL;
+
/* NEW! 20010120 -sralston
* Register ourselves (mptbase) in order to facilitate
* EventNotification handling.
*/
mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
+ /* Register for hard reset handling callbacks.
+ */
+ if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
+ dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
+ } else {
+ /* FIXME! */
+ }
+
if ((i = mpt_pci_scan()) < 0)
return i;
@@ -3649,13 +5369,14 @@
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
+/*
* fusion_exit - Perform driver unload cleanup.
*
* This routine frees all resources associated with each MPT adapter
* and removes all %MPT_PROCFS_MPTBASEDIR entries.
*/
-static void fusion_exit(void)
+static void
+fusion_exit(void)
{
MPT_ADAPTER *this;
@@ -3665,7 +5386,7 @@
* Moved this *above* removal of all MptAdapters!
*/
#ifdef CONFIG_PROC_FS
- procmpt_destroy();
+ (void) procmpt_destroy();
#endif
while (! Q_IS_EMPTY(&MptAdapters)) {
@@ -3673,6 +5394,8 @@
Q_DEL_ITEM(this);
mpt_adapter_dispose(this);
}
+
+ mpt_reset_deregister(mpt_base_index);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)