blob: 673cdd955eed9da9736da6f02decf751bb9094e4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
49#include <linux/config.h>
50#include <linux/version.h>
51#include <linux/kernel.h>
52#include <linux/module.h>
53#include <linux/errno.h>
54#include <linux/init.h>
55#include <linux/slab.h>
56#include <linux/types.h>
57#include <linux/pci.h>
58#include <linux/kdev_t.h>
59#include <linux/blkdev.h>
60#include <linux/delay.h>
61#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040062#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#include <asm/io.h>
64#ifdef CONFIG_MTRR
65#include <asm/mtrr.h>
66#endif
67#ifdef __sparc__
68#include <asm/irq.h> /* needed for __irq_itoa() proto */
69#endif
70
71#include "mptbase.h"
72
73/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
74#define my_NAME "Fusion MPT base driver"
75#define my_VERSION MPT_LINUX_VERSION_COMMON
76#define MYNAM "mptbase"
77
78MODULE_AUTHOR(MODULEAUTHOR);
79MODULE_DESCRIPTION(my_NAME);
80MODULE_LICENSE("GPL");
81
82/*
83 * cmd line parameters
84 */
85#ifdef MFCNT
86static int mfcounter = 0;
87#define PRINT_MF_COUNT 20000
88#endif
89
90/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
91/*
92 * Public data...
93 */
94int mpt_lan_index = -1;
95int mpt_stm_index = -1;
96
97struct proc_dir_entry *mpt_proc_root_dir;
98
99#define WHOINIT_UNKNOWN 0xAA
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Private data...
104 */
105 /* Adapter link list */
106LIST_HEAD(ioc_list);
107 /* Callback lookup table */
108static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
109 /* Protocol driver class lookup table */
110static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
111 /* Event handler lookup table */
112static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Reset handler lookup table */
114static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116
117static int mpt_base_index = -1;
118static int last_drv_idx = -1;
119
120static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Forward protos...
125 */
126static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
127static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
128static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
129 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
130 int sleepFlag);
131static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
132static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
133static void mpt_adapter_disable(MPT_ADAPTER *ioc);
134static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
135
136static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
137static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
138//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
139static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
140static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
141static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
142static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
143static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
144static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);
145static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
146static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
147static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
148static int PrimeIocFifos(MPT_ADAPTER *ioc);
149static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
151static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
152static int GetLanConfigPages(MPT_ADAPTER *ioc);
153static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
154static int GetIoUnitPage2(MPT_ADAPTER *ioc);
155static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
156static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
157static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
158static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
159static void mpt_timer_expired(unsigned long data);
160static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
161static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
162
163#ifdef CONFIG_PROC_FS
164static int procmpt_summary_read(char *buf, char **start, off_t offset,
165 int request, int *eof, void *data);
166static int procmpt_version_read(char *buf, char **start, off_t offset,
167 int request, int *eof, void *data);
168static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170#endif
171static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
172
173//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
174static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
175static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
176static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
177static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
178
179/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static int __init fusion_init (void);
181static void __exit fusion_exit (void);
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#define CHIPREG_READ32(addr) readl_relaxed(addr)
184#define CHIPREG_READ32_dmasync(addr) readl(addr)
185#define CHIPREG_WRITE32(addr,val) writel(val, addr)
186#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
187#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
188
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600189static void
190pci_disable_io_access(struct pci_dev *pdev)
191{
192 u16 command_reg;
193
194 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
195 command_reg &= ~1;
196 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
197}
198
199static void
200pci_enable_io_access(struct pci_dev *pdev)
201{
202 u16 command_reg;
203
204 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
205 command_reg |= 1;
206 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
207}
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
210/*
211 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
212 * @irq: irq number (not used)
213 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
214 * @r: pt_regs pointer (not used)
215 *
216 * This routine is registered via the request_irq() kernel API call,
217 * and handles all interrupts generated from a specific MPT adapter
218 * (also referred to as a IO Controller or IOC).
219 * This routine must clear the interrupt from the adapter and does
220 * so by reading the reply FIFO. Multiple replies may be processed
221 * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR
222 * which is currently set to 32 in mptbase.h.
223 *
224 * This routine handles register-level access of the adapter but
225 * dispatches (calls) a protocol-specific callback routine to handle
226 * the protocol-specific details of the MPT request completion.
227 */
228static irqreturn_t
229mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
230{
231 MPT_ADAPTER *ioc;
232 MPT_FRAME_HDR *mf;
233 MPT_FRAME_HDR *mr;
234 u32 pa;
235 int req_idx;
236 int cb_idx;
237 int type;
238 int freeme;
239
240 ioc = (MPT_ADAPTER *)bus_id;
241
242 /*
243 * Drain the reply FIFO!
244 *
245 * NOTES: I've seen up to 10 replies processed in this loop, so far...
246 * Update: I've seen up to 9182 replies processed in this loop! ??
247 * Update: Limit ourselves to processing max of N replies
248 * (bottom of loop).
249 */
250 while (1) {
251
252 if ((pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF)
253 return IRQ_HANDLED;
254
255 cb_idx = 0;
256 freeme = 0;
257
258 /*
259 * Check for non-TURBO reply!
260 */
261 if (pa & MPI_ADDRESS_REPLY_A_BIT) {
262 u32 reply_dma_low;
263 u16 ioc_stat;
264
265 /* non-TURBO reply! Hmmm, something may be up...
266 * Newest turbo reply mechanism; get address
267 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
268 */
269
270 /* Map DMA address of reply header to cpu address.
271 * pa is 32 bits - but the dma address may be 32 or 64 bits
272 * get offset based only only the low addresses
273 */
274 reply_dma_low = (pa = (pa << 1));
275 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
276 (reply_dma_low - ioc->reply_frames_low_dma));
277
278 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
279 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
280 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
281
282 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n",
283 ioc->name, mr, req_idx));
284 DBG_DUMP_REPLY_FRAME(mr)
285
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400286 /* Check/log IOC log info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 */
288 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
289 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
290 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
291 if (ioc->bus_type == FC)
292 mpt_fc_log_info(ioc, log_info);
293 else if (ioc->bus_type == SCSI)
294 mpt_sp_log_info(ioc, log_info);
295 }
296 if (ioc_stat & MPI_IOCSTATUS_MASK) {
297 if (ioc->bus_type == SCSI)
298 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
299 }
300 } else {
301 /*
302 * Process turbo (context) reply...
303 */
304 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa));
305 type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT);
306 if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) {
307 cb_idx = mpt_stm_index;
308 mf = NULL;
309 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
310 } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) {
311 cb_idx = mpt_lan_index;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400312 /* Blind set of mf to NULL here was fatal
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 * after lan_reply says "freeme"
314 * Fix sort of combined with an optimization here;
315 * added explicit check for case where lan_reply
316 * was just returning 1 and doing nothing else.
317 * For this case skip the callback, but set up
318 * proper mf value first here:-)
319 */
320 if ((pa & 0x58000000) == 0x58000000) {
321 req_idx = pa & 0x0000FFFF;
322 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
323 freeme = 1;
324 /*
325 * IMPORTANT! Invalidate the callback!
326 */
327 cb_idx = 0;
328 } else {
329 mf = NULL;
330 }
331 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
332 } else {
333 req_idx = pa & 0x0000FFFF;
334 cb_idx = (pa & 0x00FF0000) >> 16;
335 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
336 mr = NULL;
337 }
338 pa = 0; /* No reply flush! */
339 }
340
341#ifdef MPT_DEBUG_IRQ
342 if (ioc->bus_type == SCSI) {
343 /* Verify mf, mr are reasonable.
344 */
345 if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
346 || (mf < ioc->req_frames)) ) {
347 printk(MYIOC_s_WARN_FMT
348 "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
349 cb_idx = 0;
350 pa = 0;
351 freeme = 0;
352 }
353 if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
354 || (mr < ioc->reply_frames)) ) {
355 printk(MYIOC_s_WARN_FMT
356 "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
357 cb_idx = 0;
358 pa = 0;
359 freeme = 0;
360 }
361 if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
362 printk(MYIOC_s_WARN_FMT
363 "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
364 cb_idx = 0;
365 pa = 0;
366 freeme = 0;
367 }
368 }
369#endif
370
371 /* Check for (valid) IO callback! */
372 if (cb_idx) {
373 /* Do the callback! */
374 freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr);
375 }
376
377 if (pa) {
378 /* Flush (non-TURBO) reply with a WRITE! */
379 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
380 }
381
382 if (freeme) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* Put Request back on FreeQ! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500384 mpt_free_msg_frame(ioc, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
387 mb();
388 } /* drain reply FIFO */
389
390 return IRQ_HANDLED;
391}
392
393/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
394/*
395 * mpt_base_reply - MPT base driver's callback routine; all base driver
396 * "internal" request/reply processing is routed here.
397 * Currently used for EventNotification and EventAck handling.
398 * @ioc: Pointer to MPT_ADAPTER structure
399 * @mf: Pointer to original MPT request frame
400 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
401 *
402 * Returns 1 indicating original alloc'd request frame ptr
403 * should be freed, or 0 if it shouldn't.
404 */
405static int
406mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
407{
408 int freereq = 1;
409 u8 func;
410
411 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
412
413 if ((mf == NULL) ||
414 (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
415 printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n",
416 ioc->name, (void *)mf);
417 return 1;
418 }
419
420 if (reply == NULL) {
421 dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n",
422 ioc->name));
423 return 1;
424 }
425
426 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
427 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
428 DBG_DUMP_REQUEST_FRAME_HDR(mf)
429 }
430
431 func = reply->u.hdr.Function;
432 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
433 ioc->name, func));
434
435 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
436 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
437 int evHandlers = 0;
438 int results;
439
440 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
441 if (results != evHandlers) {
442 /* CHECKME! Any special handling needed here? */
443 devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
444 ioc->name, evHandlers, results));
445 }
446
447 /*
448 * Hmmm... It seems that EventNotificationReply is an exception
449 * to the rule of one reply per request.
450 */
451 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
452 freereq = 0;
453
454#ifdef CONFIG_PROC_FS
455// LogEvent(ioc, pEvReply);
456#endif
457
458 } else if (func == MPI_FUNCTION_EVENT_ACK) {
459 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
460 ioc->name));
461 } else if (func == MPI_FUNCTION_CONFIG ||
462 func == MPI_FUNCTION_TOOLBOX) {
463 CONFIGPARMS *pCfg;
464 unsigned long flags;
465
466 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
467 ioc->name, mf, reply));
468
469 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
470
471 if (pCfg) {
472 /* disable timer and remove from linked list */
473 del_timer(&pCfg->timer);
474
475 spin_lock_irqsave(&ioc->FreeQlock, flags);
476 list_del(&pCfg->linkage);
477 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
478
479 /*
480 * If IOC Status is SUCCESS, save the header
481 * and set the status code to GOOD.
482 */
483 pCfg->status = MPT_CONFIG_ERROR;
484 if (reply) {
485 ConfigReply_t *pReply = (ConfigReply_t *)reply;
486 u16 status;
487
488 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
489 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
490 status, le32_to_cpu(pReply->IOCLogInfo)));
491
492 pCfg->status = status;
493 if (status == MPI_IOCSTATUS_SUCCESS) {
494 pCfg->hdr->PageVersion = pReply->Header.PageVersion;
495 pCfg->hdr->PageLength = pReply->Header.PageLength;
496 pCfg->hdr->PageNumber = pReply->Header.PageNumber;
497 pCfg->hdr->PageType = pReply->Header.PageType;
498 }
499 }
500
501 /*
502 * Wake up the original calling thread
503 */
504 pCfg->wait_done = 1;
505 wake_up(&mpt_waitq);
506 }
507 } else {
508 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
509 ioc->name, func);
510 }
511
512 /*
513 * Conditionally tell caller to free the original
514 * EventNotification/EventAck/unexpected request frame!
515 */
516 return freereq;
517}
518
519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
520/**
521 * mpt_register - Register protocol-specific main callback handler.
522 * @cbfunc: callback function pointer
523 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
524 *
525 * This routine is called by a protocol-specific driver (SCSI host,
526 * LAN, SCSI target) to register it's reply callback routine. Each
527 * protocol-specific driver must do this before it will be able to
528 * use any IOC resources, such as obtaining request frames.
529 *
530 * NOTES: The SCSI protocol driver currently calls this routine thrice
531 * in order to register separate callbacks; one for "normal" SCSI IO;
532 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
533 *
534 * Returns a positive integer valued "handle" in the
535 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
536 * Any non-positive return value (including zero!) should be considered
537 * an error by the caller.
538 */
539int
540mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
541{
542 int i;
543
544 last_drv_idx = -1;
545
546 /*
547 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
548 * (slot/handle 0 is reserved!)
549 */
550 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
551 if (MptCallbacks[i] == NULL) {
552 MptCallbacks[i] = cbfunc;
553 MptDriverClass[i] = dclass;
554 MptEvHandlers[i] = NULL;
555 last_drv_idx = i;
556 break;
557 }
558 }
559
560 return last_drv_idx;
561}
562
563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
564/**
565 * mpt_deregister - Deregister a protocol drivers resources.
566 * @cb_idx: previously registered callback handle
567 *
568 * Each protocol-specific driver should call this routine when it's
569 * module is unloaded.
570 */
571void
572mpt_deregister(int cb_idx)
573{
574 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
575 MptCallbacks[cb_idx] = NULL;
576 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
577 MptEvHandlers[cb_idx] = NULL;
578
579 last_drv_idx++;
580 }
581}
582
583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
584/**
585 * mpt_event_register - Register protocol-specific event callback
586 * handler.
587 * @cb_idx: previously registered (via mpt_register) callback handle
588 * @ev_cbfunc: callback function
589 *
590 * This routine can be called by one or more protocol-specific drivers
591 * if/when they choose to be notified of MPT events.
592 *
593 * Returns 0 for success.
594 */
595int
596mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
597{
598 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
599 return -1;
600
601 MptEvHandlers[cb_idx] = ev_cbfunc;
602 return 0;
603}
604
605/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
606/**
607 * mpt_event_deregister - Deregister protocol-specific event callback
608 * handler.
609 * @cb_idx: previously registered callback handle
610 *
611 * Each protocol-specific driver should call this routine
612 * when it does not (or can no longer) handle events,
613 * or when it's module is unloaded.
614 */
615void
616mpt_event_deregister(int cb_idx)
617{
618 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
619 return;
620
621 MptEvHandlers[cb_idx] = NULL;
622}
623
624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
625/**
626 * mpt_reset_register - Register protocol-specific IOC reset handler.
627 * @cb_idx: previously registered (via mpt_register) callback handle
628 * @reset_func: reset function
629 *
630 * This routine can be called by one or more protocol-specific drivers
631 * if/when they choose to be notified of IOC resets.
632 *
633 * Returns 0 for success.
634 */
635int
636mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
637{
638 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
639 return -1;
640
641 MptResetHandlers[cb_idx] = reset_func;
642 return 0;
643}
644
645/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
646/**
647 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
648 * @cb_idx: previously registered callback handle
649 *
650 * Each protocol-specific driver should call this routine
651 * when it does not (or can no longer) handle IOC reset handling,
652 * or when it's module is unloaded.
653 */
654void
655mpt_reset_deregister(int cb_idx)
656{
657 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
658 return;
659
660 MptResetHandlers[cb_idx] = NULL;
661}
662
663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
664/**
665 * mpt_device_driver_register - Register device driver hooks
666 */
667int
668mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
669{
670 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400673 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 }
675
676 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
677
678 /* call per pci device probe entry point */
679 list_for_each_entry(ioc, &ioc_list, list) {
680 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400681 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
684 }
685
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
691 * mpt_device_driver_deregister - DeRegister device driver hooks
692 */
693void
694mpt_device_driver_deregister(int cb_idx)
695{
696 struct mpt_pci_driver *dd_cbfunc;
697 MPT_ADAPTER *ioc;
698
699 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
700 return;
701
702 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
703
704 list_for_each_entry(ioc, &ioc_list, list) {
705 if (dd_cbfunc->remove)
706 dd_cbfunc->remove(ioc->pcidev);
707 }
708
709 MptDeviceDriverHandlers[cb_idx] = NULL;
710}
711
712
713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
714/**
715 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
716 * allocated per MPT adapter.
717 * @handle: Handle of registered MPT protocol driver
718 * @ioc: Pointer to MPT adapter structure
719 *
720 * Returns pointer to a MPT request frame or %NULL if none are available
721 * or IOC is not active.
722 */
723MPT_FRAME_HDR*
724mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
725{
726 MPT_FRAME_HDR *mf;
727 unsigned long flags;
728 u16 req_idx; /* Request index */
729
730 /* validate handle and ioc identifier */
731
732#ifdef MFCNT
733 if (!ioc->active)
734 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
735#endif
736
737 /* If interrupts are not attached, do not return a request frame */
738 if (!ioc->active)
739 return NULL;
740
741 spin_lock_irqsave(&ioc->FreeQlock, flags);
742 if (!list_empty(&ioc->FreeQ)) {
743 int req_offset;
744
745 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
746 u.frame.linkage.list);
747 list_del(&mf->u.frame.linkage.list);
748 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
749 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
750 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500751 req_idx = req_offset / ioc->req_sz;
752 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
754 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
755#ifdef MFCNT
756 ioc->mfcnt++;
757#endif
758 }
759 else
760 mf = NULL;
761 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
762
763#ifdef MFCNT
764 if (mf == NULL)
765 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
766 mfcounter++;
767 if (mfcounter == PRINT_MF_COUNT)
768 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
769#endif
770
771 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
772 ioc->name, handle, ioc->id, mf));
773 return mf;
774}
775
776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
777/**
778 * mpt_put_msg_frame - Send a protocol specific MPT request frame
779 * to a IOC.
780 * @handle: Handle of registered MPT protocol driver
781 * @ioc: Pointer to MPT adapter structure
782 * @mf: Pointer to MPT request frame
783 *
784 * This routine posts a MPT request frame to the request post FIFO of a
785 * specific MPT adapter.
786 */
787void
788mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
789{
790 u32 mf_dma_addr;
791 int req_offset;
792 u16 req_idx; /* Request index */
793
794 /* ensure values are reset properly! */
795 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
796 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
797 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500798 req_idx = req_offset / ioc->req_sz;
799 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
801
802#ifdef MPT_DEBUG_MSG_FRAME
803 {
804 u32 *m = mf->u.frame.hwhdr.__hdr;
805 int ii, n;
806
807 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
808 ioc->name, m);
809 n = ioc->req_sz/4 - 1;
810 while (m[n] == 0)
811 n--;
812 for (ii=0; ii<=n; ii++) {
813 if (ii && ((ii%8)==0))
814 printk("\n" KERN_INFO " ");
815 printk(" %08x", le32_to_cpu(m[ii]));
816 }
817 printk("\n");
818 }
819#endif
820
821 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
822 dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
823 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
824}
825
826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
827/**
828 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
829 * @handle: Handle of registered MPT protocol driver
830 * @ioc: Pointer to MPT adapter structure
831 * @mf: Pointer to MPT request frame
832 *
833 * This routine places a MPT request frame back on the MPT adapter's
834 * FreeQ.
835 */
836void
837mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
838{
839 unsigned long flags;
840
841 /* Put Request back on FreeQ! */
842 spin_lock_irqsave(&ioc->FreeQlock, flags);
843 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
844#ifdef MFCNT
845 ioc->mfcnt--;
846#endif
847 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
848}
849
850/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
851/**
852 * mpt_add_sge - Place a simple SGE at address pAddr.
853 * @pAddr: virtual address for SGE
854 * @flagslength: SGE flags and data transfer length
855 * @dma_addr: Physical address
856 *
857 * This routine places a MPT request frame back on the MPT adapter's
858 * FreeQ.
859 */
860void
861mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
862{
863 if (sizeof(dma_addr_t) == sizeof(u64)) {
864 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
865 u32 tmp = dma_addr & 0xFFFFFFFF;
866
867 pSge->FlagsLength = cpu_to_le32(flagslength);
868 pSge->Address.Low = cpu_to_le32(tmp);
869 tmp = (u32) ((u64)dma_addr >> 32);
870 pSge->Address.High = cpu_to_le32(tmp);
871
872 } else {
873 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
874 pSge->FlagsLength = cpu_to_le32(flagslength);
875 pSge->Address = cpu_to_le32(dma_addr);
876 }
877}
878
879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
880/**
881 * mpt_send_handshake_request - Send MPT request via doorbell
882 * handshake method.
883 * @handle: Handle of registered MPT protocol driver
884 * @ioc: Pointer to MPT adapter structure
885 * @reqBytes: Size of the request in bytes
886 * @req: Pointer to MPT request frame
887 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
888 *
889 * This routine is used exclusively to send MptScsiTaskMgmt
890 * requests since they are required to be sent via doorbell handshake.
891 *
892 * NOTE: It is the callers responsibility to byte-swap fields in the
893 * request which are greater than 1 byte in size.
894 *
895 * Returns 0 for success, non-zero for failure.
896 */
897int
898mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
899{
900 int r = 0;
901 u8 *req_as_bytes;
902 int ii;
903
904 /* State is known to be good upon entering
905 * this function so issue the bus reset
906 * request.
907 */
908
909 /*
910 * Emulate what mpt_put_msg_frame() does /wrt to sanity
911 * setting cb_idx/req_idx. But ONLY if this request
912 * is in proper (pre-alloc'd) request buffer range...
913 */
914 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
915 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
916 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
917 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
918 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
919 }
920
921 /* Make sure there are no doorbells */
922 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
923
924 CHIPREG_WRITE32(&ioc->chip->Doorbell,
925 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
926 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
927
928 /* Wait for IOC doorbell int */
929 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
930 return ii;
931 }
932
933 /* Read doorbell and check for active bit */
934 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
935 return -5;
936
937 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
938 ioc->name, ii));
939
940 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
941
942 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
943 return -2;
944 }
945
946 /* Send request via doorbell handshake */
947 req_as_bytes = (u8 *) req;
948 for (ii = 0; ii < reqBytes/4; ii++) {
949 u32 word;
950
951 word = ((req_as_bytes[(ii*4) + 0] << 0) |
952 (req_as_bytes[(ii*4) + 1] << 8) |
953 (req_as_bytes[(ii*4) + 2] << 16) |
954 (req_as_bytes[(ii*4) + 3] << 24));
955 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
956 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
957 r = -3;
958 break;
959 }
960 }
961
962 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
963 r = 0;
964 else
965 r = -4;
966
967 /* Make sure there are no doorbells */
968 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
969
970 return r;
971}
972
973/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
974/**
975 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
976 * the associated MPT adapter structure.
977 * @iocid: IOC unique identifier (integer)
978 * @iocpp: Pointer to pointer to IOC adapter
979 *
980 * Returns iocid and sets iocpp.
981 */
982int
983mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
984{
985 MPT_ADAPTER *ioc;
986
987 list_for_each_entry(ioc,&ioc_list,list) {
988 if (ioc->id == iocid) {
989 *iocpp =ioc;
990 return iocid;
991 }
992 }
993
994 *iocpp = NULL;
995 return -1;
996}
997
998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
999/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001000 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 * @pdev: Pointer to pci_dev structure
1002 *
1003 * This routine performs all the steps necessary to bring the IOC of
1004 * a MPT adapter to a OPERATIONAL state. This includes registering
1005 * memory regions, registering the interrupt, and allocating request
1006 * and reply memory pools.
1007 *
1008 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1009 * MPT adapter.
1010 *
1011 * Returns 0 for success, non-zero for failure.
1012 *
1013 * TODO: Add support for polled controllers
1014 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001015int
1016mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017{
1018 MPT_ADAPTER *ioc;
1019 u8 __iomem *mem;
1020 unsigned long mem_phys;
1021 unsigned long port;
1022 u32 msize;
1023 u32 psize;
1024 int ii;
1025 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 u8 revision;
1027 u8 pcixcmd;
1028 static int mpt_ids = 0;
1029#ifdef CONFIG_PROC_FS
1030 struct proc_dir_entry *dent, *ent;
1031#endif
1032
1033 if (pci_enable_device(pdev))
1034 return r;
1035
1036 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
1037
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001038 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 dprintk((KERN_INFO MYNAM
1040 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001041 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1043 return r;
1044 }
1045
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001046 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 dprintk((KERN_INFO MYNAM
1048 ": Using 64 bit consistent mask\n"));
1049 else
1050 dprintk((KERN_INFO MYNAM
1051 ": Not using 64 bit consistent mask\n"));
1052
1053 ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1054 if (ioc == NULL) {
1055 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1056 return -ENOMEM;
1057 }
1058 memset(ioc, 0, sizeof(MPT_ADAPTER));
1059 ioc->alloc_total = sizeof(MPT_ADAPTER);
1060 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1061 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
1062
1063 ioc->pcidev = pdev;
1064 ioc->diagPending = 0;
1065 spin_lock_init(&ioc->diagLock);
1066
1067 /* Initialize the event logging.
1068 */
1069 ioc->eventTypes = 0; /* None */
1070 ioc->eventContext = 0;
1071 ioc->eventLogSize = 0;
1072 ioc->events = NULL;
1073
1074#ifdef MFCNT
1075 ioc->mfcnt = 0;
1076#endif
1077
1078 ioc->cached_fw = NULL;
1079
1080 /* Initilize SCSI Config Data structure
1081 */
1082 memset(&ioc->spi_data, 0, sizeof(ScsiCfgData));
1083
1084 /* Initialize the running configQ head.
1085 */
1086 INIT_LIST_HEAD(&ioc->configQ);
1087
1088 /* Find lookup slot. */
1089 INIT_LIST_HEAD(&ioc->list);
1090 ioc->id = mpt_ids++;
1091
1092 mem_phys = msize = 0;
1093 port = psize = 0;
1094 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1095 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1096 /* Get I/O space! */
1097 port = pci_resource_start(pdev, ii);
1098 psize = pci_resource_len(pdev,ii);
1099 } else {
1100 /* Get memmap */
1101 mem_phys = pci_resource_start(pdev, ii);
1102 msize = pci_resource_len(pdev,ii);
1103 break;
1104 }
1105 }
1106 ioc->mem_size = msize;
1107
1108 if (ii == DEVICE_COUNT_RESOURCE) {
1109 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1110 kfree(ioc);
1111 return -EINVAL;
1112 }
1113
1114 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1115 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1116
1117 mem = NULL;
1118 /* Get logical ptr for PciMem0 space */
1119 /*mem = ioremap(mem_phys, msize);*/
1120 mem = ioremap(mem_phys, 0x100);
1121 if (mem == NULL) {
1122 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1123 kfree(ioc);
1124 return -EINVAL;
1125 }
1126 ioc->memmap = mem;
1127 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1128
1129 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1130 &ioc->facts, &ioc->pfacts[0]));
1131
1132 ioc->mem_phys = mem_phys;
1133 ioc->chip = (SYSIF_REGS __iomem *)mem;
1134
1135 /* Save Port IO values in case we need to do downloadboot */
1136 {
1137 u8 *pmem = (u8*)port;
1138 ioc->pio_mem_phys = port;
1139 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1140 }
1141
1142 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1143 ioc->prod_name = "LSIFC909";
1144 ioc->bus_type = FC;
1145 }
1146 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
1147 ioc->prod_name = "LSIFC929";
1148 ioc->bus_type = FC;
1149 }
1150 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1151 ioc->prod_name = "LSIFC919";
1152 ioc->bus_type = FC;
1153 }
1154 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1155 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1156 ioc->bus_type = FC;
1157 if (revision < XL_929) {
1158 ioc->prod_name = "LSIFC929X";
1159 /* 929X Chip Fix. Set Split transactions level
1160 * for PCIX. Set MOST bits to zero.
1161 */
1162 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1163 pcixcmd &= 0x8F;
1164 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1165 } else {
1166 ioc->prod_name = "LSIFC929XL";
1167 /* 929XL Chip Fix. Set MMRBC to 0x08.
1168 */
1169 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1170 pcixcmd |= 0x08;
1171 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1172 }
1173 }
1174 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1175 ioc->prod_name = "LSIFC919X";
1176 ioc->bus_type = FC;
1177 /* 919X Chip Fix. Set Split transactions level
1178 * for PCIX. Set MOST bits to zero.
1179 */
1180 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1181 pcixcmd &= 0x8F;
1182 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1183 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001184 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1185 ioc->prod_name = "LSIFC939X";
1186 ioc->bus_type = FC;
1187 ioc->errata_flag_1064 = 1;
1188 }
1189 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1190 ioc->prod_name = "LSIFC949X";
1191 ioc->bus_type = FC;
1192 ioc->errata_flag_1064 = 1;
1193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1195 ioc->prod_name = "LSI53C1030";
1196 ioc->bus_type = SCSI;
1197 /* 1030 Chip Fix. Disable Split transactions
1198 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1199 */
1200 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1201 if (revision < C0_1030) {
1202 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1203 pcixcmd &= 0x8F;
1204 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1205 }
1206 }
1207 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1208 ioc->prod_name = "LSI53C1035";
1209 ioc->bus_type = SCSI;
1210 }
1211
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001212 if (ioc->errata_flag_1064)
1213 pci_disable_io_access(pdev);
1214
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 sprintf(ioc->name, "ioc%d", ioc->id);
1216
1217 spin_lock_init(&ioc->FreeQlock);
1218
1219 /* Disable all! */
1220 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1221 ioc->active = 0;
1222 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1223
1224 /* Set lookup ptr. */
1225 list_add_tail(&ioc->list, &ioc_list);
1226
1227 ioc->pci_irq = -1;
1228 if (pdev->irq) {
1229 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1230
1231 if (r < 0) {
1232#ifndef __sparc__
1233 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1234 ioc->name, pdev->irq);
1235#else
1236 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1237 ioc->name, __irq_itoa(pdev->irq));
1238#endif
1239 list_del(&ioc->list);
1240 iounmap(mem);
1241 kfree(ioc);
1242 return -EBUSY;
1243 }
1244
1245 ioc->pci_irq = pdev->irq;
1246
1247 pci_set_master(pdev); /* ?? */
1248 pci_set_drvdata(pdev, ioc);
1249
1250#ifndef __sparc__
1251 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1252#else
1253 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1254#endif
1255 }
1256
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001257 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 */
1259 mpt_detect_bound_ports(ioc, pdev);
1260
1261 if ((r = mpt_do_ioc_recovery(ioc,
1262 MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) {
1263 printk(KERN_WARNING MYNAM
1264 ": WARNING - %s did not initialize properly! (%d)\n",
1265 ioc->name, r);
1266
1267 list_del(&ioc->list);
1268 free_irq(ioc->pci_irq, ioc);
1269 iounmap(mem);
1270 kfree(ioc);
1271 pci_set_drvdata(pdev, NULL);
1272 return r;
1273 }
1274
1275 /* call per device driver probe entry point */
1276 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1277 if(MptDeviceDriverHandlers[ii] &&
1278 MptDeviceDriverHandlers[ii]->probe) {
1279 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1280 }
1281 }
1282
1283#ifdef CONFIG_PROC_FS
1284 /*
1285 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1286 */
1287 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1288 if (dent) {
1289 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1290 if (ent) {
1291 ent->read_proc = procmpt_iocinfo_read;
1292 ent->data = ioc;
1293 }
1294 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1295 if (ent) {
1296 ent->read_proc = procmpt_summary_read;
1297 ent->data = ioc;
1298 }
1299 }
1300#endif
1301
1302 return 0;
1303}
1304
1305/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1306/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001307 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 * @pdev: Pointer to pci_dev structure
1309 *
1310 */
1311
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001312void
1313mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
1315 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1316 char pname[32];
1317 int ii;
1318
1319 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1320 remove_proc_entry(pname, NULL);
1321 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1322 remove_proc_entry(pname, NULL);
1323 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1324 remove_proc_entry(pname, NULL);
1325
1326 /* call per device driver remove entry point */
1327 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1328 if(MptDeviceDriverHandlers[ii] &&
1329 MptDeviceDriverHandlers[ii]->remove) {
1330 MptDeviceDriverHandlers[ii]->remove(pdev);
1331 }
1332 }
1333
1334 /* Disable interrupts! */
1335 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1336
1337 ioc->active = 0;
1338 synchronize_irq(pdev->irq);
1339
1340 /* Clear any lingering interrupt */
1341 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1342
1343 CHIPREG_READ32(&ioc->chip->IntStatus);
1344
1345 mpt_adapter_dispose(ioc);
1346
1347 pci_set_drvdata(pdev, NULL);
1348}
1349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350/**************************************************************************
1351 * Power Management
1352 */
1353#ifdef CONFIG_PM
1354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1355/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001356 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 *
1358 *
1359 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001360int
1361mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362{
1363 u32 device_state;
1364 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 switch(state)
1367 {
1368 case 1: /* S1 */
1369 device_state=1; /* D1 */;
1370 break;
1371 case 3: /* S3 */
1372 case 4: /* S4 */
1373 device_state=3; /* D3 */;
1374 break;
1375 default:
1376 return -EAGAIN /*FIXME*/;
1377 break;
1378 }
1379
1380 printk(MYIOC_s_INFO_FMT
1381 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1382 ioc->name, pdev, pci_name(pdev), device_state);
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 pci_save_state(pdev);
1385
1386 /* put ioc into READY_STATE */
1387 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1388 printk(MYIOC_s_ERR_FMT
1389 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1390 }
1391
1392 /* disable interrupts */
1393 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1394 ioc->active = 0;
1395
1396 /* Clear any lingering interrupt */
1397 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1398
1399 pci_disable_device(pdev);
1400 pci_set_power_state(pdev, device_state);
1401
1402 return 0;
1403}
1404
1405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1406/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001407 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 *
1409 *
1410 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001411int
1412mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413{
1414 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1415 u32 device_state = pdev->current_state;
1416 int recovery_state;
1417 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 printk(MYIOC_s_INFO_FMT
1420 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1421 ioc->name, pdev, pci_name(pdev), device_state);
1422
1423 pci_set_power_state(pdev, 0);
1424 pci_restore_state(pdev);
1425 pci_enable_device(pdev);
1426
1427 /* enable interrupts */
1428 CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
1429 ioc->active = 1;
1430
1431 /* F/W not running */
1432 if(!CHIPREG_READ32(&ioc->chip->Doorbell)) {
1433 /* enable domain validation flags */
1434 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
1435 ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV;
1436 }
1437 }
1438
1439 printk(MYIOC_s_INFO_FMT
1440 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1441 ioc->name,
1442 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1443 CHIPREG_READ32(&ioc->chip->Doorbell));
1444
1445 /* bring ioc to operational state */
1446 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1447 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1448 printk(MYIOC_s_INFO_FMT
1449 "pci-resume: Cannot recover, error:[%x]\n",
1450 ioc->name, recovery_state);
1451 } else {
1452 printk(MYIOC_s_INFO_FMT
1453 "pci-resume: success\n", ioc->name);
1454 }
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 return 0;
1457}
1458#endif
1459
1460/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1461/*
1462 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1463 * @ioc: Pointer to MPT adapter structure
1464 * @reason: Event word / reason
1465 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1466 *
1467 * This routine performs all the steps necessary to bring the IOC
1468 * to a OPERATIONAL state.
1469 *
1470 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1471 * MPT adapter.
1472 *
1473 * Returns:
1474 * 0 for success
1475 * -1 if failed to get board READY
1476 * -2 if READY but IOCFacts Failed
1477 * -3 if READY but PrimeIOCFifos Failed
1478 * -4 if READY but IOCInit Failed
1479 */
1480static int
1481mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1482{
1483 int hard_reset_done = 0;
1484 int alt_ioc_ready = 0;
1485 int hard;
1486 int rc=0;
1487 int ii;
1488 int handlers;
1489 int ret = 0;
1490 int reset_alt_ioc_active = 0;
1491
1492 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1493 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1494
1495 /* Disable reply interrupts (also blocks FreeQ) */
1496 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1497 ioc->active = 0;
1498
1499 if (ioc->alt_ioc) {
1500 if (ioc->alt_ioc->active)
1501 reset_alt_ioc_active = 1;
1502
1503 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1504 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1505 ioc->alt_ioc->active = 0;
1506 }
1507
1508 hard = 1;
1509 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1510 hard = 0;
1511
1512 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1513 if (hard_reset_done == -4) {
1514 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1515 ioc->name);
1516
1517 if (reset_alt_ioc_active && ioc->alt_ioc) {
1518 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1519 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1520 ioc->alt_ioc->name));
1521 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
1522 ioc->alt_ioc->active = 1;
1523 }
1524
1525 } else {
1526 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1527 ioc->name);
1528 }
1529 return -1;
1530 }
1531
1532 /* hard_reset_done = 0 if a soft reset was performed
1533 * and 1 if a hard reset was performed.
1534 */
1535 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1536 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1537 alt_ioc_ready = 1;
1538 else
1539 printk(KERN_WARNING MYNAM
1540 ": alt-%s: Not ready WARNING!\n",
1541 ioc->alt_ioc->name);
1542 }
1543
1544 for (ii=0; ii<5; ii++) {
1545 /* Get IOC facts! Allow 5 retries */
1546 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1547 break;
1548 }
1549
1550
1551 if (ii == 5) {
1552 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1553 ret = -2;
1554 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1555 MptDisplayIocCapabilities(ioc);
1556 }
1557
1558 if (alt_ioc_ready) {
1559 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1560 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1561 /* Retry - alt IOC was initialized once
1562 */
1563 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1564 }
1565 if (rc) {
1566 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1567 alt_ioc_ready = 0;
1568 reset_alt_ioc_active = 0;
1569 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1570 MptDisplayIocCapabilities(ioc->alt_ioc);
1571 }
1572 }
1573
1574 /* Prime reply & request queues!
1575 * (mucho alloc's) Must be done prior to
1576 * init as upper addresses are needed for init.
1577 * If fails, continue with alt-ioc processing
1578 */
1579 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1580 ret = -3;
1581
1582 /* May need to check/upload firmware & data here!
1583 * If fails, continue with alt-ioc processing
1584 */
1585 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1586 ret = -4;
1587// NEW!
1588 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1589 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1590 ioc->alt_ioc->name, rc);
1591 alt_ioc_ready = 0;
1592 reset_alt_ioc_active = 0;
1593 }
1594
1595 if (alt_ioc_ready) {
1596 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1597 alt_ioc_ready = 0;
1598 reset_alt_ioc_active = 0;
1599 printk(KERN_WARNING MYNAM
1600 ": alt-%s: (%d) init failure WARNING!\n",
1601 ioc->alt_ioc->name, rc);
1602 }
1603 }
1604
1605 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1606 if (ioc->upload_fw) {
1607 ddlprintk((MYIOC_s_INFO_FMT
1608 "firmware upload required!\n", ioc->name));
1609
1610 /* Controller is not operational, cannot do upload
1611 */
1612 if (ret == 0) {
1613 rc = mpt_do_upload(ioc, sleepFlag);
1614 if (rc != 0)
1615 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
1616 }
1617 }
1618 }
1619
1620 if (ret == 0) {
1621 /* Enable! (reply interrupt) */
1622 CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
1623 ioc->active = 1;
1624 }
1625
1626 if (reset_alt_ioc_active && ioc->alt_ioc) {
1627 /* (re)Enable alt-IOC! (reply interrupt) */
1628 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1629 ioc->alt_ioc->name));
1630 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
1631 ioc->alt_ioc->active = 1;
1632 }
1633
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001634 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 * and EventAck handling.
1636 */
1637 if ((ret == 0) && (!ioc->facts.EventState))
1638 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1639
1640 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1641 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1642
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001643 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1645 * recursive scenario; GetLanConfigPages times out, timer expired
1646 * routine calls HardResetHandler, which calls into here again,
1647 * and we try GetLanConfigPages again...
1648 */
1649 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1650 if (ioc->bus_type == FC) {
1651 /*
1652 * Pre-fetch FC port WWN and stuff...
1653 * (FCPortPage0_t stuff)
1654 */
1655 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1656 (void) GetFcPortPage0(ioc, ii);
1657 }
1658
1659 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1660 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1661 /*
1662 * Pre-fetch the ports LAN MAC address!
1663 * (LANPage1_t stuff)
1664 */
1665 (void) GetLanConfigPages(ioc);
1666#ifdef MPT_DEBUG
1667 {
1668 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1669 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1670 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1671 }
1672#endif
1673 }
1674 } else {
1675 /* Get NVRAM and adapter maximums from SPP 0 and 2
1676 */
1677 mpt_GetScsiPortSettings(ioc, 0);
1678
1679 /* Get version and length of SDP 1
1680 */
1681 mpt_readScsiDevicePageHeaders(ioc, 0);
1682
1683 /* Find IM volumes
1684 */
1685 if (ioc->facts.MsgVersion >= 0x0102)
1686 mpt_findImVolumes(ioc);
1687
1688 /* Check, and possibly reset, the coalescing value
1689 */
1690 mpt_read_ioc_pg_1(ioc);
1691
1692 mpt_read_ioc_pg_4(ioc);
1693 }
1694
1695 GetIoUnitPage2(ioc);
1696 }
1697
1698 /*
1699 * Call each currently registered protocol IOC reset handler
1700 * with post-reset indication.
1701 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1702 * MptResetHandlers[] registered yet.
1703 */
1704 if (hard_reset_done) {
1705 rc = handlers = 0;
1706 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1707 if ((ret == 0) && MptResetHandlers[ii]) {
1708 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1709 ioc->name, ii));
1710 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1711 handlers++;
1712 }
1713
1714 if (alt_ioc_ready && MptResetHandlers[ii]) {
1715 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
1716 ioc->name, ioc->alt_ioc->name, ii));
1717 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1718 handlers++;
1719 }
1720 }
1721 /* FIXME? Examine results here? */
1722 }
1723
1724 return ret;
1725}
1726
1727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1728/*
1729 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1730 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1731 * 929X, 1030 or 1035.
1732 * @ioc: Pointer to MPT adapter structure
1733 * @pdev: Pointer to (struct pci_dev) structure
1734 *
1735 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1736 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1737 */
1738static void
1739mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1740{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001741 struct pci_dev *peer=NULL;
1742 unsigned int slot = PCI_SLOT(pdev->devfn);
1743 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 MPT_ADAPTER *ioc_srch;
1745
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001746 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1747 " searching for devfn match on %x or %x\n",
1748 ioc->name, pci_name(pdev), pdev->devfn,
1749 func-1, func+1));
1750
1751 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1752 if (!peer) {
1753 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1754 if (!peer)
1755 return;
1756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 list_for_each_entry(ioc_srch, &ioc_list, list) {
1759 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001760 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 /* Paranoia checks */
1762 if (ioc->alt_ioc != NULL) {
1763 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001764 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 break;
1766 } else if (ioc_srch->alt_ioc != NULL) {
1767 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001768 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 break;
1770 }
1771 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001772 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc_srch->alt_ioc = ioc;
1774 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 }
1776 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001777 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778}
1779
1780/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1781/*
1782 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1783 * @this: Pointer to MPT adapter structure
1784 */
1785static void
1786mpt_adapter_disable(MPT_ADAPTER *ioc)
1787{
1788 int sz;
1789 int ret;
1790
1791 if (ioc->cached_fw != NULL) {
1792 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
1793 if ((ret = mpt_downloadboot(ioc, NO_SLEEP)) < 0) {
1794 printk(KERN_WARNING MYNAM
1795 ": firmware downloadboot failure (%d)!\n", ret);
1796 }
1797 }
1798
1799 /* Disable adapter interrupts! */
1800 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1801 ioc->active = 0;
1802 /* Clear any lingering interrupt */
1803 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1804
1805 if (ioc->alloc != NULL) {
1806 sz = ioc->alloc_sz;
1807 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1808 ioc->name, ioc->alloc, ioc->alloc_sz));
1809 pci_free_consistent(ioc->pcidev, sz,
1810 ioc->alloc, ioc->alloc_dma);
1811 ioc->reply_frames = NULL;
1812 ioc->req_frames = NULL;
1813 ioc->alloc = NULL;
1814 ioc->alloc_total -= sz;
1815 }
1816
1817 if (ioc->sense_buf_pool != NULL) {
1818 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1819 pci_free_consistent(ioc->pcidev, sz,
1820 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
1821 ioc->sense_buf_pool = NULL;
1822 ioc->alloc_total -= sz;
1823 }
1824
1825 if (ioc->events != NULL){
1826 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
1827 kfree(ioc->events);
1828 ioc->events = NULL;
1829 ioc->alloc_total -= sz;
1830 }
1831
1832 if (ioc->cached_fw != NULL) {
1833 sz = ioc->facts.FWImageSize;
1834 pci_free_consistent(ioc->pcidev, sz,
1835 ioc->cached_fw, ioc->cached_fw_dma);
1836 ioc->cached_fw = NULL;
1837 ioc->alloc_total -= sz;
1838 }
1839
1840 if (ioc->spi_data.nvram != NULL) {
1841 kfree(ioc->spi_data.nvram);
1842 ioc->spi_data.nvram = NULL;
1843 }
1844
1845 if (ioc->spi_data.pIocPg3 != NULL) {
1846 kfree(ioc->spi_data.pIocPg3);
1847 ioc->spi_data.pIocPg3 = NULL;
1848 }
1849
1850 if (ioc->spi_data.pIocPg4 != NULL) {
1851 sz = ioc->spi_data.IocPg4Sz;
1852 pci_free_consistent(ioc->pcidev, sz,
1853 ioc->spi_data.pIocPg4,
1854 ioc->spi_data.IocPg4_dma);
1855 ioc->spi_data.pIocPg4 = NULL;
1856 ioc->alloc_total -= sz;
1857 }
1858
1859 if (ioc->ReqToChain != NULL) {
1860 kfree(ioc->ReqToChain);
1861 kfree(ioc->RequestNB);
1862 ioc->ReqToChain = NULL;
1863 }
1864
1865 if (ioc->ChainToChain != NULL) {
1866 kfree(ioc->ChainToChain);
1867 ioc->ChainToChain = NULL;
1868 }
1869}
1870
1871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1872/*
1873 * mpt_adapter_dispose - Free all resources associated with a MPT
1874 * adapter.
1875 * @ioc: Pointer to MPT adapter structure
1876 *
1877 * This routine unregisters h/w resources and frees all alloc'd memory
1878 * associated with a MPT adapter structure.
1879 */
1880static void
1881mpt_adapter_dispose(MPT_ADAPTER *ioc)
1882{
1883 if (ioc != NULL) {
1884 int sz_first, sz_last;
1885
1886 sz_first = ioc->alloc_total;
1887
1888 mpt_adapter_disable(ioc);
1889
1890 if (ioc->pci_irq != -1) {
1891 free_irq(ioc->pci_irq, ioc);
1892 ioc->pci_irq = -1;
1893 }
1894
1895 if (ioc->memmap != NULL)
1896 iounmap(ioc->memmap);
1897
1898#if defined(CONFIG_MTRR) && 0
1899 if (ioc->mtrr_reg > 0) {
1900 mtrr_del(ioc->mtrr_reg, 0, 0);
1901 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
1902 }
1903#endif
1904
1905 /* Zap the adapter lookup ptr! */
1906 list_del(&ioc->list);
1907
1908 sz_last = ioc->alloc_total;
1909 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
1910 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
1911 kfree(ioc);
1912 }
1913}
1914
1915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1916/*
1917 * MptDisplayIocCapabilities - Disply IOC's capacilities.
1918 * @ioc: Pointer to MPT adapter structure
1919 */
1920static void
1921MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
1922{
1923 int i = 0;
1924
1925 printk(KERN_INFO "%s: ", ioc->name);
1926 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
1927 printk("%s: ", ioc->prod_name+3);
1928 printk("Capabilities={");
1929
1930 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
1931 printk("Initiator");
1932 i++;
1933 }
1934
1935 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
1936 printk("%sTarget", i ? "," : "");
1937 i++;
1938 }
1939
1940 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
1941 printk("%sLAN", i ? "," : "");
1942 i++;
1943 }
1944
1945#if 0
1946 /*
1947 * This would probably evoke more questions than it's worth
1948 */
1949 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
1950 printk("%sLogBusAddr", i ? "," : "");
1951 i++;
1952 }
1953#endif
1954
1955 printk("}\n");
1956}
1957
1958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1959/*
1960 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
1961 * @ioc: Pointer to MPT_ADAPTER structure
1962 * @force: Force hard KickStart of IOC
1963 * @sleepFlag: Specifies whether the process can sleep
1964 *
1965 * Returns:
1966 * 1 - DIAG reset and READY
1967 * 0 - READY initially OR soft reset and READY
1968 * -1 - Any failure on KickStart
1969 * -2 - Msg Unit Reset Failed
1970 * -3 - IO Unit Reset Failed
1971 * -4 - IOC owned by a PEER
1972 */
1973static int
1974MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
1975{
1976 u32 ioc_state;
1977 int statefault = 0;
1978 int cntdn;
1979 int hard_reset_done = 0;
1980 int r;
1981 int ii;
1982 int whoinit;
1983
1984 /* Get current [raw] IOC state */
1985 ioc_state = mpt_GetIocState(ioc, 0);
1986 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
1987
1988 /*
1989 * Check to see if IOC got left/stuck in doorbell handshake
1990 * grip of death. If so, hard reset the IOC.
1991 */
1992 if (ioc_state & MPI_DOORBELL_ACTIVE) {
1993 statefault = 1;
1994 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
1995 ioc->name);
1996 }
1997
1998 /* Is it already READY? */
1999 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
2000 return 0;
2001
2002 /*
2003 * Check to see if IOC is in FAULT state.
2004 */
2005 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2006 statefault = 2;
2007 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2008 ioc->name);
2009 printk(KERN_WARNING " FAULT code = %04xh\n",
2010 ioc_state & MPI_DOORBELL_DATA_MASK);
2011 }
2012
2013 /*
2014 * Hmmm... Did it get left operational?
2015 */
2016 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
2017 dinitprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
2018 ioc->name));
2019
2020 /* Check WhoInit.
2021 * If PCI Peer, exit.
2022 * Else, if no fault conditions are present, issue a MessageUnitReset
2023 * Else, fall through to KickStart case
2024 */
2025 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
2026 dprintk((KERN_WARNING MYNAM
2027 ": whoinit 0x%x\n statefault %d force %d\n",
2028 whoinit, statefault, force));
2029 if (whoinit == MPI_WHOINIT_PCI_PEER)
2030 return -4;
2031 else {
2032 if ((statefault == 0 ) && (force == 0)) {
2033 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2034 return 0;
2035 }
2036 statefault = 3;
2037 }
2038 }
2039
2040 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2041 if (hard_reset_done < 0)
2042 return -1;
2043
2044 /*
2045 * Loop here waiting for IOC to come READY.
2046 */
2047 ii = 0;
2048 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
2049
2050 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2051 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2052 /*
2053 * BIOS or previous driver load left IOC in OP state.
2054 * Reset messaging FIFOs.
2055 */
2056 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2057 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2058 return -2;
2059 }
2060 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2061 /*
2062 * Something is wrong. Try to get IOC back
2063 * to a known state.
2064 */
2065 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2066 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2067 return -3;
2068 }
2069 }
2070
2071 ii++; cntdn--;
2072 if (!cntdn) {
2073 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2074 ioc->name, (int)((ii+5)/HZ));
2075 return -ETIME;
2076 }
2077
2078 if (sleepFlag == CAN_SLEEP) {
2079 msleep_interruptible(1);
2080 } else {
2081 mdelay (1); /* 1 msec delay */
2082 }
2083
2084 }
2085
2086 if (statefault < 3) {
2087 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2088 ioc->name,
2089 statefault==1 ? "stuck handshake" : "IOC FAULT");
2090 }
2091
2092 return hard_reset_done;
2093}
2094
2095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2096/*
2097 * mpt_GetIocState - Get the current state of a MPT adapter.
2098 * @ioc: Pointer to MPT_ADAPTER structure
2099 * @cooked: Request raw or cooked IOC state
2100 *
2101 * Returns all IOC Doorbell register bits if cooked==0, else just the
2102 * Doorbell bits in MPI_IOC_STATE_MASK.
2103 */
2104u32
2105mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2106{
2107 u32 s, sc;
2108
2109 /* Get! */
2110 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2111// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2112 sc = s & MPI_IOC_STATE_MASK;
2113
2114 /* Save! */
2115 ioc->last_state = sc;
2116
2117 return cooked ? sc : s;
2118}
2119
2120/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2121/*
2122 * GetIocFacts - Send IOCFacts request to MPT adapter.
2123 * @ioc: Pointer to MPT_ADAPTER structure
2124 * @sleepFlag: Specifies whether the process can sleep
2125 * @reason: If recovery, only update facts.
2126 *
2127 * Returns 0 for success, non-zero for failure.
2128 */
2129static int
2130GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2131{
2132 IOCFacts_t get_facts;
2133 IOCFactsReply_t *facts;
2134 int r;
2135 int req_sz;
2136 int reply_sz;
2137 int sz;
2138 u32 status, vv;
2139 u8 shiftFactor=1;
2140
2141 /* IOC *must* NOT be in RESET state! */
2142 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2143 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2144 ioc->name,
2145 ioc->last_state );
2146 return -44;
2147 }
2148
2149 facts = &ioc->facts;
2150
2151 /* Destination (reply area)... */
2152 reply_sz = sizeof(*facts);
2153 memset(facts, 0, reply_sz);
2154
2155 /* Request area (get_facts on the stack right now!) */
2156 req_sz = sizeof(get_facts);
2157 memset(&get_facts, 0, req_sz);
2158
2159 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2160 /* Assert: All other get_facts fields are zero! */
2161
2162 dinitprintk((MYIOC_s_INFO_FMT
2163 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
2164 ioc->name, req_sz, reply_sz));
2165
2166 /* No non-zero fields in the get_facts request are greater than
2167 * 1 byte in size, so we can just fire it off as is.
2168 */
2169 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2170 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2171 if (r != 0)
2172 return r;
2173
2174 /*
2175 * Now byte swap (GRRR) the necessary fields before any further
2176 * inspection of reply contents.
2177 *
2178 * But need to do some sanity checks on MsgLength (byte) field
2179 * to make sure we don't zero IOC's req_sz!
2180 */
2181 /* Did we get a valid reply? */
2182 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2183 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2184 /*
2185 * If not been here, done that, save off first WhoInit value
2186 */
2187 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2188 ioc->FirstWhoInit = facts->WhoInit;
2189 }
2190
2191 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2192 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2193 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2194 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2195 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
2196 status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
2197 /* CHECKME! IOCStatus, IOCLogInfo */
2198
2199 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2200 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2201
2202 /*
2203 * FC f/w version changed between 1.1 and 1.2
2204 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2205 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2206 */
2207 if (facts->MsgVersion < 0x0102) {
2208 /*
2209 * Handle old FC f/w style, convert to new...
2210 */
2211 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2212 facts->FWVersion.Word =
2213 ((oldv<<12) & 0xFF000000) |
2214 ((oldv<<8) & 0x000FFF00);
2215 } else
2216 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2217
2218 facts->ProductID = le16_to_cpu(facts->ProductID);
2219 facts->CurrentHostMfaHighAddr =
2220 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2221 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2222 facts->CurrentSenseBufferHighAddr =
2223 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2224 facts->CurReplyFrameSize =
2225 le16_to_cpu(facts->CurReplyFrameSize);
2226
2227 /*
2228 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2229 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2230 * to 14 in MPI-1.01.0x.
2231 */
2232 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2233 facts->MsgVersion > 0x0100) {
2234 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2235 }
2236
2237 sz = facts->FWImageSize;
2238 if ( sz & 0x01 )
2239 sz += 1;
2240 if ( sz & 0x02 )
2241 sz += 2;
2242 facts->FWImageSize = sz;
2243
2244 if (!facts->RequestFrameSize) {
2245 /* Something is wrong! */
2246 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2247 ioc->name);
2248 return -55;
2249 }
2250
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002251 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 vv = ((63 / (sz * 4)) + 1) & 0x03;
2253 ioc->NB_for_64_byte_frame = vv;
2254 while ( sz )
2255 {
2256 shiftFactor++;
2257 sz = sz >> 1;
2258 }
2259 ioc->NBShiftFactor = shiftFactor;
2260 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2261 ioc->name, vv, shiftFactor, r));
2262
2263 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2264 /*
2265 * Set values for this IOC's request & reply frame sizes,
2266 * and request & reply queue depths...
2267 */
2268 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2269 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2270 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2271 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2272
2273 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2274 ioc->name, ioc->reply_sz, ioc->reply_depth));
2275 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2276 ioc->name, ioc->req_sz, ioc->req_depth));
2277
2278 /* Get port facts! */
2279 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2280 return r;
2281 }
2282 } else {
2283 printk(MYIOC_s_ERR_FMT
2284 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2285 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2286 RequestFrameSize)/sizeof(u32)));
2287 return -66;
2288 }
2289
2290 return 0;
2291}
2292
2293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2294/*
2295 * GetPortFacts - Send PortFacts request to MPT adapter.
2296 * @ioc: Pointer to MPT_ADAPTER structure
2297 * @portnum: Port number
2298 * @sleepFlag: Specifies whether the process can sleep
2299 *
2300 * Returns 0 for success, non-zero for failure.
2301 */
2302static int
2303GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2304{
2305 PortFacts_t get_pfacts;
2306 PortFactsReply_t *pfacts;
2307 int ii;
2308 int req_sz;
2309 int reply_sz;
2310
2311 /* IOC *must* NOT be in RESET state! */
2312 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2313 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2314 ioc->name,
2315 ioc->last_state );
2316 return -4;
2317 }
2318
2319 pfacts = &ioc->pfacts[portnum];
2320
2321 /* Destination (reply area)... */
2322 reply_sz = sizeof(*pfacts);
2323 memset(pfacts, 0, reply_sz);
2324
2325 /* Request area (get_pfacts on the stack right now!) */
2326 req_sz = sizeof(get_pfacts);
2327 memset(&get_pfacts, 0, req_sz);
2328
2329 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2330 get_pfacts.PortNumber = portnum;
2331 /* Assert: All other get_pfacts fields are zero! */
2332
2333 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2334 ioc->name, portnum));
2335
2336 /* No non-zero fields in the get_pfacts request are greater than
2337 * 1 byte in size, so we can just fire it off as is.
2338 */
2339 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2340 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2341 if (ii != 0)
2342 return ii;
2343
2344 /* Did we get a valid reply? */
2345
2346 /* Now byte swap the necessary fields in the response. */
2347 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2348 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2349 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2350 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2351 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2352 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2353 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2354 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2355 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2356
2357 return 0;
2358}
2359
2360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2361/*
2362 * SendIocInit - Send IOCInit request to MPT adapter.
2363 * @ioc: Pointer to MPT_ADAPTER structure
2364 * @sleepFlag: Specifies whether the process can sleep
2365 *
2366 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2367 *
2368 * Returns 0 for success, non-zero for failure.
2369 */
2370static int
2371SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2372{
2373 IOCInit_t ioc_init;
2374 MPIDefaultReply_t init_reply;
2375 u32 state;
2376 int r;
2377 int count;
2378 int cntdn;
2379
2380 memset(&ioc_init, 0, sizeof(ioc_init));
2381 memset(&init_reply, 0, sizeof(init_reply));
2382
2383 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2384 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2385
2386 /* If we are in a recovery mode and we uploaded the FW image,
2387 * then this pointer is not NULL. Skip the upload a second time.
2388 * Set this flag if cached_fw set for either IOC.
2389 */
2390 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2391 ioc->upload_fw = 1;
2392 else
2393 ioc->upload_fw = 0;
2394 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2395 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2396
2397 if (ioc->bus_type == FC)
2398 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2399 else
2400 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
2401
2402 ioc_init.MaxBuses = MPT_MAX_BUS;
2403
2404 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2405
2406 if (sizeof(dma_addr_t) == sizeof(u64)) {
2407 /* Save the upper 32-bits of the request
2408 * (reply) and sense buffers.
2409 */
2410 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2411 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2412 } else {
2413 /* Force 32-bit addressing */
2414 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2415 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2416 }
2417
2418 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2419 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
2420
2421 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2422 ioc->name, &ioc_init));
2423
2424 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2425 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
2426 if (r != 0)
2427 return r;
2428
2429 /* No need to byte swap the multibyte fields in the reply
2430 * since we don't even look at it's contents.
2431 */
2432
2433 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2434 ioc->name, &ioc_init));
2435
2436 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
2437 return r;
2438
2439 /* YIKES! SUPER IMPORTANT!!!
2440 * Poll IocState until _OPERATIONAL while IOC is doing
2441 * LoopInit and TargetDiscovery!
2442 */
2443 count = 0;
2444 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2445 state = mpt_GetIocState(ioc, 1);
2446 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2447 if (sleepFlag == CAN_SLEEP) {
2448 msleep_interruptible(1);
2449 } else {
2450 mdelay(1);
2451 }
2452
2453 if (!cntdn) {
2454 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2455 ioc->name, (int)((count+5)/HZ));
2456 return -9;
2457 }
2458
2459 state = mpt_GetIocState(ioc, 1);
2460 count++;
2461 }
2462 dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
2463 ioc->name, count));
2464
2465 return r;
2466}
2467
2468/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2469/*
2470 * SendPortEnable - Send PortEnable request to MPT adapter port.
2471 * @ioc: Pointer to MPT_ADAPTER structure
2472 * @portnum: Port number to enable
2473 * @sleepFlag: Specifies whether the process can sleep
2474 *
2475 * Send PortEnable to bring IOC to OPERATIONAL state.
2476 *
2477 * Returns 0 for success, non-zero for failure.
2478 */
2479static int
2480SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2481{
2482 PortEnable_t port_enable;
2483 MPIDefaultReply_t reply_buf;
2484 int ii;
2485 int req_sz;
2486 int reply_sz;
2487
2488 /* Destination... */
2489 reply_sz = sizeof(MPIDefaultReply_t);
2490 memset(&reply_buf, 0, reply_sz);
2491
2492 req_sz = sizeof(PortEnable_t);
2493 memset(&port_enable, 0, req_sz);
2494
2495 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2496 port_enable.PortNumber = portnum;
2497/* port_enable.ChainOffset = 0; */
2498/* port_enable.MsgFlags = 0; */
2499/* port_enable.MsgContext = 0; */
2500
2501 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2502 ioc->name, portnum, &port_enable));
2503
2504 /* RAID FW may take a long time to enable
2505 */
2506 if (ioc->bus_type == FC) {
2507 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
2508 reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
2509 } else {
2510 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
2511 reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
2512 }
2513
2514 if (ii != 0)
2515 return ii;
2516
2517 /* We do not even look at the reply, so we need not
2518 * swap the multi-byte fields.
2519 */
2520
2521 return 0;
2522}
2523
2524/*
2525 * ioc: Pointer to MPT_ADAPTER structure
2526 * size - total FW bytes
2527 */
2528void
2529mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2530{
2531 if (ioc->cached_fw)
2532 return; /* use already allocated memory */
2533 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2534 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2535 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2536 } else {
2537 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2538 ioc->alloc_total += size;
2539 }
2540}
2541/*
2542 * If alt_img is NULL, delete from ioc structure.
2543 * Else, delete a secondary image in same format.
2544 */
2545void
2546mpt_free_fw_memory(MPT_ADAPTER *ioc)
2547{
2548 int sz;
2549
2550 sz = ioc->facts.FWImageSize;
2551 dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
2552 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2553 pci_free_consistent(ioc->pcidev, sz,
2554 ioc->cached_fw, ioc->cached_fw_dma);
2555 ioc->cached_fw = NULL;
2556
2557 return;
2558}
2559
2560
2561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2562/*
2563 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2564 * @ioc: Pointer to MPT_ADAPTER structure
2565 * @sleepFlag: Specifies whether the process can sleep
2566 *
2567 * Returns 0 for success, >0 for handshake failure
2568 * <0 for fw upload failure.
2569 *
2570 * Remark: If bound IOC and a successful FWUpload was performed
2571 * on the bound IOC, the second image is discarded
2572 * and memory is free'd. Both channels must upload to prevent
2573 * IOC from running in degraded mode.
2574 */
2575static int
2576mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2577{
2578 u8 request[ioc->req_sz];
2579 u8 reply[sizeof(FWUploadReply_t)];
2580 FWUpload_t *prequest;
2581 FWUploadReply_t *preply;
2582 FWUploadTCSGE_t *ptcsge;
2583 int sgeoffset;
2584 u32 flagsLength;
2585 int ii, sz, reply_sz;
2586 int cmdStatus;
2587
2588 /* If the image size is 0, we are done.
2589 */
2590 if ((sz = ioc->facts.FWImageSize) == 0)
2591 return 0;
2592
2593 mpt_alloc_fw_memory(ioc, sz);
2594
2595 dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
2596 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2597
2598 if (ioc->cached_fw == NULL) {
2599 /* Major Failure.
2600 */
2601 return -ENOMEM;
2602 }
2603
2604 prequest = (FWUpload_t *)&request;
2605 preply = (FWUploadReply_t *)&reply;
2606
2607 /* Destination... */
2608 memset(prequest, 0, ioc->req_sz);
2609
2610 reply_sz = sizeof(reply);
2611 memset(preply, 0, reply_sz);
2612
2613 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2614 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2615
2616 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2617 ptcsge->DetailsLength = 12;
2618 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2619 ptcsge->ImageSize = cpu_to_le32(sz);
2620
2621 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2622
2623 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2624 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2625
2626 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
2627 dinitprintk((KERN_WARNING MYNAM "Sending FW Upload (req @ %p) sgeoffset=%d \n",
2628 prequest, sgeoffset));
2629 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2630
2631 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2632 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2633
2634 dinitprintk((KERN_WARNING MYNAM "FW Upload completed rc=%x \n", ii));
2635
2636 cmdStatus = -EFAULT;
2637 if (ii == 0) {
2638 /* Handshake transfer was complete and successful.
2639 * Check the Reply Frame.
2640 */
2641 int status, transfer_sz;
2642 status = le16_to_cpu(preply->IOCStatus);
2643 if (status == MPI_IOCSTATUS_SUCCESS) {
2644 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2645 if (transfer_sz == sz)
2646 cmdStatus = 0;
2647 }
2648 }
2649 dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
2650 ioc->name, cmdStatus));
2651
2652
2653 if (cmdStatus) {
2654
2655 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2656 ioc->name));
2657 mpt_free_fw_memory(ioc);
2658 }
2659
2660 return cmdStatus;
2661}
2662
2663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2664/*
2665 * mpt_downloadboot - DownloadBoot code
2666 * @ioc: Pointer to MPT_ADAPTER structure
2667 * @flag: Specify which part of IOC memory is to be uploaded.
2668 * @sleepFlag: Specifies whether the process can sleep
2669 *
2670 * FwDownloadBoot requires Programmed IO access.
2671 *
2672 * Returns 0 for success
2673 * -1 FW Image size is 0
2674 * -2 No valid cached_fw Pointer
2675 * <0 for fw upload failure.
2676 */
2677static int
2678mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
2679{
2680 MpiFwHeader_t *pFwHeader;
2681 MpiExtImageHeader_t *pExtImage;
2682 u32 fwSize;
2683 u32 diag0val;
2684 int count;
2685 u32 *ptrFw;
2686 u32 diagRwData;
2687 u32 nextImage;
2688 u32 load_addr;
2689 u32 ioc_state=0;
2690
2691 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n",
2692 ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
2693
2694 if ( ioc->facts.FWImageSize == 0 )
2695 return -1;
2696
2697 if (ioc->cached_fw == NULL)
2698 return -2;
2699
2700 /* prevent a second downloadboot and memory free with alt_ioc */
2701 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
2702 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002703
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2708 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2710
2711 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2712
2713 /* wait 1 msec */
2714 if (sleepFlag == CAN_SLEEP) {
2715 msleep_interruptible(1);
2716 } else {
2717 mdelay (1);
2718 }
2719
2720 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2721 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2722
2723 for (count = 0; count < 30; count ++) {
2724 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2725 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2726 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2727 ioc->name, count));
2728 break;
2729 }
2730 /* wait 1 sec */
2731 if (sleepFlag == CAN_SLEEP) {
2732 msleep_interruptible (1000);
2733 } else {
2734 mdelay (1000);
2735 }
2736 }
2737
2738 if ( count == 30 ) {
2739 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! Unable to RESET_ADAPTER diag0val=%x\n",
2740 ioc->name, diag0val));
2741 return -3;
2742 }
2743
2744 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2745 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2746 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2747 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2748 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2749 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2750
2751 /* Set the DiagRwEn and Disable ARM bits */
2752 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2753
2754 pFwHeader = (MpiFwHeader_t *) ioc->cached_fw;
2755 fwSize = (pFwHeader->ImageSize + 3)/4;
2756 ptrFw = (u32 *) pFwHeader;
2757
2758 /* Write the LoadStartAddress to the DiagRw Address Register
2759 * using Programmed IO
2760 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002761 if (ioc->errata_flag_1064)
2762 pci_enable_io_access(ioc->pcidev);
2763
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2765 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2766 ioc->name, pFwHeader->LoadStartAddress));
2767
2768 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2769 ioc->name, fwSize*4, ptrFw));
2770 while (fwSize--) {
2771 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2772 }
2773
2774 nextImage = pFwHeader->NextImageHeaderOffset;
2775 while (nextImage) {
2776 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2777
2778 load_addr = pExtImage->LoadStartAddress;
2779
2780 fwSize = (pExtImage->ImageSize + 3) >> 2;
2781 ptrFw = (u32 *)pExtImage;
2782
2783 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x bytes @ %p load_addr=%x\n",
2784 ioc->name, fwSize*4, ptrFw, load_addr));
2785 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2786
2787 while (fwSize--) {
2788 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2789 }
2790 nextImage = pExtImage->NextImageHeaderOffset;
2791 }
2792
2793 /* Write the IopResetVectorRegAddr */
2794 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2795 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2796
2797 /* Write the IopResetVectorValue */
2798 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
2799 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
2800
2801 /* Clear the internal flash bad bit - autoincrementing register,
2802 * so must do two writes.
2803 */
2804 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
2805 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
2806 diagRwData |= 0x4000000;
2807 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
2808 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
2809
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002810 if (ioc->errata_flag_1064)
2811 pci_disable_io_access(ioc->pcidev);
2812
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2814 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n",
2815 ioc->name, diag0val));
2816 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM);
2817 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
2818 ioc->name, diag0val));
2819 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
2820
2821 /* Write 0xFF to reset the sequencer */
2822 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2823
2824 for (count=0; count<HZ*20; count++) {
2825 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
2826 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
2827 ioc->name, count, ioc_state));
2828 if ((SendIocInit(ioc, sleepFlag)) != 0) {
2829 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
2830 ioc->name));
2831 return -EFAULT;
2832 }
2833 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
2834 ioc->name));
2835 return 0;
2836 }
2837 if (sleepFlag == CAN_SLEEP) {
2838 msleep_interruptible (10);
2839 } else {
2840 mdelay (10);
2841 }
2842 }
2843 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
2844 ioc->name, ioc_state));
2845 return -EFAULT;
2846}
2847
2848/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2849/*
2850 * KickStart - Perform hard reset of MPT adapter.
2851 * @ioc: Pointer to MPT_ADAPTER structure
2852 * @force: Force hard reset
2853 * @sleepFlag: Specifies whether the process can sleep
2854 *
2855 * This routine places MPT adapter in diagnostic mode via the
2856 * WriteSequence register, and then performs a hard reset of adapter
2857 * via the Diagnostic register.
2858 *
2859 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
2860 * or NO_SLEEP (interrupt thread, use mdelay)
2861 * force - 1 if doorbell active, board fault state
2862 * board operational, IOC_RECOVERY or
2863 * IOC_BRINGUP and there is an alt_ioc.
2864 * 0 else
2865 *
2866 * Returns:
2867 * 1 - hard reset, READY
2868 * 0 - no reset due to History bit, READY
2869 * -1 - no reset due to History bit but not READY
2870 * OR reset but failed to come READY
2871 * -2 - no reset, could not enter DIAG mode
2872 * -3 - reset but bad FW bit
2873 */
2874static int
2875KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
2876{
2877 int hard_reset_done = 0;
2878 u32 ioc_state=0;
2879 int cnt,cntdn;
2880
2881 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
2882 if (ioc->bus_type == SCSI) {
2883 /* Always issue a Msg Unit Reset first. This will clear some
2884 * SCSI bus hang conditions.
2885 */
2886 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
2887
2888 if (sleepFlag == CAN_SLEEP) {
2889 msleep_interruptible (1000);
2890 } else {
2891 mdelay (1000);
2892 }
2893 }
2894
2895 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
2896 if (hard_reset_done < 0)
2897 return hard_reset_done;
2898
2899 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
2900 ioc->name));
2901
2902 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
2903 for (cnt=0; cnt<cntdn; cnt++) {
2904 ioc_state = mpt_GetIocState(ioc, 1);
2905 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
2906 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
2907 ioc->name, cnt));
2908 return hard_reset_done;
2909 }
2910 if (sleepFlag == CAN_SLEEP) {
2911 msleep_interruptible (10);
2912 } else {
2913 mdelay (10);
2914 }
2915 }
2916
2917 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
2918 ioc->name, ioc_state);
2919 return -1;
2920}
2921
2922/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2923/*
2924 * mpt_diag_reset - Perform hard reset of the adapter.
2925 * @ioc: Pointer to MPT_ADAPTER structure
2926 * @ignore: Set if to honor and clear to ignore
2927 * the reset history bit
2928 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
2929 * else set to NO_SLEEP (use mdelay instead)
2930 *
2931 * This routine places the adapter in diagnostic mode via the
2932 * WriteSequence register and then performs a hard reset of adapter
2933 * via the Diagnostic register. Adapter should be in ready state
2934 * upon successful completion.
2935 *
2936 * Returns: 1 hard reset successful
2937 * 0 no reset performed because reset history bit set
2938 * -2 enabling diagnostic mode failed
2939 * -3 diagnostic reset failed
2940 */
2941static int
2942mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
2943{
2944 u32 diag0val;
2945 u32 doorbell;
2946 int hard_reset_done = 0;
2947 int count = 0;
2948#ifdef MPT_DEBUG
2949 u32 diag1val = 0;
2950#endif
2951
2952 /* Clear any existing interrupts */
2953 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2954
2955 /* Use "Diagnostic reset" method! (only thing available!) */
2956 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2957
2958#ifdef MPT_DEBUG
2959 if (ioc->alt_ioc)
2960 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
2961 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
2962 ioc->name, diag0val, diag1val));
2963#endif
2964
2965 /* Do the reset if we are told to ignore the reset history
2966 * or if the reset history is 0
2967 */
2968 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
2969 while ((diag0val & MPI_DIAG_DRWE) == 0) {
2970 /* Write magic sequence to WriteSequence register
2971 * Loop until in diagnostic mode
2972 */
2973 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2979
2980 /* wait 100 msec */
2981 if (sleepFlag == CAN_SLEEP) {
2982 msleep_interruptible (100);
2983 } else {
2984 mdelay (100);
2985 }
2986
2987 count++;
2988 if (count > 20) {
2989 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
2990 ioc->name, diag0val);
2991 return -2;
2992
2993 }
2994
2995 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2996
2997 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
2998 ioc->name, diag0val));
2999 }
3000
3001#ifdef MPT_DEBUG
3002 if (ioc->alt_ioc)
3003 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3004 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3005 ioc->name, diag0val, diag1val));
3006#endif
3007 /*
3008 * Disable the ARM (Bug fix)
3009 *
3010 */
3011 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
3012 mdelay (1);
3013
3014 /*
3015 * Now hit the reset bit in the Diagnostic register
3016 * (THE BIG HAMMER!) (Clears DRWE bit).
3017 */
3018 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3019 hard_reset_done = 1;
3020 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3021 ioc->name));
3022
3023 /*
3024 * Call each currently registered protocol IOC reset handler
3025 * with pre-reset indication.
3026 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3027 * MptResetHandlers[] registered yet.
3028 */
3029 {
3030 int ii;
3031 int r = 0;
3032
3033 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3034 if (MptResetHandlers[ii]) {
3035 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3036 ioc->name, ii));
3037 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3038 if (ioc->alt_ioc) {
3039 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3040 ioc->name, ioc->alt_ioc->name, ii));
3041 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3042 }
3043 }
3044 }
3045 /* FIXME? Examine results here? */
3046 }
3047
3048 if (ioc->cached_fw) {
3049 /* If the DownloadBoot operation fails, the
3050 * IOC will be left unusable. This is a fatal error
3051 * case. _diag_reset will return < 0
3052 */
3053 for (count = 0; count < 30; count ++) {
3054 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3055 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3056 break;
3057 }
3058
3059 /* wait 1 sec */
3060 if (sleepFlag == CAN_SLEEP) {
3061 ssleep(1);
3062 } else {
3063 mdelay (1000);
3064 }
3065 }
3066 if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
3067 printk(KERN_WARNING MYNAM
3068 ": firmware downloadboot failure (%d)!\n", count);
3069 }
3070
3071 } else {
3072 /* Wait for FW to reload and for board
3073 * to go to the READY state.
3074 * Maximum wait is 60 seconds.
3075 * If fail, no error will check again
3076 * with calling program.
3077 */
3078 for (count = 0; count < 60; count ++) {
3079 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3080 doorbell &= MPI_IOC_STATE_MASK;
3081
3082 if (doorbell == MPI_IOC_STATE_READY) {
3083 break;
3084 }
3085
3086 /* wait 1 sec */
3087 if (sleepFlag == CAN_SLEEP) {
3088 msleep_interruptible (1000);
3089 } else {
3090 mdelay (1000);
3091 }
3092 }
3093 }
3094 }
3095
3096 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3097#ifdef MPT_DEBUG
3098 if (ioc->alt_ioc)
3099 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3100 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3101 ioc->name, diag0val, diag1val));
3102#endif
3103
3104 /* Clear RESET_HISTORY bit! Place board in the
3105 * diagnostic mode to update the diag register.
3106 */
3107 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3108 count = 0;
3109 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3110 /* Write magic sequence to WriteSequence register
3111 * Loop until in diagnostic mode
3112 */
3113 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3114 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3115 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3116 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3117 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3118 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3119
3120 /* wait 100 msec */
3121 if (sleepFlag == CAN_SLEEP) {
3122 msleep_interruptible (100);
3123 } else {
3124 mdelay (100);
3125 }
3126
3127 count++;
3128 if (count > 20) {
3129 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3130 ioc->name, diag0val);
3131 break;
3132 }
3133 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3134 }
3135 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3136 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3137 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3138 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3139 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3140 ioc->name);
3141 }
3142
3143 /* Disable Diagnostic Mode
3144 */
3145 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3146
3147 /* Check FW reload status flags.
3148 */
3149 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3150 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3151 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3152 ioc->name, diag0val);
3153 return -3;
3154 }
3155
3156#ifdef MPT_DEBUG
3157 if (ioc->alt_ioc)
3158 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3159 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3160 ioc->name, diag0val, diag1val));
3161#endif
3162
3163 /*
3164 * Reset flag that says we've enabled event notification
3165 */
3166 ioc->facts.EventState = 0;
3167
3168 if (ioc->alt_ioc)
3169 ioc->alt_ioc->facts.EventState = 0;
3170
3171 return hard_reset_done;
3172}
3173
3174/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3175/*
3176 * SendIocReset - Send IOCReset request to MPT adapter.
3177 * @ioc: Pointer to MPT_ADAPTER structure
3178 * @reset_type: reset type, expected values are
3179 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3180 *
3181 * Send IOCReset request to the MPT adapter.
3182 *
3183 * Returns 0 for success, non-zero for failure.
3184 */
3185static int
3186SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3187{
3188 int r;
3189 u32 state;
3190 int cntdn, count;
3191
3192 drsprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
3193 ioc->name, reset_type));
3194 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3195 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3196 return r;
3197
3198 /* FW ACK'd request, wait for READY state
3199 */
3200 count = 0;
3201 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3202
3203 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3204 cntdn--;
3205 count++;
3206 if (!cntdn) {
3207 if (sleepFlag != CAN_SLEEP)
3208 count *= 10;
3209
3210 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3211 ioc->name, (int)((count+5)/HZ));
3212 return -ETIME;
3213 }
3214
3215 if (sleepFlag == CAN_SLEEP) {
3216 msleep_interruptible(1);
3217 } else {
3218 mdelay (1); /* 1 msec delay */
3219 }
3220 }
3221
3222 /* TODO!
3223 * Cleanup all event stuff for this IOC; re-issue EventNotification
3224 * request if needed.
3225 */
3226 if (ioc->facts.Function)
3227 ioc->facts.EventState = 0;
3228
3229 return 0;
3230}
3231
3232/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3233/*
3234 * initChainBuffers - Allocate memory for and initialize
3235 * chain buffers, chain buffer control arrays and spinlock.
3236 * @hd: Pointer to MPT_SCSI_HOST structure
3237 * @init: If set, initialize the spin lock.
3238 */
3239static int
3240initChainBuffers(MPT_ADAPTER *ioc)
3241{
3242 u8 *mem;
3243 int sz, ii, num_chain;
3244 int scale, num_sge, numSGE;
3245
3246 /* ReqToChain size must equal the req_depth
3247 * index = req_idx
3248 */
3249 if (ioc->ReqToChain == NULL) {
3250 sz = ioc->req_depth * sizeof(int);
3251 mem = kmalloc(sz, GFP_ATOMIC);
3252 if (mem == NULL)
3253 return -1;
3254
3255 ioc->ReqToChain = (int *) mem;
3256 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3257 ioc->name, mem, sz));
3258 mem = kmalloc(sz, GFP_ATOMIC);
3259 if (mem == NULL)
3260 return -1;
3261
3262 ioc->RequestNB = (int *) mem;
3263 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3264 ioc->name, mem, sz));
3265 }
3266 for (ii = 0; ii < ioc->req_depth; ii++) {
3267 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3268 }
3269
3270 /* ChainToChain size must equal the total number
3271 * of chain buffers to be allocated.
3272 * index = chain_idx
3273 *
3274 * Calculate the number of chain buffers needed(plus 1) per I/O
3275 * then multiply the the maximum number of simultaneous cmds
3276 *
3277 * num_sge = num sge in request frame + last chain buffer
3278 * scale = num sge per chain buffer if no chain element
3279 */
3280 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3281 if (sizeof(dma_addr_t) == sizeof(u64))
3282 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3283 else
3284 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3285
3286 if (sizeof(dma_addr_t) == sizeof(u64)) {
3287 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3288 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3289 } else {
3290 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3291 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3292 }
3293 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3294 ioc->name, num_sge, numSGE));
3295
3296 if ( numSGE > MPT_SCSI_SG_DEPTH )
3297 numSGE = MPT_SCSI_SG_DEPTH;
3298
3299 num_chain = 1;
3300 while (numSGE - num_sge > 0) {
3301 num_chain++;
3302 num_sge += (scale - 1);
3303 }
3304 num_chain++;
3305
3306 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3307 ioc->name, numSGE, num_sge, num_chain));
3308
3309 if (ioc->bus_type == SCSI)
3310 num_chain *= MPT_SCSI_CAN_QUEUE;
3311 else
3312 num_chain *= MPT_FC_CAN_QUEUE;
3313
3314 ioc->num_chain = num_chain;
3315
3316 sz = num_chain * sizeof(int);
3317 if (ioc->ChainToChain == NULL) {
3318 mem = kmalloc(sz, GFP_ATOMIC);
3319 if (mem == NULL)
3320 return -1;
3321
3322 ioc->ChainToChain = (int *) mem;
3323 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3324 ioc->name, mem, sz));
3325 } else {
3326 mem = (u8 *) ioc->ChainToChain;
3327 }
3328 memset(mem, 0xFF, sz);
3329 return num_chain;
3330}
3331
3332/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3333/*
3334 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3335 * @ioc: Pointer to MPT_ADAPTER structure
3336 *
3337 * This routine allocates memory for the MPT reply and request frame
3338 * pools (if necessary), and primes the IOC reply FIFO with
3339 * reply frames.
3340 *
3341 * Returns 0 for success, non-zero for failure.
3342 */
3343static int
3344PrimeIocFifos(MPT_ADAPTER *ioc)
3345{
3346 MPT_FRAME_HDR *mf;
3347 unsigned long flags;
3348 dma_addr_t alloc_dma;
3349 u8 *mem;
3350 int i, reply_sz, sz, total_size, num_chain;
3351
3352 /* Prime reply FIFO... */
3353
3354 if (ioc->reply_frames == NULL) {
3355 if ( (num_chain = initChainBuffers(ioc)) < 0)
3356 return -1;
3357
3358 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3359 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3360 ioc->name, ioc->reply_sz, ioc->reply_depth));
3361 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3362 ioc->name, reply_sz, reply_sz));
3363
3364 sz = (ioc->req_sz * ioc->req_depth);
3365 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3366 ioc->name, ioc->req_sz, ioc->req_depth));
3367 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3368 ioc->name, sz, sz));
3369 total_size += sz;
3370
3371 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3372 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3373 ioc->name, ioc->req_sz, num_chain));
3374 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3375 ioc->name, sz, sz, num_chain));
3376
3377 total_size += sz;
3378 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3379 if (mem == NULL) {
3380 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3381 ioc->name);
3382 goto out_fail;
3383 }
3384
3385 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3386 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3387
3388 memset(mem, 0, total_size);
3389 ioc->alloc_total += total_size;
3390 ioc->alloc = mem;
3391 ioc->alloc_dma = alloc_dma;
3392 ioc->alloc_sz = total_size;
3393 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3394 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3395
3396 alloc_dma += reply_sz;
3397 mem += reply_sz;
3398
3399 /* Request FIFO - WE manage this! */
3400
3401 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3402 ioc->req_frames_dma = alloc_dma;
3403
3404 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n",
3405 ioc->name, mem, (void *)(ulong)alloc_dma));
3406
3407 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3408
3409#if defined(CONFIG_MTRR) && 0
3410 /*
3411 * Enable Write Combining MTRR for IOC's memory region.
3412 * (at least as much as we can; "size and base must be
3413 * multiples of 4 kiB"
3414 */
3415 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3416 sz,
3417 MTRR_TYPE_WRCOMB, 1);
3418 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3419 ioc->name, ioc->req_frames_dma, sz));
3420#endif
3421
3422 for (i = 0; i < ioc->req_depth; i++) {
3423 alloc_dma += ioc->req_sz;
3424 mem += ioc->req_sz;
3425 }
3426
3427 ioc->ChainBuffer = mem;
3428 ioc->ChainBufferDMA = alloc_dma;
3429
3430 dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n",
3431 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3432
3433 /* Initialize the free chain Q.
3434 */
3435
3436 INIT_LIST_HEAD(&ioc->FreeChainQ);
3437
3438 /* Post the chain buffers to the FreeChainQ.
3439 */
3440 mem = (u8 *)ioc->ChainBuffer;
3441 for (i=0; i < num_chain; i++) {
3442 mf = (MPT_FRAME_HDR *) mem;
3443 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3444 mem += ioc->req_sz;
3445 }
3446
3447 /* Initialize Request frames linked list
3448 */
3449 alloc_dma = ioc->req_frames_dma;
3450 mem = (u8 *) ioc->req_frames;
3451
3452 spin_lock_irqsave(&ioc->FreeQlock, flags);
3453 INIT_LIST_HEAD(&ioc->FreeQ);
3454 for (i = 0; i < ioc->req_depth; i++) {
3455 mf = (MPT_FRAME_HDR *) mem;
3456
3457 /* Queue REQUESTs *internally*! */
3458 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3459
3460 mem += ioc->req_sz;
3461 }
3462 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3463
3464 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3465 ioc->sense_buf_pool =
3466 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3467 if (ioc->sense_buf_pool == NULL) {
3468 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3469 ioc->name);
3470 goto out_fail;
3471 }
3472
3473 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3474 ioc->alloc_total += sz;
3475 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3476 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3477
3478 }
3479
3480 /* Post Reply frames to FIFO
3481 */
3482 alloc_dma = ioc->alloc_dma;
3483 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3484 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3485
3486 for (i = 0; i < ioc->reply_depth; i++) {
3487 /* Write each address to the IOC! */
3488 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3489 alloc_dma += ioc->reply_sz;
3490 }
3491
3492 return 0;
3493
3494out_fail:
3495 if (ioc->alloc != NULL) {
3496 sz = ioc->alloc_sz;
3497 pci_free_consistent(ioc->pcidev,
3498 sz,
3499 ioc->alloc, ioc->alloc_dma);
3500 ioc->reply_frames = NULL;
3501 ioc->req_frames = NULL;
3502 ioc->alloc_total -= sz;
3503 }
3504 if (ioc->sense_buf_pool != NULL) {
3505 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3506 pci_free_consistent(ioc->pcidev,
3507 sz,
3508 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3509 ioc->sense_buf_pool = NULL;
3510 }
3511 return -1;
3512}
3513
3514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3515/**
3516 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3517 * from IOC via doorbell handshake method.
3518 * @ioc: Pointer to MPT_ADAPTER structure
3519 * @reqBytes: Size of the request in bytes
3520 * @req: Pointer to MPT request frame
3521 * @replyBytes: Expected size of the reply in bytes
3522 * @u16reply: Pointer to area where reply should be written
3523 * @maxwait: Max wait time for a reply (in seconds)
3524 * @sleepFlag: Specifies whether the process can sleep
3525 *
3526 * NOTES: It is the callers responsibility to byte-swap fields in the
3527 * request which are greater than 1 byte in size. It is also the
3528 * callers responsibility to byte-swap response fields which are
3529 * greater than 1 byte in size.
3530 *
3531 * Returns 0 for success, non-zero for failure.
3532 */
3533static int
3534mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
3535 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
3536{
3537 MPIDefaultReply_t *mptReply;
3538 int failcnt = 0;
3539 int t;
3540
3541 /*
3542 * Get ready to cache a handshake reply
3543 */
3544 ioc->hs_reply_idx = 0;
3545 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3546 mptReply->MsgLength = 0;
3547
3548 /*
3549 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3550 * then tell IOC that we want to handshake a request of N words.
3551 * (WRITE u32val to Doorbell reg).
3552 */
3553 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3554 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3555 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3556 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3557
3558 /*
3559 * Wait for IOC's doorbell handshake int
3560 */
3561 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3562 failcnt++;
3563
3564 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3565 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3566
3567 /* Read doorbell and check for active bit */
3568 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3569 return -1;
3570
3571 /*
3572 * Clear doorbell int (WRITE 0 to IntStatus reg),
3573 * then wait for IOC to ACKnowledge that it's ready for
3574 * our handshake request.
3575 */
3576 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3577 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3578 failcnt++;
3579
3580 if (!failcnt) {
3581 int ii;
3582 u8 *req_as_bytes = (u8 *) req;
3583
3584 /*
3585 * Stuff request words via doorbell handshake,
3586 * with ACK from IOC for each.
3587 */
3588 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3589 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3590 (req_as_bytes[(ii*4) + 1] << 8) |
3591 (req_as_bytes[(ii*4) + 2] << 16) |
3592 (req_as_bytes[(ii*4) + 3] << 24));
3593
3594 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3595 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3596 failcnt++;
3597 }
3598
3599 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3600 DBG_DUMP_REQUEST_FRAME_HDR(req)
3601
3602 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3603 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3604
3605 /*
3606 * Wait for completion of doorbell handshake reply from the IOC
3607 */
3608 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3609 failcnt++;
3610
3611 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3612 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3613
3614 /*
3615 * Copy out the cached reply...
3616 */
3617 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3618 u16reply[ii] = ioc->hs_reply[ii];
3619 } else {
3620 return -99;
3621 }
3622
3623 return -failcnt;
3624}
3625
3626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3627/*
3628 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3629 * in it's IntStatus register.
3630 * @ioc: Pointer to MPT_ADAPTER structure
3631 * @howlong: How long to wait (in seconds)
3632 * @sleepFlag: Specifies whether the process can sleep
3633 *
3634 * This routine waits (up to ~2 seconds max) for IOC doorbell
3635 * handshake ACKnowledge.
3636 *
3637 * Returns a negative value on failure, else wait loop count.
3638 */
3639static int
3640WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3641{
3642 int cntdn;
3643 int count = 0;
3644 u32 intstat=0;
3645
3646 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
3647
3648 if (sleepFlag == CAN_SLEEP) {
3649 while (--cntdn) {
3650 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3651 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3652 break;
3653 msleep_interruptible (1);
3654 count++;
3655 }
3656 } else {
3657 while (--cntdn) {
3658 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3659 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3660 break;
3661 mdelay (1);
3662 count++;
3663 }
3664 }
3665
3666 if (cntdn) {
3667 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3668 ioc->name, count));
3669 return count;
3670 }
3671
3672 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3673 ioc->name, count, intstat);
3674 return -1;
3675}
3676
3677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3678/*
3679 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3680 * in it's IntStatus register.
3681 * @ioc: Pointer to MPT_ADAPTER structure
3682 * @howlong: How long to wait (in seconds)
3683 * @sleepFlag: Specifies whether the process can sleep
3684 *
3685 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3686 *
3687 * Returns a negative value on failure, else wait loop count.
3688 */
3689static int
3690WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3691{
3692 int cntdn;
3693 int count = 0;
3694 u32 intstat=0;
3695
3696 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
3697 if (sleepFlag == CAN_SLEEP) {
3698 while (--cntdn) {
3699 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3700 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3701 break;
3702 msleep_interruptible(1);
3703 count++;
3704 }
3705 } else {
3706 while (--cntdn) {
3707 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3708 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3709 break;
3710 mdelay(1);
3711 count++;
3712 }
3713 }
3714
3715 if (cntdn) {
3716 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3717 ioc->name, count, howlong));
3718 return count;
3719 }
3720
3721 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3722 ioc->name, count, intstat);
3723 return -1;
3724}
3725
3726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3727/*
3728 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3729 * @ioc: Pointer to MPT_ADAPTER structure
3730 * @howlong: How long to wait (in seconds)
3731 * @sleepFlag: Specifies whether the process can sleep
3732 *
3733 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3734 * Reply is cached to IOC private area large enough to hold a maximum
3735 * of 128 bytes of reply data.
3736 *
3737 * Returns a negative value on failure, else size of reply in WORDS.
3738 */
3739static int
3740WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3741{
3742 int u16cnt = 0;
3743 int failcnt = 0;
3744 int t;
3745 u16 *hs_reply = ioc->hs_reply;
3746 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3747 u16 hword;
3748
3749 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
3750
3751 /*
3752 * Get first two u16's so we can look at IOC's intended reply MsgLength
3753 */
3754 u16cnt=0;
3755 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
3756 failcnt++;
3757 } else {
3758 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3759 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3760 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3761 failcnt++;
3762 else {
3763 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3764 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3765 }
3766 }
3767
3768 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
3769 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
3770 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3771
3772 /*
3773 * If no error (and IOC said MsgLength is > 0), piece together
3774 * reply 16 bits at a time.
3775 */
3776 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
3777 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3778 failcnt++;
3779 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3780 /* don't overflow our IOC hs_reply[] buffer! */
3781 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
3782 hs_reply[u16cnt] = hword;
3783 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3784 }
3785
3786 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3787 failcnt++;
3788 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3789
3790 if (failcnt) {
3791 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
3792 ioc->name);
3793 return -failcnt;
3794 }
3795#if 0
3796 else if (u16cnt != (2 * mptReply->MsgLength)) {
3797 return -101;
3798 }
3799 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
3800 return -102;
3801 }
3802#endif
3803
3804 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
3805 DBG_DUMP_REPLY_FRAME(mptReply)
3806
3807 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
3808 ioc->name, t, u16cnt/2));
3809 return u16cnt/2;
3810}
3811
3812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3813/*
3814 * GetLanConfigPages - Fetch LANConfig pages.
3815 * @ioc: Pointer to MPT_ADAPTER structure
3816 *
3817 * Return: 0 for success
3818 * -ENOMEM if no memory available
3819 * -EPERM if not allowed due to ISR context
3820 * -EAGAIN if no msg frames currently available
3821 * -EFAULT for non-successful reply or no reply (timeout)
3822 */
3823static int
3824GetLanConfigPages(MPT_ADAPTER *ioc)
3825{
3826 ConfigPageHeader_t hdr;
3827 CONFIGPARMS cfg;
3828 LANPage0_t *ppage0_alloc;
3829 dma_addr_t page0_dma;
3830 LANPage1_t *ppage1_alloc;
3831 dma_addr_t page1_dma;
3832 int rc = 0;
3833 int data_sz;
3834 int copy_sz;
3835
3836 /* Get LAN Page 0 header */
3837 hdr.PageVersion = 0;
3838 hdr.PageLength = 0;
3839 hdr.PageNumber = 0;
3840 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
3841 cfg.hdr = &hdr;
3842 cfg.physAddr = -1;
3843 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3844 cfg.dir = 0;
3845 cfg.pageAddr = 0;
3846 cfg.timeout = 0;
3847
3848 if ((rc = mpt_config(ioc, &cfg)) != 0)
3849 return rc;
3850
3851 if (hdr.PageLength > 0) {
3852 data_sz = hdr.PageLength * 4;
3853 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
3854 rc = -ENOMEM;
3855 if (ppage0_alloc) {
3856 memset((u8 *)ppage0_alloc, 0, data_sz);
3857 cfg.physAddr = page0_dma;
3858 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3859
3860 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3861 /* save the data */
3862 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
3863 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
3864
3865 }
3866
3867 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
3868
3869 /* FIXME!
3870 * Normalize endianness of structure data,
3871 * by byte-swapping all > 1 byte fields!
3872 */
3873
3874 }
3875
3876 if (rc)
3877 return rc;
3878 }
3879
3880 /* Get LAN Page 1 header */
3881 hdr.PageVersion = 0;
3882 hdr.PageLength = 0;
3883 hdr.PageNumber = 1;
3884 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
3885 cfg.hdr = &hdr;
3886 cfg.physAddr = -1;
3887 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3888 cfg.dir = 0;
3889 cfg.pageAddr = 0;
3890
3891 if ((rc = mpt_config(ioc, &cfg)) != 0)
3892 return rc;
3893
3894 if (hdr.PageLength == 0)
3895 return 0;
3896
3897 data_sz = hdr.PageLength * 4;
3898 rc = -ENOMEM;
3899 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
3900 if (ppage1_alloc) {
3901 memset((u8 *)ppage1_alloc, 0, data_sz);
3902 cfg.physAddr = page1_dma;
3903 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3904
3905 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3906 /* save the data */
3907 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
3908 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
3909 }
3910
3911 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
3912
3913 /* FIXME!
3914 * Normalize endianness of structure data,
3915 * by byte-swapping all > 1 byte fields!
3916 */
3917
3918 }
3919
3920 return rc;
3921}
3922
3923/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3924/*
3925 * GetFcPortPage0 - Fetch FCPort config Page0.
3926 * @ioc: Pointer to MPT_ADAPTER structure
3927 * @portnum: IOC Port number
3928 *
3929 * Return: 0 for success
3930 * -ENOMEM if no memory available
3931 * -EPERM if not allowed due to ISR context
3932 * -EAGAIN if no msg frames currently available
3933 * -EFAULT for non-successful reply or no reply (timeout)
3934 */
3935static int
3936GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
3937{
3938 ConfigPageHeader_t hdr;
3939 CONFIGPARMS cfg;
3940 FCPortPage0_t *ppage0_alloc;
3941 FCPortPage0_t *pp0dest;
3942 dma_addr_t page0_dma;
3943 int data_sz;
3944 int copy_sz;
3945 int rc;
3946
3947 /* Get FCPort Page 0 header */
3948 hdr.PageVersion = 0;
3949 hdr.PageLength = 0;
3950 hdr.PageNumber = 0;
3951 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
3952 cfg.hdr = &hdr;
3953 cfg.physAddr = -1;
3954 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3955 cfg.dir = 0;
3956 cfg.pageAddr = portnum;
3957 cfg.timeout = 0;
3958
3959 if ((rc = mpt_config(ioc, &cfg)) != 0)
3960 return rc;
3961
3962 if (hdr.PageLength == 0)
3963 return 0;
3964
3965 data_sz = hdr.PageLength * 4;
3966 rc = -ENOMEM;
3967 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
3968 if (ppage0_alloc) {
3969 memset((u8 *)ppage0_alloc, 0, data_sz);
3970 cfg.physAddr = page0_dma;
3971 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3972
3973 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3974 /* save the data */
3975 pp0dest = &ioc->fc_port_page0[portnum];
3976 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
3977 memcpy(pp0dest, ppage0_alloc, copy_sz);
3978
3979 /*
3980 * Normalize endianness of structure data,
3981 * by byte-swapping all > 1 byte fields!
3982 */
3983 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
3984 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
3985 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
3986 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
3987 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
3988 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
3989 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
3990 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
3991 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
3992 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
3993 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
3994 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
3995 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
3996 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
3997 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
3998 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
3999
4000 }
4001
4002 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4003 }
4004
4005 return rc;
4006}
4007
4008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4009/*
4010 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4011 * @ioc: Pointer to MPT_ADAPTER structure
4012 *
4013 * Returns: 0 for success
4014 * -ENOMEM if no memory available
4015 * -EPERM if not allowed due to ISR context
4016 * -EAGAIN if no msg frames currently available
4017 * -EFAULT for non-successful reply or no reply (timeout)
4018 */
4019static int
4020GetIoUnitPage2(MPT_ADAPTER *ioc)
4021{
4022 ConfigPageHeader_t hdr;
4023 CONFIGPARMS cfg;
4024 IOUnitPage2_t *ppage_alloc;
4025 dma_addr_t page_dma;
4026 int data_sz;
4027 int rc;
4028
4029 /* Get the page header */
4030 hdr.PageVersion = 0;
4031 hdr.PageLength = 0;
4032 hdr.PageNumber = 2;
4033 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
4034 cfg.hdr = &hdr;
4035 cfg.physAddr = -1;
4036 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4037 cfg.dir = 0;
4038 cfg.pageAddr = 0;
4039 cfg.timeout = 0;
4040
4041 if ((rc = mpt_config(ioc, &cfg)) != 0)
4042 return rc;
4043
4044 if (hdr.PageLength == 0)
4045 return 0;
4046
4047 /* Read the config page */
4048 data_sz = hdr.PageLength * 4;
4049 rc = -ENOMEM;
4050 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4051 if (ppage_alloc) {
4052 memset((u8 *)ppage_alloc, 0, data_sz);
4053 cfg.physAddr = page_dma;
4054 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4055
4056 /* If Good, save data */
4057 if ((rc = mpt_config(ioc, &cfg)) == 0)
4058 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4059
4060 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4061 }
4062
4063 return rc;
4064}
4065
4066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4067/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4068 * @ioc: Pointer to a Adapter Strucutre
4069 * @portnum: IOC port number
4070 *
4071 * Return: -EFAULT if read of config page header fails
4072 * or if no nvram
4073 * If read of SCSI Port Page 0 fails,
4074 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4075 * Adapter settings: async, narrow
4076 * Return 1
4077 * If read of SCSI Port Page 2 fails,
4078 * Adapter settings valid
4079 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4080 * Return 1
4081 * Else
4082 * Both valid
4083 * Return 0
4084 * CHECK - what type of locking mechanisms should be used????
4085 */
4086static int
4087mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4088{
4089 u8 *pbuf;
4090 dma_addr_t buf_dma;
4091 CONFIGPARMS cfg;
4092 ConfigPageHeader_t header;
4093 int ii;
4094 int data, rc = 0;
4095
4096 /* Allocate memory
4097 */
4098 if (!ioc->spi_data.nvram) {
4099 int sz;
4100 u8 *mem;
4101 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4102 mem = kmalloc(sz, GFP_ATOMIC);
4103 if (mem == NULL)
4104 return -EFAULT;
4105
4106 ioc->spi_data.nvram = (int *) mem;
4107
4108 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4109 ioc->name, ioc->spi_data.nvram, sz));
4110 }
4111
4112 /* Invalidate NVRAM information
4113 */
4114 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4115 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4116 }
4117
4118 /* Read SPP0 header, allocate memory, then read page.
4119 */
4120 header.PageVersion = 0;
4121 header.PageLength = 0;
4122 header.PageNumber = 0;
4123 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
4124 cfg.hdr = &header;
4125 cfg.physAddr = -1;
4126 cfg.pageAddr = portnum;
4127 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4128 cfg.dir = 0;
4129 cfg.timeout = 0; /* use default */
4130 if (mpt_config(ioc, &cfg) != 0)
4131 return -EFAULT;
4132
4133 if (header.PageLength > 0) {
4134 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4135 if (pbuf) {
4136 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4137 cfg.physAddr = buf_dma;
4138 if (mpt_config(ioc, &cfg) != 0) {
4139 ioc->spi_data.maxBusWidth = MPT_NARROW;
4140 ioc->spi_data.maxSyncOffset = 0;
4141 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4142 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4143 rc = 1;
4144 } else {
4145 /* Save the Port Page 0 data
4146 */
4147 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4148 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4149 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4150
4151 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4152 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
4153 dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
4154 ioc->name, pPP0->Capabilities));
4155 }
4156 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4157 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4158 if (data) {
4159 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4160 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4161 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
4162 } else {
4163 ioc->spi_data.maxSyncOffset = 0;
4164 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4165 }
4166
4167 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4168
4169 /* Update the minSyncFactor based on bus type.
4170 */
4171 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4172 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4173
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004174 if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 ioc->spi_data.minSyncFactor = MPT_ULTRA;
4176 }
4177 }
4178 if (pbuf) {
4179 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4180 }
4181 }
4182 }
4183
4184 /* SCSI Port Page 2 - Read the header then the page.
4185 */
4186 header.PageVersion = 0;
4187 header.PageLength = 0;
4188 header.PageNumber = 2;
4189 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
4190 cfg.hdr = &header;
4191 cfg.physAddr = -1;
4192 cfg.pageAddr = portnum;
4193 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4194 cfg.dir = 0;
4195 if (mpt_config(ioc, &cfg) != 0)
4196 return -EFAULT;
4197
4198 if (header.PageLength > 0) {
4199 /* Allocate memory and read SCSI Port Page 2
4200 */
4201 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4202 if (pbuf) {
4203 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4204 cfg.physAddr = buf_dma;
4205 if (mpt_config(ioc, &cfg) != 0) {
4206 /* Nvram data is left with INVALID mark
4207 */
4208 rc = 1;
4209 } else {
4210 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4211 MpiDeviceInfo_t *pdevice = NULL;
4212
4213 /* Save the Port Page 2 data
4214 * (reformat into a 32bit quantity)
4215 */
4216 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4217 ioc->spi_data.PortFlags = data;
4218 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4219 pdevice = &pPP2->DeviceSettings[ii];
4220 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4221 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4222 ioc->spi_data.nvram[ii] = data;
4223 }
4224 }
4225
4226 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4227 }
4228 }
4229
4230 /* Update Adapter limits with those from NVRAM
4231 * Comment: Don't need to do this. Target performance
4232 * parameters will never exceed the adapters limits.
4233 */
4234
4235 return rc;
4236}
4237
4238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4239/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4240 * @ioc: Pointer to a Adapter Strucutre
4241 * @portnum: IOC port number
4242 *
4243 * Return: -EFAULT if read of config page header fails
4244 * or 0 if success.
4245 */
4246static int
4247mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4248{
4249 CONFIGPARMS cfg;
4250 ConfigPageHeader_t header;
4251
4252 /* Read the SCSI Device Page 1 header
4253 */
4254 header.PageVersion = 0;
4255 header.PageLength = 0;
4256 header.PageNumber = 1;
4257 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4258 cfg.hdr = &header;
4259 cfg.physAddr = -1;
4260 cfg.pageAddr = portnum;
4261 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4262 cfg.dir = 0;
4263 cfg.timeout = 0;
4264 if (mpt_config(ioc, &cfg) != 0)
4265 return -EFAULT;
4266
4267 ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
4268 ioc->spi_data.sdp1length = cfg.hdr->PageLength;
4269
4270 header.PageVersion = 0;
4271 header.PageLength = 0;
4272 header.PageNumber = 0;
4273 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4274 if (mpt_config(ioc, &cfg) != 0)
4275 return -EFAULT;
4276
4277 ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
4278 ioc->spi_data.sdp0length = cfg.hdr->PageLength;
4279
4280 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4281 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4282
4283 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4284 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4285 return 0;
4286}
4287
4288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4289/**
4290 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4291 * @ioc: Pointer to a Adapter Strucutre
4292 * @portnum: IOC port number
4293 *
4294 * Return:
4295 * 0 on success
4296 * -EFAULT if read of config page header fails or data pointer not NULL
4297 * -ENOMEM if pci_alloc failed
4298 */
4299int
4300mpt_findImVolumes(MPT_ADAPTER *ioc)
4301{
4302 IOCPage2_t *pIoc2;
4303 u8 *mem;
4304 ConfigPageIoc2RaidVol_t *pIocRv;
4305 dma_addr_t ioc2_dma;
4306 CONFIGPARMS cfg;
4307 ConfigPageHeader_t header;
4308 int jj;
4309 int rc = 0;
4310 int iocpage2sz;
4311 u8 nVols, nPhys;
4312 u8 vid, vbus, vioc;
4313
4314 /* Read IOCP2 header then the page.
4315 */
4316 header.PageVersion = 0;
4317 header.PageLength = 0;
4318 header.PageNumber = 2;
4319 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4320 cfg.hdr = &header;
4321 cfg.physAddr = -1;
4322 cfg.pageAddr = 0;
4323 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4324 cfg.dir = 0;
4325 cfg.timeout = 0;
4326 if (mpt_config(ioc, &cfg) != 0)
4327 return -EFAULT;
4328
4329 if (header.PageLength == 0)
4330 return -EFAULT;
4331
4332 iocpage2sz = header.PageLength * 4;
4333 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4334 if (!pIoc2)
4335 return -ENOMEM;
4336
4337 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4338 cfg.physAddr = ioc2_dma;
4339 if (mpt_config(ioc, &cfg) != 0)
4340 goto done_and_free;
4341
4342 if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) {
4343 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4344 if (mem) {
4345 ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem;
4346 } else {
4347 goto done_and_free;
4348 }
4349 }
4350 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4351
4352 /* Identify RAID Volume Id's */
4353 nVols = pIoc2->NumActiveVolumes;
4354 if ( nVols == 0) {
4355 /* No RAID Volume.
4356 */
4357 goto done_and_free;
4358 } else {
4359 /* At least 1 RAID Volume
4360 */
4361 pIocRv = pIoc2->RaidVolume;
4362 ioc->spi_data.isRaid = 0;
4363 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4364 vid = pIocRv->VolumeID;
4365 vbus = pIocRv->VolumeBus;
4366 vioc = pIocRv->VolumeIOC;
4367
4368 /* find the match
4369 */
4370 if (vbus == 0) {
4371 ioc->spi_data.isRaid |= (1 << vid);
4372 } else {
4373 /* Error! Always bus 0
4374 */
4375 }
4376 }
4377 }
4378
4379 /* Identify Hidden Physical Disk Id's */
4380 nPhys = pIoc2->NumActivePhysDisks;
4381 if (nPhys == 0) {
4382 /* No physical disks.
4383 */
4384 } else {
4385 mpt_read_ioc_pg_3(ioc);
4386 }
4387
4388done_and_free:
4389 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4390
4391 return rc;
4392}
4393
4394int
4395mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4396{
4397 IOCPage3_t *pIoc3;
4398 u8 *mem;
4399 CONFIGPARMS cfg;
4400 ConfigPageHeader_t header;
4401 dma_addr_t ioc3_dma;
4402 int iocpage3sz = 0;
4403
4404 /* Free the old page
4405 */
4406 if (ioc->spi_data.pIocPg3) {
4407 kfree(ioc->spi_data.pIocPg3);
4408 ioc->spi_data.pIocPg3 = NULL;
4409 }
4410
4411 /* There is at least one physical disk.
4412 * Read and save IOC Page 3
4413 */
4414 header.PageVersion = 0;
4415 header.PageLength = 0;
4416 header.PageNumber = 3;
4417 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4418 cfg.hdr = &header;
4419 cfg.physAddr = -1;
4420 cfg.pageAddr = 0;
4421 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4422 cfg.dir = 0;
4423 cfg.timeout = 0;
4424 if (mpt_config(ioc, &cfg) != 0)
4425 return 0;
4426
4427 if (header.PageLength == 0)
4428 return 0;
4429
4430 /* Read Header good, alloc memory
4431 */
4432 iocpage3sz = header.PageLength * 4;
4433 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4434 if (!pIoc3)
4435 return 0;
4436
4437 /* Read the Page and save the data
4438 * into malloc'd memory.
4439 */
4440 cfg.physAddr = ioc3_dma;
4441 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4442 if (mpt_config(ioc, &cfg) == 0) {
4443 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4444 if (mem) {
4445 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
4446 ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
4447 }
4448 }
4449
4450 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4451
4452 return 0;
4453}
4454
4455static void
4456mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4457{
4458 IOCPage4_t *pIoc4;
4459 CONFIGPARMS cfg;
4460 ConfigPageHeader_t header;
4461 dma_addr_t ioc4_dma;
4462 int iocpage4sz;
4463
4464 /* Read and save IOC Page 4
4465 */
4466 header.PageVersion = 0;
4467 header.PageLength = 0;
4468 header.PageNumber = 4;
4469 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4470 cfg.hdr = &header;
4471 cfg.physAddr = -1;
4472 cfg.pageAddr = 0;
4473 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4474 cfg.dir = 0;
4475 cfg.timeout = 0;
4476 if (mpt_config(ioc, &cfg) != 0)
4477 return;
4478
4479 if (header.PageLength == 0)
4480 return;
4481
4482 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4483 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4484 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4485 if (!pIoc4)
4486 return;
4487 } else {
4488 ioc4_dma = ioc->spi_data.IocPg4_dma;
4489 iocpage4sz = ioc->spi_data.IocPg4Sz;
4490 }
4491
4492 /* Read the Page into dma memory.
4493 */
4494 cfg.physAddr = ioc4_dma;
4495 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4496 if (mpt_config(ioc, &cfg) == 0) {
4497 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4498 ioc->spi_data.IocPg4_dma = ioc4_dma;
4499 ioc->spi_data.IocPg4Sz = iocpage4sz;
4500 } else {
4501 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4502 ioc->spi_data.pIocPg4 = NULL;
4503 }
4504}
4505
4506static void
4507mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4508{
4509 IOCPage1_t *pIoc1;
4510 CONFIGPARMS cfg;
4511 ConfigPageHeader_t header;
4512 dma_addr_t ioc1_dma;
4513 int iocpage1sz = 0;
4514 u32 tmp;
4515
4516 /* Check the Coalescing Timeout in IOC Page 1
4517 */
4518 header.PageVersion = 0;
4519 header.PageLength = 0;
4520 header.PageNumber = 1;
4521 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4522 cfg.hdr = &header;
4523 cfg.physAddr = -1;
4524 cfg.pageAddr = 0;
4525 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4526 cfg.dir = 0;
4527 cfg.timeout = 0;
4528 if (mpt_config(ioc, &cfg) != 0)
4529 return;
4530
4531 if (header.PageLength == 0)
4532 return;
4533
4534 /* Read Header good, alloc memory
4535 */
4536 iocpage1sz = header.PageLength * 4;
4537 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4538 if (!pIoc1)
4539 return;
4540
4541 /* Read the Page and check coalescing timeout
4542 */
4543 cfg.physAddr = ioc1_dma;
4544 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4545 if (mpt_config(ioc, &cfg) == 0) {
4546
4547 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4548 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4549 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4550
4551 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4552 ioc->name, tmp));
4553
4554 if (tmp > MPT_COALESCING_TIMEOUT) {
4555 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4556
4557 /* Write NVRAM and current
4558 */
4559 cfg.dir = 1;
4560 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4561 if (mpt_config(ioc, &cfg) == 0) {
4562 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4563 ioc->name, MPT_COALESCING_TIMEOUT));
4564
4565 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4566 if (mpt_config(ioc, &cfg) == 0) {
4567 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4568 ioc->name, MPT_COALESCING_TIMEOUT));
4569 } else {
4570 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4571 ioc->name));
4572 }
4573
4574 } else {
4575 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4576 ioc->name));
4577 }
4578 }
4579
4580 } else {
4581 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4582 }
4583 }
4584
4585 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4586
4587 return;
4588}
4589
4590/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4591/*
4592 * SendEventNotification - Send EventNotification (on or off) request
4593 * to MPT adapter.
4594 * @ioc: Pointer to MPT_ADAPTER structure
4595 * @EvSwitch: Event switch flags
4596 */
4597static int
4598SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4599{
4600 EventNotification_t *evnp;
4601
4602 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
4603 if (evnp == NULL) {
4604 dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
4605 ioc->name));
4606 return 0;
4607 }
4608 memset(evnp, 0, sizeof(*evnp));
4609
4610 dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
4611
4612 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
4613 evnp->ChainOffset = 0;
4614 evnp->MsgFlags = 0;
4615 evnp->Switch = EvSwitch;
4616
4617 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
4618
4619 return 0;
4620}
4621
4622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4623/**
4624 * SendEventAck - Send EventAck request to MPT adapter.
4625 * @ioc: Pointer to MPT_ADAPTER structure
4626 * @evnp: Pointer to original EventNotification request
4627 */
4628static int
4629SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
4630{
4631 EventAck_t *pAck;
4632
4633 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4634 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
4635 ioc->name);
4636 return -1;
4637 }
4638 memset(pAck, 0, sizeof(*pAck));
4639
4640 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
4641
4642 pAck->Function = MPI_FUNCTION_EVENT_ACK;
4643 pAck->ChainOffset = 0;
4644 pAck->MsgFlags = 0;
4645 pAck->Event = evnp->Event;
4646 pAck->EventContext = evnp->EventContext;
4647
4648 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
4649
4650 return 0;
4651}
4652
4653/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4654/**
4655 * mpt_config - Generic function to issue config message
4656 * @ioc - Pointer to an adapter structure
4657 * @cfg - Pointer to a configuration structure. Struct contains
4658 * action, page address, direction, physical address
4659 * and pointer to a configuration page header
4660 * Page header is updated.
4661 *
4662 * Returns 0 for success
4663 * -EPERM if not allowed due to ISR context
4664 * -EAGAIN if no msg frames currently available
4665 * -EFAULT for non-successful reply or no reply (timeout)
4666 */
4667int
4668mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
4669{
4670 Config_t *pReq;
4671 MPT_FRAME_HDR *mf;
4672 unsigned long flags;
4673 int ii, rc;
4674 u32 flagsLength;
4675 int in_isr;
4676
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004677 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 * to be in ISR context, because that is fatal!
4679 */
4680 in_isr = in_interrupt();
4681 if (in_isr) {
4682 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
4683 ioc->name));
4684 return -EPERM;
4685 }
4686
4687 /* Get and Populate a free Frame
4688 */
4689 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4690 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
4691 ioc->name));
4692 return -EAGAIN;
4693 }
4694 pReq = (Config_t *)mf;
4695 pReq->Action = pCfg->action;
4696 pReq->Reserved = 0;
4697 pReq->ChainOffset = 0;
4698 pReq->Function = MPI_FUNCTION_CONFIG;
4699 pReq->ExtPageLength = 0;
4700 pReq->ExtPageType = 0;
4701 pReq->MsgFlags = 0;
4702 for (ii=0; ii < 8; ii++)
4703 pReq->Reserved2[ii] = 0;
4704
4705 pReq->Header.PageVersion = pCfg->hdr->PageVersion;
4706 pReq->Header.PageLength = pCfg->hdr->PageLength;
4707 pReq->Header.PageNumber = pCfg->hdr->PageNumber;
4708 pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
4709 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
4710
4711 /* Add a SGE to the config request.
4712 */
4713 if (pCfg->dir)
4714 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
4715 else
4716 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
4717
4718 flagsLength |= pCfg->hdr->PageLength * 4;
4719
4720 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
4721
4722 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
4723 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
4724
4725 /* Append pCfg pointer to end of mf
4726 */
4727 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
4728
4729 /* Initalize the timer
4730 */
4731 init_timer(&pCfg->timer);
4732 pCfg->timer.data = (unsigned long) ioc;
4733 pCfg->timer.function = mpt_timer_expired;
4734 pCfg->wait_done = 0;
4735
4736 /* Set the timer; ensure 10 second minimum */
4737 if (pCfg->timeout < 10)
4738 pCfg->timer.expires = jiffies + HZ*10;
4739 else
4740 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
4741
4742 /* Add to end of Q, set timer and then issue this command */
4743 spin_lock_irqsave(&ioc->FreeQlock, flags);
4744 list_add_tail(&pCfg->linkage, &ioc->configQ);
4745 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4746
4747 add_timer(&pCfg->timer);
4748 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4749 wait_event(mpt_waitq, pCfg->wait_done);
4750
4751 /* mf has been freed - do not access */
4752
4753 rc = pCfg->status;
4754
4755 return rc;
4756}
4757
4758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4759/**
4760 * mpt_toolbox - Generic function to issue toolbox message
4761 * @ioc - Pointer to an adapter structure
4762 * @cfg - Pointer to a toolbox structure. Struct contains
4763 * action, page address, direction, physical address
4764 * and pointer to a configuration page header
4765 * Page header is updated.
4766 *
4767 * Returns 0 for success
4768 * -EPERM if not allowed due to ISR context
4769 * -EAGAIN if no msg frames currently available
4770 * -EFAULT for non-successful reply or no reply (timeout)
4771 */
4772int
4773mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
4774{
4775 ToolboxIstwiReadWriteRequest_t *pReq;
4776 MPT_FRAME_HDR *mf;
4777 struct pci_dev *pdev;
4778 unsigned long flags;
4779 int rc;
4780 u32 flagsLength;
4781 int in_isr;
4782
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004783 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 * to be in ISR context, because that is fatal!
4785 */
4786 in_isr = in_interrupt();
4787 if (in_isr) {
4788 dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n",
4789 ioc->name));
4790 return -EPERM;
4791 }
4792
4793 /* Get and Populate a free Frame
4794 */
4795 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4796 dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n",
4797 ioc->name));
4798 return -EAGAIN;
4799 }
4800 pReq = (ToolboxIstwiReadWriteRequest_t *)mf;
4801 pReq->Tool = pCfg->action;
4802 pReq->Reserved = 0;
4803 pReq->ChainOffset = 0;
4804 pReq->Function = MPI_FUNCTION_TOOLBOX;
4805 pReq->Reserved1 = 0;
4806 pReq->Reserved2 = 0;
4807 pReq->MsgFlags = 0;
4808 pReq->Flags = pCfg->dir;
4809 pReq->BusNum = 0;
4810 pReq->Reserved3 = 0;
4811 pReq->NumAddressBytes = 0x01;
4812 pReq->Reserved4 = 0;
4813 pReq->DataLength = 0x04;
4814 pdev = (struct pci_dev *) ioc->pcidev;
4815 if (pdev->devfn & 1)
4816 pReq->DeviceAddr = 0xB2;
4817 else
4818 pReq->DeviceAddr = 0xB0;
4819 pReq->Addr1 = 0;
4820 pReq->Addr2 = 0;
4821 pReq->Addr3 = 0;
4822 pReq->Reserved5 = 0;
4823
4824 /* Add a SGE to the config request.
4825 */
4826
4827 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4;
4828
4829 mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr);
4830
4831 dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n",
4832 ioc->name, pReq->Tool));
4833
4834 /* Append pCfg pointer to end of mf
4835 */
4836 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
4837
4838 /* Initalize the timer
4839 */
4840 init_timer(&pCfg->timer);
4841 pCfg->timer.data = (unsigned long) ioc;
4842 pCfg->timer.function = mpt_timer_expired;
4843 pCfg->wait_done = 0;
4844
4845 /* Set the timer; ensure 10 second minimum */
4846 if (pCfg->timeout < 10)
4847 pCfg->timer.expires = jiffies + HZ*10;
4848 else
4849 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
4850
4851 /* Add to end of Q, set timer and then issue this command */
4852 spin_lock_irqsave(&ioc->FreeQlock, flags);
4853 list_add_tail(&pCfg->linkage, &ioc->configQ);
4854 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4855
4856 add_timer(&pCfg->timer);
4857 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4858 wait_event(mpt_waitq, pCfg->wait_done);
4859
4860 /* mf has been freed - do not access */
4861
4862 rc = pCfg->status;
4863
4864 return rc;
4865}
4866
4867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4868/*
4869 * mpt_timer_expired - Call back for timer process.
4870 * Used only internal config functionality.
4871 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
4872 */
4873static void
4874mpt_timer_expired(unsigned long data)
4875{
4876 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
4877
4878 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
4879
4880 /* Perform a FW reload */
4881 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
4882 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
4883
4884 /* No more processing.
4885 * Hard reset clean-up will wake up
4886 * process and free all resources.
4887 */
4888 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
4889
4890 return;
4891}
4892
4893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4894/*
4895 * mpt_ioc_reset - Base cleanup for hard reset
4896 * @ioc: Pointer to the adapter structure
4897 * @reset_phase: Indicates pre- or post-reset functionality
4898 *
4899 * Remark: Free's resources with internally generated commands.
4900 */
4901static int
4902mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
4903{
4904 CONFIGPARMS *pCfg;
4905 unsigned long flags;
4906
4907 dprintk((KERN_WARNING MYNAM
4908 ": IOC %s_reset routed to MPT base driver!\n",
4909 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
4910 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
4911
4912 if (reset_phase == MPT_IOC_SETUP_RESET) {
4913 ;
4914 } else if (reset_phase == MPT_IOC_PRE_RESET) {
4915 /* If the internal config Q is not empty -
4916 * delete timer. MF resources will be freed when
4917 * the FIFO's are primed.
4918 */
4919 spin_lock_irqsave(&ioc->FreeQlock, flags);
4920 list_for_each_entry(pCfg, &ioc->configQ, linkage)
4921 del_timer(&pCfg->timer);
4922 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4923
4924 } else {
4925 CONFIGPARMS *pNext;
4926
4927 /* Search the configQ for internal commands.
4928 * Flush the Q, and wake up all suspended threads.
4929 */
4930 spin_lock_irqsave(&ioc->FreeQlock, flags);
4931 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
4932 list_del(&pCfg->linkage);
4933
4934 pCfg->status = MPT_CONFIG_ERROR;
4935 pCfg->wait_done = 1;
4936 wake_up(&mpt_waitq);
4937 }
4938 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4939 }
4940
4941 return 1; /* currently means nothing really */
4942}
4943
4944
4945#ifdef CONFIG_PROC_FS /* { */
4946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4947/*
4948 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
4949 */
4950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4951/*
4952 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
4953 *
4954 * Returns 0 for success, non-zero for failure.
4955 */
4956static int
4957procmpt_create(void)
4958{
4959 struct proc_dir_entry *ent;
4960
4961 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
4962 if (mpt_proc_root_dir == NULL)
4963 return -ENOTDIR;
4964
4965 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
4966 if (ent)
4967 ent->read_proc = procmpt_summary_read;
4968
4969 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
4970 if (ent)
4971 ent->read_proc = procmpt_version_read;
4972
4973 return 0;
4974}
4975
4976/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4977/*
4978 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
4979 *
4980 * Returns 0 for success, non-zero for failure.
4981 */
4982static void
4983procmpt_destroy(void)
4984{
4985 remove_proc_entry("version", mpt_proc_root_dir);
4986 remove_proc_entry("summary", mpt_proc_root_dir);
4987 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
4988}
4989
4990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4991/*
4992 * procmpt_summary_read - Handle read request from /proc/mpt/summary
4993 * or from /proc/mpt/iocN/summary.
4994 * @buf: Pointer to area to write information
4995 * @start: Pointer to start pointer
4996 * @offset: Offset to start writing
4997 * @request:
4998 * @eof: Pointer to EOF integer
4999 * @data: Pointer
5000 *
5001 * Returns number of characters written to process performing the read.
5002 */
5003static int
5004procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5005{
5006 MPT_ADAPTER *ioc;
5007 char *out = buf;
5008 int len;
5009
5010 if (data) {
5011 int more = 0;
5012
5013 ioc = data;
5014 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5015
5016 out += more;
5017 } else {
5018 list_for_each_entry(ioc, &ioc_list, list) {
5019 int more = 0;
5020
5021 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5022
5023 out += more;
5024 if ((out-buf) >= request)
5025 break;
5026 }
5027 }
5028
5029 len = out - buf;
5030
5031 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5032}
5033
5034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5035/*
5036 * procmpt_version_read - Handle read request from /proc/mpt/version.
5037 * @buf: Pointer to area to write information
5038 * @start: Pointer to start pointer
5039 * @offset: Offset to start writing
5040 * @request:
5041 * @eof: Pointer to EOF integer
5042 * @data: Pointer
5043 *
5044 * Returns number of characters written to process performing the read.
5045 */
5046static int
5047procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5048{
5049 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005050 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 char *drvname;
5052 int len;
5053
5054 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5055 len += sprintf(buf+len, " Fusion MPT base driver\n");
5056
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005057 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5059 drvname = NULL;
5060 if (MptCallbacks[ii]) {
5061 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005062 case MPTSPI_DRIVER:
5063 if (!scsi++) drvname = "SPI host";
5064 break;
5065 case MPTFC_DRIVER:
5066 if (!fc++) drvname = "FC host";
5067 break;
5068 case MPTSAS_DRIVER:
5069 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 break;
5071 case MPTLAN_DRIVER:
5072 if (!lan++) drvname = "LAN";
5073 break;
5074 case MPTSTM_DRIVER:
5075 if (!targ++) drvname = "SCSI target";
5076 break;
5077 case MPTCTL_DRIVER:
5078 if (!ctl++) drvname = "ioctl";
5079 break;
5080 }
5081
5082 if (drvname)
5083 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5084 }
5085 }
5086
5087 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5088}
5089
5090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5091/*
5092 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5093 * @buf: Pointer to area to write information
5094 * @start: Pointer to start pointer
5095 * @offset: Offset to start writing
5096 * @request:
5097 * @eof: Pointer to EOF integer
5098 * @data: Pointer
5099 *
5100 * Returns number of characters written to process performing the read.
5101 */
5102static int
5103procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5104{
5105 MPT_ADAPTER *ioc = data;
5106 int len;
5107 char expVer[32];
5108 int sz;
5109 int p;
5110
5111 mpt_get_fw_exp_ver(expVer, ioc);
5112
5113 len = sprintf(buf, "%s:", ioc->name);
5114 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5115 len += sprintf(buf+len, " (f/w download boot flag set)");
5116// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5117// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5118
5119 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5120 ioc->facts.ProductID,
5121 ioc->prod_name);
5122 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5123 if (ioc->facts.FWImageSize)
5124 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5125 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5126 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5127 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5128
5129 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5130 ioc->facts.CurrentHostMfaHighAddr);
5131 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5132 ioc->facts.CurrentSenseBufferHighAddr);
5133
5134 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5135 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5136
5137 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5138 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5139 /*
5140 * Rounding UP to nearest 4-kB boundary here...
5141 */
5142 sz = (ioc->req_sz * ioc->req_depth) + 128;
5143 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5144 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5145 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5146 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5147 4*ioc->facts.RequestFrameSize,
5148 ioc->facts.GlobalCredits);
5149
5150 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5151 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5152 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5153 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5154 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5155 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5156 ioc->facts.CurReplyFrameSize,
5157 ioc->facts.ReplyQueueDepth);
5158
5159 len += sprintf(buf+len, " MaxDevices = %d\n",
5160 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5161 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5162
5163 /* per-port info */
5164 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5165 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5166 p+1,
5167 ioc->facts.NumberOfPorts);
5168 if (ioc->bus_type == FC) {
5169 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5170 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5171 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5172 a[5], a[4], a[3], a[2], a[1], a[0]);
5173 }
5174 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5175 ioc->fc_port_page0[p].WWNN.High,
5176 ioc->fc_port_page0[p].WWNN.Low,
5177 ioc->fc_port_page0[p].WWPN.High,
5178 ioc->fc_port_page0[p].WWPN.Low);
5179 }
5180 }
5181
5182 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5183}
5184
5185#endif /* CONFIG_PROC_FS } */
5186
5187/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5188static void
5189mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5190{
5191 buf[0] ='\0';
5192 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5193 sprintf(buf, " (Exp %02d%02d)",
5194 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5195 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5196
5197 /* insider hack! */
5198 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5199 strcat(buf, " [MDBG]");
5200 }
5201}
5202
5203/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5204/**
5205 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5206 * @ioc: Pointer to MPT_ADAPTER structure
5207 * @buffer: Pointer to buffer where IOC summary info should be written
5208 * @size: Pointer to number of bytes we wrote (set by this routine)
5209 * @len: Offset at which to start writing in buffer
5210 * @showlan: Display LAN stuff?
5211 *
5212 * This routine writes (english readable) ASCII text, which represents
5213 * a summary of IOC information, to a buffer.
5214 */
5215void
5216mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5217{
5218 char expVer[32];
5219 int y;
5220
5221 mpt_get_fw_exp_ver(expVer, ioc);
5222
5223 /*
5224 * Shorter summary of attached ioc's...
5225 */
5226 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5227 ioc->name,
5228 ioc->prod_name,
5229 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5230 ioc->facts.FWVersion.Word,
5231 expVer,
5232 ioc->facts.NumberOfPorts,
5233 ioc->req_depth);
5234
5235 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5236 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5237 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5238 a[5], a[4], a[3], a[2], a[1], a[0]);
5239 }
5240
5241#ifndef __sparc__
5242 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5243#else
5244 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5245#endif
5246
5247 if (!ioc->active)
5248 y += sprintf(buffer+len+y, " (disabled)");
5249
5250 y += sprintf(buffer+len+y, "\n");
5251
5252 *size = y;
5253}
5254
5255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5256/*
5257 * Reset Handling
5258 */
5259/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5260/**
5261 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5262 * Management call based on input arg values. If TaskMgmt fails,
5263 * return associated SCSI request.
5264 * @ioc: Pointer to MPT_ADAPTER structure
5265 * @sleepFlag: Indicates if sleep or schedule must be called.
5266 *
5267 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5268 * or a non-interrupt thread. In the former, must not call schedule().
5269 *
5270 * Remark: A return of -1 is a FATAL error case, as it means a
5271 * FW reload/initialization failed.
5272 *
5273 * Returns 0 for SUCCESS or -1 if FAILED.
5274 */
5275int
5276mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5277{
5278 int rc;
5279 unsigned long flags;
5280
5281 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5282#ifdef MFCNT
5283 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5284 printk("MF count 0x%x !\n", ioc->mfcnt);
5285#endif
5286
5287 /* Reset the adapter. Prevent more than 1 call to
5288 * mpt_do_ioc_recovery at any instant in time.
5289 */
5290 spin_lock_irqsave(&ioc->diagLock, flags);
5291 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5292 spin_unlock_irqrestore(&ioc->diagLock, flags);
5293 return 0;
5294 } else {
5295 ioc->diagPending = 1;
5296 }
5297 spin_unlock_irqrestore(&ioc->diagLock, flags);
5298
5299 /* FIXME: If do_ioc_recovery fails, repeat....
5300 */
5301
5302 /* The SCSI driver needs to adjust timeouts on all current
5303 * commands prior to the diagnostic reset being issued.
5304 * Prevents timeouts occuring during a diagnostic reset...very bad.
5305 * For all other protocol drivers, this is a no-op.
5306 */
5307 {
5308 int ii;
5309 int r = 0;
5310
5311 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5312 if (MptResetHandlers[ii]) {
5313 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5314 ioc->name, ii));
5315 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5316 if (ioc->alt_ioc) {
5317 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5318 ioc->name, ioc->alt_ioc->name, ii));
5319 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5320 }
5321 }
5322 }
5323 }
5324
5325 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5326 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5327 rc, ioc->name);
5328 }
5329 ioc->reload_fw = 0;
5330 if (ioc->alt_ioc)
5331 ioc->alt_ioc->reload_fw = 0;
5332
5333 spin_lock_irqsave(&ioc->diagLock, flags);
5334 ioc->diagPending = 0;
5335 if (ioc->alt_ioc)
5336 ioc->alt_ioc->diagPending = 0;
5337 spin_unlock_irqrestore(&ioc->diagLock, flags);
5338
5339 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5340
5341 return rc;
5342}
5343
5344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5345static char *
5346EventDescriptionStr(u8 event, u32 evData0)
5347{
5348 char *ds;
5349
5350 switch(event) {
5351 case MPI_EVENT_NONE:
5352 ds = "None";
5353 break;
5354 case MPI_EVENT_LOG_DATA:
5355 ds = "Log Data";
5356 break;
5357 case MPI_EVENT_STATE_CHANGE:
5358 ds = "State Change";
5359 break;
5360 case MPI_EVENT_UNIT_ATTENTION:
5361 ds = "Unit Attention";
5362 break;
5363 case MPI_EVENT_IOC_BUS_RESET:
5364 ds = "IOC Bus Reset";
5365 break;
5366 case MPI_EVENT_EXT_BUS_RESET:
5367 ds = "External Bus Reset";
5368 break;
5369 case MPI_EVENT_RESCAN:
5370 ds = "Bus Rescan Event";
5371 /* Ok, do we need to do anything here? As far as
5372 I can tell, this is when a new device gets added
5373 to the loop. */
5374 break;
5375 case MPI_EVENT_LINK_STATUS_CHANGE:
5376 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5377 ds = "Link Status(FAILURE) Change";
5378 else
5379 ds = "Link Status(ACTIVE) Change";
5380 break;
5381 case MPI_EVENT_LOOP_STATE_CHANGE:
5382 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5383 ds = "Loop State(LIP) Change";
5384 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5385 ds = "Loop State(LPE) Change"; /* ??? */
5386 else
5387 ds = "Loop State(LPB) Change"; /* ??? */
5388 break;
5389 case MPI_EVENT_LOGOUT:
5390 ds = "Logout";
5391 break;
5392 case MPI_EVENT_EVENT_CHANGE:
5393 if (evData0)
5394 ds = "Events(ON) Change";
5395 else
5396 ds = "Events(OFF) Change";
5397 break;
5398 case MPI_EVENT_INTEGRATED_RAID:
5399 ds = "Integrated Raid";
5400 break;
5401 /*
5402 * MPT base "custom" events may be added here...
5403 */
5404 default:
5405 ds = "Unknown";
5406 break;
5407 }
5408 return ds;
5409}
5410
5411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5412/*
5413 * ProcessEventNotification - Route a received EventNotificationReply to
5414 * all currently regeistered event handlers.
5415 * @ioc: Pointer to MPT_ADAPTER structure
5416 * @pEventReply: Pointer to EventNotification reply frame
5417 * @evHandlers: Pointer to integer, number of event handlers
5418 *
5419 * Returns sum of event handlers return values.
5420 */
5421static int
5422ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5423{
5424 u16 evDataLen;
5425 u32 evData0 = 0;
5426// u32 evCtx;
5427 int ii;
5428 int r = 0;
5429 int handlers = 0;
5430 char *evStr;
5431 u8 event;
5432
5433 /*
5434 * Do platform normalization of values
5435 */
5436 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5437// evCtx = le32_to_cpu(pEventReply->EventContext);
5438 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5439 if (evDataLen) {
5440 evData0 = le32_to_cpu(pEventReply->Data[0]);
5441 }
5442
5443 evStr = EventDescriptionStr(event, evData0);
5444 devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
5445 ioc->name,
5446 evStr,
5447 event));
5448
5449#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
5450 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5451 for (ii = 0; ii < evDataLen; ii++)
5452 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5453 printk("\n");
5454#endif
5455
5456 /*
5457 * Do general / base driver event processing
5458 */
5459 switch(event) {
5460 case MPI_EVENT_NONE: /* 00 */
5461 case MPI_EVENT_LOG_DATA: /* 01 */
5462 case MPI_EVENT_STATE_CHANGE: /* 02 */
5463 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
5464 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
5465 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
5466 case MPI_EVENT_RESCAN: /* 06 */
5467 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
5468 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
5469 case MPI_EVENT_LOGOUT: /* 09 */
5470 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
5471 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */
5472 default:
5473 break;
5474 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5475 if (evDataLen) {
5476 u8 evState = evData0 & 0xFF;
5477
5478 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5479
5480 /* Update EventState field in cached IocFacts */
5481 if (ioc->facts.Function) {
5482 ioc->facts.EventState = evState;
5483 }
5484 }
5485 break;
5486 }
5487
5488 /*
5489 * Should this event be logged? Events are written sequentially.
5490 * When buffer is full, start again at the top.
5491 */
5492 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
5493 int idx;
5494
5495 idx = ioc->eventContext % ioc->eventLogSize;
5496
5497 ioc->events[idx].event = event;
5498 ioc->events[idx].eventContext = ioc->eventContext;
5499
5500 for (ii = 0; ii < 2; ii++) {
5501 if (ii < evDataLen)
5502 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
5503 else
5504 ioc->events[idx].data[ii] = 0;
5505 }
5506
5507 ioc->eventContext++;
5508 }
5509
5510
5511 /*
5512 * Call each currently registered protocol event handler.
5513 */
5514 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5515 if (MptEvHandlers[ii]) {
5516 devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
5517 ioc->name, ii));
5518 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
5519 handlers++;
5520 }
5521 }
5522 /* FIXME? Examine results here? */
5523
5524 /*
5525 * If needed, send (a single) EventAck.
5526 */
5527 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
5528 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
5529 devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
5530 ioc->name, ii));
5531 }
5532 }
5533
5534 *evHandlers = handlers;
5535 return r;
5536}
5537
5538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5539/*
5540 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
5541 * @ioc: Pointer to MPT_ADAPTER structure
5542 * @log_info: U32 LogInfo reply word from the IOC
5543 *
5544 * Refer to lsi/fc_log.h.
5545 */
5546static void
5547mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
5548{
5549 static char *subcl_str[8] = {
5550 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
5551 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
5552 };
5553 u8 subcl = (log_info >> 24) & 0x7;
5554
5555 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
5556 ioc->name, log_info, subcl_str[subcl]);
5557}
5558
5559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5560/*
5561 * mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
5562 * @ioc: Pointer to MPT_ADAPTER structure
5563 * @mr: Pointer to MPT reply frame
5564 * @log_info: U32 LogInfo word from the IOC
5565 *
5566 * Refer to lsi/sp_log.h.
5567 */
5568static void
5569mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
5570{
5571 u32 info = log_info & 0x00FF0000;
5572 char *desc = "unknown";
5573
5574 switch (info) {
5575 case 0x00010000:
5576 desc = "bug! MID not found";
5577 if (ioc->reload_fw == 0)
5578 ioc->reload_fw++;
5579 break;
5580
5581 case 0x00020000:
5582 desc = "Parity Error";
5583 break;
5584
5585 case 0x00030000:
5586 desc = "ASYNC Outbound Overrun";
5587 break;
5588
5589 case 0x00040000:
5590 desc = "SYNC Offset Error";
5591 break;
5592
5593 case 0x00050000:
5594 desc = "BM Change";
5595 break;
5596
5597 case 0x00060000:
5598 desc = "Msg In Overflow";
5599 break;
5600
5601 case 0x00070000:
5602 desc = "DMA Error";
5603 break;
5604
5605 case 0x00080000:
5606 desc = "Outbound DMA Overrun";
5607 break;
5608
5609 case 0x00090000:
5610 desc = "Task Management";
5611 break;
5612
5613 case 0x000A0000:
5614 desc = "Device Problem";
5615 break;
5616
5617 case 0x000B0000:
5618 desc = "Invalid Phase Change";
5619 break;
5620
5621 case 0x000C0000:
5622 desc = "Untagged Table Size";
5623 break;
5624
5625 }
5626
5627 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
5628}
5629
5630/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5631/*
5632 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
5633 * @ioc: Pointer to MPT_ADAPTER structure
5634 * @ioc_status: U32 IOCStatus word from IOC
5635 * @mf: Pointer to MPT request frame
5636 *
5637 * Refer to lsi/mpi.h.
5638 */
5639static void
5640mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
5641{
5642 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
5643 char *desc = "";
5644
5645 switch (status) {
5646 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
5647 desc = "Invalid Function";
5648 break;
5649
5650 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
5651 desc = "Busy";
5652 break;
5653
5654 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
5655 desc = "Invalid SGL";
5656 break;
5657
5658 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
5659 desc = "Internal Error";
5660 break;
5661
5662 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
5663 desc = "Reserved";
5664 break;
5665
5666 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
5667 desc = "Insufficient Resources";
5668 break;
5669
5670 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
5671 desc = "Invalid Field";
5672 break;
5673
5674 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
5675 desc = "Invalid State";
5676 break;
5677
5678 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
5679 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
5680 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
5681 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
5682 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
5683 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
5684 /* No message for Config IOCStatus values */
5685 break;
5686
5687 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
5688 /* No message for recovered error
5689 desc = "SCSI Recovered Error";
5690 */
5691 break;
5692
5693 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
5694 desc = "SCSI Invalid Bus";
5695 break;
5696
5697 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
5698 desc = "SCSI Invalid TargetID";
5699 break;
5700
5701 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
5702 {
5703 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
5704 U8 cdb = pScsiReq->CDB[0];
5705 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
5706 desc = "SCSI Device Not There";
5707 }
5708 break;
5709 }
5710
5711 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
5712 desc = "SCSI Data Overrun";
5713 break;
5714
5715 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
5716 /* This error is checked in scsi_io_done(). Skip.
5717 desc = "SCSI Data Underrun";
5718 */
5719 break;
5720
5721 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
5722 desc = "SCSI I/O Data Error";
5723 break;
5724
5725 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
5726 desc = "SCSI Protocol Error";
5727 break;
5728
5729 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
5730 desc = "SCSI Task Terminated";
5731 break;
5732
5733 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
5734 desc = "SCSI Residual Mismatch";
5735 break;
5736
5737 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
5738 desc = "SCSI Task Management Failed";
5739 break;
5740
5741 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
5742 desc = "SCSI IOC Terminated";
5743 break;
5744
5745 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
5746 desc = "SCSI Ext Terminated";
5747 break;
5748
5749 default:
5750 desc = "Others";
5751 break;
5752 }
5753 if (desc != "")
5754 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
5755}
5756
5757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005758EXPORT_SYMBOL(mpt_attach);
5759EXPORT_SYMBOL(mpt_detach);
5760#ifdef CONFIG_PM
5761EXPORT_SYMBOL(mpt_resume);
5762EXPORT_SYMBOL(mpt_suspend);
5763#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764EXPORT_SYMBOL(ioc_list);
5765EXPORT_SYMBOL(mpt_proc_root_dir);
5766EXPORT_SYMBOL(mpt_register);
5767EXPORT_SYMBOL(mpt_deregister);
5768EXPORT_SYMBOL(mpt_event_register);
5769EXPORT_SYMBOL(mpt_event_deregister);
5770EXPORT_SYMBOL(mpt_reset_register);
5771EXPORT_SYMBOL(mpt_reset_deregister);
5772EXPORT_SYMBOL(mpt_device_driver_register);
5773EXPORT_SYMBOL(mpt_device_driver_deregister);
5774EXPORT_SYMBOL(mpt_get_msg_frame);
5775EXPORT_SYMBOL(mpt_put_msg_frame);
5776EXPORT_SYMBOL(mpt_free_msg_frame);
5777EXPORT_SYMBOL(mpt_add_sge);
5778EXPORT_SYMBOL(mpt_send_handshake_request);
5779EXPORT_SYMBOL(mpt_verify_adapter);
5780EXPORT_SYMBOL(mpt_GetIocState);
5781EXPORT_SYMBOL(mpt_print_ioc_summary);
5782EXPORT_SYMBOL(mpt_lan_index);
5783EXPORT_SYMBOL(mpt_stm_index);
5784EXPORT_SYMBOL(mpt_HardResetHandler);
5785EXPORT_SYMBOL(mpt_config);
5786EXPORT_SYMBOL(mpt_toolbox);
5787EXPORT_SYMBOL(mpt_findImVolumes);
5788EXPORT_SYMBOL(mpt_read_ioc_pg_3);
5789EXPORT_SYMBOL(mpt_alloc_fw_memory);
5790EXPORT_SYMBOL(mpt_free_fw_memory);
5791
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792
5793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5794/*
5795 * fusion_init - Fusion MPT base driver initialization routine.
5796 *
5797 * Returns 0 for success, non-zero for failure.
5798 */
5799static int __init
5800fusion_init(void)
5801{
5802 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
5804 show_mptmod_ver(my_NAME, my_VERSION);
5805 printk(KERN_INFO COPYRIGHT "\n");
5806
5807 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
5808 MptCallbacks[i] = NULL;
5809 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
5810 MptEvHandlers[i] = NULL;
5811 MptResetHandlers[i] = NULL;
5812 }
5813
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005814 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 * EventNotification handling.
5816 */
5817 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
5818
5819 /* Register for hard reset handling callbacks.
5820 */
5821 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
5822 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
5823 } else {
5824 /* FIXME! */
5825 }
5826
5827#ifdef CONFIG_PROC_FS
5828 (void) procmpt_create();
5829#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005830 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831}
5832
5833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5834/*
5835 * fusion_exit - Perform driver unload cleanup.
5836 *
5837 * This routine frees all resources associated with each MPT adapter
5838 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
5839 */
5840static void __exit
5841fusion_exit(void)
5842{
5843
5844 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
5845
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 mpt_reset_deregister(mpt_base_index);
5847
5848#ifdef CONFIG_PROC_FS
5849 procmpt_destroy();
5850#endif
5851}
5852
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853module_init(fusion_init);
5854module_exit(fusion_exit);