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