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