blob: 8b623278ccd24f90e9966d13b508d35136923329 [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
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001840 kfree(ioc->spi_data.nvram);
1841 kfree(ioc->spi_data.pIocPg3);
1842 ioc->spi_data.nvram = NULL;
1843 ioc->spi_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 if (ioc->spi_data.pIocPg4 != NULL) {
1846 sz = ioc->spi_data.IocPg4Sz;
1847 pci_free_consistent(ioc->pcidev, sz,
1848 ioc->spi_data.pIocPg4,
1849 ioc->spi_data.IocPg4_dma);
1850 ioc->spi_data.pIocPg4 = NULL;
1851 ioc->alloc_total -= sz;
1852 }
1853
1854 if (ioc->ReqToChain != NULL) {
1855 kfree(ioc->ReqToChain);
1856 kfree(ioc->RequestNB);
1857 ioc->ReqToChain = NULL;
1858 }
1859
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06001860 kfree(ioc->ChainToChain);
1861 ioc->ChainToChain = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
1864/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1865/*
1866 * mpt_adapter_dispose - Free all resources associated with a MPT
1867 * adapter.
1868 * @ioc: Pointer to MPT adapter structure
1869 *
1870 * This routine unregisters h/w resources and frees all alloc'd memory
1871 * associated with a MPT adapter structure.
1872 */
1873static void
1874mpt_adapter_dispose(MPT_ADAPTER *ioc)
1875{
1876 if (ioc != NULL) {
1877 int sz_first, sz_last;
1878
1879 sz_first = ioc->alloc_total;
1880
1881 mpt_adapter_disable(ioc);
1882
1883 if (ioc->pci_irq != -1) {
1884 free_irq(ioc->pci_irq, ioc);
1885 ioc->pci_irq = -1;
1886 }
1887
1888 if (ioc->memmap != NULL)
1889 iounmap(ioc->memmap);
1890
1891#if defined(CONFIG_MTRR) && 0
1892 if (ioc->mtrr_reg > 0) {
1893 mtrr_del(ioc->mtrr_reg, 0, 0);
1894 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
1895 }
1896#endif
1897
1898 /* Zap the adapter lookup ptr! */
1899 list_del(&ioc->list);
1900
1901 sz_last = ioc->alloc_total;
1902 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
1903 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
1904 kfree(ioc);
1905 }
1906}
1907
1908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1909/*
1910 * MptDisplayIocCapabilities - Disply IOC's capacilities.
1911 * @ioc: Pointer to MPT adapter structure
1912 */
1913static void
1914MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
1915{
1916 int i = 0;
1917
1918 printk(KERN_INFO "%s: ", ioc->name);
1919 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
1920 printk("%s: ", ioc->prod_name+3);
1921 printk("Capabilities={");
1922
1923 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
1924 printk("Initiator");
1925 i++;
1926 }
1927
1928 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
1929 printk("%sTarget", i ? "," : "");
1930 i++;
1931 }
1932
1933 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
1934 printk("%sLAN", i ? "," : "");
1935 i++;
1936 }
1937
1938#if 0
1939 /*
1940 * This would probably evoke more questions than it's worth
1941 */
1942 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
1943 printk("%sLogBusAddr", i ? "," : "");
1944 i++;
1945 }
1946#endif
1947
1948 printk("}\n");
1949}
1950
1951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1952/*
1953 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
1954 * @ioc: Pointer to MPT_ADAPTER structure
1955 * @force: Force hard KickStart of IOC
1956 * @sleepFlag: Specifies whether the process can sleep
1957 *
1958 * Returns:
1959 * 1 - DIAG reset and READY
1960 * 0 - READY initially OR soft reset and READY
1961 * -1 - Any failure on KickStart
1962 * -2 - Msg Unit Reset Failed
1963 * -3 - IO Unit Reset Failed
1964 * -4 - IOC owned by a PEER
1965 */
1966static int
1967MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
1968{
1969 u32 ioc_state;
1970 int statefault = 0;
1971 int cntdn;
1972 int hard_reset_done = 0;
1973 int r;
1974 int ii;
1975 int whoinit;
1976
1977 /* Get current [raw] IOC state */
1978 ioc_state = mpt_GetIocState(ioc, 0);
1979 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
1980
1981 /*
1982 * Check to see if IOC got left/stuck in doorbell handshake
1983 * grip of death. If so, hard reset the IOC.
1984 */
1985 if (ioc_state & MPI_DOORBELL_ACTIVE) {
1986 statefault = 1;
1987 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
1988 ioc->name);
1989 }
1990
1991 /* Is it already READY? */
1992 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
1993 return 0;
1994
1995 /*
1996 * Check to see if IOC is in FAULT state.
1997 */
1998 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
1999 statefault = 2;
2000 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2001 ioc->name);
2002 printk(KERN_WARNING " FAULT code = %04xh\n",
2003 ioc_state & MPI_DOORBELL_DATA_MASK);
2004 }
2005
2006 /*
2007 * Hmmm... Did it get left operational?
2008 */
2009 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
2010 dinitprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n",
2011 ioc->name));
2012
2013 /* Check WhoInit.
2014 * If PCI Peer, exit.
2015 * Else, if no fault conditions are present, issue a MessageUnitReset
2016 * Else, fall through to KickStart case
2017 */
2018 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
2019 dprintk((KERN_WARNING MYNAM
2020 ": whoinit 0x%x\n statefault %d force %d\n",
2021 whoinit, statefault, force));
2022 if (whoinit == MPI_WHOINIT_PCI_PEER)
2023 return -4;
2024 else {
2025 if ((statefault == 0 ) && (force == 0)) {
2026 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2027 return 0;
2028 }
2029 statefault = 3;
2030 }
2031 }
2032
2033 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2034 if (hard_reset_done < 0)
2035 return -1;
2036
2037 /*
2038 * Loop here waiting for IOC to come READY.
2039 */
2040 ii = 0;
2041 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
2042
2043 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2044 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2045 /*
2046 * BIOS or previous driver load left IOC in OP state.
2047 * Reset messaging FIFOs.
2048 */
2049 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2050 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2051 return -2;
2052 }
2053 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2054 /*
2055 * Something is wrong. Try to get IOC back
2056 * to a known state.
2057 */
2058 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2059 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2060 return -3;
2061 }
2062 }
2063
2064 ii++; cntdn--;
2065 if (!cntdn) {
2066 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2067 ioc->name, (int)((ii+5)/HZ));
2068 return -ETIME;
2069 }
2070
2071 if (sleepFlag == CAN_SLEEP) {
2072 msleep_interruptible(1);
2073 } else {
2074 mdelay (1); /* 1 msec delay */
2075 }
2076
2077 }
2078
2079 if (statefault < 3) {
2080 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2081 ioc->name,
2082 statefault==1 ? "stuck handshake" : "IOC FAULT");
2083 }
2084
2085 return hard_reset_done;
2086}
2087
2088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2089/*
2090 * mpt_GetIocState - Get the current state of a MPT adapter.
2091 * @ioc: Pointer to MPT_ADAPTER structure
2092 * @cooked: Request raw or cooked IOC state
2093 *
2094 * Returns all IOC Doorbell register bits if cooked==0, else just the
2095 * Doorbell bits in MPI_IOC_STATE_MASK.
2096 */
2097u32
2098mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2099{
2100 u32 s, sc;
2101
2102 /* Get! */
2103 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2104// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2105 sc = s & MPI_IOC_STATE_MASK;
2106
2107 /* Save! */
2108 ioc->last_state = sc;
2109
2110 return cooked ? sc : s;
2111}
2112
2113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2114/*
2115 * GetIocFacts - Send IOCFacts request to MPT adapter.
2116 * @ioc: Pointer to MPT_ADAPTER structure
2117 * @sleepFlag: Specifies whether the process can sleep
2118 * @reason: If recovery, only update facts.
2119 *
2120 * Returns 0 for success, non-zero for failure.
2121 */
2122static int
2123GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2124{
2125 IOCFacts_t get_facts;
2126 IOCFactsReply_t *facts;
2127 int r;
2128 int req_sz;
2129 int reply_sz;
2130 int sz;
2131 u32 status, vv;
2132 u8 shiftFactor=1;
2133
2134 /* IOC *must* NOT be in RESET state! */
2135 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2136 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2137 ioc->name,
2138 ioc->last_state );
2139 return -44;
2140 }
2141
2142 facts = &ioc->facts;
2143
2144 /* Destination (reply area)... */
2145 reply_sz = sizeof(*facts);
2146 memset(facts, 0, reply_sz);
2147
2148 /* Request area (get_facts on the stack right now!) */
2149 req_sz = sizeof(get_facts);
2150 memset(&get_facts, 0, req_sz);
2151
2152 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2153 /* Assert: All other get_facts fields are zero! */
2154
2155 dinitprintk((MYIOC_s_INFO_FMT
2156 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
2157 ioc->name, req_sz, reply_sz));
2158
2159 /* No non-zero fields in the get_facts request are greater than
2160 * 1 byte in size, so we can just fire it off as is.
2161 */
2162 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2163 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2164 if (r != 0)
2165 return r;
2166
2167 /*
2168 * Now byte swap (GRRR) the necessary fields before any further
2169 * inspection of reply contents.
2170 *
2171 * But need to do some sanity checks on MsgLength (byte) field
2172 * to make sure we don't zero IOC's req_sz!
2173 */
2174 /* Did we get a valid reply? */
2175 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2176 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2177 /*
2178 * If not been here, done that, save off first WhoInit value
2179 */
2180 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2181 ioc->FirstWhoInit = facts->WhoInit;
2182 }
2183
2184 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2185 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2186 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2187 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2188 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
2189 status = facts->IOCStatus & MPI_IOCSTATUS_MASK;
2190 /* CHECKME! IOCStatus, IOCLogInfo */
2191
2192 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2193 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2194
2195 /*
2196 * FC f/w version changed between 1.1 and 1.2
2197 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2198 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2199 */
2200 if (facts->MsgVersion < 0x0102) {
2201 /*
2202 * Handle old FC f/w style, convert to new...
2203 */
2204 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2205 facts->FWVersion.Word =
2206 ((oldv<<12) & 0xFF000000) |
2207 ((oldv<<8) & 0x000FFF00);
2208 } else
2209 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2210
2211 facts->ProductID = le16_to_cpu(facts->ProductID);
2212 facts->CurrentHostMfaHighAddr =
2213 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2214 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2215 facts->CurrentSenseBufferHighAddr =
2216 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2217 facts->CurReplyFrameSize =
2218 le16_to_cpu(facts->CurReplyFrameSize);
2219
2220 /*
2221 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2222 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2223 * to 14 in MPI-1.01.0x.
2224 */
2225 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2226 facts->MsgVersion > 0x0100) {
2227 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2228 }
2229
2230 sz = facts->FWImageSize;
2231 if ( sz & 0x01 )
2232 sz += 1;
2233 if ( sz & 0x02 )
2234 sz += 2;
2235 facts->FWImageSize = sz;
2236
2237 if (!facts->RequestFrameSize) {
2238 /* Something is wrong! */
2239 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2240 ioc->name);
2241 return -55;
2242 }
2243
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002244 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 vv = ((63 / (sz * 4)) + 1) & 0x03;
2246 ioc->NB_for_64_byte_frame = vv;
2247 while ( sz )
2248 {
2249 shiftFactor++;
2250 sz = sz >> 1;
2251 }
2252 ioc->NBShiftFactor = shiftFactor;
2253 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2254 ioc->name, vv, shiftFactor, r));
2255
2256 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2257 /*
2258 * Set values for this IOC's request & reply frame sizes,
2259 * and request & reply queue depths...
2260 */
2261 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2262 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2263 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2264 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2265
2266 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2267 ioc->name, ioc->reply_sz, ioc->reply_depth));
2268 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2269 ioc->name, ioc->req_sz, ioc->req_depth));
2270
2271 /* Get port facts! */
2272 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2273 return r;
2274 }
2275 } else {
2276 printk(MYIOC_s_ERR_FMT
2277 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2278 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2279 RequestFrameSize)/sizeof(u32)));
2280 return -66;
2281 }
2282
2283 return 0;
2284}
2285
2286/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2287/*
2288 * GetPortFacts - Send PortFacts request to MPT adapter.
2289 * @ioc: Pointer to MPT_ADAPTER structure
2290 * @portnum: Port number
2291 * @sleepFlag: Specifies whether the process can sleep
2292 *
2293 * Returns 0 for success, non-zero for failure.
2294 */
2295static int
2296GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2297{
2298 PortFacts_t get_pfacts;
2299 PortFactsReply_t *pfacts;
2300 int ii;
2301 int req_sz;
2302 int reply_sz;
2303
2304 /* IOC *must* NOT be in RESET state! */
2305 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2306 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2307 ioc->name,
2308 ioc->last_state );
2309 return -4;
2310 }
2311
2312 pfacts = &ioc->pfacts[portnum];
2313
2314 /* Destination (reply area)... */
2315 reply_sz = sizeof(*pfacts);
2316 memset(pfacts, 0, reply_sz);
2317
2318 /* Request area (get_pfacts on the stack right now!) */
2319 req_sz = sizeof(get_pfacts);
2320 memset(&get_pfacts, 0, req_sz);
2321
2322 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2323 get_pfacts.PortNumber = portnum;
2324 /* Assert: All other get_pfacts fields are zero! */
2325
2326 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2327 ioc->name, portnum));
2328
2329 /* No non-zero fields in the get_pfacts request are greater than
2330 * 1 byte in size, so we can just fire it off as is.
2331 */
2332 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2333 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2334 if (ii != 0)
2335 return ii;
2336
2337 /* Did we get a valid reply? */
2338
2339 /* Now byte swap the necessary fields in the response. */
2340 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2341 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2342 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2343 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2344 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2345 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2346 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2347 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2348 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2349
2350 return 0;
2351}
2352
2353/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2354/*
2355 * SendIocInit - Send IOCInit request to MPT adapter.
2356 * @ioc: Pointer to MPT_ADAPTER structure
2357 * @sleepFlag: Specifies whether the process can sleep
2358 *
2359 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2360 *
2361 * Returns 0 for success, non-zero for failure.
2362 */
2363static int
2364SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2365{
2366 IOCInit_t ioc_init;
2367 MPIDefaultReply_t init_reply;
2368 u32 state;
2369 int r;
2370 int count;
2371 int cntdn;
2372
2373 memset(&ioc_init, 0, sizeof(ioc_init));
2374 memset(&init_reply, 0, sizeof(init_reply));
2375
2376 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2377 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2378
2379 /* If we are in a recovery mode and we uploaded the FW image,
2380 * then this pointer is not NULL. Skip the upload a second time.
2381 * Set this flag if cached_fw set for either IOC.
2382 */
2383 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2384 ioc->upload_fw = 1;
2385 else
2386 ioc->upload_fw = 0;
2387 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2388 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2389
2390 if (ioc->bus_type == FC)
2391 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2392 else
2393 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
2394
2395 ioc_init.MaxBuses = MPT_MAX_BUS;
2396
2397 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2398
2399 if (sizeof(dma_addr_t) == sizeof(u64)) {
2400 /* Save the upper 32-bits of the request
2401 * (reply) and sense buffers.
2402 */
2403 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2404 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2405 } else {
2406 /* Force 32-bit addressing */
2407 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2408 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2409 }
2410
2411 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2412 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
2413
2414 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2415 ioc->name, &ioc_init));
2416
2417 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2418 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
2419 if (r != 0)
2420 return r;
2421
2422 /* No need to byte swap the multibyte fields in the reply
2423 * since we don't even look at it's contents.
2424 */
2425
2426 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2427 ioc->name, &ioc_init));
2428
2429 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0)
2430 return r;
2431
2432 /* YIKES! SUPER IMPORTANT!!!
2433 * Poll IocState until _OPERATIONAL while IOC is doing
2434 * LoopInit and TargetDiscovery!
2435 */
2436 count = 0;
2437 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2438 state = mpt_GetIocState(ioc, 1);
2439 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2440 if (sleepFlag == CAN_SLEEP) {
2441 msleep_interruptible(1);
2442 } else {
2443 mdelay(1);
2444 }
2445
2446 if (!cntdn) {
2447 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2448 ioc->name, (int)((count+5)/HZ));
2449 return -9;
2450 }
2451
2452 state = mpt_GetIocState(ioc, 1);
2453 count++;
2454 }
2455 dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
2456 ioc->name, count));
2457
2458 return r;
2459}
2460
2461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2462/*
2463 * SendPortEnable - Send PortEnable request to MPT adapter port.
2464 * @ioc: Pointer to MPT_ADAPTER structure
2465 * @portnum: Port number to enable
2466 * @sleepFlag: Specifies whether the process can sleep
2467 *
2468 * Send PortEnable to bring IOC to OPERATIONAL state.
2469 *
2470 * Returns 0 for success, non-zero for failure.
2471 */
2472static int
2473SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2474{
2475 PortEnable_t port_enable;
2476 MPIDefaultReply_t reply_buf;
2477 int ii;
2478 int req_sz;
2479 int reply_sz;
2480
2481 /* Destination... */
2482 reply_sz = sizeof(MPIDefaultReply_t);
2483 memset(&reply_buf, 0, reply_sz);
2484
2485 req_sz = sizeof(PortEnable_t);
2486 memset(&port_enable, 0, req_sz);
2487
2488 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2489 port_enable.PortNumber = portnum;
2490/* port_enable.ChainOffset = 0; */
2491/* port_enable.MsgFlags = 0; */
2492/* port_enable.MsgContext = 0; */
2493
2494 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2495 ioc->name, portnum, &port_enable));
2496
2497 /* RAID FW may take a long time to enable
2498 */
2499 if (ioc->bus_type == FC) {
2500 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
2501 reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag);
2502 } else {
2503 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
2504 reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
2505 }
2506
2507 if (ii != 0)
2508 return ii;
2509
2510 /* We do not even look at the reply, so we need not
2511 * swap the multi-byte fields.
2512 */
2513
2514 return 0;
2515}
2516
2517/*
2518 * ioc: Pointer to MPT_ADAPTER structure
2519 * size - total FW bytes
2520 */
2521void
2522mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2523{
2524 if (ioc->cached_fw)
2525 return; /* use already allocated memory */
2526 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2527 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2528 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2529 } else {
2530 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2531 ioc->alloc_total += size;
2532 }
2533}
2534/*
2535 * If alt_img is NULL, delete from ioc structure.
2536 * Else, delete a secondary image in same format.
2537 */
2538void
2539mpt_free_fw_memory(MPT_ADAPTER *ioc)
2540{
2541 int sz;
2542
2543 sz = ioc->facts.FWImageSize;
2544 dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
2545 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2546 pci_free_consistent(ioc->pcidev, sz,
2547 ioc->cached_fw, ioc->cached_fw_dma);
2548 ioc->cached_fw = NULL;
2549
2550 return;
2551}
2552
2553
2554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2555/*
2556 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2557 * @ioc: Pointer to MPT_ADAPTER structure
2558 * @sleepFlag: Specifies whether the process can sleep
2559 *
2560 * Returns 0 for success, >0 for handshake failure
2561 * <0 for fw upload failure.
2562 *
2563 * Remark: If bound IOC and a successful FWUpload was performed
2564 * on the bound IOC, the second image is discarded
2565 * and memory is free'd. Both channels must upload to prevent
2566 * IOC from running in degraded mode.
2567 */
2568static int
2569mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2570{
2571 u8 request[ioc->req_sz];
2572 u8 reply[sizeof(FWUploadReply_t)];
2573 FWUpload_t *prequest;
2574 FWUploadReply_t *preply;
2575 FWUploadTCSGE_t *ptcsge;
2576 int sgeoffset;
2577 u32 flagsLength;
2578 int ii, sz, reply_sz;
2579 int cmdStatus;
2580
2581 /* If the image size is 0, we are done.
2582 */
2583 if ((sz = ioc->facts.FWImageSize) == 0)
2584 return 0;
2585
2586 mpt_alloc_fw_memory(ioc, sz);
2587
2588 dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
2589 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2590
2591 if (ioc->cached_fw == NULL) {
2592 /* Major Failure.
2593 */
2594 return -ENOMEM;
2595 }
2596
2597 prequest = (FWUpload_t *)&request;
2598 preply = (FWUploadReply_t *)&reply;
2599
2600 /* Destination... */
2601 memset(prequest, 0, ioc->req_sz);
2602
2603 reply_sz = sizeof(reply);
2604 memset(preply, 0, reply_sz);
2605
2606 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2607 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2608
2609 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2610 ptcsge->DetailsLength = 12;
2611 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2612 ptcsge->ImageSize = cpu_to_le32(sz);
2613
2614 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2615
2616 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2617 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2618
2619 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
2620 dinitprintk((KERN_WARNING MYNAM "Sending FW Upload (req @ %p) sgeoffset=%d \n",
2621 prequest, sgeoffset));
2622 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2623
2624 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2625 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2626
2627 dinitprintk((KERN_WARNING MYNAM "FW Upload completed rc=%x \n", ii));
2628
2629 cmdStatus = -EFAULT;
2630 if (ii == 0) {
2631 /* Handshake transfer was complete and successful.
2632 * Check the Reply Frame.
2633 */
2634 int status, transfer_sz;
2635 status = le16_to_cpu(preply->IOCStatus);
2636 if (status == MPI_IOCSTATUS_SUCCESS) {
2637 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2638 if (transfer_sz == sz)
2639 cmdStatus = 0;
2640 }
2641 }
2642 dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n",
2643 ioc->name, cmdStatus));
2644
2645
2646 if (cmdStatus) {
2647
2648 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2649 ioc->name));
2650 mpt_free_fw_memory(ioc);
2651 }
2652
2653 return cmdStatus;
2654}
2655
2656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2657/*
2658 * mpt_downloadboot - DownloadBoot code
2659 * @ioc: Pointer to MPT_ADAPTER structure
2660 * @flag: Specify which part of IOC memory is to be uploaded.
2661 * @sleepFlag: Specifies whether the process can sleep
2662 *
2663 * FwDownloadBoot requires Programmed IO access.
2664 *
2665 * Returns 0 for success
2666 * -1 FW Image size is 0
2667 * -2 No valid cached_fw Pointer
2668 * <0 for fw upload failure.
2669 */
2670static int
2671mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag)
2672{
2673 MpiFwHeader_t *pFwHeader;
2674 MpiExtImageHeader_t *pExtImage;
2675 u32 fwSize;
2676 u32 diag0val;
2677 int count;
2678 u32 *ptrFw;
2679 u32 diagRwData;
2680 u32 nextImage;
2681 u32 load_addr;
2682 u32 ioc_state=0;
2683
2684 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n",
2685 ioc->name, ioc->facts.FWImageSize, ioc->cached_fw));
2686
2687 if ( ioc->facts.FWImageSize == 0 )
2688 return -1;
2689
2690 if (ioc->cached_fw == NULL)
2691 return -2;
2692
2693 /* prevent a second downloadboot and memory free with alt_ioc */
2694 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
2695 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002696
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2698 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2699 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2700 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2701 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2702 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2703
2704 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2705
2706 /* wait 1 msec */
2707 if (sleepFlag == CAN_SLEEP) {
2708 msleep_interruptible(1);
2709 } else {
2710 mdelay (1);
2711 }
2712
2713 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2714 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2715
2716 for (count = 0; count < 30; count ++) {
2717 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2718 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2719 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2720 ioc->name, count));
2721 break;
2722 }
2723 /* wait 1 sec */
2724 if (sleepFlag == CAN_SLEEP) {
2725 msleep_interruptible (1000);
2726 } else {
2727 mdelay (1000);
2728 }
2729 }
2730
2731 if ( count == 30 ) {
2732 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! Unable to RESET_ADAPTER diag0val=%x\n",
2733 ioc->name, diag0val));
2734 return -3;
2735 }
2736
2737 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2738 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2739 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2740 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2741 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2742 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2743
2744 /* Set the DiagRwEn and Disable ARM bits */
2745 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2746
2747 pFwHeader = (MpiFwHeader_t *) ioc->cached_fw;
2748 fwSize = (pFwHeader->ImageSize + 3)/4;
2749 ptrFw = (u32 *) pFwHeader;
2750
2751 /* Write the LoadStartAddress to the DiagRw Address Register
2752 * using Programmed IO
2753 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002754 if (ioc->errata_flag_1064)
2755 pci_enable_io_access(ioc->pcidev);
2756
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2758 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2759 ioc->name, pFwHeader->LoadStartAddress));
2760
2761 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2762 ioc->name, fwSize*4, ptrFw));
2763 while (fwSize--) {
2764 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2765 }
2766
2767 nextImage = pFwHeader->NextImageHeaderOffset;
2768 while (nextImage) {
2769 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2770
2771 load_addr = pExtImage->LoadStartAddress;
2772
2773 fwSize = (pExtImage->ImageSize + 3) >> 2;
2774 ptrFw = (u32 *)pExtImage;
2775
2776 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x bytes @ %p load_addr=%x\n",
2777 ioc->name, fwSize*4, ptrFw, load_addr));
2778 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2779
2780 while (fwSize--) {
2781 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2782 }
2783 nextImage = pExtImage->NextImageHeaderOffset;
2784 }
2785
2786 /* Write the IopResetVectorRegAddr */
2787 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2788 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
2789
2790 /* Write the IopResetVectorValue */
2791 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
2792 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
2793
2794 /* Clear the internal flash bad bit - autoincrementing register,
2795 * so must do two writes.
2796 */
2797 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
2798 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
2799 diagRwData |= 0x4000000;
2800 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
2801 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
2802
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002803 if (ioc->errata_flag_1064)
2804 pci_disable_io_access(ioc->pcidev);
2805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2807 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n",
2808 ioc->name, diag0val));
2809 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM);
2810 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
2811 ioc->name, diag0val));
2812 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
2813
2814 /* Write 0xFF to reset the sequencer */
2815 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2816
2817 for (count=0; count<HZ*20; count++) {
2818 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
2819 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
2820 ioc->name, count, ioc_state));
2821 if ((SendIocInit(ioc, sleepFlag)) != 0) {
2822 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
2823 ioc->name));
2824 return -EFAULT;
2825 }
2826 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
2827 ioc->name));
2828 return 0;
2829 }
2830 if (sleepFlag == CAN_SLEEP) {
2831 msleep_interruptible (10);
2832 } else {
2833 mdelay (10);
2834 }
2835 }
2836 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
2837 ioc->name, ioc_state));
2838 return -EFAULT;
2839}
2840
2841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2842/*
2843 * KickStart - Perform hard reset of MPT adapter.
2844 * @ioc: Pointer to MPT_ADAPTER structure
2845 * @force: Force hard reset
2846 * @sleepFlag: Specifies whether the process can sleep
2847 *
2848 * This routine places MPT adapter in diagnostic mode via the
2849 * WriteSequence register, and then performs a hard reset of adapter
2850 * via the Diagnostic register.
2851 *
2852 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
2853 * or NO_SLEEP (interrupt thread, use mdelay)
2854 * force - 1 if doorbell active, board fault state
2855 * board operational, IOC_RECOVERY or
2856 * IOC_BRINGUP and there is an alt_ioc.
2857 * 0 else
2858 *
2859 * Returns:
2860 * 1 - hard reset, READY
2861 * 0 - no reset due to History bit, READY
2862 * -1 - no reset due to History bit but not READY
2863 * OR reset but failed to come READY
2864 * -2 - no reset, could not enter DIAG mode
2865 * -3 - reset but bad FW bit
2866 */
2867static int
2868KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
2869{
2870 int hard_reset_done = 0;
2871 u32 ioc_state=0;
2872 int cnt,cntdn;
2873
2874 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
2875 if (ioc->bus_type == SCSI) {
2876 /* Always issue a Msg Unit Reset first. This will clear some
2877 * SCSI bus hang conditions.
2878 */
2879 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
2880
2881 if (sleepFlag == CAN_SLEEP) {
2882 msleep_interruptible (1000);
2883 } else {
2884 mdelay (1000);
2885 }
2886 }
2887
2888 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
2889 if (hard_reset_done < 0)
2890 return hard_reset_done;
2891
2892 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
2893 ioc->name));
2894
2895 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
2896 for (cnt=0; cnt<cntdn; cnt++) {
2897 ioc_state = mpt_GetIocState(ioc, 1);
2898 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
2899 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
2900 ioc->name, cnt));
2901 return hard_reset_done;
2902 }
2903 if (sleepFlag == CAN_SLEEP) {
2904 msleep_interruptible (10);
2905 } else {
2906 mdelay (10);
2907 }
2908 }
2909
2910 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
2911 ioc->name, ioc_state);
2912 return -1;
2913}
2914
2915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2916/*
2917 * mpt_diag_reset - Perform hard reset of the adapter.
2918 * @ioc: Pointer to MPT_ADAPTER structure
2919 * @ignore: Set if to honor and clear to ignore
2920 * the reset history bit
2921 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
2922 * else set to NO_SLEEP (use mdelay instead)
2923 *
2924 * This routine places the adapter in diagnostic mode via the
2925 * WriteSequence register and then performs a hard reset of adapter
2926 * via the Diagnostic register. Adapter should be in ready state
2927 * upon successful completion.
2928 *
2929 * Returns: 1 hard reset successful
2930 * 0 no reset performed because reset history bit set
2931 * -2 enabling diagnostic mode failed
2932 * -3 diagnostic reset failed
2933 */
2934static int
2935mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
2936{
2937 u32 diag0val;
2938 u32 doorbell;
2939 int hard_reset_done = 0;
2940 int count = 0;
2941#ifdef MPT_DEBUG
2942 u32 diag1val = 0;
2943#endif
2944
2945 /* Clear any existing interrupts */
2946 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2947
2948 /* Use "Diagnostic reset" method! (only thing available!) */
2949 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2950
2951#ifdef MPT_DEBUG
2952 if (ioc->alt_ioc)
2953 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
2954 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
2955 ioc->name, diag0val, diag1val));
2956#endif
2957
2958 /* Do the reset if we are told to ignore the reset history
2959 * or if the reset history is 0
2960 */
2961 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
2962 while ((diag0val & MPI_DIAG_DRWE) == 0) {
2963 /* Write magic sequence to WriteSequence register
2964 * Loop until in diagnostic mode
2965 */
2966 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2967 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2968 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2969 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2970 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2971 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2972
2973 /* wait 100 msec */
2974 if (sleepFlag == CAN_SLEEP) {
2975 msleep_interruptible (100);
2976 } else {
2977 mdelay (100);
2978 }
2979
2980 count++;
2981 if (count > 20) {
2982 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
2983 ioc->name, diag0val);
2984 return -2;
2985
2986 }
2987
2988 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2989
2990 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
2991 ioc->name, diag0val));
2992 }
2993
2994#ifdef MPT_DEBUG
2995 if (ioc->alt_ioc)
2996 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
2997 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
2998 ioc->name, diag0val, diag1val));
2999#endif
3000 /*
3001 * Disable the ARM (Bug fix)
3002 *
3003 */
3004 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
3005 mdelay (1);
3006
3007 /*
3008 * Now hit the reset bit in the Diagnostic register
3009 * (THE BIG HAMMER!) (Clears DRWE bit).
3010 */
3011 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3012 hard_reset_done = 1;
3013 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3014 ioc->name));
3015
3016 /*
3017 * Call each currently registered protocol IOC reset handler
3018 * with pre-reset indication.
3019 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3020 * MptResetHandlers[] registered yet.
3021 */
3022 {
3023 int ii;
3024 int r = 0;
3025
3026 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3027 if (MptResetHandlers[ii]) {
3028 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3029 ioc->name, ii));
3030 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3031 if (ioc->alt_ioc) {
3032 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3033 ioc->name, ioc->alt_ioc->name, ii));
3034 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3035 }
3036 }
3037 }
3038 /* FIXME? Examine results here? */
3039 }
3040
3041 if (ioc->cached_fw) {
3042 /* If the DownloadBoot operation fails, the
3043 * IOC will be left unusable. This is a fatal error
3044 * case. _diag_reset will return < 0
3045 */
3046 for (count = 0; count < 30; count ++) {
3047 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3048 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3049 break;
3050 }
3051
3052 /* wait 1 sec */
3053 if (sleepFlag == CAN_SLEEP) {
3054 ssleep(1);
3055 } else {
3056 mdelay (1000);
3057 }
3058 }
3059 if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
3060 printk(KERN_WARNING MYNAM
3061 ": firmware downloadboot failure (%d)!\n", count);
3062 }
3063
3064 } else {
3065 /* Wait for FW to reload and for board
3066 * to go to the READY state.
3067 * Maximum wait is 60 seconds.
3068 * If fail, no error will check again
3069 * with calling program.
3070 */
3071 for (count = 0; count < 60; count ++) {
3072 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3073 doorbell &= MPI_IOC_STATE_MASK;
3074
3075 if (doorbell == MPI_IOC_STATE_READY) {
3076 break;
3077 }
3078
3079 /* wait 1 sec */
3080 if (sleepFlag == CAN_SLEEP) {
3081 msleep_interruptible (1000);
3082 } else {
3083 mdelay (1000);
3084 }
3085 }
3086 }
3087 }
3088
3089 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3090#ifdef MPT_DEBUG
3091 if (ioc->alt_ioc)
3092 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3093 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3094 ioc->name, diag0val, diag1val));
3095#endif
3096
3097 /* Clear RESET_HISTORY bit! Place board in the
3098 * diagnostic mode to update the diag register.
3099 */
3100 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3101 count = 0;
3102 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3103 /* Write magic sequence to WriteSequence register
3104 * Loop until in diagnostic mode
3105 */
3106 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3107 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3108 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3109 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3110 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3111 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3112
3113 /* wait 100 msec */
3114 if (sleepFlag == CAN_SLEEP) {
3115 msleep_interruptible (100);
3116 } else {
3117 mdelay (100);
3118 }
3119
3120 count++;
3121 if (count > 20) {
3122 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3123 ioc->name, diag0val);
3124 break;
3125 }
3126 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3127 }
3128 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3129 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3130 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3131 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3132 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3133 ioc->name);
3134 }
3135
3136 /* Disable Diagnostic Mode
3137 */
3138 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3139
3140 /* Check FW reload status flags.
3141 */
3142 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3143 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3144 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3145 ioc->name, diag0val);
3146 return -3;
3147 }
3148
3149#ifdef MPT_DEBUG
3150 if (ioc->alt_ioc)
3151 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3152 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3153 ioc->name, diag0val, diag1val));
3154#endif
3155
3156 /*
3157 * Reset flag that says we've enabled event notification
3158 */
3159 ioc->facts.EventState = 0;
3160
3161 if (ioc->alt_ioc)
3162 ioc->alt_ioc->facts.EventState = 0;
3163
3164 return hard_reset_done;
3165}
3166
3167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3168/*
3169 * SendIocReset - Send IOCReset request to MPT adapter.
3170 * @ioc: Pointer to MPT_ADAPTER structure
3171 * @reset_type: reset type, expected values are
3172 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3173 *
3174 * Send IOCReset request to the MPT adapter.
3175 *
3176 * Returns 0 for success, non-zero for failure.
3177 */
3178static int
3179SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3180{
3181 int r;
3182 u32 state;
3183 int cntdn, count;
3184
3185 drsprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
3186 ioc->name, reset_type));
3187 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3188 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3189 return r;
3190
3191 /* FW ACK'd request, wait for READY state
3192 */
3193 count = 0;
3194 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3195
3196 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3197 cntdn--;
3198 count++;
3199 if (!cntdn) {
3200 if (sleepFlag != CAN_SLEEP)
3201 count *= 10;
3202
3203 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3204 ioc->name, (int)((count+5)/HZ));
3205 return -ETIME;
3206 }
3207
3208 if (sleepFlag == CAN_SLEEP) {
3209 msleep_interruptible(1);
3210 } else {
3211 mdelay (1); /* 1 msec delay */
3212 }
3213 }
3214
3215 /* TODO!
3216 * Cleanup all event stuff for this IOC; re-issue EventNotification
3217 * request if needed.
3218 */
3219 if (ioc->facts.Function)
3220 ioc->facts.EventState = 0;
3221
3222 return 0;
3223}
3224
3225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3226/*
3227 * initChainBuffers - Allocate memory for and initialize
3228 * chain buffers, chain buffer control arrays and spinlock.
3229 * @hd: Pointer to MPT_SCSI_HOST structure
3230 * @init: If set, initialize the spin lock.
3231 */
3232static int
3233initChainBuffers(MPT_ADAPTER *ioc)
3234{
3235 u8 *mem;
3236 int sz, ii, num_chain;
3237 int scale, num_sge, numSGE;
3238
3239 /* ReqToChain size must equal the req_depth
3240 * index = req_idx
3241 */
3242 if (ioc->ReqToChain == NULL) {
3243 sz = ioc->req_depth * sizeof(int);
3244 mem = kmalloc(sz, GFP_ATOMIC);
3245 if (mem == NULL)
3246 return -1;
3247
3248 ioc->ReqToChain = (int *) mem;
3249 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3250 ioc->name, mem, sz));
3251 mem = kmalloc(sz, GFP_ATOMIC);
3252 if (mem == NULL)
3253 return -1;
3254
3255 ioc->RequestNB = (int *) mem;
3256 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3257 ioc->name, mem, sz));
3258 }
3259 for (ii = 0; ii < ioc->req_depth; ii++) {
3260 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3261 }
3262
3263 /* ChainToChain size must equal the total number
3264 * of chain buffers to be allocated.
3265 * index = chain_idx
3266 *
3267 * Calculate the number of chain buffers needed(plus 1) per I/O
3268 * then multiply the the maximum number of simultaneous cmds
3269 *
3270 * num_sge = num sge in request frame + last chain buffer
3271 * scale = num sge per chain buffer if no chain element
3272 */
3273 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3274 if (sizeof(dma_addr_t) == sizeof(u64))
3275 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3276 else
3277 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3278
3279 if (sizeof(dma_addr_t) == sizeof(u64)) {
3280 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3281 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3282 } else {
3283 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3284 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3285 }
3286 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3287 ioc->name, num_sge, numSGE));
3288
3289 if ( numSGE > MPT_SCSI_SG_DEPTH )
3290 numSGE = MPT_SCSI_SG_DEPTH;
3291
3292 num_chain = 1;
3293 while (numSGE - num_sge > 0) {
3294 num_chain++;
3295 num_sge += (scale - 1);
3296 }
3297 num_chain++;
3298
3299 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3300 ioc->name, numSGE, num_sge, num_chain));
3301
3302 if (ioc->bus_type == SCSI)
3303 num_chain *= MPT_SCSI_CAN_QUEUE;
3304 else
3305 num_chain *= MPT_FC_CAN_QUEUE;
3306
3307 ioc->num_chain = num_chain;
3308
3309 sz = num_chain * sizeof(int);
3310 if (ioc->ChainToChain == NULL) {
3311 mem = kmalloc(sz, GFP_ATOMIC);
3312 if (mem == NULL)
3313 return -1;
3314
3315 ioc->ChainToChain = (int *) mem;
3316 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3317 ioc->name, mem, sz));
3318 } else {
3319 mem = (u8 *) ioc->ChainToChain;
3320 }
3321 memset(mem, 0xFF, sz);
3322 return num_chain;
3323}
3324
3325/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3326/*
3327 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3328 * @ioc: Pointer to MPT_ADAPTER structure
3329 *
3330 * This routine allocates memory for the MPT reply and request frame
3331 * pools (if necessary), and primes the IOC reply FIFO with
3332 * reply frames.
3333 *
3334 * Returns 0 for success, non-zero for failure.
3335 */
3336static int
3337PrimeIocFifos(MPT_ADAPTER *ioc)
3338{
3339 MPT_FRAME_HDR *mf;
3340 unsigned long flags;
3341 dma_addr_t alloc_dma;
3342 u8 *mem;
3343 int i, reply_sz, sz, total_size, num_chain;
3344
3345 /* Prime reply FIFO... */
3346
3347 if (ioc->reply_frames == NULL) {
3348 if ( (num_chain = initChainBuffers(ioc)) < 0)
3349 return -1;
3350
3351 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3352 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3353 ioc->name, ioc->reply_sz, ioc->reply_depth));
3354 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3355 ioc->name, reply_sz, reply_sz));
3356
3357 sz = (ioc->req_sz * ioc->req_depth);
3358 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3359 ioc->name, ioc->req_sz, ioc->req_depth));
3360 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3361 ioc->name, sz, sz));
3362 total_size += sz;
3363
3364 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3365 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3366 ioc->name, ioc->req_sz, num_chain));
3367 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3368 ioc->name, sz, sz, num_chain));
3369
3370 total_size += sz;
3371 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3372 if (mem == NULL) {
3373 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3374 ioc->name);
3375 goto out_fail;
3376 }
3377
3378 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3379 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3380
3381 memset(mem, 0, total_size);
3382 ioc->alloc_total += total_size;
3383 ioc->alloc = mem;
3384 ioc->alloc_dma = alloc_dma;
3385 ioc->alloc_sz = total_size;
3386 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3387 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3388
3389 alloc_dma += reply_sz;
3390 mem += reply_sz;
3391
3392 /* Request FIFO - WE manage this! */
3393
3394 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3395 ioc->req_frames_dma = alloc_dma;
3396
3397 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n",
3398 ioc->name, mem, (void *)(ulong)alloc_dma));
3399
3400 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3401
3402#if defined(CONFIG_MTRR) && 0
3403 /*
3404 * Enable Write Combining MTRR for IOC's memory region.
3405 * (at least as much as we can; "size and base must be
3406 * multiples of 4 kiB"
3407 */
3408 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3409 sz,
3410 MTRR_TYPE_WRCOMB, 1);
3411 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3412 ioc->name, ioc->req_frames_dma, sz));
3413#endif
3414
3415 for (i = 0; i < ioc->req_depth; i++) {
3416 alloc_dma += ioc->req_sz;
3417 mem += ioc->req_sz;
3418 }
3419
3420 ioc->ChainBuffer = mem;
3421 ioc->ChainBufferDMA = alloc_dma;
3422
3423 dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n",
3424 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3425
3426 /* Initialize the free chain Q.
3427 */
3428
3429 INIT_LIST_HEAD(&ioc->FreeChainQ);
3430
3431 /* Post the chain buffers to the FreeChainQ.
3432 */
3433 mem = (u8 *)ioc->ChainBuffer;
3434 for (i=0; i < num_chain; i++) {
3435 mf = (MPT_FRAME_HDR *) mem;
3436 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3437 mem += ioc->req_sz;
3438 }
3439
3440 /* Initialize Request frames linked list
3441 */
3442 alloc_dma = ioc->req_frames_dma;
3443 mem = (u8 *) ioc->req_frames;
3444
3445 spin_lock_irqsave(&ioc->FreeQlock, flags);
3446 INIT_LIST_HEAD(&ioc->FreeQ);
3447 for (i = 0; i < ioc->req_depth; i++) {
3448 mf = (MPT_FRAME_HDR *) mem;
3449
3450 /* Queue REQUESTs *internally*! */
3451 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3452
3453 mem += ioc->req_sz;
3454 }
3455 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3456
3457 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3458 ioc->sense_buf_pool =
3459 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3460 if (ioc->sense_buf_pool == NULL) {
3461 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3462 ioc->name);
3463 goto out_fail;
3464 }
3465
3466 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3467 ioc->alloc_total += sz;
3468 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3469 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3470
3471 }
3472
3473 /* Post Reply frames to FIFO
3474 */
3475 alloc_dma = ioc->alloc_dma;
3476 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3477 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3478
3479 for (i = 0; i < ioc->reply_depth; i++) {
3480 /* Write each address to the IOC! */
3481 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3482 alloc_dma += ioc->reply_sz;
3483 }
3484
3485 return 0;
3486
3487out_fail:
3488 if (ioc->alloc != NULL) {
3489 sz = ioc->alloc_sz;
3490 pci_free_consistent(ioc->pcidev,
3491 sz,
3492 ioc->alloc, ioc->alloc_dma);
3493 ioc->reply_frames = NULL;
3494 ioc->req_frames = NULL;
3495 ioc->alloc_total -= sz;
3496 }
3497 if (ioc->sense_buf_pool != NULL) {
3498 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3499 pci_free_consistent(ioc->pcidev,
3500 sz,
3501 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3502 ioc->sense_buf_pool = NULL;
3503 }
3504 return -1;
3505}
3506
3507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3508/**
3509 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3510 * from IOC via doorbell handshake method.
3511 * @ioc: Pointer to MPT_ADAPTER structure
3512 * @reqBytes: Size of the request in bytes
3513 * @req: Pointer to MPT request frame
3514 * @replyBytes: Expected size of the reply in bytes
3515 * @u16reply: Pointer to area where reply should be written
3516 * @maxwait: Max wait time for a reply (in seconds)
3517 * @sleepFlag: Specifies whether the process can sleep
3518 *
3519 * NOTES: It is the callers responsibility to byte-swap fields in the
3520 * request which are greater than 1 byte in size. It is also the
3521 * callers responsibility to byte-swap response fields which are
3522 * greater than 1 byte in size.
3523 *
3524 * Returns 0 for success, non-zero for failure.
3525 */
3526static int
3527mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
3528 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
3529{
3530 MPIDefaultReply_t *mptReply;
3531 int failcnt = 0;
3532 int t;
3533
3534 /*
3535 * Get ready to cache a handshake reply
3536 */
3537 ioc->hs_reply_idx = 0;
3538 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3539 mptReply->MsgLength = 0;
3540
3541 /*
3542 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3543 * then tell IOC that we want to handshake a request of N words.
3544 * (WRITE u32val to Doorbell reg).
3545 */
3546 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3547 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3548 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3549 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3550
3551 /*
3552 * Wait for IOC's doorbell handshake int
3553 */
3554 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3555 failcnt++;
3556
3557 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3558 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3559
3560 /* Read doorbell and check for active bit */
3561 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3562 return -1;
3563
3564 /*
3565 * Clear doorbell int (WRITE 0 to IntStatus reg),
3566 * then wait for IOC to ACKnowledge that it's ready for
3567 * our handshake request.
3568 */
3569 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3570 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3571 failcnt++;
3572
3573 if (!failcnt) {
3574 int ii;
3575 u8 *req_as_bytes = (u8 *) req;
3576
3577 /*
3578 * Stuff request words via doorbell handshake,
3579 * with ACK from IOC for each.
3580 */
3581 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3582 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3583 (req_as_bytes[(ii*4) + 1] << 8) |
3584 (req_as_bytes[(ii*4) + 2] << 16) |
3585 (req_as_bytes[(ii*4) + 3] << 24));
3586
3587 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3588 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3589 failcnt++;
3590 }
3591
3592 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3593 DBG_DUMP_REQUEST_FRAME_HDR(req)
3594
3595 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3596 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3597
3598 /*
3599 * Wait for completion of doorbell handshake reply from the IOC
3600 */
3601 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3602 failcnt++;
3603
3604 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3605 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3606
3607 /*
3608 * Copy out the cached reply...
3609 */
3610 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3611 u16reply[ii] = ioc->hs_reply[ii];
3612 } else {
3613 return -99;
3614 }
3615
3616 return -failcnt;
3617}
3618
3619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3620/*
3621 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3622 * in it's IntStatus register.
3623 * @ioc: Pointer to MPT_ADAPTER structure
3624 * @howlong: How long to wait (in seconds)
3625 * @sleepFlag: Specifies whether the process can sleep
3626 *
3627 * This routine waits (up to ~2 seconds max) for IOC doorbell
3628 * handshake ACKnowledge.
3629 *
3630 * Returns a negative value on failure, else wait loop count.
3631 */
3632static int
3633WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3634{
3635 int cntdn;
3636 int count = 0;
3637 u32 intstat=0;
3638
3639 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
3640
3641 if (sleepFlag == CAN_SLEEP) {
3642 while (--cntdn) {
3643 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3644 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3645 break;
3646 msleep_interruptible (1);
3647 count++;
3648 }
3649 } else {
3650 while (--cntdn) {
3651 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3652 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3653 break;
3654 mdelay (1);
3655 count++;
3656 }
3657 }
3658
3659 if (cntdn) {
3660 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3661 ioc->name, count));
3662 return count;
3663 }
3664
3665 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3666 ioc->name, count, intstat);
3667 return -1;
3668}
3669
3670/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3671/*
3672 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3673 * in it's IntStatus register.
3674 * @ioc: Pointer to MPT_ADAPTER structure
3675 * @howlong: How long to wait (in seconds)
3676 * @sleepFlag: Specifies whether the process can sleep
3677 *
3678 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3679 *
3680 * Returns a negative value on failure, else wait loop count.
3681 */
3682static int
3683WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3684{
3685 int cntdn;
3686 int count = 0;
3687 u32 intstat=0;
3688
3689 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
3690 if (sleepFlag == CAN_SLEEP) {
3691 while (--cntdn) {
3692 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3693 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3694 break;
3695 msleep_interruptible(1);
3696 count++;
3697 }
3698 } else {
3699 while (--cntdn) {
3700 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3701 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3702 break;
3703 mdelay(1);
3704 count++;
3705 }
3706 }
3707
3708 if (cntdn) {
3709 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3710 ioc->name, count, howlong));
3711 return count;
3712 }
3713
3714 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3715 ioc->name, count, intstat);
3716 return -1;
3717}
3718
3719/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3720/*
3721 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3722 * @ioc: Pointer to MPT_ADAPTER structure
3723 * @howlong: How long to wait (in seconds)
3724 * @sleepFlag: Specifies whether the process can sleep
3725 *
3726 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3727 * Reply is cached to IOC private area large enough to hold a maximum
3728 * of 128 bytes of reply data.
3729 *
3730 * Returns a negative value on failure, else size of reply in WORDS.
3731 */
3732static int
3733WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3734{
3735 int u16cnt = 0;
3736 int failcnt = 0;
3737 int t;
3738 u16 *hs_reply = ioc->hs_reply;
3739 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3740 u16 hword;
3741
3742 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
3743
3744 /*
3745 * Get first two u16's so we can look at IOC's intended reply MsgLength
3746 */
3747 u16cnt=0;
3748 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
3749 failcnt++;
3750 } else {
3751 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3752 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3753 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3754 failcnt++;
3755 else {
3756 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3757 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3758 }
3759 }
3760
3761 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
3762 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
3763 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3764
3765 /*
3766 * If no error (and IOC said MsgLength is > 0), piece together
3767 * reply 16 bits at a time.
3768 */
3769 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
3770 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3771 failcnt++;
3772 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3773 /* don't overflow our IOC hs_reply[] buffer! */
3774 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
3775 hs_reply[u16cnt] = hword;
3776 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3777 }
3778
3779 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3780 failcnt++;
3781 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3782
3783 if (failcnt) {
3784 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
3785 ioc->name);
3786 return -failcnt;
3787 }
3788#if 0
3789 else if (u16cnt != (2 * mptReply->MsgLength)) {
3790 return -101;
3791 }
3792 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
3793 return -102;
3794 }
3795#endif
3796
3797 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
3798 DBG_DUMP_REPLY_FRAME(mptReply)
3799
3800 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
3801 ioc->name, t, u16cnt/2));
3802 return u16cnt/2;
3803}
3804
3805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3806/*
3807 * GetLanConfigPages - Fetch LANConfig pages.
3808 * @ioc: Pointer to MPT_ADAPTER structure
3809 *
3810 * Return: 0 for success
3811 * -ENOMEM if no memory available
3812 * -EPERM if not allowed due to ISR context
3813 * -EAGAIN if no msg frames currently available
3814 * -EFAULT for non-successful reply or no reply (timeout)
3815 */
3816static int
3817GetLanConfigPages(MPT_ADAPTER *ioc)
3818{
3819 ConfigPageHeader_t hdr;
3820 CONFIGPARMS cfg;
3821 LANPage0_t *ppage0_alloc;
3822 dma_addr_t page0_dma;
3823 LANPage1_t *ppage1_alloc;
3824 dma_addr_t page1_dma;
3825 int rc = 0;
3826 int data_sz;
3827 int copy_sz;
3828
3829 /* Get LAN Page 0 header */
3830 hdr.PageVersion = 0;
3831 hdr.PageLength = 0;
3832 hdr.PageNumber = 0;
3833 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
3834 cfg.hdr = &hdr;
3835 cfg.physAddr = -1;
3836 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3837 cfg.dir = 0;
3838 cfg.pageAddr = 0;
3839 cfg.timeout = 0;
3840
3841 if ((rc = mpt_config(ioc, &cfg)) != 0)
3842 return rc;
3843
3844 if (hdr.PageLength > 0) {
3845 data_sz = hdr.PageLength * 4;
3846 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
3847 rc = -ENOMEM;
3848 if (ppage0_alloc) {
3849 memset((u8 *)ppage0_alloc, 0, data_sz);
3850 cfg.physAddr = page0_dma;
3851 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3852
3853 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3854 /* save the data */
3855 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
3856 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
3857
3858 }
3859
3860 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
3861
3862 /* FIXME!
3863 * Normalize endianness of structure data,
3864 * by byte-swapping all > 1 byte fields!
3865 */
3866
3867 }
3868
3869 if (rc)
3870 return rc;
3871 }
3872
3873 /* Get LAN Page 1 header */
3874 hdr.PageVersion = 0;
3875 hdr.PageLength = 0;
3876 hdr.PageNumber = 1;
3877 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
3878 cfg.hdr = &hdr;
3879 cfg.physAddr = -1;
3880 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3881 cfg.dir = 0;
3882 cfg.pageAddr = 0;
3883
3884 if ((rc = mpt_config(ioc, &cfg)) != 0)
3885 return rc;
3886
3887 if (hdr.PageLength == 0)
3888 return 0;
3889
3890 data_sz = hdr.PageLength * 4;
3891 rc = -ENOMEM;
3892 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
3893 if (ppage1_alloc) {
3894 memset((u8 *)ppage1_alloc, 0, data_sz);
3895 cfg.physAddr = page1_dma;
3896 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3897
3898 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3899 /* save the data */
3900 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
3901 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
3902 }
3903
3904 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
3905
3906 /* FIXME!
3907 * Normalize endianness of structure data,
3908 * by byte-swapping all > 1 byte fields!
3909 */
3910
3911 }
3912
3913 return rc;
3914}
3915
3916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3917/*
3918 * GetFcPortPage0 - Fetch FCPort config Page0.
3919 * @ioc: Pointer to MPT_ADAPTER structure
3920 * @portnum: IOC Port number
3921 *
3922 * Return: 0 for success
3923 * -ENOMEM if no memory available
3924 * -EPERM if not allowed due to ISR context
3925 * -EAGAIN if no msg frames currently available
3926 * -EFAULT for non-successful reply or no reply (timeout)
3927 */
3928static int
3929GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
3930{
3931 ConfigPageHeader_t hdr;
3932 CONFIGPARMS cfg;
3933 FCPortPage0_t *ppage0_alloc;
3934 FCPortPage0_t *pp0dest;
3935 dma_addr_t page0_dma;
3936 int data_sz;
3937 int copy_sz;
3938 int rc;
3939
3940 /* Get FCPort Page 0 header */
3941 hdr.PageVersion = 0;
3942 hdr.PageLength = 0;
3943 hdr.PageNumber = 0;
3944 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
3945 cfg.hdr = &hdr;
3946 cfg.physAddr = -1;
3947 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3948 cfg.dir = 0;
3949 cfg.pageAddr = portnum;
3950 cfg.timeout = 0;
3951
3952 if ((rc = mpt_config(ioc, &cfg)) != 0)
3953 return rc;
3954
3955 if (hdr.PageLength == 0)
3956 return 0;
3957
3958 data_sz = hdr.PageLength * 4;
3959 rc = -ENOMEM;
3960 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
3961 if (ppage0_alloc) {
3962 memset((u8 *)ppage0_alloc, 0, data_sz);
3963 cfg.physAddr = page0_dma;
3964 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3965
3966 if ((rc = mpt_config(ioc, &cfg)) == 0) {
3967 /* save the data */
3968 pp0dest = &ioc->fc_port_page0[portnum];
3969 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
3970 memcpy(pp0dest, ppage0_alloc, copy_sz);
3971
3972 /*
3973 * Normalize endianness of structure data,
3974 * by byte-swapping all > 1 byte fields!
3975 */
3976 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
3977 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
3978 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
3979 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
3980 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
3981 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
3982 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
3983 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
3984 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
3985 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
3986 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
3987 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
3988 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
3989 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
3990 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
3991 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
3992
3993 }
3994
3995 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
3996 }
3997
3998 return rc;
3999}
4000
4001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4002/*
4003 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4004 * @ioc: Pointer to MPT_ADAPTER structure
4005 *
4006 * Returns: 0 for success
4007 * -ENOMEM if no memory available
4008 * -EPERM if not allowed due to ISR context
4009 * -EAGAIN if no msg frames currently available
4010 * -EFAULT for non-successful reply or no reply (timeout)
4011 */
4012static int
4013GetIoUnitPage2(MPT_ADAPTER *ioc)
4014{
4015 ConfigPageHeader_t hdr;
4016 CONFIGPARMS cfg;
4017 IOUnitPage2_t *ppage_alloc;
4018 dma_addr_t page_dma;
4019 int data_sz;
4020 int rc;
4021
4022 /* Get the page header */
4023 hdr.PageVersion = 0;
4024 hdr.PageLength = 0;
4025 hdr.PageNumber = 2;
4026 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
4027 cfg.hdr = &hdr;
4028 cfg.physAddr = -1;
4029 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4030 cfg.dir = 0;
4031 cfg.pageAddr = 0;
4032 cfg.timeout = 0;
4033
4034 if ((rc = mpt_config(ioc, &cfg)) != 0)
4035 return rc;
4036
4037 if (hdr.PageLength == 0)
4038 return 0;
4039
4040 /* Read the config page */
4041 data_sz = hdr.PageLength * 4;
4042 rc = -ENOMEM;
4043 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4044 if (ppage_alloc) {
4045 memset((u8 *)ppage_alloc, 0, data_sz);
4046 cfg.physAddr = page_dma;
4047 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4048
4049 /* If Good, save data */
4050 if ((rc = mpt_config(ioc, &cfg)) == 0)
4051 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4052
4053 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4054 }
4055
4056 return rc;
4057}
4058
4059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4060/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4061 * @ioc: Pointer to a Adapter Strucutre
4062 * @portnum: IOC port number
4063 *
4064 * Return: -EFAULT if read of config page header fails
4065 * or if no nvram
4066 * If read of SCSI Port Page 0 fails,
4067 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4068 * Adapter settings: async, narrow
4069 * Return 1
4070 * If read of SCSI Port Page 2 fails,
4071 * Adapter settings valid
4072 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4073 * Return 1
4074 * Else
4075 * Both valid
4076 * Return 0
4077 * CHECK - what type of locking mechanisms should be used????
4078 */
4079static int
4080mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4081{
4082 u8 *pbuf;
4083 dma_addr_t buf_dma;
4084 CONFIGPARMS cfg;
4085 ConfigPageHeader_t header;
4086 int ii;
4087 int data, rc = 0;
4088
4089 /* Allocate memory
4090 */
4091 if (!ioc->spi_data.nvram) {
4092 int sz;
4093 u8 *mem;
4094 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4095 mem = kmalloc(sz, GFP_ATOMIC);
4096 if (mem == NULL)
4097 return -EFAULT;
4098
4099 ioc->spi_data.nvram = (int *) mem;
4100
4101 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4102 ioc->name, ioc->spi_data.nvram, sz));
4103 }
4104
4105 /* Invalidate NVRAM information
4106 */
4107 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4108 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4109 }
4110
4111 /* Read SPP0 header, allocate memory, then read page.
4112 */
4113 header.PageVersion = 0;
4114 header.PageLength = 0;
4115 header.PageNumber = 0;
4116 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
4117 cfg.hdr = &header;
4118 cfg.physAddr = -1;
4119 cfg.pageAddr = portnum;
4120 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4121 cfg.dir = 0;
4122 cfg.timeout = 0; /* use default */
4123 if (mpt_config(ioc, &cfg) != 0)
4124 return -EFAULT;
4125
4126 if (header.PageLength > 0) {
4127 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4128 if (pbuf) {
4129 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4130 cfg.physAddr = buf_dma;
4131 if (mpt_config(ioc, &cfg) != 0) {
4132 ioc->spi_data.maxBusWidth = MPT_NARROW;
4133 ioc->spi_data.maxSyncOffset = 0;
4134 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4135 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4136 rc = 1;
4137 } else {
4138 /* Save the Port Page 0 data
4139 */
4140 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4141 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4142 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4143
4144 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4145 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
4146 dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
4147 ioc->name, pPP0->Capabilities));
4148 }
4149 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4150 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4151 if (data) {
4152 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4153 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4154 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
4155 } else {
4156 ioc->spi_data.maxSyncOffset = 0;
4157 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4158 }
4159
4160 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4161
4162 /* Update the minSyncFactor based on bus type.
4163 */
4164 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4165 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4166
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004167 if (ioc->spi_data.minSyncFactor < MPT_ULTRA)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 ioc->spi_data.minSyncFactor = MPT_ULTRA;
4169 }
4170 }
4171 if (pbuf) {
4172 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4173 }
4174 }
4175 }
4176
4177 /* SCSI Port Page 2 - Read the header then the page.
4178 */
4179 header.PageVersion = 0;
4180 header.PageLength = 0;
4181 header.PageNumber = 2;
4182 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
4183 cfg.hdr = &header;
4184 cfg.physAddr = -1;
4185 cfg.pageAddr = portnum;
4186 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4187 cfg.dir = 0;
4188 if (mpt_config(ioc, &cfg) != 0)
4189 return -EFAULT;
4190
4191 if (header.PageLength > 0) {
4192 /* Allocate memory and read SCSI Port Page 2
4193 */
4194 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4195 if (pbuf) {
4196 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4197 cfg.physAddr = buf_dma;
4198 if (mpt_config(ioc, &cfg) != 0) {
4199 /* Nvram data is left with INVALID mark
4200 */
4201 rc = 1;
4202 } else {
4203 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4204 MpiDeviceInfo_t *pdevice = NULL;
4205
4206 /* Save the Port Page 2 data
4207 * (reformat into a 32bit quantity)
4208 */
4209 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4210 ioc->spi_data.PortFlags = data;
4211 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4212 pdevice = &pPP2->DeviceSettings[ii];
4213 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4214 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4215 ioc->spi_data.nvram[ii] = data;
4216 }
4217 }
4218
4219 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4220 }
4221 }
4222
4223 /* Update Adapter limits with those from NVRAM
4224 * Comment: Don't need to do this. Target performance
4225 * parameters will never exceed the adapters limits.
4226 */
4227
4228 return rc;
4229}
4230
4231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4232/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4233 * @ioc: Pointer to a Adapter Strucutre
4234 * @portnum: IOC port number
4235 *
4236 * Return: -EFAULT if read of config page header fails
4237 * or 0 if success.
4238 */
4239static int
4240mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4241{
4242 CONFIGPARMS cfg;
4243 ConfigPageHeader_t header;
4244
4245 /* Read the SCSI Device Page 1 header
4246 */
4247 header.PageVersion = 0;
4248 header.PageLength = 0;
4249 header.PageNumber = 1;
4250 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4251 cfg.hdr = &header;
4252 cfg.physAddr = -1;
4253 cfg.pageAddr = portnum;
4254 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4255 cfg.dir = 0;
4256 cfg.timeout = 0;
4257 if (mpt_config(ioc, &cfg) != 0)
4258 return -EFAULT;
4259
4260 ioc->spi_data.sdp1version = cfg.hdr->PageVersion;
4261 ioc->spi_data.sdp1length = cfg.hdr->PageLength;
4262
4263 header.PageVersion = 0;
4264 header.PageLength = 0;
4265 header.PageNumber = 0;
4266 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4267 if (mpt_config(ioc, &cfg) != 0)
4268 return -EFAULT;
4269
4270 ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
4271 ioc->spi_data.sdp0length = cfg.hdr->PageLength;
4272
4273 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4274 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4275
4276 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4277 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4278 return 0;
4279}
4280
4281/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4282/**
4283 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4284 * @ioc: Pointer to a Adapter Strucutre
4285 * @portnum: IOC port number
4286 *
4287 * Return:
4288 * 0 on success
4289 * -EFAULT if read of config page header fails or data pointer not NULL
4290 * -ENOMEM if pci_alloc failed
4291 */
4292int
4293mpt_findImVolumes(MPT_ADAPTER *ioc)
4294{
4295 IOCPage2_t *pIoc2;
4296 u8 *mem;
4297 ConfigPageIoc2RaidVol_t *pIocRv;
4298 dma_addr_t ioc2_dma;
4299 CONFIGPARMS cfg;
4300 ConfigPageHeader_t header;
4301 int jj;
4302 int rc = 0;
4303 int iocpage2sz;
4304 u8 nVols, nPhys;
4305 u8 vid, vbus, vioc;
4306
4307 /* Read IOCP2 header then the page.
4308 */
4309 header.PageVersion = 0;
4310 header.PageLength = 0;
4311 header.PageNumber = 2;
4312 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4313 cfg.hdr = &header;
4314 cfg.physAddr = -1;
4315 cfg.pageAddr = 0;
4316 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4317 cfg.dir = 0;
4318 cfg.timeout = 0;
4319 if (mpt_config(ioc, &cfg) != 0)
4320 return -EFAULT;
4321
4322 if (header.PageLength == 0)
4323 return -EFAULT;
4324
4325 iocpage2sz = header.PageLength * 4;
4326 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4327 if (!pIoc2)
4328 return -ENOMEM;
4329
4330 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4331 cfg.physAddr = ioc2_dma;
4332 if (mpt_config(ioc, &cfg) != 0)
4333 goto done_and_free;
4334
4335 if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) {
4336 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4337 if (mem) {
4338 ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem;
4339 } else {
4340 goto done_and_free;
4341 }
4342 }
4343 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4344
4345 /* Identify RAID Volume Id's */
4346 nVols = pIoc2->NumActiveVolumes;
4347 if ( nVols == 0) {
4348 /* No RAID Volume.
4349 */
4350 goto done_and_free;
4351 } else {
4352 /* At least 1 RAID Volume
4353 */
4354 pIocRv = pIoc2->RaidVolume;
4355 ioc->spi_data.isRaid = 0;
4356 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4357 vid = pIocRv->VolumeID;
4358 vbus = pIocRv->VolumeBus;
4359 vioc = pIocRv->VolumeIOC;
4360
4361 /* find the match
4362 */
4363 if (vbus == 0) {
4364 ioc->spi_data.isRaid |= (1 << vid);
4365 } else {
4366 /* Error! Always bus 0
4367 */
4368 }
4369 }
4370 }
4371
4372 /* Identify Hidden Physical Disk Id's */
4373 nPhys = pIoc2->NumActivePhysDisks;
4374 if (nPhys == 0) {
4375 /* No physical disks.
4376 */
4377 } else {
4378 mpt_read_ioc_pg_3(ioc);
4379 }
4380
4381done_and_free:
4382 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4383
4384 return rc;
4385}
4386
4387int
4388mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4389{
4390 IOCPage3_t *pIoc3;
4391 u8 *mem;
4392 CONFIGPARMS cfg;
4393 ConfigPageHeader_t header;
4394 dma_addr_t ioc3_dma;
4395 int iocpage3sz = 0;
4396
4397 /* Free the old page
4398 */
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06004399 kfree(ioc->spi_data.pIocPg3);
4400 ioc->spi_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
4402 /* There is at least one physical disk.
4403 * Read and save IOC Page 3
4404 */
4405 header.PageVersion = 0;
4406 header.PageLength = 0;
4407 header.PageNumber = 3;
4408 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4409 cfg.hdr = &header;
4410 cfg.physAddr = -1;
4411 cfg.pageAddr = 0;
4412 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4413 cfg.dir = 0;
4414 cfg.timeout = 0;
4415 if (mpt_config(ioc, &cfg) != 0)
4416 return 0;
4417
4418 if (header.PageLength == 0)
4419 return 0;
4420
4421 /* Read Header good, alloc memory
4422 */
4423 iocpage3sz = header.PageLength * 4;
4424 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4425 if (!pIoc3)
4426 return 0;
4427
4428 /* Read the Page and save the data
4429 * into malloc'd memory.
4430 */
4431 cfg.physAddr = ioc3_dma;
4432 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4433 if (mpt_config(ioc, &cfg) == 0) {
4434 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4435 if (mem) {
4436 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
4437 ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem;
4438 }
4439 }
4440
4441 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4442
4443 return 0;
4444}
4445
4446static void
4447mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4448{
4449 IOCPage4_t *pIoc4;
4450 CONFIGPARMS cfg;
4451 ConfigPageHeader_t header;
4452 dma_addr_t ioc4_dma;
4453 int iocpage4sz;
4454
4455 /* Read and save IOC Page 4
4456 */
4457 header.PageVersion = 0;
4458 header.PageLength = 0;
4459 header.PageNumber = 4;
4460 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4461 cfg.hdr = &header;
4462 cfg.physAddr = -1;
4463 cfg.pageAddr = 0;
4464 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4465 cfg.dir = 0;
4466 cfg.timeout = 0;
4467 if (mpt_config(ioc, &cfg) != 0)
4468 return;
4469
4470 if (header.PageLength == 0)
4471 return;
4472
4473 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4474 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4475 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4476 if (!pIoc4)
4477 return;
4478 } else {
4479 ioc4_dma = ioc->spi_data.IocPg4_dma;
4480 iocpage4sz = ioc->spi_data.IocPg4Sz;
4481 }
4482
4483 /* Read the Page into dma memory.
4484 */
4485 cfg.physAddr = ioc4_dma;
4486 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4487 if (mpt_config(ioc, &cfg) == 0) {
4488 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4489 ioc->spi_data.IocPg4_dma = ioc4_dma;
4490 ioc->spi_data.IocPg4Sz = iocpage4sz;
4491 } else {
4492 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4493 ioc->spi_data.pIocPg4 = NULL;
4494 }
4495}
4496
4497static void
4498mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4499{
4500 IOCPage1_t *pIoc1;
4501 CONFIGPARMS cfg;
4502 ConfigPageHeader_t header;
4503 dma_addr_t ioc1_dma;
4504 int iocpage1sz = 0;
4505 u32 tmp;
4506
4507 /* Check the Coalescing Timeout in IOC Page 1
4508 */
4509 header.PageVersion = 0;
4510 header.PageLength = 0;
4511 header.PageNumber = 1;
4512 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
4513 cfg.hdr = &header;
4514 cfg.physAddr = -1;
4515 cfg.pageAddr = 0;
4516 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4517 cfg.dir = 0;
4518 cfg.timeout = 0;
4519 if (mpt_config(ioc, &cfg) != 0)
4520 return;
4521
4522 if (header.PageLength == 0)
4523 return;
4524
4525 /* Read Header good, alloc memory
4526 */
4527 iocpage1sz = header.PageLength * 4;
4528 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4529 if (!pIoc1)
4530 return;
4531
4532 /* Read the Page and check coalescing timeout
4533 */
4534 cfg.physAddr = ioc1_dma;
4535 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4536 if (mpt_config(ioc, &cfg) == 0) {
4537
4538 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4539 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4540 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4541
4542 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4543 ioc->name, tmp));
4544
4545 if (tmp > MPT_COALESCING_TIMEOUT) {
4546 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4547
4548 /* Write NVRAM and current
4549 */
4550 cfg.dir = 1;
4551 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4552 if (mpt_config(ioc, &cfg) == 0) {
4553 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4554 ioc->name, MPT_COALESCING_TIMEOUT));
4555
4556 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4557 if (mpt_config(ioc, &cfg) == 0) {
4558 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4559 ioc->name, MPT_COALESCING_TIMEOUT));
4560 } else {
4561 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4562 ioc->name));
4563 }
4564
4565 } else {
4566 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4567 ioc->name));
4568 }
4569 }
4570
4571 } else {
4572 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4573 }
4574 }
4575
4576 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4577
4578 return;
4579}
4580
4581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4582/*
4583 * SendEventNotification - Send EventNotification (on or off) request
4584 * to MPT adapter.
4585 * @ioc: Pointer to MPT_ADAPTER structure
4586 * @EvSwitch: Event switch flags
4587 */
4588static int
4589SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4590{
4591 EventNotification_t *evnp;
4592
4593 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
4594 if (evnp == NULL) {
4595 dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
4596 ioc->name));
4597 return 0;
4598 }
4599 memset(evnp, 0, sizeof(*evnp));
4600
4601 dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch));
4602
4603 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
4604 evnp->ChainOffset = 0;
4605 evnp->MsgFlags = 0;
4606 evnp->Switch = EvSwitch;
4607
4608 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
4609
4610 return 0;
4611}
4612
4613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4614/**
4615 * SendEventAck - Send EventAck request to MPT adapter.
4616 * @ioc: Pointer to MPT_ADAPTER structure
4617 * @evnp: Pointer to original EventNotification request
4618 */
4619static int
4620SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
4621{
4622 EventAck_t *pAck;
4623
4624 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4625 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n",
4626 ioc->name);
4627 return -1;
4628 }
4629 memset(pAck, 0, sizeof(*pAck));
4630
4631 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
4632
4633 pAck->Function = MPI_FUNCTION_EVENT_ACK;
4634 pAck->ChainOffset = 0;
4635 pAck->MsgFlags = 0;
4636 pAck->Event = evnp->Event;
4637 pAck->EventContext = evnp->EventContext;
4638
4639 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
4640
4641 return 0;
4642}
4643
4644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4645/**
4646 * mpt_config - Generic function to issue config message
4647 * @ioc - Pointer to an adapter structure
4648 * @cfg - Pointer to a configuration structure. Struct contains
4649 * action, page address, direction, physical address
4650 * and pointer to a configuration page header
4651 * Page header is updated.
4652 *
4653 * Returns 0 for success
4654 * -EPERM if not allowed due to ISR context
4655 * -EAGAIN if no msg frames currently available
4656 * -EFAULT for non-successful reply or no reply (timeout)
4657 */
4658int
4659mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
4660{
4661 Config_t *pReq;
4662 MPT_FRAME_HDR *mf;
4663 unsigned long flags;
4664 int ii, rc;
4665 u32 flagsLength;
4666 int in_isr;
4667
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004668 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 * to be in ISR context, because that is fatal!
4670 */
4671 in_isr = in_interrupt();
4672 if (in_isr) {
4673 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
4674 ioc->name));
4675 return -EPERM;
4676 }
4677
4678 /* Get and Populate a free Frame
4679 */
4680 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4681 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
4682 ioc->name));
4683 return -EAGAIN;
4684 }
4685 pReq = (Config_t *)mf;
4686 pReq->Action = pCfg->action;
4687 pReq->Reserved = 0;
4688 pReq->ChainOffset = 0;
4689 pReq->Function = MPI_FUNCTION_CONFIG;
4690 pReq->ExtPageLength = 0;
4691 pReq->ExtPageType = 0;
4692 pReq->MsgFlags = 0;
4693 for (ii=0; ii < 8; ii++)
4694 pReq->Reserved2[ii] = 0;
4695
4696 pReq->Header.PageVersion = pCfg->hdr->PageVersion;
4697 pReq->Header.PageLength = pCfg->hdr->PageLength;
4698 pReq->Header.PageNumber = pCfg->hdr->PageNumber;
4699 pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
4700 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
4701
4702 /* Add a SGE to the config request.
4703 */
4704 if (pCfg->dir)
4705 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
4706 else
4707 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
4708
4709 flagsLength |= pCfg->hdr->PageLength * 4;
4710
4711 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
4712
4713 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
4714 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
4715
4716 /* Append pCfg pointer to end of mf
4717 */
4718 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
4719
4720 /* Initalize the timer
4721 */
4722 init_timer(&pCfg->timer);
4723 pCfg->timer.data = (unsigned long) ioc;
4724 pCfg->timer.function = mpt_timer_expired;
4725 pCfg->wait_done = 0;
4726
4727 /* Set the timer; ensure 10 second minimum */
4728 if (pCfg->timeout < 10)
4729 pCfg->timer.expires = jiffies + HZ*10;
4730 else
4731 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
4732
4733 /* Add to end of Q, set timer and then issue this command */
4734 spin_lock_irqsave(&ioc->FreeQlock, flags);
4735 list_add_tail(&pCfg->linkage, &ioc->configQ);
4736 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4737
4738 add_timer(&pCfg->timer);
4739 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4740 wait_event(mpt_waitq, pCfg->wait_done);
4741
4742 /* mf has been freed - do not access */
4743
4744 rc = pCfg->status;
4745
4746 return rc;
4747}
4748
4749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4750/**
4751 * mpt_toolbox - Generic function to issue toolbox message
4752 * @ioc - Pointer to an adapter structure
4753 * @cfg - Pointer to a toolbox structure. Struct contains
4754 * action, page address, direction, physical address
4755 * and pointer to a configuration page header
4756 * Page header is updated.
4757 *
4758 * Returns 0 for success
4759 * -EPERM if not allowed due to ISR context
4760 * -EAGAIN if no msg frames currently available
4761 * -EFAULT for non-successful reply or no reply (timeout)
4762 */
4763int
4764mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
4765{
4766 ToolboxIstwiReadWriteRequest_t *pReq;
4767 MPT_FRAME_HDR *mf;
4768 struct pci_dev *pdev;
4769 unsigned long flags;
4770 int rc;
4771 u32 flagsLength;
4772 int in_isr;
4773
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04004774 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 * to be in ISR context, because that is fatal!
4776 */
4777 in_isr = in_interrupt();
4778 if (in_isr) {
4779 dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n",
4780 ioc->name));
4781 return -EPERM;
4782 }
4783
4784 /* Get and Populate a free Frame
4785 */
4786 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4787 dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n",
4788 ioc->name));
4789 return -EAGAIN;
4790 }
4791 pReq = (ToolboxIstwiReadWriteRequest_t *)mf;
4792 pReq->Tool = pCfg->action;
4793 pReq->Reserved = 0;
4794 pReq->ChainOffset = 0;
4795 pReq->Function = MPI_FUNCTION_TOOLBOX;
4796 pReq->Reserved1 = 0;
4797 pReq->Reserved2 = 0;
4798 pReq->MsgFlags = 0;
4799 pReq->Flags = pCfg->dir;
4800 pReq->BusNum = 0;
4801 pReq->Reserved3 = 0;
4802 pReq->NumAddressBytes = 0x01;
4803 pReq->Reserved4 = 0;
4804 pReq->DataLength = 0x04;
4805 pdev = (struct pci_dev *) ioc->pcidev;
4806 if (pdev->devfn & 1)
4807 pReq->DeviceAddr = 0xB2;
4808 else
4809 pReq->DeviceAddr = 0xB0;
4810 pReq->Addr1 = 0;
4811 pReq->Addr2 = 0;
4812 pReq->Addr3 = 0;
4813 pReq->Reserved5 = 0;
4814
4815 /* Add a SGE to the config request.
4816 */
4817
4818 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4;
4819
4820 mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr);
4821
4822 dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n",
4823 ioc->name, pReq->Tool));
4824
4825 /* Append pCfg pointer to end of mf
4826 */
4827 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
4828
4829 /* Initalize the timer
4830 */
4831 init_timer(&pCfg->timer);
4832 pCfg->timer.data = (unsigned long) ioc;
4833 pCfg->timer.function = mpt_timer_expired;
4834 pCfg->wait_done = 0;
4835
4836 /* Set the timer; ensure 10 second minimum */
4837 if (pCfg->timeout < 10)
4838 pCfg->timer.expires = jiffies + HZ*10;
4839 else
4840 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
4841
4842 /* Add to end of Q, set timer and then issue this command */
4843 spin_lock_irqsave(&ioc->FreeQlock, flags);
4844 list_add_tail(&pCfg->linkage, &ioc->configQ);
4845 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4846
4847 add_timer(&pCfg->timer);
4848 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4849 wait_event(mpt_waitq, pCfg->wait_done);
4850
4851 /* mf has been freed - do not access */
4852
4853 rc = pCfg->status;
4854
4855 return rc;
4856}
4857
4858/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4859/*
4860 * mpt_timer_expired - Call back for timer process.
4861 * Used only internal config functionality.
4862 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
4863 */
4864static void
4865mpt_timer_expired(unsigned long data)
4866{
4867 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
4868
4869 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
4870
4871 /* Perform a FW reload */
4872 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
4873 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
4874
4875 /* No more processing.
4876 * Hard reset clean-up will wake up
4877 * process and free all resources.
4878 */
4879 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
4880
4881 return;
4882}
4883
4884/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4885/*
4886 * mpt_ioc_reset - Base cleanup for hard reset
4887 * @ioc: Pointer to the adapter structure
4888 * @reset_phase: Indicates pre- or post-reset functionality
4889 *
4890 * Remark: Free's resources with internally generated commands.
4891 */
4892static int
4893mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
4894{
4895 CONFIGPARMS *pCfg;
4896 unsigned long flags;
4897
4898 dprintk((KERN_WARNING MYNAM
4899 ": IOC %s_reset routed to MPT base driver!\n",
4900 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
4901 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
4902
4903 if (reset_phase == MPT_IOC_SETUP_RESET) {
4904 ;
4905 } else if (reset_phase == MPT_IOC_PRE_RESET) {
4906 /* If the internal config Q is not empty -
4907 * delete timer. MF resources will be freed when
4908 * the FIFO's are primed.
4909 */
4910 spin_lock_irqsave(&ioc->FreeQlock, flags);
4911 list_for_each_entry(pCfg, &ioc->configQ, linkage)
4912 del_timer(&pCfg->timer);
4913 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4914
4915 } else {
4916 CONFIGPARMS *pNext;
4917
4918 /* Search the configQ for internal commands.
4919 * Flush the Q, and wake up all suspended threads.
4920 */
4921 spin_lock_irqsave(&ioc->FreeQlock, flags);
4922 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
4923 list_del(&pCfg->linkage);
4924
4925 pCfg->status = MPT_CONFIG_ERROR;
4926 pCfg->wait_done = 1;
4927 wake_up(&mpt_waitq);
4928 }
4929 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4930 }
4931
4932 return 1; /* currently means nothing really */
4933}
4934
4935
4936#ifdef CONFIG_PROC_FS /* { */
4937/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4938/*
4939 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
4940 */
4941/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4942/*
4943 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
4944 *
4945 * Returns 0 for success, non-zero for failure.
4946 */
4947static int
4948procmpt_create(void)
4949{
4950 struct proc_dir_entry *ent;
4951
4952 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
4953 if (mpt_proc_root_dir == NULL)
4954 return -ENOTDIR;
4955
4956 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
4957 if (ent)
4958 ent->read_proc = procmpt_summary_read;
4959
4960 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
4961 if (ent)
4962 ent->read_proc = procmpt_version_read;
4963
4964 return 0;
4965}
4966
4967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4968/*
4969 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
4970 *
4971 * Returns 0 for success, non-zero for failure.
4972 */
4973static void
4974procmpt_destroy(void)
4975{
4976 remove_proc_entry("version", mpt_proc_root_dir);
4977 remove_proc_entry("summary", mpt_proc_root_dir);
4978 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
4979}
4980
4981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4982/*
4983 * procmpt_summary_read - Handle read request from /proc/mpt/summary
4984 * or from /proc/mpt/iocN/summary.
4985 * @buf: Pointer to area to write information
4986 * @start: Pointer to start pointer
4987 * @offset: Offset to start writing
4988 * @request:
4989 * @eof: Pointer to EOF integer
4990 * @data: Pointer
4991 *
4992 * Returns number of characters written to process performing the read.
4993 */
4994static int
4995procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
4996{
4997 MPT_ADAPTER *ioc;
4998 char *out = buf;
4999 int len;
5000
5001 if (data) {
5002 int more = 0;
5003
5004 ioc = data;
5005 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5006
5007 out += more;
5008 } else {
5009 list_for_each_entry(ioc, &ioc_list, list) {
5010 int more = 0;
5011
5012 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5013
5014 out += more;
5015 if ((out-buf) >= request)
5016 break;
5017 }
5018 }
5019
5020 len = out - buf;
5021
5022 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5023}
5024
5025/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5026/*
5027 * procmpt_version_read - Handle read request from /proc/mpt/version.
5028 * @buf: Pointer to area to write information
5029 * @start: Pointer to start pointer
5030 * @offset: Offset to start writing
5031 * @request:
5032 * @eof: Pointer to EOF integer
5033 * @data: Pointer
5034 *
5035 * Returns number of characters written to process performing the read.
5036 */
5037static int
5038procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5039{
5040 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005041 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 char *drvname;
5043 int len;
5044
5045 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5046 len += sprintf(buf+len, " Fusion MPT base driver\n");
5047
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005048 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5050 drvname = NULL;
5051 if (MptCallbacks[ii]) {
5052 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005053 case MPTSPI_DRIVER:
5054 if (!scsi++) drvname = "SPI host";
5055 break;
5056 case MPTFC_DRIVER:
5057 if (!fc++) drvname = "FC host";
5058 break;
5059 case MPTSAS_DRIVER:
5060 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 break;
5062 case MPTLAN_DRIVER:
5063 if (!lan++) drvname = "LAN";
5064 break;
5065 case MPTSTM_DRIVER:
5066 if (!targ++) drvname = "SCSI target";
5067 break;
5068 case MPTCTL_DRIVER:
5069 if (!ctl++) drvname = "ioctl";
5070 break;
5071 }
5072
5073 if (drvname)
5074 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5075 }
5076 }
5077
5078 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5079}
5080
5081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5082/*
5083 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5084 * @buf: Pointer to area to write information
5085 * @start: Pointer to start pointer
5086 * @offset: Offset to start writing
5087 * @request:
5088 * @eof: Pointer to EOF integer
5089 * @data: Pointer
5090 *
5091 * Returns number of characters written to process performing the read.
5092 */
5093static int
5094procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5095{
5096 MPT_ADAPTER *ioc = data;
5097 int len;
5098 char expVer[32];
5099 int sz;
5100 int p;
5101
5102 mpt_get_fw_exp_ver(expVer, ioc);
5103
5104 len = sprintf(buf, "%s:", ioc->name);
5105 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5106 len += sprintf(buf+len, " (f/w download boot flag set)");
5107// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5108// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5109
5110 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5111 ioc->facts.ProductID,
5112 ioc->prod_name);
5113 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5114 if (ioc->facts.FWImageSize)
5115 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5116 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5117 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5118 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5119
5120 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5121 ioc->facts.CurrentHostMfaHighAddr);
5122 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5123 ioc->facts.CurrentSenseBufferHighAddr);
5124
5125 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5126 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5127
5128 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5129 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5130 /*
5131 * Rounding UP to nearest 4-kB boundary here...
5132 */
5133 sz = (ioc->req_sz * ioc->req_depth) + 128;
5134 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5135 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5136 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5137 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5138 4*ioc->facts.RequestFrameSize,
5139 ioc->facts.GlobalCredits);
5140
5141 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5142 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5143 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5144 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5145 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5146 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5147 ioc->facts.CurReplyFrameSize,
5148 ioc->facts.ReplyQueueDepth);
5149
5150 len += sprintf(buf+len, " MaxDevices = %d\n",
5151 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5152 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5153
5154 /* per-port info */
5155 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5156 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5157 p+1,
5158 ioc->facts.NumberOfPorts);
5159 if (ioc->bus_type == FC) {
5160 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5161 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5162 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5163 a[5], a[4], a[3], a[2], a[1], a[0]);
5164 }
5165 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5166 ioc->fc_port_page0[p].WWNN.High,
5167 ioc->fc_port_page0[p].WWNN.Low,
5168 ioc->fc_port_page0[p].WWPN.High,
5169 ioc->fc_port_page0[p].WWPN.Low);
5170 }
5171 }
5172
5173 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5174}
5175
5176#endif /* CONFIG_PROC_FS } */
5177
5178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5179static void
5180mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5181{
5182 buf[0] ='\0';
5183 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5184 sprintf(buf, " (Exp %02d%02d)",
5185 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5186 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5187
5188 /* insider hack! */
5189 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5190 strcat(buf, " [MDBG]");
5191 }
5192}
5193
5194/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5195/**
5196 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5197 * @ioc: Pointer to MPT_ADAPTER structure
5198 * @buffer: Pointer to buffer where IOC summary info should be written
5199 * @size: Pointer to number of bytes we wrote (set by this routine)
5200 * @len: Offset at which to start writing in buffer
5201 * @showlan: Display LAN stuff?
5202 *
5203 * This routine writes (english readable) ASCII text, which represents
5204 * a summary of IOC information, to a buffer.
5205 */
5206void
5207mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5208{
5209 char expVer[32];
5210 int y;
5211
5212 mpt_get_fw_exp_ver(expVer, ioc);
5213
5214 /*
5215 * Shorter summary of attached ioc's...
5216 */
5217 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5218 ioc->name,
5219 ioc->prod_name,
5220 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5221 ioc->facts.FWVersion.Word,
5222 expVer,
5223 ioc->facts.NumberOfPorts,
5224 ioc->req_depth);
5225
5226 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5227 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5228 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5229 a[5], a[4], a[3], a[2], a[1], a[0]);
5230 }
5231
5232#ifndef __sparc__
5233 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5234#else
5235 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5236#endif
5237
5238 if (!ioc->active)
5239 y += sprintf(buffer+len+y, " (disabled)");
5240
5241 y += sprintf(buffer+len+y, "\n");
5242
5243 *size = y;
5244}
5245
5246/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5247/*
5248 * Reset Handling
5249 */
5250/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5251/**
5252 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5253 * Management call based on input arg values. If TaskMgmt fails,
5254 * return associated SCSI request.
5255 * @ioc: Pointer to MPT_ADAPTER structure
5256 * @sleepFlag: Indicates if sleep or schedule must be called.
5257 *
5258 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5259 * or a non-interrupt thread. In the former, must not call schedule().
5260 *
5261 * Remark: A return of -1 is a FATAL error case, as it means a
5262 * FW reload/initialization failed.
5263 *
5264 * Returns 0 for SUCCESS or -1 if FAILED.
5265 */
5266int
5267mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5268{
5269 int rc;
5270 unsigned long flags;
5271
5272 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5273#ifdef MFCNT
5274 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5275 printk("MF count 0x%x !\n", ioc->mfcnt);
5276#endif
5277
5278 /* Reset the adapter. Prevent more than 1 call to
5279 * mpt_do_ioc_recovery at any instant in time.
5280 */
5281 spin_lock_irqsave(&ioc->diagLock, flags);
5282 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5283 spin_unlock_irqrestore(&ioc->diagLock, flags);
5284 return 0;
5285 } else {
5286 ioc->diagPending = 1;
5287 }
5288 spin_unlock_irqrestore(&ioc->diagLock, flags);
5289
5290 /* FIXME: If do_ioc_recovery fails, repeat....
5291 */
5292
5293 /* The SCSI driver needs to adjust timeouts on all current
5294 * commands prior to the diagnostic reset being issued.
5295 * Prevents timeouts occuring during a diagnostic reset...very bad.
5296 * For all other protocol drivers, this is a no-op.
5297 */
5298 {
5299 int ii;
5300 int r = 0;
5301
5302 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5303 if (MptResetHandlers[ii]) {
5304 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5305 ioc->name, ii));
5306 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5307 if (ioc->alt_ioc) {
5308 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5309 ioc->name, ioc->alt_ioc->name, ii));
5310 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5311 }
5312 }
5313 }
5314 }
5315
5316 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5317 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5318 rc, ioc->name);
5319 }
5320 ioc->reload_fw = 0;
5321 if (ioc->alt_ioc)
5322 ioc->alt_ioc->reload_fw = 0;
5323
5324 spin_lock_irqsave(&ioc->diagLock, flags);
5325 ioc->diagPending = 0;
5326 if (ioc->alt_ioc)
5327 ioc->alt_ioc->diagPending = 0;
5328 spin_unlock_irqrestore(&ioc->diagLock, flags);
5329
5330 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5331
5332 return rc;
5333}
5334
5335/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5336static char *
5337EventDescriptionStr(u8 event, u32 evData0)
5338{
5339 char *ds;
5340
5341 switch(event) {
5342 case MPI_EVENT_NONE:
5343 ds = "None";
5344 break;
5345 case MPI_EVENT_LOG_DATA:
5346 ds = "Log Data";
5347 break;
5348 case MPI_EVENT_STATE_CHANGE:
5349 ds = "State Change";
5350 break;
5351 case MPI_EVENT_UNIT_ATTENTION:
5352 ds = "Unit Attention";
5353 break;
5354 case MPI_EVENT_IOC_BUS_RESET:
5355 ds = "IOC Bus Reset";
5356 break;
5357 case MPI_EVENT_EXT_BUS_RESET:
5358 ds = "External Bus Reset";
5359 break;
5360 case MPI_EVENT_RESCAN:
5361 ds = "Bus Rescan Event";
5362 /* Ok, do we need to do anything here? As far as
5363 I can tell, this is when a new device gets added
5364 to the loop. */
5365 break;
5366 case MPI_EVENT_LINK_STATUS_CHANGE:
5367 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5368 ds = "Link Status(FAILURE) Change";
5369 else
5370 ds = "Link Status(ACTIVE) Change";
5371 break;
5372 case MPI_EVENT_LOOP_STATE_CHANGE:
5373 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5374 ds = "Loop State(LIP) Change";
5375 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5376 ds = "Loop State(LPE) Change"; /* ??? */
5377 else
5378 ds = "Loop State(LPB) Change"; /* ??? */
5379 break;
5380 case MPI_EVENT_LOGOUT:
5381 ds = "Logout";
5382 break;
5383 case MPI_EVENT_EVENT_CHANGE:
5384 if (evData0)
5385 ds = "Events(ON) Change";
5386 else
5387 ds = "Events(OFF) Change";
5388 break;
5389 case MPI_EVENT_INTEGRATED_RAID:
5390 ds = "Integrated Raid";
5391 break;
5392 /*
5393 * MPT base "custom" events may be added here...
5394 */
5395 default:
5396 ds = "Unknown";
5397 break;
5398 }
5399 return ds;
5400}
5401
5402/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5403/*
5404 * ProcessEventNotification - Route a received EventNotificationReply to
5405 * all currently regeistered event handlers.
5406 * @ioc: Pointer to MPT_ADAPTER structure
5407 * @pEventReply: Pointer to EventNotification reply frame
5408 * @evHandlers: Pointer to integer, number of event handlers
5409 *
5410 * Returns sum of event handlers return values.
5411 */
5412static int
5413ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5414{
5415 u16 evDataLen;
5416 u32 evData0 = 0;
5417// u32 evCtx;
5418 int ii;
5419 int r = 0;
5420 int handlers = 0;
5421 char *evStr;
5422 u8 event;
5423
5424 /*
5425 * Do platform normalization of values
5426 */
5427 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5428// evCtx = le32_to_cpu(pEventReply->EventContext);
5429 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5430 if (evDataLen) {
5431 evData0 = le32_to_cpu(pEventReply->Data[0]);
5432 }
5433
5434 evStr = EventDescriptionStr(event, evData0);
5435 devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
5436 ioc->name,
5437 evStr,
5438 event));
5439
5440#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
5441 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5442 for (ii = 0; ii < evDataLen; ii++)
5443 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5444 printk("\n");
5445#endif
5446
5447 /*
5448 * Do general / base driver event processing
5449 */
5450 switch(event) {
5451 case MPI_EVENT_NONE: /* 00 */
5452 case MPI_EVENT_LOG_DATA: /* 01 */
5453 case MPI_EVENT_STATE_CHANGE: /* 02 */
5454 case MPI_EVENT_UNIT_ATTENTION: /* 03 */
5455 case MPI_EVENT_IOC_BUS_RESET: /* 04 */
5456 case MPI_EVENT_EXT_BUS_RESET: /* 05 */
5457 case MPI_EVENT_RESCAN: /* 06 */
5458 case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
5459 case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
5460 case MPI_EVENT_LOGOUT: /* 09 */
5461 case MPI_EVENT_INTEGRATED_RAID: /* 0B */
5462 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */
5463 default:
5464 break;
5465 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5466 if (evDataLen) {
5467 u8 evState = evData0 & 0xFF;
5468
5469 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5470
5471 /* Update EventState field in cached IocFacts */
5472 if (ioc->facts.Function) {
5473 ioc->facts.EventState = evState;
5474 }
5475 }
5476 break;
5477 }
5478
5479 /*
5480 * Should this event be logged? Events are written sequentially.
5481 * When buffer is full, start again at the top.
5482 */
5483 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
5484 int idx;
5485
5486 idx = ioc->eventContext % ioc->eventLogSize;
5487
5488 ioc->events[idx].event = event;
5489 ioc->events[idx].eventContext = ioc->eventContext;
5490
5491 for (ii = 0; ii < 2; ii++) {
5492 if (ii < evDataLen)
5493 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
5494 else
5495 ioc->events[idx].data[ii] = 0;
5496 }
5497
5498 ioc->eventContext++;
5499 }
5500
5501
5502 /*
5503 * Call each currently registered protocol event handler.
5504 */
5505 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5506 if (MptEvHandlers[ii]) {
5507 devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
5508 ioc->name, ii));
5509 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
5510 handlers++;
5511 }
5512 }
5513 /* FIXME? Examine results here? */
5514
5515 /*
5516 * If needed, send (a single) EventAck.
5517 */
5518 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
5519 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
5520 devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
5521 ioc->name, ii));
5522 }
5523 }
5524
5525 *evHandlers = handlers;
5526 return r;
5527}
5528
5529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5530/*
5531 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
5532 * @ioc: Pointer to MPT_ADAPTER structure
5533 * @log_info: U32 LogInfo reply word from the IOC
5534 *
5535 * Refer to lsi/fc_log.h.
5536 */
5537static void
5538mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
5539{
5540 static char *subcl_str[8] = {
5541 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
5542 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
5543 };
5544 u8 subcl = (log_info >> 24) & 0x7;
5545
5546 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
5547 ioc->name, log_info, subcl_str[subcl]);
5548}
5549
5550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5551/*
5552 * mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
5553 * @ioc: Pointer to MPT_ADAPTER structure
5554 * @mr: Pointer to MPT reply frame
5555 * @log_info: U32 LogInfo word from the IOC
5556 *
5557 * Refer to lsi/sp_log.h.
5558 */
5559static void
5560mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
5561{
5562 u32 info = log_info & 0x00FF0000;
5563 char *desc = "unknown";
5564
5565 switch (info) {
5566 case 0x00010000:
5567 desc = "bug! MID not found";
5568 if (ioc->reload_fw == 0)
5569 ioc->reload_fw++;
5570 break;
5571
5572 case 0x00020000:
5573 desc = "Parity Error";
5574 break;
5575
5576 case 0x00030000:
5577 desc = "ASYNC Outbound Overrun";
5578 break;
5579
5580 case 0x00040000:
5581 desc = "SYNC Offset Error";
5582 break;
5583
5584 case 0x00050000:
5585 desc = "BM Change";
5586 break;
5587
5588 case 0x00060000:
5589 desc = "Msg In Overflow";
5590 break;
5591
5592 case 0x00070000:
5593 desc = "DMA Error";
5594 break;
5595
5596 case 0x00080000:
5597 desc = "Outbound DMA Overrun";
5598 break;
5599
5600 case 0x00090000:
5601 desc = "Task Management";
5602 break;
5603
5604 case 0x000A0000:
5605 desc = "Device Problem";
5606 break;
5607
5608 case 0x000B0000:
5609 desc = "Invalid Phase Change";
5610 break;
5611
5612 case 0x000C0000:
5613 desc = "Untagged Table Size";
5614 break;
5615
5616 }
5617
5618 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
5619}
5620
5621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5622/*
5623 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
5624 * @ioc: Pointer to MPT_ADAPTER structure
5625 * @ioc_status: U32 IOCStatus word from IOC
5626 * @mf: Pointer to MPT request frame
5627 *
5628 * Refer to lsi/mpi.h.
5629 */
5630static void
5631mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
5632{
5633 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
5634 char *desc = "";
5635
5636 switch (status) {
5637 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
5638 desc = "Invalid Function";
5639 break;
5640
5641 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
5642 desc = "Busy";
5643 break;
5644
5645 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
5646 desc = "Invalid SGL";
5647 break;
5648
5649 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
5650 desc = "Internal Error";
5651 break;
5652
5653 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
5654 desc = "Reserved";
5655 break;
5656
5657 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
5658 desc = "Insufficient Resources";
5659 break;
5660
5661 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
5662 desc = "Invalid Field";
5663 break;
5664
5665 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
5666 desc = "Invalid State";
5667 break;
5668
5669 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
5670 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
5671 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
5672 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
5673 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
5674 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
5675 /* No message for Config IOCStatus values */
5676 break;
5677
5678 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
5679 /* No message for recovered error
5680 desc = "SCSI Recovered Error";
5681 */
5682 break;
5683
5684 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
5685 desc = "SCSI Invalid Bus";
5686 break;
5687
5688 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
5689 desc = "SCSI Invalid TargetID";
5690 break;
5691
5692 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
5693 {
5694 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
5695 U8 cdb = pScsiReq->CDB[0];
5696 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
5697 desc = "SCSI Device Not There";
5698 }
5699 break;
5700 }
5701
5702 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
5703 desc = "SCSI Data Overrun";
5704 break;
5705
5706 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
5707 /* This error is checked in scsi_io_done(). Skip.
5708 desc = "SCSI Data Underrun";
5709 */
5710 break;
5711
5712 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
5713 desc = "SCSI I/O Data Error";
5714 break;
5715
5716 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
5717 desc = "SCSI Protocol Error";
5718 break;
5719
5720 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
5721 desc = "SCSI Task Terminated";
5722 break;
5723
5724 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
5725 desc = "SCSI Residual Mismatch";
5726 break;
5727
5728 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
5729 desc = "SCSI Task Management Failed";
5730 break;
5731
5732 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
5733 desc = "SCSI IOC Terminated";
5734 break;
5735
5736 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
5737 desc = "SCSI Ext Terminated";
5738 break;
5739
5740 default:
5741 desc = "Others";
5742 break;
5743 }
5744 if (desc != "")
5745 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
5746}
5747
5748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005749EXPORT_SYMBOL(mpt_attach);
5750EXPORT_SYMBOL(mpt_detach);
5751#ifdef CONFIG_PM
5752EXPORT_SYMBOL(mpt_resume);
5753EXPORT_SYMBOL(mpt_suspend);
5754#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755EXPORT_SYMBOL(ioc_list);
5756EXPORT_SYMBOL(mpt_proc_root_dir);
5757EXPORT_SYMBOL(mpt_register);
5758EXPORT_SYMBOL(mpt_deregister);
5759EXPORT_SYMBOL(mpt_event_register);
5760EXPORT_SYMBOL(mpt_event_deregister);
5761EXPORT_SYMBOL(mpt_reset_register);
5762EXPORT_SYMBOL(mpt_reset_deregister);
5763EXPORT_SYMBOL(mpt_device_driver_register);
5764EXPORT_SYMBOL(mpt_device_driver_deregister);
5765EXPORT_SYMBOL(mpt_get_msg_frame);
5766EXPORT_SYMBOL(mpt_put_msg_frame);
5767EXPORT_SYMBOL(mpt_free_msg_frame);
5768EXPORT_SYMBOL(mpt_add_sge);
5769EXPORT_SYMBOL(mpt_send_handshake_request);
5770EXPORT_SYMBOL(mpt_verify_adapter);
5771EXPORT_SYMBOL(mpt_GetIocState);
5772EXPORT_SYMBOL(mpt_print_ioc_summary);
5773EXPORT_SYMBOL(mpt_lan_index);
5774EXPORT_SYMBOL(mpt_stm_index);
5775EXPORT_SYMBOL(mpt_HardResetHandler);
5776EXPORT_SYMBOL(mpt_config);
5777EXPORT_SYMBOL(mpt_toolbox);
5778EXPORT_SYMBOL(mpt_findImVolumes);
5779EXPORT_SYMBOL(mpt_read_ioc_pg_3);
5780EXPORT_SYMBOL(mpt_alloc_fw_memory);
5781EXPORT_SYMBOL(mpt_free_fw_memory);
5782
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783
5784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5785/*
5786 * fusion_init - Fusion MPT base driver initialization routine.
5787 *
5788 * Returns 0 for success, non-zero for failure.
5789 */
5790static int __init
5791fusion_init(void)
5792{
5793 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
5795 show_mptmod_ver(my_NAME, my_VERSION);
5796 printk(KERN_INFO COPYRIGHT "\n");
5797
5798 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
5799 MptCallbacks[i] = NULL;
5800 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
5801 MptEvHandlers[i] = NULL;
5802 MptResetHandlers[i] = NULL;
5803 }
5804
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005805 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 * EventNotification handling.
5807 */
5808 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
5809
5810 /* Register for hard reset handling callbacks.
5811 */
5812 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
5813 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
5814 } else {
5815 /* FIXME! */
5816 }
5817
5818#ifdef CONFIG_PROC_FS
5819 (void) procmpt_create();
5820#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005821 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822}
5823
5824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5825/*
5826 * fusion_exit - Perform driver unload cleanup.
5827 *
5828 * This routine frees all resources associated with each MPT adapter
5829 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
5830 */
5831static void __exit
5832fusion_exit(void)
5833{
5834
5835 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
5836
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 mpt_reset_deregister(mpt_base_index);
5838
5839#ifdef CONFIG_PROC_FS
5840 procmpt_destroy();
5841#endif
5842}
5843
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844module_init(fusion_init);
5845module_exit(fusion_exit);