blob: 780e8be9066edd11d03ee926b8cf4cab85da29bf [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66#ifdef __sparc__
67#include <asm/irq.h> /* needed for __irq_itoa() proto */
68#endif
69
70#include "mptbase.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
80
81/*
82 * cmd line parameters
83 */
84#ifdef MFCNT
85static int mfcounter = 0;
86#define PRINT_MF_COUNT 20000
87#endif
88
89/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
90/*
91 * Public data...
92 */
93int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080094int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Linus Torvaldsf7473072005-11-29 14:21:57 -080096struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98#define WHOINIT_UNKNOWN 0xAA
99
100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
101/*
102 * Private data...
103 */
104 /* Adapter link list */
105LIST_HEAD(ioc_list);
106 /* Callback lookup table */
107static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
108 /* Protocol driver class lookup table */
109static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
110 /* Event handler lookup table */
111static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Reset handler lookup table */
113static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
114static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115
116static int mpt_base_index = -1;
117static int last_drv_idx = -1;
118
119static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
120
121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
122/*
123 * Forward protos...
124 */
125static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
126static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
127static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
128 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
129 int sleepFlag);
130static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
131static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
132static void mpt_adapter_disable(MPT_ADAPTER *ioc);
133static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
134
135static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
136static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
138static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
139static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
140static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
141static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200142static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
144static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
146static int PrimeIocFifos(MPT_ADAPTER *ioc);
147static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
148static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200152int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
154static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
155static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
156static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
157static void mpt_timer_expired(unsigned long data);
158static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
159static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200160static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
161static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
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);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600178static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int __init fusion_init (void);
182static void __exit fusion_exit (void);
183
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#define CHIPREG_READ32(addr) readl_relaxed(addr)
185#define CHIPREG_READ32_dmasync(addr) readl(addr)
186#define CHIPREG_WRITE32(addr,val) writel(val, addr)
187#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
188#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
189
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600190static void
191pci_disable_io_access(struct pci_dev *pdev)
192{
193 u16 command_reg;
194
195 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
196 command_reg &= ~1;
197 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
198}
199
200static void
201pci_enable_io_access(struct pci_dev *pdev)
202{
203 u16 command_reg;
204
205 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
206 command_reg |= 1;
207 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
208}
209
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600210/*
211 * Process turbo (context) reply...
212 */
213static void
214mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
215{
216 MPT_FRAME_HDR *mf = NULL;
217 MPT_FRAME_HDR *mr = NULL;
218 int req_idx = 0;
219 int cb_idx;
220
221 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
222 ioc->name, pa));
223
224 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
225 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
226 req_idx = pa & 0x0000FFFF;
227 cb_idx = (pa & 0x00FF0000) >> 16;
228 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
229 break;
230 case MPI_CONTEXT_REPLY_TYPE_LAN:
231 cb_idx = mpt_lan_index;
232 /*
233 * Blind set of mf to NULL here was fatal
234 * after lan_reply says "freeme"
235 * Fix sort of combined with an optimization here;
236 * added explicit check for case where lan_reply
237 * was just returning 1 and doing nothing else.
238 * For this case skip the callback, but set up
239 * proper mf value first here:-)
240 */
241 if ((pa & 0x58000000) == 0x58000000) {
242 req_idx = pa & 0x0000FFFF;
243 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
244 mpt_free_msg_frame(ioc, mf);
245 mb();
246 return;
247 break;
248 }
249 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
250 break;
251 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
252 cb_idx = mpt_stm_index;
253 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
254 break;
255 default:
256 cb_idx = 0;
257 BUG();
258 }
259
260 /* Check for (valid) IO callback! */
261 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
262 MptCallbacks[cb_idx] == NULL) {
263 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
264 __FUNCTION__, ioc->name, cb_idx);
265 goto out;
266 }
267
268 if (MptCallbacks[cb_idx](ioc, mf, mr))
269 mpt_free_msg_frame(ioc, mf);
270 out:
271 mb();
272}
273
274static void
275mpt_reply(MPT_ADAPTER *ioc, u32 pa)
276{
277 MPT_FRAME_HDR *mf;
278 MPT_FRAME_HDR *mr;
279 int req_idx;
280 int cb_idx;
281 int freeme;
282
283 u32 reply_dma_low;
284 u16 ioc_stat;
285
286 /* non-TURBO reply! Hmmm, something may be up...
287 * Newest turbo reply mechanism; get address
288 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
289 */
290
291 /* Map DMA address of reply header to cpu address.
292 * pa is 32 bits - but the dma address may be 32 or 64 bits
293 * get offset based only only the low addresses
294 */
295
296 reply_dma_low = (pa <<= 1);
297 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
298 (reply_dma_low - ioc->reply_frames_low_dma));
299
300 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
301 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
302 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
303
304 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
305 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
306 DBG_DUMP_REPLY_FRAME(mr)
307
308 /* Check/log IOC log info
309 */
310 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
311 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
312 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
313 if (ioc->bus_type == FC)
314 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700315 else if (ioc->bus_type == SPI)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600316 mpt_sp_log_info(ioc, log_info);
317 else if (ioc->bus_type == SAS)
318 mpt_sas_log_info(ioc, log_info);
319 }
320 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700321 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600322 cb_idx != mpt_stm_index &&
323 cb_idx != mpt_lan_index)
324 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
325 }
326
327
328 /* Check for (valid) IO callback! */
329 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
330 MptCallbacks[cb_idx] == NULL) {
331 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
332 __FUNCTION__, ioc->name, cb_idx);
333 freeme = 0;
334 goto out;
335 }
336
337 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
338
339 out:
340 /* Flush (non-TURBO) reply with a WRITE! */
341 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
342
343 if (freeme)
344 mpt_free_msg_frame(ioc, mf);
345 mb();
346}
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
349/*
350 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
351 * @irq: irq number (not used)
352 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
353 * @r: pt_regs pointer (not used)
354 *
355 * This routine is registered via the request_irq() kernel API call,
356 * and handles all interrupts generated from a specific MPT adapter
357 * (also referred to as a IO Controller or IOC).
358 * This routine must clear the interrupt from the adapter and does
359 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200360 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 *
362 * This routine handles register-level access of the adapter but
363 * dispatches (calls) a protocol-specific callback routine to handle
364 * the protocol-specific details of the MPT request completion.
365 */
366static irqreturn_t
367mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
368{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600369 MPT_ADAPTER *ioc = bus_id;
370 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 /*
373 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 */
375 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600376 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
377 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600379 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
380 mpt_reply(ioc, pa);
381 else
382 mpt_turbo_reply(ioc, pa);
383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 return IRQ_HANDLED;
386}
387
388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
389/*
390 * mpt_base_reply - MPT base driver's callback routine; all base driver
391 * "internal" request/reply processing is routed here.
392 * Currently used for EventNotification and EventAck handling.
393 * @ioc: Pointer to MPT_ADAPTER structure
394 * @mf: Pointer to original MPT request frame
395 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
396 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200397 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 * should be freed, or 0 if it shouldn't.
399 */
400static int
401mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
402{
403 int freereq = 1;
404 u8 func;
405
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200406 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200408#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
410 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
411 DBG_DUMP_REQUEST_FRAME_HDR(mf)
412 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200413#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200416 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ioc->name, func));
418
419 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
420 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
421 int evHandlers = 0;
422 int results;
423
424 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
425 if (results != evHandlers) {
426 /* CHECKME! Any special handling needed here? */
427 devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
428 ioc->name, evHandlers, results));
429 }
430
431 /*
432 * Hmmm... It seems that EventNotificationReply is an exception
433 * to the rule of one reply per request.
434 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200435 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200437 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
438 ioc->name, pEvReply));
439 } else {
440 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
441 ioc->name, pEvReply));
442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444#ifdef CONFIG_PROC_FS
445// LogEvent(ioc, pEvReply);
446#endif
447
448 } else if (func == MPI_FUNCTION_EVENT_ACK) {
449 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
450 ioc->name));
451 } else if (func == MPI_FUNCTION_CONFIG ||
452 func == MPI_FUNCTION_TOOLBOX) {
453 CONFIGPARMS *pCfg;
454 unsigned long flags;
455
456 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
457 ioc->name, mf, reply));
458
459 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
460
461 if (pCfg) {
462 /* disable timer and remove from linked list */
463 del_timer(&pCfg->timer);
464
465 spin_lock_irqsave(&ioc->FreeQlock, flags);
466 list_del(&pCfg->linkage);
467 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
468
469 /*
470 * If IOC Status is SUCCESS, save the header
471 * and set the status code to GOOD.
472 */
473 pCfg->status = MPT_CONFIG_ERROR;
474 if (reply) {
475 ConfigReply_t *pReply = (ConfigReply_t *)reply;
476 u16 status;
477
478 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
479 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
480 status, le32_to_cpu(pReply->IOCLogInfo)));
481
482 pCfg->status = status;
483 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200484 if ((pReply->Header.PageType &
485 MPI_CONFIG_PAGETYPE_MASK) ==
486 MPI_CONFIG_PAGETYPE_EXTENDED) {
487 pCfg->cfghdr.ehdr->ExtPageLength =
488 le16_to_cpu(pReply->ExtPageLength);
489 pCfg->cfghdr.ehdr->ExtPageType =
490 pReply->ExtPageType;
491 }
492 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
493
494 /* If this is a regular header, save PageLength. */
495 /* LMP Do this better so not using a reserved field! */
496 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
497 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
498 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500 }
501
502 /*
503 * Wake up the original calling thread
504 */
505 pCfg->wait_done = 1;
506 wake_up(&mpt_waitq);
507 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200508 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
509 /* we should be always getting a reply frame */
510 memcpy(ioc->persist_reply_frame, reply,
511 min(MPT_DEFAULT_FRAME_SIZE,
512 4*reply->u.reply.MsgLength));
513 del_timer(&ioc->persist_timer);
514 ioc->persist_wait_done = 1;
515 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 } else {
517 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
518 ioc->name, func);
519 }
520
521 /*
522 * Conditionally tell caller to free the original
523 * EventNotification/EventAck/unexpected request frame!
524 */
525 return freereq;
526}
527
528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
529/**
530 * mpt_register - Register protocol-specific main callback handler.
531 * @cbfunc: callback function pointer
532 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
533 *
534 * This routine is called by a protocol-specific driver (SCSI host,
535 * LAN, SCSI target) to register it's reply callback routine. Each
536 * protocol-specific driver must do this before it will be able to
537 * use any IOC resources, such as obtaining request frames.
538 *
539 * NOTES: The SCSI protocol driver currently calls this routine thrice
540 * in order to register separate callbacks; one for "normal" SCSI IO;
541 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
542 *
543 * Returns a positive integer valued "handle" in the
544 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
545 * Any non-positive return value (including zero!) should be considered
546 * an error by the caller.
547 */
548int
549mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
550{
551 int i;
552
553 last_drv_idx = -1;
554
555 /*
556 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
557 * (slot/handle 0 is reserved!)
558 */
559 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
560 if (MptCallbacks[i] == NULL) {
561 MptCallbacks[i] = cbfunc;
562 MptDriverClass[i] = dclass;
563 MptEvHandlers[i] = NULL;
564 last_drv_idx = i;
565 break;
566 }
567 }
568
569 return last_drv_idx;
570}
571
572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
573/**
574 * mpt_deregister - Deregister a protocol drivers resources.
575 * @cb_idx: previously registered callback handle
576 *
577 * Each protocol-specific driver should call this routine when it's
578 * module is unloaded.
579 */
580void
581mpt_deregister(int cb_idx)
582{
583 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
584 MptCallbacks[cb_idx] = NULL;
585 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
586 MptEvHandlers[cb_idx] = NULL;
587
588 last_drv_idx++;
589 }
590}
591
592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
593/**
594 * mpt_event_register - Register protocol-specific event callback
595 * handler.
596 * @cb_idx: previously registered (via mpt_register) callback handle
597 * @ev_cbfunc: callback function
598 *
599 * This routine can be called by one or more protocol-specific drivers
600 * if/when they choose to be notified of MPT events.
601 *
602 * Returns 0 for success.
603 */
604int
605mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
606{
607 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
608 return -1;
609
610 MptEvHandlers[cb_idx] = ev_cbfunc;
611 return 0;
612}
613
614/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
615/**
616 * mpt_event_deregister - Deregister protocol-specific event callback
617 * handler.
618 * @cb_idx: previously registered callback handle
619 *
620 * Each protocol-specific driver should call this routine
621 * when it does not (or can no longer) handle events,
622 * or when it's module is unloaded.
623 */
624void
625mpt_event_deregister(int cb_idx)
626{
627 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
628 return;
629
630 MptEvHandlers[cb_idx] = NULL;
631}
632
633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
634/**
635 * mpt_reset_register - Register protocol-specific IOC reset handler.
636 * @cb_idx: previously registered (via mpt_register) callback handle
637 * @reset_func: reset function
638 *
639 * This routine can be called by one or more protocol-specific drivers
640 * if/when they choose to be notified of IOC resets.
641 *
642 * Returns 0 for success.
643 */
644int
645mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
646{
647 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
648 return -1;
649
650 MptResetHandlers[cb_idx] = reset_func;
651 return 0;
652}
653
654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
655/**
656 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
657 * @cb_idx: previously registered callback handle
658 *
659 * Each protocol-specific driver should call this routine
660 * when it does not (or can no longer) handle IOC reset handling,
661 * or when it's module is unloaded.
662 */
663void
664mpt_reset_deregister(int cb_idx)
665{
666 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
667 return;
668
669 MptResetHandlers[cb_idx] = NULL;
670}
671
672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
673/**
674 * mpt_device_driver_register - Register device driver hooks
675 */
676int
677mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
678{
679 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400682 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
684
685 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
686
687 /* call per pci device probe entry point */
688 list_for_each_entry(ioc, &ioc_list, list) {
689 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400690 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
693 }
694
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400695 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696}
697
698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
699/**
700 * mpt_device_driver_deregister - DeRegister device driver hooks
701 */
702void
703mpt_device_driver_deregister(int cb_idx)
704{
705 struct mpt_pci_driver *dd_cbfunc;
706 MPT_ADAPTER *ioc;
707
708 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
709 return;
710
711 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
712
713 list_for_each_entry(ioc, &ioc_list, list) {
714 if (dd_cbfunc->remove)
715 dd_cbfunc->remove(ioc->pcidev);
716 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 MptDeviceDriverHandlers[cb_idx] = NULL;
719}
720
721
722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
723/**
724 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
725 * allocated per MPT adapter.
726 * @handle: Handle of registered MPT protocol driver
727 * @ioc: Pointer to MPT adapter structure
728 *
729 * Returns pointer to a MPT request frame or %NULL if none are available
730 * or IOC is not active.
731 */
732MPT_FRAME_HDR*
733mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
734{
735 MPT_FRAME_HDR *mf;
736 unsigned long flags;
737 u16 req_idx; /* Request index */
738
739 /* validate handle and ioc identifier */
740
741#ifdef MFCNT
742 if (!ioc->active)
743 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
744#endif
745
746 /* If interrupts are not attached, do not return a request frame */
747 if (!ioc->active)
748 return NULL;
749
750 spin_lock_irqsave(&ioc->FreeQlock, flags);
751 if (!list_empty(&ioc->FreeQ)) {
752 int req_offset;
753
754 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
755 u.frame.linkage.list);
756 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200757 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
759 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
760 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500761 req_idx = req_offset / ioc->req_sz;
762 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
764 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
765#ifdef MFCNT
766 ioc->mfcnt++;
767#endif
768 }
769 else
770 mf = NULL;
771 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
772
773#ifdef MFCNT
774 if (mf == NULL)
775 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
776 mfcounter++;
777 if (mfcounter == PRINT_MF_COUNT)
778 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
779#endif
780
781 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
782 ioc->name, handle, ioc->id, mf));
783 return mf;
784}
785
786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
787/**
788 * mpt_put_msg_frame - Send a protocol specific MPT request frame
789 * to a IOC.
790 * @handle: Handle of registered MPT protocol driver
791 * @ioc: Pointer to MPT adapter structure
792 * @mf: Pointer to MPT request frame
793 *
794 * This routine posts a MPT request frame to the request post FIFO of a
795 * specific MPT adapter.
796 */
797void
798mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
799{
800 u32 mf_dma_addr;
801 int req_offset;
802 u16 req_idx; /* Request index */
803
804 /* ensure values are reset properly! */
805 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
806 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
807 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500808 req_idx = req_offset / ioc->req_sz;
809 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
811
812#ifdef MPT_DEBUG_MSG_FRAME
813 {
814 u32 *m = mf->u.frame.hwhdr.__hdr;
815 int ii, n;
816
817 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
818 ioc->name, m);
819 n = ioc->req_sz/4 - 1;
820 while (m[n] == 0)
821 n--;
822 for (ii=0; ii<=n; ii++) {
823 if (ii && ((ii%8)==0))
824 printk("\n" KERN_INFO " ");
825 printk(" %08x", le32_to_cpu(m[ii]));
826 }
827 printk("\n");
828 }
829#endif
830
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200831 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 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]));
833 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
834}
835
836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
837/**
838 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
839 * @handle: Handle of registered MPT protocol driver
840 * @ioc: Pointer to MPT adapter structure
841 * @mf: Pointer to MPT request frame
842 *
843 * This routine places a MPT request frame back on the MPT adapter's
844 * FreeQ.
845 */
846void
847mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
848{
849 unsigned long flags;
850
851 /* Put Request back on FreeQ! */
852 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200853 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
855#ifdef MFCNT
856 ioc->mfcnt--;
857#endif
858 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
859}
860
861/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
862/**
863 * mpt_add_sge - Place a simple SGE at address pAddr.
864 * @pAddr: virtual address for SGE
865 * @flagslength: SGE flags and data transfer length
866 * @dma_addr: Physical address
867 *
868 * This routine places a MPT request frame back on the MPT adapter's
869 * FreeQ.
870 */
871void
872mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
873{
874 if (sizeof(dma_addr_t) == sizeof(u64)) {
875 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
876 u32 tmp = dma_addr & 0xFFFFFFFF;
877
878 pSge->FlagsLength = cpu_to_le32(flagslength);
879 pSge->Address.Low = cpu_to_le32(tmp);
880 tmp = (u32) ((u64)dma_addr >> 32);
881 pSge->Address.High = cpu_to_le32(tmp);
882
883 } else {
884 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
885 pSge->FlagsLength = cpu_to_le32(flagslength);
886 pSge->Address = cpu_to_le32(dma_addr);
887 }
888}
889
890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
891/**
892 * mpt_send_handshake_request - Send MPT request via doorbell
893 * handshake method.
894 * @handle: Handle of registered MPT protocol driver
895 * @ioc: Pointer to MPT adapter structure
896 * @reqBytes: Size of the request in bytes
897 * @req: Pointer to MPT request frame
898 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
899 *
900 * This routine is used exclusively to send MptScsiTaskMgmt
901 * requests since they are required to be sent via doorbell handshake.
902 *
903 * NOTE: It is the callers responsibility to byte-swap fields in the
904 * request which are greater than 1 byte in size.
905 *
906 * Returns 0 for success, non-zero for failure.
907 */
908int
909mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
910{
911 int r = 0;
912 u8 *req_as_bytes;
913 int ii;
914
915 /* State is known to be good upon entering
916 * this function so issue the bus reset
917 * request.
918 */
919
920 /*
921 * Emulate what mpt_put_msg_frame() does /wrt to sanity
922 * setting cb_idx/req_idx. But ONLY if this request
923 * is in proper (pre-alloc'd) request buffer range...
924 */
925 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
926 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
927 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
928 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
929 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
930 }
931
932 /* Make sure there are no doorbells */
933 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 CHIPREG_WRITE32(&ioc->chip->Doorbell,
936 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
937 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
938
939 /* Wait for IOC doorbell int */
940 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
941 return ii;
942 }
943
944 /* Read doorbell and check for active bit */
945 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
946 return -5;
947
948 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200949 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
952
953 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
954 return -2;
955 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 /* Send request via doorbell handshake */
958 req_as_bytes = (u8 *) req;
959 for (ii = 0; ii < reqBytes/4; ii++) {
960 u32 word;
961
962 word = ((req_as_bytes[(ii*4) + 0] << 0) |
963 (req_as_bytes[(ii*4) + 1] << 8) |
964 (req_as_bytes[(ii*4) + 2] << 16) |
965 (req_as_bytes[(ii*4) + 3] << 24));
966 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
967 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
968 r = -3;
969 break;
970 }
971 }
972
973 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
974 r = 0;
975 else
976 r = -4;
977
978 /* Make sure there are no doorbells */
979 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return r;
982}
983
984/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
985/**
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200986 * mpt_host_page_access_control - provides mechanism for the host
987 * driver to control the IOC's Host Page Buffer access.
988 * @ioc: Pointer to MPT adapter structure
989 * @access_control_value: define bits below
990 *
991 * Access Control Value - bits[15:12]
992 * 0h Reserved
993 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
994 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
995 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
996 *
997 * Returns 0 for success, non-zero for failure.
998 */
999
1000static int
1001mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1002{
1003 int r = 0;
1004
1005 /* return if in use */
1006 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1007 & MPI_DOORBELL_ACTIVE)
1008 return -1;
1009
1010 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1011
1012 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1013 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1014 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1015 (access_control_value<<12)));
1016
1017 /* Wait for IOC to clear Doorbell Status bit */
1018 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1019 return -2;
1020 }else
1021 return 0;
1022}
1023
1024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1025/**
1026 * mpt_host_page_alloc - allocate system memory for the fw
1027 * If we already allocated memory in past, then resend the same pointer.
1028 * ioc@: Pointer to pointer to IOC adapter
1029 * ioc_init@: Pointer to ioc init config page
1030 *
1031 * Returns 0 for success, non-zero for failure.
1032 */
1033static int
1034mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1035{
1036 char *psge;
1037 int flags_length;
1038 u32 host_page_buffer_sz=0;
1039
1040 if(!ioc->HostPageBuffer) {
1041
1042 host_page_buffer_sz =
1043 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1044
1045 if(!host_page_buffer_sz)
1046 return 0; /* fw doesn't need any host buffers */
1047
1048 /* spin till we get enough memory */
1049 while(host_page_buffer_sz > 0) {
1050
1051 if((ioc->HostPageBuffer = pci_alloc_consistent(
1052 ioc->pcidev,
1053 host_page_buffer_sz,
1054 &ioc->HostPageBuffer_dma)) != NULL) {
1055
1056 dinitprintk((MYIOC_s_INFO_FMT
1057 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1058 ioc->name,
1059 ioc->HostPageBuffer,
1060 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001061 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001062 ioc->alloc_total += host_page_buffer_sz;
1063 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1064 break;
1065 }
1066
1067 host_page_buffer_sz -= (4*1024);
1068 }
1069 }
1070
1071 if(!ioc->HostPageBuffer) {
1072 printk(MYIOC_s_ERR_FMT
1073 "Failed to alloc memory for host_page_buffer!\n",
1074 ioc->name);
1075 return -999;
1076 }
1077
1078 psge = (char *)&ioc_init->HostPageBufferSGE;
1079 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1080 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1081 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1082 MPI_SGE_FLAGS_HOST_TO_IOC |
1083 MPI_SGE_FLAGS_END_OF_BUFFER;
1084 if (sizeof(dma_addr_t) == sizeof(u64)) {
1085 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1086 }
1087 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1088 flags_length |= ioc->HostPageBuffer_sz;
1089 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1090 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1091
1092return 0;
1093}
1094
1095/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1096/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1098 * the associated MPT adapter structure.
1099 * @iocid: IOC unique identifier (integer)
1100 * @iocpp: Pointer to pointer to IOC adapter
1101 *
1102 * Returns iocid and sets iocpp.
1103 */
1104int
1105mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1106{
1107 MPT_ADAPTER *ioc;
1108
1109 list_for_each_entry(ioc,&ioc_list,list) {
1110 if (ioc->id == iocid) {
1111 *iocpp =ioc;
1112 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 *iocpp = NULL;
1117 return -1;
1118}
1119
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001120int
1121mpt_alt_ioc_wait(MPT_ADAPTER *ioc)
1122{
1123 int loop_count = 30 * 4; /* Wait 30 seconds */
1124 int status = -1; /* -1 means failed to get board READY */
1125
1126 do {
1127 spin_lock(&ioc->initializing_hba_lock);
1128 if (ioc->initializing_hba_lock_flag == 0) {
1129 ioc->initializing_hba_lock_flag=1;
1130 spin_unlock(&ioc->initializing_hba_lock);
1131 status = 0;
1132 break;
1133 }
1134 spin_unlock(&ioc->initializing_hba_lock);
1135 set_current_state(TASK_INTERRUPTIBLE);
1136 schedule_timeout(HZ/4);
1137 } while (--loop_count);
1138
1139 return status;
1140}
1141
1142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1143/*
1144 * mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery
1145 * @ioc: Pointer to MPT adapter structure
1146 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1147 *
1148 * This routine performs all the steps necessary to bring the IOC
1149 * to a OPERATIONAL state.
1150 *
1151 * Special Note: This function was added with spin lock's so as to allow
1152 * the dv(domain validation) work thread to succeed on the other channel
1153 * that maybe occuring at the same time when this function is called.
1154 * Without this lock, the dv would fail when message frames were
1155 * requested during hba bringup on the alternate ioc.
1156 */
1157static int
1158mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag)
1159{
1160 int r;
1161
1162 if(ioc->alt_ioc) {
1163 if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0))
1164 return r;
1165 }
1166
1167 r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1168 CAN_SLEEP);
1169
1170 if(ioc->alt_ioc) {
1171 spin_lock(&ioc->alt_ioc->initializing_hba_lock);
1172 ioc->alt_ioc->initializing_hba_lock_flag=0;
1173 spin_unlock(&ioc->alt_ioc->initializing_hba_lock);
1174 }
1175
1176return r;
1177}
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1180/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001181 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 * @pdev: Pointer to pci_dev structure
1183 *
1184 * This routine performs all the steps necessary to bring the IOC of
1185 * a MPT adapter to a OPERATIONAL state. This includes registering
1186 * memory regions, registering the interrupt, and allocating request
1187 * and reply memory pools.
1188 *
1189 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1190 * MPT adapter.
1191 *
1192 * Returns 0 for success, non-zero for failure.
1193 *
1194 * TODO: Add support for polled controllers
1195 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001196int
1197mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
1199 MPT_ADAPTER *ioc;
1200 u8 __iomem *mem;
1201 unsigned long mem_phys;
1202 unsigned long port;
1203 u32 msize;
1204 u32 psize;
1205 int ii;
1206 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 u8 revision;
1208 u8 pcixcmd;
1209 static int mpt_ids = 0;
1210#ifdef CONFIG_PROC_FS
1211 struct proc_dir_entry *dent, *ent;
1212#endif
1213
1214 if (pci_enable_device(pdev))
1215 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001216
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001218
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001219 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 dprintk((KERN_INFO MYNAM
1221 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001222 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1224 return r;
1225 }
1226
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001227 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 dprintk((KERN_INFO MYNAM
1229 ": Using 64 bit consistent mask\n"));
1230 else
1231 dprintk((KERN_INFO MYNAM
1232 ": Not using 64 bit consistent mask\n"));
1233
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001234 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (ioc == NULL) {
1236 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1237 return -ENOMEM;
1238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 ioc->alloc_total = sizeof(MPT_ADAPTER);
1240 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1241 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 ioc->pcidev = pdev;
1244 ioc->diagPending = 0;
1245 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001246 spin_lock_init(&ioc->fc_rescan_work_lock);
1247 spin_lock_init(&ioc->fc_rport_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001248 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 /* Initialize the event logging.
1251 */
1252 ioc->eventTypes = 0; /* None */
1253 ioc->eventContext = 0;
1254 ioc->eventLogSize = 0;
1255 ioc->events = NULL;
1256
1257#ifdef MFCNT
1258 ioc->mfcnt = 0;
1259#endif
1260
1261 ioc->cached_fw = NULL;
1262
1263 /* Initilize SCSI Config Data structure
1264 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001265 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267 /* Initialize the running configQ head.
1268 */
1269 INIT_LIST_HEAD(&ioc->configQ);
1270
Michael Reed05e8ec12006-01-13 14:31:54 -06001271 /* Initialize the fc rport list head.
1272 */
1273 INIT_LIST_HEAD(&ioc->fc_rports);
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 /* Find lookup slot. */
1276 INIT_LIST_HEAD(&ioc->list);
1277 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 mem_phys = msize = 0;
1280 port = psize = 0;
1281 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1282 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1283 /* Get I/O space! */
1284 port = pci_resource_start(pdev, ii);
1285 psize = pci_resource_len(pdev,ii);
1286 } else {
1287 /* Get memmap */
1288 mem_phys = pci_resource_start(pdev, ii);
1289 msize = pci_resource_len(pdev,ii);
1290 break;
1291 }
1292 }
1293 ioc->mem_size = msize;
1294
1295 if (ii == DEVICE_COUNT_RESOURCE) {
1296 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1297 kfree(ioc);
1298 return -EINVAL;
1299 }
1300
1301 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1302 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1303
1304 mem = NULL;
1305 /* Get logical ptr for PciMem0 space */
1306 /*mem = ioremap(mem_phys, msize);*/
1307 mem = ioremap(mem_phys, 0x100);
1308 if (mem == NULL) {
1309 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1310 kfree(ioc);
1311 return -EINVAL;
1312 }
1313 ioc->memmap = mem;
1314 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1315
1316 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1317 &ioc->facts, &ioc->pfacts[0]));
1318
1319 ioc->mem_phys = mem_phys;
1320 ioc->chip = (SYSIF_REGS __iomem *)mem;
1321
1322 /* Save Port IO values in case we need to do downloadboot */
1323 {
1324 u8 *pmem = (u8*)port;
1325 ioc->pio_mem_phys = port;
1326 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1327 }
1328
1329 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1330 ioc->prod_name = "LSIFC909";
1331 ioc->bus_type = FC;
1332 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 ioc->prod_name = "LSIFC929";
1335 ioc->bus_type = FC;
1336 }
1337 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1338 ioc->prod_name = "LSIFC919";
1339 ioc->bus_type = FC;
1340 }
1341 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1342 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1343 ioc->bus_type = FC;
1344 if (revision < XL_929) {
1345 ioc->prod_name = "LSIFC929X";
1346 /* 929X Chip Fix. Set Split transactions level
1347 * for PCIX. Set MOST bits to zero.
1348 */
1349 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1350 pcixcmd &= 0x8F;
1351 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1352 } else {
1353 ioc->prod_name = "LSIFC929XL";
1354 /* 929XL Chip Fix. Set MMRBC to 0x08.
1355 */
1356 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1357 pcixcmd |= 0x08;
1358 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1359 }
1360 }
1361 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1362 ioc->prod_name = "LSIFC919X";
1363 ioc->bus_type = FC;
1364 /* 919X Chip Fix. Set Split transactions level
1365 * for PCIX. Set MOST bits to zero.
1366 */
1367 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1368 pcixcmd &= 0x8F;
1369 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1370 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001371 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1372 ioc->prod_name = "LSIFC939X";
1373 ioc->bus_type = FC;
1374 ioc->errata_flag_1064 = 1;
1375 }
1376 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1377 ioc->prod_name = "LSIFC949X";
1378 ioc->bus_type = FC;
1379 ioc->errata_flag_1064 = 1;
1380 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001381 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1382 ioc->prod_name = "LSIFC949E";
1383 ioc->bus_type = FC;
1384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1386 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001387 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 /* 1030 Chip Fix. Disable Split transactions
1389 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1390 */
1391 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1392 if (revision < C0_1030) {
1393 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1394 pcixcmd &= 0x8F;
1395 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1396 }
1397 }
1398 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1399 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001400 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001402 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1403 ioc->prod_name = "LSISAS1064";
1404 ioc->bus_type = SAS;
1405 ioc->errata_flag_1064 = 1;
1406 }
1407 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1408 ioc->prod_name = "LSISAS1066";
1409 ioc->bus_type = SAS;
1410 ioc->errata_flag_1064 = 1;
1411 }
1412 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1413 ioc->prod_name = "LSISAS1068";
1414 ioc->bus_type = SAS;
1415 ioc->errata_flag_1064 = 1;
1416 }
1417 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1418 ioc->prod_name = "LSISAS1064E";
1419 ioc->bus_type = SAS;
1420 }
1421 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1422 ioc->prod_name = "LSISAS1066E";
1423 ioc->bus_type = SAS;
1424 }
1425 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1426 ioc->prod_name = "LSISAS1068E";
1427 ioc->bus_type = SAS;
1428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001430 if (ioc->errata_flag_1064)
1431 pci_disable_io_access(pdev);
1432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 sprintf(ioc->name, "ioc%d", ioc->id);
1434
1435 spin_lock_init(&ioc->FreeQlock);
1436
1437 /* Disable all! */
1438 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1439 ioc->active = 0;
1440 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1441
1442 /* Set lookup ptr. */
1443 list_add_tail(&ioc->list, &ioc_list);
1444
1445 ioc->pci_irq = -1;
1446 if (pdev->irq) {
1447 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1448
1449 if (r < 0) {
1450#ifndef __sparc__
1451 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1452 ioc->name, pdev->irq);
1453#else
1454 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1455 ioc->name, __irq_itoa(pdev->irq));
1456#endif
1457 list_del(&ioc->list);
1458 iounmap(mem);
1459 kfree(ioc);
1460 return -EBUSY;
1461 }
1462
1463 ioc->pci_irq = pdev->irq;
1464
1465 pci_set_master(pdev); /* ?? */
1466 pci_set_drvdata(pdev, ioc);
1467
1468#ifndef __sparc__
1469 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1470#else
1471 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1472#endif
1473 }
1474
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001475 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 */
1477 mpt_detect_bound_ports(ioc, pdev);
1478
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001479 if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 printk(KERN_WARNING MYNAM
1481 ": WARNING - %s did not initialize properly! (%d)\n",
1482 ioc->name, r);
1483
1484 list_del(&ioc->list);
1485 free_irq(ioc->pci_irq, ioc);
1486 iounmap(mem);
1487 kfree(ioc);
1488 pci_set_drvdata(pdev, NULL);
1489 return r;
1490 }
1491
1492 /* call per device driver probe entry point */
1493 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1494 if(MptDeviceDriverHandlers[ii] &&
1495 MptDeviceDriverHandlers[ii]->probe) {
1496 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1497 }
1498 }
1499
1500#ifdef CONFIG_PROC_FS
1501 /*
1502 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1503 */
1504 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1505 if (dent) {
1506 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1507 if (ent) {
1508 ent->read_proc = procmpt_iocinfo_read;
1509 ent->data = ioc;
1510 }
1511 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1512 if (ent) {
1513 ent->read_proc = procmpt_summary_read;
1514 ent->data = ioc;
1515 }
1516 }
1517#endif
1518
1519 return 0;
1520}
1521
1522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1523/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001524 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 * @pdev: Pointer to pci_dev structure
1526 *
1527 */
1528
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001529void
1530mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1533 char pname[32];
1534 int ii;
1535
1536 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1537 remove_proc_entry(pname, NULL);
1538 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1539 remove_proc_entry(pname, NULL);
1540 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1541 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 /* call per device driver remove entry point */
1544 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1545 if(MptDeviceDriverHandlers[ii] &&
1546 MptDeviceDriverHandlers[ii]->remove) {
1547 MptDeviceDriverHandlers[ii]->remove(pdev);
1548 }
1549 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 /* Disable interrupts! */
1552 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1553
1554 ioc->active = 0;
1555 synchronize_irq(pdev->irq);
1556
1557 /* Clear any lingering interrupt */
1558 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1559
1560 CHIPREG_READ32(&ioc->chip->IntStatus);
1561
1562 mpt_adapter_dispose(ioc);
1563
1564 pci_set_drvdata(pdev, NULL);
1565}
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567/**************************************************************************
1568 * Power Management
1569 */
1570#ifdef CONFIG_PM
1571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1572/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001573 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 *
1575 *
1576 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001577int
1578mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579{
1580 u32 device_state;
1581 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Pavel Machek2a569572005-07-07 17:56:40 -07001583 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 printk(MYIOC_s_INFO_FMT
1586 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1587 ioc->name, pdev, pci_name(pdev), device_state);
1588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 pci_save_state(pdev);
1590
1591 /* put ioc into READY_STATE */
1592 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1593 printk(MYIOC_s_ERR_FMT
1594 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1595 }
1596
1597 /* disable interrupts */
1598 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1599 ioc->active = 0;
1600
1601 /* Clear any lingering interrupt */
1602 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1603
1604 pci_disable_device(pdev);
1605 pci_set_power_state(pdev, device_state);
1606
1607 return 0;
1608}
1609
1610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1611/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001612 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 *
1614 *
1615 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001616int
1617mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
1619 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1620 u32 device_state = pdev->current_state;
1621 int recovery_state;
1622 int ii;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001623
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 printk(MYIOC_s_INFO_FMT
1625 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1626 ioc->name, pdev, pci_name(pdev), device_state);
1627
1628 pci_set_power_state(pdev, 0);
1629 pci_restore_state(pdev);
1630 pci_enable_device(pdev);
1631
1632 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001633 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 ioc->active = 1;
1635
1636 /* F/W not running */
1637 if(!CHIPREG_READ32(&ioc->chip->Doorbell)) {
1638 /* enable domain validation flags */
1639 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
1640 ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV;
1641 }
1642 }
1643
1644 printk(MYIOC_s_INFO_FMT
1645 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1646 ioc->name,
1647 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1648 CHIPREG_READ32(&ioc->chip->Doorbell));
1649
1650 /* bring ioc to operational state */
1651 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1652 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1653 printk(MYIOC_s_INFO_FMT
1654 "pci-resume: Cannot recover, error:[%x]\n",
1655 ioc->name, recovery_state);
1656 } else {
1657 printk(MYIOC_s_INFO_FMT
1658 "pci-resume: success\n", ioc->name);
1659 }
1660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 return 0;
1662}
1663#endif
1664
1665/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1666/*
1667 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1668 * @ioc: Pointer to MPT adapter structure
1669 * @reason: Event word / reason
1670 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1671 *
1672 * This routine performs all the steps necessary to bring the IOC
1673 * to a OPERATIONAL state.
1674 *
1675 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1676 * MPT adapter.
1677 *
1678 * Returns:
1679 * 0 for success
1680 * -1 if failed to get board READY
1681 * -2 if READY but IOCFacts Failed
1682 * -3 if READY but PrimeIOCFifos Failed
1683 * -4 if READY but IOCInit Failed
1684 */
1685static int
1686mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1687{
1688 int hard_reset_done = 0;
1689 int alt_ioc_ready = 0;
1690 int hard;
1691 int rc=0;
1692 int ii;
1693 int handlers;
1694 int ret = 0;
1695 int reset_alt_ioc_active = 0;
1696
1697 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1698 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1699
1700 /* Disable reply interrupts (also blocks FreeQ) */
1701 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1702 ioc->active = 0;
1703
1704 if (ioc->alt_ioc) {
1705 if (ioc->alt_ioc->active)
1706 reset_alt_ioc_active = 1;
1707
1708 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1709 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1710 ioc->alt_ioc->active = 0;
1711 }
1712
1713 hard = 1;
1714 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1715 hard = 0;
1716
1717 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1718 if (hard_reset_done == -4) {
1719 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1720 ioc->name);
1721
1722 if (reset_alt_ioc_active && ioc->alt_ioc) {
1723 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1724 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1725 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001726 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 ioc->alt_ioc->active = 1;
1728 }
1729
1730 } else {
1731 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1732 ioc->name);
1733 }
1734 return -1;
1735 }
1736
1737 /* hard_reset_done = 0 if a soft reset was performed
1738 * and 1 if a hard reset was performed.
1739 */
1740 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1741 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1742 alt_ioc_ready = 1;
1743 else
1744 printk(KERN_WARNING MYNAM
1745 ": alt-%s: Not ready WARNING!\n",
1746 ioc->alt_ioc->name);
1747 }
1748
1749 for (ii=0; ii<5; ii++) {
1750 /* Get IOC facts! Allow 5 retries */
1751 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1752 break;
1753 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 if (ii == 5) {
1757 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1758 ret = -2;
1759 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1760 MptDisplayIocCapabilities(ioc);
1761 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 if (alt_ioc_ready) {
1764 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1765 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1766 /* Retry - alt IOC was initialized once
1767 */
1768 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1769 }
1770 if (rc) {
1771 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1772 alt_ioc_ready = 0;
1773 reset_alt_ioc_active = 0;
1774 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1775 MptDisplayIocCapabilities(ioc->alt_ioc);
1776 }
1777 }
1778
1779 /* Prime reply & request queues!
1780 * (mucho alloc's) Must be done prior to
1781 * init as upper addresses are needed for init.
1782 * If fails, continue with alt-ioc processing
1783 */
1784 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1785 ret = -3;
1786
1787 /* May need to check/upload firmware & data here!
1788 * If fails, continue with alt-ioc processing
1789 */
1790 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1791 ret = -4;
1792// NEW!
1793 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1794 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1795 ioc->alt_ioc->name, rc);
1796 alt_ioc_ready = 0;
1797 reset_alt_ioc_active = 0;
1798 }
1799
1800 if (alt_ioc_ready) {
1801 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1802 alt_ioc_ready = 0;
1803 reset_alt_ioc_active = 0;
1804 printk(KERN_WARNING MYNAM
1805 ": alt-%s: (%d) init failure WARNING!\n",
1806 ioc->alt_ioc->name, rc);
1807 }
1808 }
1809
1810 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1811 if (ioc->upload_fw) {
1812 ddlprintk((MYIOC_s_INFO_FMT
1813 "firmware upload required!\n", ioc->name));
1814
1815 /* Controller is not operational, cannot do upload
1816 */
1817 if (ret == 0) {
1818 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001819 if (rc == 0) {
1820 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1821 /*
1822 * Maintain only one pointer to FW memory
1823 * so there will not be two attempt to
1824 * downloadboot onboard dual function
1825 * chips (mpt_adapter_disable,
1826 * mpt_diag_reset)
1827 */
1828 ioc->cached_fw = NULL;
1829 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1830 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1831 }
1832 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001834 ret = -5;
1835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
1837 }
1838 }
1839
1840 if (ret == 0) {
1841 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001842 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 ioc->active = 1;
1844 }
1845
1846 if (reset_alt_ioc_active && ioc->alt_ioc) {
1847 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001848 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001850 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 ioc->alt_ioc->active = 1;
1852 }
1853
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001854 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 * and EventAck handling.
1856 */
1857 if ((ret == 0) && (!ioc->facts.EventState))
1858 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1859
1860 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1861 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1862
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001863 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1865 * recursive scenario; GetLanConfigPages times out, timer expired
1866 * routine calls HardResetHandler, which calls into here again,
1867 * and we try GetLanConfigPages again...
1868 */
1869 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001870 if (ioc->bus_type == SAS) {
1871
1872 /* clear persistency table */
1873 if(ioc->facts.IOCExceptions &
1874 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1875 ret = mptbase_sas_persist_operation(ioc,
1876 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1877 if(ret != 0)
1878 return -1;
1879 }
1880
1881 /* Find IM volumes
1882 */
1883 mpt_findImVolumes(ioc);
1884
1885 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 /*
1887 * Pre-fetch FC port WWN and stuff...
1888 * (FCPortPage0_t stuff)
1889 */
1890 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001891 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893
1894 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1895 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1896 /*
1897 * Pre-fetch the ports LAN MAC address!
1898 * (LANPage1_t stuff)
1899 */
1900 (void) GetLanConfigPages(ioc);
1901#ifdef MPT_DEBUG
1902 {
1903 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1904 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1905 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1906 }
1907#endif
1908 }
1909 } else {
1910 /* Get NVRAM and adapter maximums from SPP 0 and 2
1911 */
1912 mpt_GetScsiPortSettings(ioc, 0);
1913
1914 /* Get version and length of SDP 1
1915 */
1916 mpt_readScsiDevicePageHeaders(ioc, 0);
1917
1918 /* Find IM volumes
1919 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001920 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 mpt_findImVolumes(ioc);
1922
1923 /* Check, and possibly reset, the coalescing value
1924 */
1925 mpt_read_ioc_pg_1(ioc);
1926
1927 mpt_read_ioc_pg_4(ioc);
1928 }
1929
1930 GetIoUnitPage2(ioc);
1931 }
1932
1933 /*
1934 * Call each currently registered protocol IOC reset handler
1935 * with post-reset indication.
1936 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1937 * MptResetHandlers[] registered yet.
1938 */
1939 if (hard_reset_done) {
1940 rc = handlers = 0;
1941 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1942 if ((ret == 0) && MptResetHandlers[ii]) {
1943 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1944 ioc->name, ii));
1945 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1946 handlers++;
1947 }
1948
1949 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001950 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 ioc->name, ioc->alt_ioc->name, ii));
1952 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1953 handlers++;
1954 }
1955 }
1956 /* FIXME? Examine results here? */
1957 }
1958
1959 return ret;
1960}
1961
1962/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1963/*
1964 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1965 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1966 * 929X, 1030 or 1035.
1967 * @ioc: Pointer to MPT adapter structure
1968 * @pdev: Pointer to (struct pci_dev) structure
1969 *
1970 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1971 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1972 */
1973static void
1974mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1975{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001976 struct pci_dev *peer=NULL;
1977 unsigned int slot = PCI_SLOT(pdev->devfn);
1978 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 MPT_ADAPTER *ioc_srch;
1980
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001981 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1982 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001983 ioc->name, pci_name(pdev), pdev->bus->number,
1984 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001985
1986 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1987 if (!peer) {
1988 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1989 if (!peer)
1990 return;
1991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 list_for_each_entry(ioc_srch, &ioc_list, list) {
1994 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001995 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 /* Paranoia checks */
1997 if (ioc->alt_ioc != NULL) {
1998 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001999 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 break;
2001 } else if (ioc_srch->alt_ioc != NULL) {
2002 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002003 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 break;
2005 }
2006 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002007 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 ioc_srch->alt_ioc = ioc;
2009 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 }
2011 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002012 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013}
2014
2015/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2016/*
2017 * mpt_adapter_disable - Disable misbehaving MPT adapter.
2018 * @this: Pointer to MPT adapter structure
2019 */
2020static void
2021mpt_adapter_disable(MPT_ADAPTER *ioc)
2022{
2023 int sz;
2024 int ret;
2025
2026 if (ioc->cached_fw != NULL) {
2027 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002028 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 printk(KERN_WARNING MYNAM
2030 ": firmware downloadboot failure (%d)!\n", ret);
2031 }
2032 }
2033
2034 /* Disable adapter interrupts! */
2035 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2036 ioc->active = 0;
2037 /* Clear any lingering interrupt */
2038 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2039
2040 if (ioc->alloc != NULL) {
2041 sz = ioc->alloc_sz;
2042 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2043 ioc->name, ioc->alloc, ioc->alloc_sz));
2044 pci_free_consistent(ioc->pcidev, sz,
2045 ioc->alloc, ioc->alloc_dma);
2046 ioc->reply_frames = NULL;
2047 ioc->req_frames = NULL;
2048 ioc->alloc = NULL;
2049 ioc->alloc_total -= sz;
2050 }
2051
2052 if (ioc->sense_buf_pool != NULL) {
2053 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2054 pci_free_consistent(ioc->pcidev, sz,
2055 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2056 ioc->sense_buf_pool = NULL;
2057 ioc->alloc_total -= sz;
2058 }
2059
2060 if (ioc->events != NULL){
2061 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2062 kfree(ioc->events);
2063 ioc->events = NULL;
2064 ioc->alloc_total -= sz;
2065 }
2066
2067 if (ioc->cached_fw != NULL) {
2068 sz = ioc->facts.FWImageSize;
2069 pci_free_consistent(ioc->pcidev, sz,
2070 ioc->cached_fw, ioc->cached_fw_dma);
2071 ioc->cached_fw = NULL;
2072 ioc->alloc_total -= sz;
2073 }
2074
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002075 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002076 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002077 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002078 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 if (ioc->spi_data.pIocPg4 != NULL) {
2081 sz = ioc->spi_data.IocPg4Sz;
2082 pci_free_consistent(ioc->pcidev, sz,
2083 ioc->spi_data.pIocPg4,
2084 ioc->spi_data.IocPg4_dma);
2085 ioc->spi_data.pIocPg4 = NULL;
2086 ioc->alloc_total -= sz;
2087 }
2088
2089 if (ioc->ReqToChain != NULL) {
2090 kfree(ioc->ReqToChain);
2091 kfree(ioc->RequestNB);
2092 ioc->ReqToChain = NULL;
2093 }
2094
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002095 kfree(ioc->ChainToChain);
2096 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002097
2098 if (ioc->HostPageBuffer != NULL) {
2099 if((ret = mpt_host_page_access_control(ioc,
2100 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2101 printk(KERN_ERR MYNAM
2102 ": %s: host page buffers free failed (%d)!\n",
2103 __FUNCTION__, ret);
2104 }
2105 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2106 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2107 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2108 ioc->HostPageBuffer,
2109 ioc->HostPageBuffer_dma);
2110 ioc->HostPageBuffer = NULL;
2111 ioc->HostPageBuffer_sz = 0;
2112 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114}
2115
2116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2117/*
2118 * mpt_adapter_dispose - Free all resources associated with a MPT
2119 * adapter.
2120 * @ioc: Pointer to MPT adapter structure
2121 *
2122 * This routine unregisters h/w resources and frees all alloc'd memory
2123 * associated with a MPT adapter structure.
2124 */
2125static void
2126mpt_adapter_dispose(MPT_ADAPTER *ioc)
2127{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002128 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002130 if (ioc == NULL)
2131 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002133 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002135 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002137 if (ioc->pci_irq != -1) {
2138 free_irq(ioc->pci_irq, ioc);
2139 ioc->pci_irq = -1;
2140 }
2141
2142 if (ioc->memmap != NULL) {
2143 iounmap(ioc->memmap);
2144 ioc->memmap = NULL;
2145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
2147#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002148 if (ioc->mtrr_reg > 0) {
2149 mtrr_del(ioc->mtrr_reg, 0, 0);
2150 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152#endif
2153
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002154 /* Zap the adapter lookup ptr! */
2155 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002157 sz_last = ioc->alloc_total;
2158 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2159 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
2160 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161}
2162
2163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2164/*
2165 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2166 * @ioc: Pointer to MPT adapter structure
2167 */
2168static void
2169MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2170{
2171 int i = 0;
2172
2173 printk(KERN_INFO "%s: ", ioc->name);
2174 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2175 printk("%s: ", ioc->prod_name+3);
2176 printk("Capabilities={");
2177
2178 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2179 printk("Initiator");
2180 i++;
2181 }
2182
2183 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2184 printk("%sTarget", i ? "," : "");
2185 i++;
2186 }
2187
2188 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2189 printk("%sLAN", i ? "," : "");
2190 i++;
2191 }
2192
2193#if 0
2194 /*
2195 * This would probably evoke more questions than it's worth
2196 */
2197 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2198 printk("%sLogBusAddr", i ? "," : "");
2199 i++;
2200 }
2201#endif
2202
2203 printk("}\n");
2204}
2205
2206/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2207/*
2208 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2209 * @ioc: Pointer to MPT_ADAPTER structure
2210 * @force: Force hard KickStart of IOC
2211 * @sleepFlag: Specifies whether the process can sleep
2212 *
2213 * Returns:
2214 * 1 - DIAG reset and READY
2215 * 0 - READY initially OR soft reset and READY
2216 * -1 - Any failure on KickStart
2217 * -2 - Msg Unit Reset Failed
2218 * -3 - IO Unit Reset Failed
2219 * -4 - IOC owned by a PEER
2220 */
2221static int
2222MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2223{
2224 u32 ioc_state;
2225 int statefault = 0;
2226 int cntdn;
2227 int hard_reset_done = 0;
2228 int r;
2229 int ii;
2230 int whoinit;
2231
2232 /* Get current [raw] IOC state */
2233 ioc_state = mpt_GetIocState(ioc, 0);
2234 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2235
2236 /*
2237 * Check to see if IOC got left/stuck in doorbell handshake
2238 * grip of death. If so, hard reset the IOC.
2239 */
2240 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2241 statefault = 1;
2242 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2243 ioc->name);
2244 }
2245
2246 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002247 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return 0;
2249
2250 /*
2251 * Check to see if IOC is in FAULT state.
2252 */
2253 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2254 statefault = 2;
2255 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2256 ioc->name);
2257 printk(KERN_WARNING " FAULT code = %04xh\n",
2258 ioc_state & MPI_DOORBELL_DATA_MASK);
2259 }
2260
2261 /*
2262 * Hmmm... Did it get left operational?
2263 */
2264 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002265 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 ioc->name));
2267
2268 /* Check WhoInit.
2269 * If PCI Peer, exit.
2270 * Else, if no fault conditions are present, issue a MessageUnitReset
2271 * Else, fall through to KickStart case
2272 */
2273 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002274 dinitprintk((KERN_INFO MYNAM
2275 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 whoinit, statefault, force));
2277 if (whoinit == MPI_WHOINIT_PCI_PEER)
2278 return -4;
2279 else {
2280 if ((statefault == 0 ) && (force == 0)) {
2281 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2282 return 0;
2283 }
2284 statefault = 3;
2285 }
2286 }
2287
2288 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2289 if (hard_reset_done < 0)
2290 return -1;
2291
2292 /*
2293 * Loop here waiting for IOC to come READY.
2294 */
2295 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002296 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
2298 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2299 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2300 /*
2301 * BIOS or previous driver load left IOC in OP state.
2302 * Reset messaging FIFOs.
2303 */
2304 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2305 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2306 return -2;
2307 }
2308 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2309 /*
2310 * Something is wrong. Try to get IOC back
2311 * to a known state.
2312 */
2313 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2314 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2315 return -3;
2316 }
2317 }
2318
2319 ii++; cntdn--;
2320 if (!cntdn) {
2321 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2322 ioc->name, (int)((ii+5)/HZ));
2323 return -ETIME;
2324 }
2325
2326 if (sleepFlag == CAN_SLEEP) {
2327 msleep_interruptible(1);
2328 } else {
2329 mdelay (1); /* 1 msec delay */
2330 }
2331
2332 }
2333
2334 if (statefault < 3) {
2335 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2336 ioc->name,
2337 statefault==1 ? "stuck handshake" : "IOC FAULT");
2338 }
2339
2340 return hard_reset_done;
2341}
2342
2343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2344/*
2345 * mpt_GetIocState - Get the current state of a MPT adapter.
2346 * @ioc: Pointer to MPT_ADAPTER structure
2347 * @cooked: Request raw or cooked IOC state
2348 *
2349 * Returns all IOC Doorbell register bits if cooked==0, else just the
2350 * Doorbell bits in MPI_IOC_STATE_MASK.
2351 */
2352u32
2353mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2354{
2355 u32 s, sc;
2356
2357 /* Get! */
2358 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2359// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2360 sc = s & MPI_IOC_STATE_MASK;
2361
2362 /* Save! */
2363 ioc->last_state = sc;
2364
2365 return cooked ? sc : s;
2366}
2367
2368/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2369/*
2370 * GetIocFacts - Send IOCFacts request to MPT adapter.
2371 * @ioc: Pointer to MPT_ADAPTER structure
2372 * @sleepFlag: Specifies whether the process can sleep
2373 * @reason: If recovery, only update facts.
2374 *
2375 * Returns 0 for success, non-zero for failure.
2376 */
2377static int
2378GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2379{
2380 IOCFacts_t get_facts;
2381 IOCFactsReply_t *facts;
2382 int r;
2383 int req_sz;
2384 int reply_sz;
2385 int sz;
2386 u32 status, vv;
2387 u8 shiftFactor=1;
2388
2389 /* IOC *must* NOT be in RESET state! */
2390 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2391 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2392 ioc->name,
2393 ioc->last_state );
2394 return -44;
2395 }
2396
2397 facts = &ioc->facts;
2398
2399 /* Destination (reply area)... */
2400 reply_sz = sizeof(*facts);
2401 memset(facts, 0, reply_sz);
2402
2403 /* Request area (get_facts on the stack right now!) */
2404 req_sz = sizeof(get_facts);
2405 memset(&get_facts, 0, req_sz);
2406
2407 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2408 /* Assert: All other get_facts fields are zero! */
2409
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002410 dinitprintk((MYIOC_s_INFO_FMT
2411 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 ioc->name, req_sz, reply_sz));
2413
2414 /* No non-zero fields in the get_facts request are greater than
2415 * 1 byte in size, so we can just fire it off as is.
2416 */
2417 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2418 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2419 if (r != 0)
2420 return r;
2421
2422 /*
2423 * Now byte swap (GRRR) the necessary fields before any further
2424 * inspection of reply contents.
2425 *
2426 * But need to do some sanity checks on MsgLength (byte) field
2427 * to make sure we don't zero IOC's req_sz!
2428 */
2429 /* Did we get a valid reply? */
2430 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2431 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2432 /*
2433 * If not been here, done that, save off first WhoInit value
2434 */
2435 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2436 ioc->FirstWhoInit = facts->WhoInit;
2437 }
2438
2439 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2440 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2441 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2442 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2443 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002444 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 /* CHECKME! IOCStatus, IOCLogInfo */
2446
2447 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2448 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2449
2450 /*
2451 * FC f/w version changed between 1.1 and 1.2
2452 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2453 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2454 */
2455 if (facts->MsgVersion < 0x0102) {
2456 /*
2457 * Handle old FC f/w style, convert to new...
2458 */
2459 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2460 facts->FWVersion.Word =
2461 ((oldv<<12) & 0xFF000000) |
2462 ((oldv<<8) & 0x000FFF00);
2463 } else
2464 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2465
2466 facts->ProductID = le16_to_cpu(facts->ProductID);
2467 facts->CurrentHostMfaHighAddr =
2468 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2469 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2470 facts->CurrentSenseBufferHighAddr =
2471 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2472 facts->CurReplyFrameSize =
2473 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002474 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
2476 /*
2477 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2478 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2479 * to 14 in MPI-1.01.0x.
2480 */
2481 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2482 facts->MsgVersion > 0x0100) {
2483 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2484 }
2485
2486 sz = facts->FWImageSize;
2487 if ( sz & 0x01 )
2488 sz += 1;
2489 if ( sz & 0x02 )
2490 sz += 2;
2491 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002492
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 if (!facts->RequestFrameSize) {
2494 /* Something is wrong! */
2495 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2496 ioc->name);
2497 return -55;
2498 }
2499
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002500 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 vv = ((63 / (sz * 4)) + 1) & 0x03;
2502 ioc->NB_for_64_byte_frame = vv;
2503 while ( sz )
2504 {
2505 shiftFactor++;
2506 sz = sz >> 1;
2507 }
2508 ioc->NBShiftFactor = shiftFactor;
2509 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2510 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002511
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2513 /*
2514 * Set values for this IOC's request & reply frame sizes,
2515 * and request & reply queue depths...
2516 */
2517 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2518 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2519 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2520 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2521
2522 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2523 ioc->name, ioc->reply_sz, ioc->reply_depth));
2524 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2525 ioc->name, ioc->req_sz, ioc->req_depth));
2526
2527 /* Get port facts! */
2528 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2529 return r;
2530 }
2531 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002532 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2534 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2535 RequestFrameSize)/sizeof(u32)));
2536 return -66;
2537 }
2538
2539 return 0;
2540}
2541
2542/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2543/*
2544 * GetPortFacts - Send PortFacts request to MPT adapter.
2545 * @ioc: Pointer to MPT_ADAPTER structure
2546 * @portnum: Port number
2547 * @sleepFlag: Specifies whether the process can sleep
2548 *
2549 * Returns 0 for success, non-zero for failure.
2550 */
2551static int
2552GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2553{
2554 PortFacts_t get_pfacts;
2555 PortFactsReply_t *pfacts;
2556 int ii;
2557 int req_sz;
2558 int reply_sz;
2559
2560 /* IOC *must* NOT be in RESET state! */
2561 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2562 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2563 ioc->name,
2564 ioc->last_state );
2565 return -4;
2566 }
2567
2568 pfacts = &ioc->pfacts[portnum];
2569
2570 /* Destination (reply area)... */
2571 reply_sz = sizeof(*pfacts);
2572 memset(pfacts, 0, reply_sz);
2573
2574 /* Request area (get_pfacts on the stack right now!) */
2575 req_sz = sizeof(get_pfacts);
2576 memset(&get_pfacts, 0, req_sz);
2577
2578 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2579 get_pfacts.PortNumber = portnum;
2580 /* Assert: All other get_pfacts fields are zero! */
2581
2582 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2583 ioc->name, portnum));
2584
2585 /* No non-zero fields in the get_pfacts request are greater than
2586 * 1 byte in size, so we can just fire it off as is.
2587 */
2588 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2589 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2590 if (ii != 0)
2591 return ii;
2592
2593 /* Did we get a valid reply? */
2594
2595 /* Now byte swap the necessary fields in the response. */
2596 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2597 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2598 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2599 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2600 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2601 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2602 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2603 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2604 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2605
2606 return 0;
2607}
2608
2609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2610/*
2611 * SendIocInit - Send IOCInit request to MPT adapter.
2612 * @ioc: Pointer to MPT_ADAPTER structure
2613 * @sleepFlag: Specifies whether the process can sleep
2614 *
2615 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2616 *
2617 * Returns 0 for success, non-zero for failure.
2618 */
2619static int
2620SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2621{
2622 IOCInit_t ioc_init;
2623 MPIDefaultReply_t init_reply;
2624 u32 state;
2625 int r;
2626 int count;
2627 int cntdn;
2628
2629 memset(&ioc_init, 0, sizeof(ioc_init));
2630 memset(&init_reply, 0, sizeof(init_reply));
2631
2632 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2633 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2634
2635 /* If we are in a recovery mode and we uploaded the FW image,
2636 * then this pointer is not NULL. Skip the upload a second time.
2637 * Set this flag if cached_fw set for either IOC.
2638 */
2639 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2640 ioc->upload_fw = 1;
2641 else
2642 ioc->upload_fw = 0;
2643 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2644 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2645
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002646 if(ioc->bus_type == SAS)
2647 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2648 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2650 else
2651 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002653 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2654 ioc->name, ioc->facts.MsgVersion));
2655 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2656 // set MsgVersion and HeaderVersion host driver was built with
2657 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2658 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002660 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2661 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2662 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2663 return -99;
2664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2666
2667 if (sizeof(dma_addr_t) == sizeof(u64)) {
2668 /* Save the upper 32-bits of the request
2669 * (reply) and sense buffers.
2670 */
2671 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2672 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2673 } else {
2674 /* Force 32-bit addressing */
2675 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2676 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2677 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2680 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002681 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2682 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2685 ioc->name, &ioc_init));
2686
2687 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2688 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002689 if (r != 0) {
2690 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
2694 /* No need to byte swap the multibyte fields in the reply
2695 * since we don't even look at it's contents.
2696 */
2697
2698 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2699 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002700
2701 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2702 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
2706 /* YIKES! SUPER IMPORTANT!!!
2707 * Poll IocState until _OPERATIONAL while IOC is doing
2708 * LoopInit and TargetDiscovery!
2709 */
2710 count = 0;
2711 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2712 state = mpt_GetIocState(ioc, 1);
2713 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2714 if (sleepFlag == CAN_SLEEP) {
2715 msleep_interruptible(1);
2716 } else {
2717 mdelay(1);
2718 }
2719
2720 if (!cntdn) {
2721 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2722 ioc->name, (int)((count+5)/HZ));
2723 return -9;
2724 }
2725
2726 state = mpt_GetIocState(ioc, 1);
2727 count++;
2728 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002729 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 ioc->name, count));
2731
2732 return r;
2733}
2734
2735/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2736/*
2737 * SendPortEnable - Send PortEnable request to MPT adapter port.
2738 * @ioc: Pointer to MPT_ADAPTER structure
2739 * @portnum: Port number to enable
2740 * @sleepFlag: Specifies whether the process can sleep
2741 *
2742 * Send PortEnable to bring IOC to OPERATIONAL state.
2743 *
2744 * Returns 0 for success, non-zero for failure.
2745 */
2746static int
2747SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2748{
2749 PortEnable_t port_enable;
2750 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002751 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 int req_sz;
2753 int reply_sz;
2754
2755 /* Destination... */
2756 reply_sz = sizeof(MPIDefaultReply_t);
2757 memset(&reply_buf, 0, reply_sz);
2758
2759 req_sz = sizeof(PortEnable_t);
2760 memset(&port_enable, 0, req_sz);
2761
2762 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2763 port_enable.PortNumber = portnum;
2764/* port_enable.ChainOffset = 0; */
2765/* port_enable.MsgFlags = 0; */
2766/* port_enable.MsgContext = 0; */
2767
2768 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2769 ioc->name, portnum, &port_enable));
2770
2771 /* RAID FW may take a long time to enable
2772 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002773 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2774 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2775 (ioc->bus_type == SAS)) {
2776 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2777 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2778 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002779 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002780 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2781 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2782 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002784 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785}
2786
2787/*
2788 * ioc: Pointer to MPT_ADAPTER structure
2789 * size - total FW bytes
2790 */
2791void
2792mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2793{
2794 if (ioc->cached_fw)
2795 return; /* use already allocated memory */
2796 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2797 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2798 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2799 } else {
2800 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2801 ioc->alloc_total += size;
2802 }
2803}
2804/*
2805 * If alt_img is NULL, delete from ioc structure.
2806 * Else, delete a secondary image in same format.
2807 */
2808void
2809mpt_free_fw_memory(MPT_ADAPTER *ioc)
2810{
2811 int sz;
2812
2813 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002814 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2816 pci_free_consistent(ioc->pcidev, sz,
2817 ioc->cached_fw, ioc->cached_fw_dma);
2818 ioc->cached_fw = NULL;
2819
2820 return;
2821}
2822
2823
2824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2825/*
2826 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2827 * @ioc: Pointer to MPT_ADAPTER structure
2828 * @sleepFlag: Specifies whether the process can sleep
2829 *
2830 * Returns 0 for success, >0 for handshake failure
2831 * <0 for fw upload failure.
2832 *
2833 * Remark: If bound IOC and a successful FWUpload was performed
2834 * on the bound IOC, the second image is discarded
2835 * and memory is free'd. Both channels must upload to prevent
2836 * IOC from running in degraded mode.
2837 */
2838static int
2839mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2840{
2841 u8 request[ioc->req_sz];
2842 u8 reply[sizeof(FWUploadReply_t)];
2843 FWUpload_t *prequest;
2844 FWUploadReply_t *preply;
2845 FWUploadTCSGE_t *ptcsge;
2846 int sgeoffset;
2847 u32 flagsLength;
2848 int ii, sz, reply_sz;
2849 int cmdStatus;
2850
2851 /* If the image size is 0, we are done.
2852 */
2853 if ((sz = ioc->facts.FWImageSize) == 0)
2854 return 0;
2855
2856 mpt_alloc_fw_memory(ioc, sz);
2857
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002858 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002860
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 if (ioc->cached_fw == NULL) {
2862 /* Major Failure.
2863 */
2864 return -ENOMEM;
2865 }
2866
2867 prequest = (FWUpload_t *)&request;
2868 preply = (FWUploadReply_t *)&reply;
2869
2870 /* Destination... */
2871 memset(prequest, 0, ioc->req_sz);
2872
2873 reply_sz = sizeof(reply);
2874 memset(preply, 0, reply_sz);
2875
2876 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2877 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2878
2879 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2880 ptcsge->DetailsLength = 12;
2881 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2882 ptcsge->ImageSize = cpu_to_le32(sz);
2883
2884 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2885
2886 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2887 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2888
2889 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002890 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 prequest, sgeoffset));
2892 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2893
2894 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2895 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2896
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002897 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
2899 cmdStatus = -EFAULT;
2900 if (ii == 0) {
2901 /* Handshake transfer was complete and successful.
2902 * Check the Reply Frame.
2903 */
2904 int status, transfer_sz;
2905 status = le16_to_cpu(preply->IOCStatus);
2906 if (status == MPI_IOCSTATUS_SUCCESS) {
2907 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2908 if (transfer_sz == sz)
2909 cmdStatus = 0;
2910 }
2911 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002912 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 ioc->name, cmdStatus));
2914
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002915
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 if (cmdStatus) {
2917
2918 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2919 ioc->name));
2920 mpt_free_fw_memory(ioc);
2921 }
2922
2923 return cmdStatus;
2924}
2925
2926/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2927/*
2928 * mpt_downloadboot - DownloadBoot code
2929 * @ioc: Pointer to MPT_ADAPTER structure
2930 * @flag: Specify which part of IOC memory is to be uploaded.
2931 * @sleepFlag: Specifies whether the process can sleep
2932 *
2933 * FwDownloadBoot requires Programmed IO access.
2934 *
2935 * Returns 0 for success
2936 * -1 FW Image size is 0
2937 * -2 No valid cached_fw Pointer
2938 * <0 for fw upload failure.
2939 */
2940static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002941mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 MpiExtImageHeader_t *pExtImage;
2944 u32 fwSize;
2945 u32 diag0val;
2946 int count;
2947 u32 *ptrFw;
2948 u32 diagRwData;
2949 u32 nextImage;
2950 u32 load_addr;
2951 u32 ioc_state=0;
2952
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002953 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2954 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002955
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2957 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2958 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2959 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2960 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2961 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2962
2963 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2964
2965 /* wait 1 msec */
2966 if (sleepFlag == CAN_SLEEP) {
2967 msleep_interruptible(1);
2968 } else {
2969 mdelay (1);
2970 }
2971
2972 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2973 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2974
2975 for (count = 0; count < 30; count ++) {
2976 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2977 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2978 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2979 ioc->name, count));
2980 break;
2981 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002982 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002984 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002986 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 }
2988 }
2989
2990 if ( count == 30 ) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002991 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2992 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 ioc->name, diag0val));
2994 return -3;
2995 }
2996
2997 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2998 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2999 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3000 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3001 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3002 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3003
3004 /* Set the DiagRwEn and Disable ARM bits */
3005 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 fwSize = (pFwHeader->ImageSize + 3)/4;
3008 ptrFw = (u32 *) pFwHeader;
3009
3010 /* Write the LoadStartAddress to the DiagRw Address Register
3011 * using Programmed IO
3012 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003013 if (ioc->errata_flag_1064)
3014 pci_enable_io_access(ioc->pcidev);
3015
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3017 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3018 ioc->name, pFwHeader->LoadStartAddress));
3019
3020 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3021 ioc->name, fwSize*4, ptrFw));
3022 while (fwSize--) {
3023 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3024 }
3025
3026 nextImage = pFwHeader->NextImageHeaderOffset;
3027 while (nextImage) {
3028 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3029
3030 load_addr = pExtImage->LoadStartAddress;
3031
3032 fwSize = (pExtImage->ImageSize + 3) >> 2;
3033 ptrFw = (u32 *)pExtImage;
3034
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003035 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3036 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3038
3039 while (fwSize--) {
3040 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3041 }
3042 nextImage = pExtImage->NextImageHeaderOffset;
3043 }
3044
3045 /* Write the IopResetVectorRegAddr */
3046 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3047 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3048
3049 /* Write the IopResetVectorValue */
3050 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3051 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3052
3053 /* Clear the internal flash bad bit - autoincrementing register,
3054 * so must do two writes.
3055 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003056 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003057 /*
3058 * 1030 and 1035 H/W errata, workaround to access
3059 * the ClearFlashBadSignatureBit
3060 */
3061 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3062 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3063 diagRwData |= 0x40000000;
3064 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3065 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3066
3067 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3068 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3069 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3070 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3071
3072 /* wait 1 msec */
3073 if (sleepFlag == CAN_SLEEP) {
3074 msleep_interruptible (1);
3075 } else {
3076 mdelay (1);
3077 }
3078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003080 if (ioc->errata_flag_1064)
3081 pci_disable_io_access(ioc->pcidev);
3082
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003084 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3085 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003087 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3089 ioc->name, diag0val));
3090 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3091
3092 /* Write 0xFF to reset the sequencer */
3093 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3094
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003095 if (ioc->bus_type == SAS) {
3096 ioc_state = mpt_GetIocState(ioc, 0);
3097 if ( (GetIocFacts(ioc, sleepFlag,
3098 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3099 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3100 ioc->name, ioc_state));
3101 return -EFAULT;
3102 }
3103 }
3104
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 for (count=0; count<HZ*20; count++) {
3106 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3107 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3108 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003109 if (ioc->bus_type == SAS) {
3110 return 0;
3111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3113 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3114 ioc->name));
3115 return -EFAULT;
3116 }
3117 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3118 ioc->name));
3119 return 0;
3120 }
3121 if (sleepFlag == CAN_SLEEP) {
3122 msleep_interruptible (10);
3123 } else {
3124 mdelay (10);
3125 }
3126 }
3127 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3128 ioc->name, ioc_state));
3129 return -EFAULT;
3130}
3131
3132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3133/*
3134 * KickStart - Perform hard reset of MPT adapter.
3135 * @ioc: Pointer to MPT_ADAPTER structure
3136 * @force: Force hard reset
3137 * @sleepFlag: Specifies whether the process can sleep
3138 *
3139 * This routine places MPT adapter in diagnostic mode via the
3140 * WriteSequence register, and then performs a hard reset of adapter
3141 * via the Diagnostic register.
3142 *
3143 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3144 * or NO_SLEEP (interrupt thread, use mdelay)
3145 * force - 1 if doorbell active, board fault state
3146 * board operational, IOC_RECOVERY or
3147 * IOC_BRINGUP and there is an alt_ioc.
3148 * 0 else
3149 *
3150 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003151 * 1 - hard reset, READY
3152 * 0 - no reset due to History bit, READY
3153 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 * OR reset but failed to come READY
3155 * -2 - no reset, could not enter DIAG mode
3156 * -3 - reset but bad FW bit
3157 */
3158static int
3159KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3160{
3161 int hard_reset_done = 0;
3162 u32 ioc_state=0;
3163 int cnt,cntdn;
3164
3165 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003166 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 /* Always issue a Msg Unit Reset first. This will clear some
3168 * SCSI bus hang conditions.
3169 */
3170 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3171
3172 if (sleepFlag == CAN_SLEEP) {
3173 msleep_interruptible (1000);
3174 } else {
3175 mdelay (1000);
3176 }
3177 }
3178
3179 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3180 if (hard_reset_done < 0)
3181 return hard_reset_done;
3182
3183 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3184 ioc->name));
3185
3186 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3187 for (cnt=0; cnt<cntdn; cnt++) {
3188 ioc_state = mpt_GetIocState(ioc, 1);
3189 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3190 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3191 ioc->name, cnt));
3192 return hard_reset_done;
3193 }
3194 if (sleepFlag == CAN_SLEEP) {
3195 msleep_interruptible (10);
3196 } else {
3197 mdelay (10);
3198 }
3199 }
3200
3201 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3202 ioc->name, ioc_state);
3203 return -1;
3204}
3205
3206/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3207/*
3208 * mpt_diag_reset - Perform hard reset of the adapter.
3209 * @ioc: Pointer to MPT_ADAPTER structure
3210 * @ignore: Set if to honor and clear to ignore
3211 * the reset history bit
3212 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3213 * else set to NO_SLEEP (use mdelay instead)
3214 *
3215 * This routine places the adapter in diagnostic mode via the
3216 * WriteSequence register and then performs a hard reset of adapter
3217 * via the Diagnostic register. Adapter should be in ready state
3218 * upon successful completion.
3219 *
3220 * Returns: 1 hard reset successful
3221 * 0 no reset performed because reset history bit set
3222 * -2 enabling diagnostic mode failed
3223 * -3 diagnostic reset failed
3224 */
3225static int
3226mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3227{
3228 u32 diag0val;
3229 u32 doorbell;
3230 int hard_reset_done = 0;
3231 int count = 0;
3232#ifdef MPT_DEBUG
3233 u32 diag1val = 0;
3234#endif
3235
3236 /* Clear any existing interrupts */
3237 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3238
3239 /* Use "Diagnostic reset" method! (only thing available!) */
3240 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3241
3242#ifdef MPT_DEBUG
3243 if (ioc->alt_ioc)
3244 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3245 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3246 ioc->name, diag0val, diag1val));
3247#endif
3248
3249 /* Do the reset if we are told to ignore the reset history
3250 * or if the reset history is 0
3251 */
3252 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3253 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3254 /* Write magic sequence to WriteSequence register
3255 * Loop until in diagnostic mode
3256 */
3257 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3258 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3259 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3260 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3261 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3262 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3263
3264 /* wait 100 msec */
3265 if (sleepFlag == CAN_SLEEP) {
3266 msleep_interruptible (100);
3267 } else {
3268 mdelay (100);
3269 }
3270
3271 count++;
3272 if (count > 20) {
3273 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3274 ioc->name, diag0val);
3275 return -2;
3276
3277 }
3278
3279 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3280
3281 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3282 ioc->name, diag0val));
3283 }
3284
3285#ifdef MPT_DEBUG
3286 if (ioc->alt_ioc)
3287 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3288 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3289 ioc->name, diag0val, diag1val));
3290#endif
3291 /*
3292 * Disable the ARM (Bug fix)
3293 *
3294 */
3295 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003296 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
3298 /*
3299 * Now hit the reset bit in the Diagnostic register
3300 * (THE BIG HAMMER!) (Clears DRWE bit).
3301 */
3302 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3303 hard_reset_done = 1;
3304 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3305 ioc->name));
3306
3307 /*
3308 * Call each currently registered protocol IOC reset handler
3309 * with pre-reset indication.
3310 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3311 * MptResetHandlers[] registered yet.
3312 */
3313 {
3314 int ii;
3315 int r = 0;
3316
3317 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3318 if (MptResetHandlers[ii]) {
3319 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3320 ioc->name, ii));
3321 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3322 if (ioc->alt_ioc) {
3323 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3324 ioc->name, ioc->alt_ioc->name, ii));
3325 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3326 }
3327 }
3328 }
3329 /* FIXME? Examine results here? */
3330 }
3331
3332 if (ioc->cached_fw) {
3333 /* If the DownloadBoot operation fails, the
3334 * IOC will be left unusable. This is a fatal error
3335 * case. _diag_reset will return < 0
3336 */
3337 for (count = 0; count < 30; count ++) {
3338 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3339 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3340 break;
3341 }
3342
3343 /* wait 1 sec */
3344 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003345 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 } else {
3347 mdelay (1000);
3348 }
3349 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003350 if ((count = mpt_downloadboot(ioc,
3351 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 printk(KERN_WARNING MYNAM
3353 ": firmware downloadboot failure (%d)!\n", count);
3354 }
3355
3356 } else {
3357 /* Wait for FW to reload and for board
3358 * to go to the READY state.
3359 * Maximum wait is 60 seconds.
3360 * If fail, no error will check again
3361 * with calling program.
3362 */
3363 for (count = 0; count < 60; count ++) {
3364 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3365 doorbell &= MPI_IOC_STATE_MASK;
3366
3367 if (doorbell == MPI_IOC_STATE_READY) {
3368 break;
3369 }
3370
3371 /* wait 1 sec */
3372 if (sleepFlag == CAN_SLEEP) {
3373 msleep_interruptible (1000);
3374 } else {
3375 mdelay (1000);
3376 }
3377 }
3378 }
3379 }
3380
3381 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3382#ifdef MPT_DEBUG
3383 if (ioc->alt_ioc)
3384 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3385 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3386 ioc->name, diag0val, diag1val));
3387#endif
3388
3389 /* Clear RESET_HISTORY bit! Place board in the
3390 * diagnostic mode to update the diag register.
3391 */
3392 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3393 count = 0;
3394 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3395 /* Write magic sequence to WriteSequence register
3396 * Loop until in diagnostic mode
3397 */
3398 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3399 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3400 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3401 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3402 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3403 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3404
3405 /* wait 100 msec */
3406 if (sleepFlag == CAN_SLEEP) {
3407 msleep_interruptible (100);
3408 } else {
3409 mdelay (100);
3410 }
3411
3412 count++;
3413 if (count > 20) {
3414 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3415 ioc->name, diag0val);
3416 break;
3417 }
3418 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3419 }
3420 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3421 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3422 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3423 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3424 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3425 ioc->name);
3426 }
3427
3428 /* Disable Diagnostic Mode
3429 */
3430 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3431
3432 /* Check FW reload status flags.
3433 */
3434 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3435 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3436 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3437 ioc->name, diag0val);
3438 return -3;
3439 }
3440
3441#ifdef MPT_DEBUG
3442 if (ioc->alt_ioc)
3443 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3444 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3445 ioc->name, diag0val, diag1val));
3446#endif
3447
3448 /*
3449 * Reset flag that says we've enabled event notification
3450 */
3451 ioc->facts.EventState = 0;
3452
3453 if (ioc->alt_ioc)
3454 ioc->alt_ioc->facts.EventState = 0;
3455
3456 return hard_reset_done;
3457}
3458
3459/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3460/*
3461 * SendIocReset - Send IOCReset request to MPT adapter.
3462 * @ioc: Pointer to MPT_ADAPTER structure
3463 * @reset_type: reset type, expected values are
3464 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3465 *
3466 * Send IOCReset request to the MPT adapter.
3467 *
3468 * Returns 0 for success, non-zero for failure.
3469 */
3470static int
3471SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3472{
3473 int r;
3474 u32 state;
3475 int cntdn, count;
3476
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003477 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 ioc->name, reset_type));
3479 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3480 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3481 return r;
3482
3483 /* FW ACK'd request, wait for READY state
3484 */
3485 count = 0;
3486 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3487
3488 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3489 cntdn--;
3490 count++;
3491 if (!cntdn) {
3492 if (sleepFlag != CAN_SLEEP)
3493 count *= 10;
3494
3495 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3496 ioc->name, (int)((count+5)/HZ));
3497 return -ETIME;
3498 }
3499
3500 if (sleepFlag == CAN_SLEEP) {
3501 msleep_interruptible(1);
3502 } else {
3503 mdelay (1); /* 1 msec delay */
3504 }
3505 }
3506
3507 /* TODO!
3508 * Cleanup all event stuff for this IOC; re-issue EventNotification
3509 * request if needed.
3510 */
3511 if (ioc->facts.Function)
3512 ioc->facts.EventState = 0;
3513
3514 return 0;
3515}
3516
3517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3518/*
3519 * initChainBuffers - Allocate memory for and initialize
3520 * chain buffers, chain buffer control arrays and spinlock.
3521 * @hd: Pointer to MPT_SCSI_HOST structure
3522 * @init: If set, initialize the spin lock.
3523 */
3524static int
3525initChainBuffers(MPT_ADAPTER *ioc)
3526{
3527 u8 *mem;
3528 int sz, ii, num_chain;
3529 int scale, num_sge, numSGE;
3530
3531 /* ReqToChain size must equal the req_depth
3532 * index = req_idx
3533 */
3534 if (ioc->ReqToChain == NULL) {
3535 sz = ioc->req_depth * sizeof(int);
3536 mem = kmalloc(sz, GFP_ATOMIC);
3537 if (mem == NULL)
3538 return -1;
3539
3540 ioc->ReqToChain = (int *) mem;
3541 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3542 ioc->name, mem, sz));
3543 mem = kmalloc(sz, GFP_ATOMIC);
3544 if (mem == NULL)
3545 return -1;
3546
3547 ioc->RequestNB = (int *) mem;
3548 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3549 ioc->name, mem, sz));
3550 }
3551 for (ii = 0; ii < ioc->req_depth; ii++) {
3552 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3553 }
3554
3555 /* ChainToChain size must equal the total number
3556 * of chain buffers to be allocated.
3557 * index = chain_idx
3558 *
3559 * Calculate the number of chain buffers needed(plus 1) per I/O
3560 * then multiply the the maximum number of simultaneous cmds
3561 *
3562 * num_sge = num sge in request frame + last chain buffer
3563 * scale = num sge per chain buffer if no chain element
3564 */
3565 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3566 if (sizeof(dma_addr_t) == sizeof(u64))
3567 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3568 else
3569 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3570
3571 if (sizeof(dma_addr_t) == sizeof(u64)) {
3572 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3573 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3574 } else {
3575 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3576 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3577 }
3578 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3579 ioc->name, num_sge, numSGE));
3580
3581 if ( numSGE > MPT_SCSI_SG_DEPTH )
3582 numSGE = MPT_SCSI_SG_DEPTH;
3583
3584 num_chain = 1;
3585 while (numSGE - num_sge > 0) {
3586 num_chain++;
3587 num_sge += (scale - 1);
3588 }
3589 num_chain++;
3590
3591 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3592 ioc->name, numSGE, num_sge, num_chain));
3593
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003594 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 num_chain *= MPT_SCSI_CAN_QUEUE;
3596 else
3597 num_chain *= MPT_FC_CAN_QUEUE;
3598
3599 ioc->num_chain = num_chain;
3600
3601 sz = num_chain * sizeof(int);
3602 if (ioc->ChainToChain == NULL) {
3603 mem = kmalloc(sz, GFP_ATOMIC);
3604 if (mem == NULL)
3605 return -1;
3606
3607 ioc->ChainToChain = (int *) mem;
3608 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3609 ioc->name, mem, sz));
3610 } else {
3611 mem = (u8 *) ioc->ChainToChain;
3612 }
3613 memset(mem, 0xFF, sz);
3614 return num_chain;
3615}
3616
3617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3618/*
3619 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3620 * @ioc: Pointer to MPT_ADAPTER structure
3621 *
3622 * This routine allocates memory for the MPT reply and request frame
3623 * pools (if necessary), and primes the IOC reply FIFO with
3624 * reply frames.
3625 *
3626 * Returns 0 for success, non-zero for failure.
3627 */
3628static int
3629PrimeIocFifos(MPT_ADAPTER *ioc)
3630{
3631 MPT_FRAME_HDR *mf;
3632 unsigned long flags;
3633 dma_addr_t alloc_dma;
3634 u8 *mem;
3635 int i, reply_sz, sz, total_size, num_chain;
3636
3637 /* Prime reply FIFO... */
3638
3639 if (ioc->reply_frames == NULL) {
3640 if ( (num_chain = initChainBuffers(ioc)) < 0)
3641 return -1;
3642
3643 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3644 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3645 ioc->name, ioc->reply_sz, ioc->reply_depth));
3646 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3647 ioc->name, reply_sz, reply_sz));
3648
3649 sz = (ioc->req_sz * ioc->req_depth);
3650 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3651 ioc->name, ioc->req_sz, ioc->req_depth));
3652 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3653 ioc->name, sz, sz));
3654 total_size += sz;
3655
3656 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3657 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3658 ioc->name, ioc->req_sz, num_chain));
3659 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3660 ioc->name, sz, sz, num_chain));
3661
3662 total_size += sz;
3663 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3664 if (mem == NULL) {
3665 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3666 ioc->name);
3667 goto out_fail;
3668 }
3669
3670 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3671 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3672
3673 memset(mem, 0, total_size);
3674 ioc->alloc_total += total_size;
3675 ioc->alloc = mem;
3676 ioc->alloc_dma = alloc_dma;
3677 ioc->alloc_sz = total_size;
3678 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3679 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3680
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003681 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3682 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 alloc_dma += reply_sz;
3685 mem += reply_sz;
3686
3687 /* Request FIFO - WE manage this! */
3688
3689 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3690 ioc->req_frames_dma = alloc_dma;
3691
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003692 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 ioc->name, mem, (void *)(ulong)alloc_dma));
3694
3695 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3696
3697#if defined(CONFIG_MTRR) && 0
3698 /*
3699 * Enable Write Combining MTRR for IOC's memory region.
3700 * (at least as much as we can; "size and base must be
3701 * multiples of 4 kiB"
3702 */
3703 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3704 sz,
3705 MTRR_TYPE_WRCOMB, 1);
3706 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3707 ioc->name, ioc->req_frames_dma, sz));
3708#endif
3709
3710 for (i = 0; i < ioc->req_depth; i++) {
3711 alloc_dma += ioc->req_sz;
3712 mem += ioc->req_sz;
3713 }
3714
3715 ioc->ChainBuffer = mem;
3716 ioc->ChainBufferDMA = alloc_dma;
3717
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003718 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3720
3721 /* Initialize the free chain Q.
3722 */
3723
3724 INIT_LIST_HEAD(&ioc->FreeChainQ);
3725
3726 /* Post the chain buffers to the FreeChainQ.
3727 */
3728 mem = (u8 *)ioc->ChainBuffer;
3729 for (i=0; i < num_chain; i++) {
3730 mf = (MPT_FRAME_HDR *) mem;
3731 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3732 mem += ioc->req_sz;
3733 }
3734
3735 /* Initialize Request frames linked list
3736 */
3737 alloc_dma = ioc->req_frames_dma;
3738 mem = (u8 *) ioc->req_frames;
3739
3740 spin_lock_irqsave(&ioc->FreeQlock, flags);
3741 INIT_LIST_HEAD(&ioc->FreeQ);
3742 for (i = 0; i < ioc->req_depth; i++) {
3743 mf = (MPT_FRAME_HDR *) mem;
3744
3745 /* Queue REQUESTs *internally*! */
3746 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3747
3748 mem += ioc->req_sz;
3749 }
3750 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3751
3752 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3753 ioc->sense_buf_pool =
3754 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3755 if (ioc->sense_buf_pool == NULL) {
3756 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3757 ioc->name);
3758 goto out_fail;
3759 }
3760
3761 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3762 ioc->alloc_total += sz;
3763 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3764 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3765
3766 }
3767
3768 /* Post Reply frames to FIFO
3769 */
3770 alloc_dma = ioc->alloc_dma;
3771 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3772 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3773
3774 for (i = 0; i < ioc->reply_depth; i++) {
3775 /* Write each address to the IOC! */
3776 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3777 alloc_dma += ioc->reply_sz;
3778 }
3779
3780 return 0;
3781
3782out_fail:
3783 if (ioc->alloc != NULL) {
3784 sz = ioc->alloc_sz;
3785 pci_free_consistent(ioc->pcidev,
3786 sz,
3787 ioc->alloc, ioc->alloc_dma);
3788 ioc->reply_frames = NULL;
3789 ioc->req_frames = NULL;
3790 ioc->alloc_total -= sz;
3791 }
3792 if (ioc->sense_buf_pool != NULL) {
3793 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3794 pci_free_consistent(ioc->pcidev,
3795 sz,
3796 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3797 ioc->sense_buf_pool = NULL;
3798 }
3799 return -1;
3800}
3801
3802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3803/**
3804 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3805 * from IOC via doorbell handshake method.
3806 * @ioc: Pointer to MPT_ADAPTER structure
3807 * @reqBytes: Size of the request in bytes
3808 * @req: Pointer to MPT request frame
3809 * @replyBytes: Expected size of the reply in bytes
3810 * @u16reply: Pointer to area where reply should be written
3811 * @maxwait: Max wait time for a reply (in seconds)
3812 * @sleepFlag: Specifies whether the process can sleep
3813 *
3814 * NOTES: It is the callers responsibility to byte-swap fields in the
3815 * request which are greater than 1 byte in size. It is also the
3816 * callers responsibility to byte-swap response fields which are
3817 * greater than 1 byte in size.
3818 *
3819 * Returns 0 for success, non-zero for failure.
3820 */
3821static int
3822mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003823 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824{
3825 MPIDefaultReply_t *mptReply;
3826 int failcnt = 0;
3827 int t;
3828
3829 /*
3830 * Get ready to cache a handshake reply
3831 */
3832 ioc->hs_reply_idx = 0;
3833 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3834 mptReply->MsgLength = 0;
3835
3836 /*
3837 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3838 * then tell IOC that we want to handshake a request of N words.
3839 * (WRITE u32val to Doorbell reg).
3840 */
3841 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3842 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3843 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3844 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3845
3846 /*
3847 * Wait for IOC's doorbell handshake int
3848 */
3849 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3850 failcnt++;
3851
3852 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3853 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3854
3855 /* Read doorbell and check for active bit */
3856 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3857 return -1;
3858
3859 /*
3860 * Clear doorbell int (WRITE 0 to IntStatus reg),
3861 * then wait for IOC to ACKnowledge that it's ready for
3862 * our handshake request.
3863 */
3864 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3865 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3866 failcnt++;
3867
3868 if (!failcnt) {
3869 int ii;
3870 u8 *req_as_bytes = (u8 *) req;
3871
3872 /*
3873 * Stuff request words via doorbell handshake,
3874 * with ACK from IOC for each.
3875 */
3876 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3877 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3878 (req_as_bytes[(ii*4) + 1] << 8) |
3879 (req_as_bytes[(ii*4) + 2] << 16) |
3880 (req_as_bytes[(ii*4) + 3] << 24));
3881
3882 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3883 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3884 failcnt++;
3885 }
3886
3887 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3888 DBG_DUMP_REQUEST_FRAME_HDR(req)
3889
3890 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3891 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3892
3893 /*
3894 * Wait for completion of doorbell handshake reply from the IOC
3895 */
3896 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3897 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003898
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3900 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3901
3902 /*
3903 * Copy out the cached reply...
3904 */
3905 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3906 u16reply[ii] = ioc->hs_reply[ii];
3907 } else {
3908 return -99;
3909 }
3910
3911 return -failcnt;
3912}
3913
3914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3915/*
3916 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3917 * in it's IntStatus register.
3918 * @ioc: Pointer to MPT_ADAPTER structure
3919 * @howlong: How long to wait (in seconds)
3920 * @sleepFlag: Specifies whether the process can sleep
3921 *
3922 * This routine waits (up to ~2 seconds max) for IOC doorbell
3923 * handshake ACKnowledge.
3924 *
3925 * Returns a negative value on failure, else wait loop count.
3926 */
3927static int
3928WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3929{
3930 int cntdn;
3931 int count = 0;
3932 u32 intstat=0;
3933
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003934 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
3936 if (sleepFlag == CAN_SLEEP) {
3937 while (--cntdn) {
3938 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3939 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3940 break;
3941 msleep_interruptible (1);
3942 count++;
3943 }
3944 } else {
3945 while (--cntdn) {
3946 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3947 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3948 break;
3949 mdelay (1);
3950 count++;
3951 }
3952 }
3953
3954 if (cntdn) {
3955 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3956 ioc->name, count));
3957 return count;
3958 }
3959
3960 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3961 ioc->name, count, intstat);
3962 return -1;
3963}
3964
3965/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3966/*
3967 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3968 * in it's IntStatus register.
3969 * @ioc: Pointer to MPT_ADAPTER structure
3970 * @howlong: How long to wait (in seconds)
3971 * @sleepFlag: Specifies whether the process can sleep
3972 *
3973 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3974 *
3975 * Returns a negative value on failure, else wait loop count.
3976 */
3977static int
3978WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3979{
3980 int cntdn;
3981 int count = 0;
3982 u32 intstat=0;
3983
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003984 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 if (sleepFlag == CAN_SLEEP) {
3986 while (--cntdn) {
3987 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3988 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3989 break;
3990 msleep_interruptible(1);
3991 count++;
3992 }
3993 } else {
3994 while (--cntdn) {
3995 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3996 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3997 break;
3998 mdelay(1);
3999 count++;
4000 }
4001 }
4002
4003 if (cntdn) {
4004 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4005 ioc->name, count, howlong));
4006 return count;
4007 }
4008
4009 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4010 ioc->name, count, intstat);
4011 return -1;
4012}
4013
4014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4015/*
4016 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
4017 * @ioc: Pointer to MPT_ADAPTER structure
4018 * @howlong: How long to wait (in seconds)
4019 * @sleepFlag: Specifies whether the process can sleep
4020 *
4021 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4022 * Reply is cached to IOC private area large enough to hold a maximum
4023 * of 128 bytes of reply data.
4024 *
4025 * Returns a negative value on failure, else size of reply in WORDS.
4026 */
4027static int
4028WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4029{
4030 int u16cnt = 0;
4031 int failcnt = 0;
4032 int t;
4033 u16 *hs_reply = ioc->hs_reply;
4034 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4035 u16 hword;
4036
4037 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4038
4039 /*
4040 * Get first two u16's so we can look at IOC's intended reply MsgLength
4041 */
4042 u16cnt=0;
4043 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4044 failcnt++;
4045 } else {
4046 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4047 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4048 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4049 failcnt++;
4050 else {
4051 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4052 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4053 }
4054 }
4055
4056 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004057 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4059
4060 /*
4061 * If no error (and IOC said MsgLength is > 0), piece together
4062 * reply 16 bits at a time.
4063 */
4064 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4065 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4066 failcnt++;
4067 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4068 /* don't overflow our IOC hs_reply[] buffer! */
4069 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4070 hs_reply[u16cnt] = hword;
4071 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4072 }
4073
4074 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4075 failcnt++;
4076 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4077
4078 if (failcnt) {
4079 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4080 ioc->name);
4081 return -failcnt;
4082 }
4083#if 0
4084 else if (u16cnt != (2 * mptReply->MsgLength)) {
4085 return -101;
4086 }
4087 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4088 return -102;
4089 }
4090#endif
4091
4092 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4093 DBG_DUMP_REPLY_FRAME(mptReply)
4094
4095 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4096 ioc->name, t, u16cnt/2));
4097 return u16cnt/2;
4098}
4099
4100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4101/*
4102 * GetLanConfigPages - Fetch LANConfig pages.
4103 * @ioc: Pointer to MPT_ADAPTER structure
4104 *
4105 * Return: 0 for success
4106 * -ENOMEM if no memory available
4107 * -EPERM if not allowed due to ISR context
4108 * -EAGAIN if no msg frames currently available
4109 * -EFAULT for non-successful reply or no reply (timeout)
4110 */
4111static int
4112GetLanConfigPages(MPT_ADAPTER *ioc)
4113{
4114 ConfigPageHeader_t hdr;
4115 CONFIGPARMS cfg;
4116 LANPage0_t *ppage0_alloc;
4117 dma_addr_t page0_dma;
4118 LANPage1_t *ppage1_alloc;
4119 dma_addr_t page1_dma;
4120 int rc = 0;
4121 int data_sz;
4122 int copy_sz;
4123
4124 /* Get LAN Page 0 header */
4125 hdr.PageVersion = 0;
4126 hdr.PageLength = 0;
4127 hdr.PageNumber = 0;
4128 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004129 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 cfg.physAddr = -1;
4131 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4132 cfg.dir = 0;
4133 cfg.pageAddr = 0;
4134 cfg.timeout = 0;
4135
4136 if ((rc = mpt_config(ioc, &cfg)) != 0)
4137 return rc;
4138
4139 if (hdr.PageLength > 0) {
4140 data_sz = hdr.PageLength * 4;
4141 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4142 rc = -ENOMEM;
4143 if (ppage0_alloc) {
4144 memset((u8 *)ppage0_alloc, 0, data_sz);
4145 cfg.physAddr = page0_dma;
4146 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4147
4148 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4149 /* save the data */
4150 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4151 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4152
4153 }
4154
4155 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4156
4157 /* FIXME!
4158 * Normalize endianness of structure data,
4159 * by byte-swapping all > 1 byte fields!
4160 */
4161
4162 }
4163
4164 if (rc)
4165 return rc;
4166 }
4167
4168 /* Get LAN Page 1 header */
4169 hdr.PageVersion = 0;
4170 hdr.PageLength = 0;
4171 hdr.PageNumber = 1;
4172 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004173 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 cfg.physAddr = -1;
4175 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4176 cfg.dir = 0;
4177 cfg.pageAddr = 0;
4178
4179 if ((rc = mpt_config(ioc, &cfg)) != 0)
4180 return rc;
4181
4182 if (hdr.PageLength == 0)
4183 return 0;
4184
4185 data_sz = hdr.PageLength * 4;
4186 rc = -ENOMEM;
4187 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4188 if (ppage1_alloc) {
4189 memset((u8 *)ppage1_alloc, 0, data_sz);
4190 cfg.physAddr = page1_dma;
4191 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4192
4193 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4194 /* save the data */
4195 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4196 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4197 }
4198
4199 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4200
4201 /* FIXME!
4202 * Normalize endianness of structure data,
4203 * by byte-swapping all > 1 byte fields!
4204 */
4205
4206 }
4207
4208 return rc;
4209}
4210
4211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4212/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004213 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 * @ioc: Pointer to MPT_ADAPTER structure
4215 * @portnum: IOC Port number
4216 *
4217 * Return: 0 for success
4218 * -ENOMEM if no memory available
4219 * -EPERM if not allowed due to ISR context
4220 * -EAGAIN if no msg frames currently available
4221 * -EFAULT for non-successful reply or no reply (timeout)
4222 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004223int
4224mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225{
4226 ConfigPageHeader_t hdr;
4227 CONFIGPARMS cfg;
4228 FCPortPage0_t *ppage0_alloc;
4229 FCPortPage0_t *pp0dest;
4230 dma_addr_t page0_dma;
4231 int data_sz;
4232 int copy_sz;
4233 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004234 int count = 400;
4235
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
4237 /* Get FCPort Page 0 header */
4238 hdr.PageVersion = 0;
4239 hdr.PageLength = 0;
4240 hdr.PageNumber = 0;
4241 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004242 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 cfg.physAddr = -1;
4244 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4245 cfg.dir = 0;
4246 cfg.pageAddr = portnum;
4247 cfg.timeout = 0;
4248
4249 if ((rc = mpt_config(ioc, &cfg)) != 0)
4250 return rc;
4251
4252 if (hdr.PageLength == 0)
4253 return 0;
4254
4255 data_sz = hdr.PageLength * 4;
4256 rc = -ENOMEM;
4257 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4258 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004259
4260 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 memset((u8 *)ppage0_alloc, 0, data_sz);
4262 cfg.physAddr = page0_dma;
4263 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4264
4265 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4266 /* save the data */
4267 pp0dest = &ioc->fc_port_page0[portnum];
4268 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4269 memcpy(pp0dest, ppage0_alloc, copy_sz);
4270
4271 /*
4272 * Normalize endianness of structure data,
4273 * by byte-swapping all > 1 byte fields!
4274 */
4275 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4276 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4277 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4278 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4279 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4280 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4281 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4282 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4283 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4284 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4285 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4286 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4287 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4288 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4289 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4290 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4291
Michael Reed05e8ec12006-01-13 14:31:54 -06004292 /*
4293 * if still doing discovery,
4294 * hang loose a while until finished
4295 */
4296 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4297 if (count-- > 0) {
4298 msleep_interruptible(100);
4299 goto try_again;
4300 }
4301 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4302 " complete.\n",
4303 ioc->name);
4304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 }
4306
4307 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4308 }
4309
4310 return rc;
4311}
4312
4313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4314/*
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004315 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4316 * @ioc: Pointer to MPT_ADAPTER structure
4317 * @sas_address: 64bit SAS Address for operation.
4318 * @target_id: specified target for operation
4319 * @bus: specified bus for operation
4320 * @persist_opcode: see below
4321 *
4322 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4323 * devices not currently present.
4324 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4325 *
4326 * NOTE: Don't use not this function during interrupt time.
4327 *
4328 * Returns: 0 for success, non-zero error
4329 */
4330
4331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4332int
4333mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4334{
4335 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4336 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4337 MPT_FRAME_HDR *mf = NULL;
4338 MPIHeader_t *mpi_hdr;
4339
4340
4341 /* insure garbage is not sent to fw */
4342 switch(persist_opcode) {
4343
4344 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4345 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4346 break;
4347
4348 default:
4349 return -1;
4350 break;
4351 }
4352
4353 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4354
4355 /* Get a MF for this command.
4356 */
4357 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4358 printk("%s: no msg frames!\n",__FUNCTION__);
4359 return -1;
4360 }
4361
4362 mpi_hdr = (MPIHeader_t *) mf;
4363 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4364 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4365 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4366 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4367 sasIoUnitCntrReq->Operation = persist_opcode;
4368
4369 init_timer(&ioc->persist_timer);
4370 ioc->persist_timer.data = (unsigned long) ioc;
4371 ioc->persist_timer.function = mpt_timer_expired;
4372 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4373 ioc->persist_wait_done=0;
4374 add_timer(&ioc->persist_timer);
4375 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4376 wait_event(mpt_waitq, ioc->persist_wait_done);
4377
4378 sasIoUnitCntrReply =
4379 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4380 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4381 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4382 __FUNCTION__,
4383 sasIoUnitCntrReply->IOCStatus,
4384 sasIoUnitCntrReply->IOCLogInfo);
4385 return -1;
4386 }
4387
4388 printk("%s: success\n",__FUNCTION__);
4389 return 0;
4390}
4391
4392/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4393/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4395 * @ioc: Pointer to MPT_ADAPTER structure
4396 *
4397 * Returns: 0 for success
4398 * -ENOMEM if no memory available
4399 * -EPERM if not allowed due to ISR context
4400 * -EAGAIN if no msg frames currently available
4401 * -EFAULT for non-successful reply or no reply (timeout)
4402 */
4403static int
4404GetIoUnitPage2(MPT_ADAPTER *ioc)
4405{
4406 ConfigPageHeader_t hdr;
4407 CONFIGPARMS cfg;
4408 IOUnitPage2_t *ppage_alloc;
4409 dma_addr_t page_dma;
4410 int data_sz;
4411 int rc;
4412
4413 /* Get the page header */
4414 hdr.PageVersion = 0;
4415 hdr.PageLength = 0;
4416 hdr.PageNumber = 2;
4417 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004418 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 cfg.physAddr = -1;
4420 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4421 cfg.dir = 0;
4422 cfg.pageAddr = 0;
4423 cfg.timeout = 0;
4424
4425 if ((rc = mpt_config(ioc, &cfg)) != 0)
4426 return rc;
4427
4428 if (hdr.PageLength == 0)
4429 return 0;
4430
4431 /* Read the config page */
4432 data_sz = hdr.PageLength * 4;
4433 rc = -ENOMEM;
4434 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4435 if (ppage_alloc) {
4436 memset((u8 *)ppage_alloc, 0, data_sz);
4437 cfg.physAddr = page_dma;
4438 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4439
4440 /* If Good, save data */
4441 if ((rc = mpt_config(ioc, &cfg)) == 0)
4442 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4443
4444 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4445 }
4446
4447 return rc;
4448}
4449
4450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4451/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4452 * @ioc: Pointer to a Adapter Strucutre
4453 * @portnum: IOC port number
4454 *
4455 * Return: -EFAULT if read of config page header fails
4456 * or if no nvram
4457 * If read of SCSI Port Page 0 fails,
4458 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4459 * Adapter settings: async, narrow
4460 * Return 1
4461 * If read of SCSI Port Page 2 fails,
4462 * Adapter settings valid
4463 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4464 * Return 1
4465 * Else
4466 * Both valid
4467 * Return 0
4468 * CHECK - what type of locking mechanisms should be used????
4469 */
4470static int
4471mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4472{
4473 u8 *pbuf;
4474 dma_addr_t buf_dma;
4475 CONFIGPARMS cfg;
4476 ConfigPageHeader_t header;
4477 int ii;
4478 int data, rc = 0;
4479
4480 /* Allocate memory
4481 */
4482 if (!ioc->spi_data.nvram) {
4483 int sz;
4484 u8 *mem;
4485 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4486 mem = kmalloc(sz, GFP_ATOMIC);
4487 if (mem == NULL)
4488 return -EFAULT;
4489
4490 ioc->spi_data.nvram = (int *) mem;
4491
4492 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4493 ioc->name, ioc->spi_data.nvram, sz));
4494 }
4495
4496 /* Invalidate NVRAM information
4497 */
4498 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4499 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4500 }
4501
4502 /* Read SPP0 header, allocate memory, then read page.
4503 */
4504 header.PageVersion = 0;
4505 header.PageLength = 0;
4506 header.PageNumber = 0;
4507 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004508 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 cfg.physAddr = -1;
4510 cfg.pageAddr = portnum;
4511 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4512 cfg.dir = 0;
4513 cfg.timeout = 0; /* use default */
4514 if (mpt_config(ioc, &cfg) != 0)
4515 return -EFAULT;
4516
4517 if (header.PageLength > 0) {
4518 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4519 if (pbuf) {
4520 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4521 cfg.physAddr = buf_dma;
4522 if (mpt_config(ioc, &cfg) != 0) {
4523 ioc->spi_data.maxBusWidth = MPT_NARROW;
4524 ioc->spi_data.maxSyncOffset = 0;
4525 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4526 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4527 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004528 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4529 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 } else {
4531 /* Save the Port Page 0 data
4532 */
4533 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4534 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4535 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4536
4537 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4538 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004539 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 ioc->name, pPP0->Capabilities));
4541 }
4542 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4543 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4544 if (data) {
4545 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4546 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4547 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004548 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4549 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 } else {
4551 ioc->spi_data.maxSyncOffset = 0;
4552 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4553 }
4554
4555 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4556
4557 /* Update the minSyncFactor based on bus type.
4558 */
4559 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4560 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4561
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004562 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004564 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4565 ioc->name, ioc->spi_data.minSyncFactor));
4566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 }
4568 }
4569 if (pbuf) {
4570 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4571 }
4572 }
4573 }
4574
4575 /* SCSI Port Page 2 - Read the header then the page.
4576 */
4577 header.PageVersion = 0;
4578 header.PageLength = 0;
4579 header.PageNumber = 2;
4580 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004581 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 cfg.physAddr = -1;
4583 cfg.pageAddr = portnum;
4584 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4585 cfg.dir = 0;
4586 if (mpt_config(ioc, &cfg) != 0)
4587 return -EFAULT;
4588
4589 if (header.PageLength > 0) {
4590 /* Allocate memory and read SCSI Port Page 2
4591 */
4592 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4593 if (pbuf) {
4594 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4595 cfg.physAddr = buf_dma;
4596 if (mpt_config(ioc, &cfg) != 0) {
4597 /* Nvram data is left with INVALID mark
4598 */
4599 rc = 1;
4600 } else {
4601 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4602 MpiDeviceInfo_t *pdevice = NULL;
4603
Moore, Ericd8e925d2006-01-16 18:53:06 -07004604 /*
4605 * Save "Set to Avoid SCSI Bus Resets" flag
4606 */
4607 ioc->spi_data.bus_reset =
4608 (le32_to_cpu(pPP2->PortFlags) &
4609 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4610 0 : 1 ;
4611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 /* Save the Port Page 2 data
4613 * (reformat into a 32bit quantity)
4614 */
4615 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4616 ioc->spi_data.PortFlags = data;
4617 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4618 pdevice = &pPP2->DeviceSettings[ii];
4619 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4620 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4621 ioc->spi_data.nvram[ii] = data;
4622 }
4623 }
4624
4625 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4626 }
4627 }
4628
4629 /* Update Adapter limits with those from NVRAM
4630 * Comment: Don't need to do this. Target performance
4631 * parameters will never exceed the adapters limits.
4632 */
4633
4634 return rc;
4635}
4636
4637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4638/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4639 * @ioc: Pointer to a Adapter Strucutre
4640 * @portnum: IOC port number
4641 *
4642 * Return: -EFAULT if read of config page header fails
4643 * or 0 if success.
4644 */
4645static int
4646mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4647{
4648 CONFIGPARMS cfg;
4649 ConfigPageHeader_t header;
4650
4651 /* Read the SCSI Device Page 1 header
4652 */
4653 header.PageVersion = 0;
4654 header.PageLength = 0;
4655 header.PageNumber = 1;
4656 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004657 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 cfg.physAddr = -1;
4659 cfg.pageAddr = portnum;
4660 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4661 cfg.dir = 0;
4662 cfg.timeout = 0;
4663 if (mpt_config(ioc, &cfg) != 0)
4664 return -EFAULT;
4665
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004666 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4667 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
4669 header.PageVersion = 0;
4670 header.PageLength = 0;
4671 header.PageNumber = 0;
4672 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4673 if (mpt_config(ioc, &cfg) != 0)
4674 return -EFAULT;
4675
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004676 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4677 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
4679 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4680 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4681
4682 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4683 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4684 return 0;
4685}
4686
4687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4688/**
4689 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4690 * @ioc: Pointer to a Adapter Strucutre
4691 * @portnum: IOC port number
4692 *
4693 * Return:
4694 * 0 on success
4695 * -EFAULT if read of config page header fails or data pointer not NULL
4696 * -ENOMEM if pci_alloc failed
4697 */
4698int
4699mpt_findImVolumes(MPT_ADAPTER *ioc)
4700{
4701 IOCPage2_t *pIoc2;
4702 u8 *mem;
4703 ConfigPageIoc2RaidVol_t *pIocRv;
4704 dma_addr_t ioc2_dma;
4705 CONFIGPARMS cfg;
4706 ConfigPageHeader_t header;
4707 int jj;
4708 int rc = 0;
4709 int iocpage2sz;
4710 u8 nVols, nPhys;
4711 u8 vid, vbus, vioc;
4712
4713 /* Read IOCP2 header then the page.
4714 */
4715 header.PageVersion = 0;
4716 header.PageLength = 0;
4717 header.PageNumber = 2;
4718 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004719 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 cfg.physAddr = -1;
4721 cfg.pageAddr = 0;
4722 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4723 cfg.dir = 0;
4724 cfg.timeout = 0;
4725 if (mpt_config(ioc, &cfg) != 0)
4726 return -EFAULT;
4727
4728 if (header.PageLength == 0)
4729 return -EFAULT;
4730
4731 iocpage2sz = header.PageLength * 4;
4732 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4733 if (!pIoc2)
4734 return -ENOMEM;
4735
4736 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4737 cfg.physAddr = ioc2_dma;
4738 if (mpt_config(ioc, &cfg) != 0)
4739 goto done_and_free;
4740
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004741 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4743 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004744 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 } else {
4746 goto done_and_free;
4747 }
4748 }
4749 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4750
4751 /* Identify RAID Volume Id's */
4752 nVols = pIoc2->NumActiveVolumes;
4753 if ( nVols == 0) {
4754 /* No RAID Volume.
4755 */
4756 goto done_and_free;
4757 } else {
4758 /* At least 1 RAID Volume
4759 */
4760 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004761 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4763 vid = pIocRv->VolumeID;
4764 vbus = pIocRv->VolumeBus;
4765 vioc = pIocRv->VolumeIOC;
4766
4767 /* find the match
4768 */
4769 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004770 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 } else {
4772 /* Error! Always bus 0
4773 */
4774 }
4775 }
4776 }
4777
4778 /* Identify Hidden Physical Disk Id's */
4779 nPhys = pIoc2->NumActivePhysDisks;
4780 if (nPhys == 0) {
4781 /* No physical disks.
4782 */
4783 } else {
4784 mpt_read_ioc_pg_3(ioc);
4785 }
4786
4787done_and_free:
4788 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4789
4790 return rc;
4791}
4792
4793int
4794mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4795{
4796 IOCPage3_t *pIoc3;
4797 u8 *mem;
4798 CONFIGPARMS cfg;
4799 ConfigPageHeader_t header;
4800 dma_addr_t ioc3_dma;
4801 int iocpage3sz = 0;
4802
4803 /* Free the old page
4804 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004805 kfree(ioc->raid_data.pIocPg3);
4806 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
4808 /* There is at least one physical disk.
4809 * Read and save IOC Page 3
4810 */
4811 header.PageVersion = 0;
4812 header.PageLength = 0;
4813 header.PageNumber = 3;
4814 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004815 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 cfg.physAddr = -1;
4817 cfg.pageAddr = 0;
4818 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4819 cfg.dir = 0;
4820 cfg.timeout = 0;
4821 if (mpt_config(ioc, &cfg) != 0)
4822 return 0;
4823
4824 if (header.PageLength == 0)
4825 return 0;
4826
4827 /* Read Header good, alloc memory
4828 */
4829 iocpage3sz = header.PageLength * 4;
4830 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4831 if (!pIoc3)
4832 return 0;
4833
4834 /* Read the Page and save the data
4835 * into malloc'd memory.
4836 */
4837 cfg.physAddr = ioc3_dma;
4838 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4839 if (mpt_config(ioc, &cfg) == 0) {
4840 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4841 if (mem) {
4842 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004843 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 }
4845 }
4846
4847 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4848
4849 return 0;
4850}
4851
4852static void
4853mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4854{
4855 IOCPage4_t *pIoc4;
4856 CONFIGPARMS cfg;
4857 ConfigPageHeader_t header;
4858 dma_addr_t ioc4_dma;
4859 int iocpage4sz;
4860
4861 /* Read and save IOC Page 4
4862 */
4863 header.PageVersion = 0;
4864 header.PageLength = 0;
4865 header.PageNumber = 4;
4866 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004867 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 cfg.physAddr = -1;
4869 cfg.pageAddr = 0;
4870 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4871 cfg.dir = 0;
4872 cfg.timeout = 0;
4873 if (mpt_config(ioc, &cfg) != 0)
4874 return;
4875
4876 if (header.PageLength == 0)
4877 return;
4878
4879 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4880 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4881 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4882 if (!pIoc4)
4883 return;
4884 } else {
4885 ioc4_dma = ioc->spi_data.IocPg4_dma;
4886 iocpage4sz = ioc->spi_data.IocPg4Sz;
4887 }
4888
4889 /* Read the Page into dma memory.
4890 */
4891 cfg.physAddr = ioc4_dma;
4892 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4893 if (mpt_config(ioc, &cfg) == 0) {
4894 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4895 ioc->spi_data.IocPg4_dma = ioc4_dma;
4896 ioc->spi_data.IocPg4Sz = iocpage4sz;
4897 } else {
4898 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4899 ioc->spi_data.pIocPg4 = NULL;
4900 }
4901}
4902
4903static void
4904mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4905{
4906 IOCPage1_t *pIoc1;
4907 CONFIGPARMS cfg;
4908 ConfigPageHeader_t header;
4909 dma_addr_t ioc1_dma;
4910 int iocpage1sz = 0;
4911 u32 tmp;
4912
4913 /* Check the Coalescing Timeout in IOC Page 1
4914 */
4915 header.PageVersion = 0;
4916 header.PageLength = 0;
4917 header.PageNumber = 1;
4918 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004919 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 cfg.physAddr = -1;
4921 cfg.pageAddr = 0;
4922 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4923 cfg.dir = 0;
4924 cfg.timeout = 0;
4925 if (mpt_config(ioc, &cfg) != 0)
4926 return;
4927
4928 if (header.PageLength == 0)
4929 return;
4930
4931 /* Read Header good, alloc memory
4932 */
4933 iocpage1sz = header.PageLength * 4;
4934 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4935 if (!pIoc1)
4936 return;
4937
4938 /* Read the Page and check coalescing timeout
4939 */
4940 cfg.physAddr = ioc1_dma;
4941 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4942 if (mpt_config(ioc, &cfg) == 0) {
4943
4944 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4945 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4946 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4947
4948 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4949 ioc->name, tmp));
4950
4951 if (tmp > MPT_COALESCING_TIMEOUT) {
4952 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4953
4954 /* Write NVRAM and current
4955 */
4956 cfg.dir = 1;
4957 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4958 if (mpt_config(ioc, &cfg) == 0) {
4959 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4960 ioc->name, MPT_COALESCING_TIMEOUT));
4961
4962 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4963 if (mpt_config(ioc, &cfg) == 0) {
4964 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4965 ioc->name, MPT_COALESCING_TIMEOUT));
4966 } else {
4967 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4968 ioc->name));
4969 }
4970
4971 } else {
4972 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
4973 ioc->name));
4974 }
4975 }
4976
4977 } else {
4978 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
4979 }
4980 }
4981
4982 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
4983
4984 return;
4985}
4986
4987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4988/*
4989 * SendEventNotification - Send EventNotification (on or off) request
4990 * to MPT adapter.
4991 * @ioc: Pointer to MPT_ADAPTER structure
4992 * @EvSwitch: Event switch flags
4993 */
4994static int
4995SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
4996{
4997 EventNotification_t *evnp;
4998
4999 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5000 if (evnp == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005001 devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 ioc->name));
5003 return 0;
5004 }
5005 memset(evnp, 0, sizeof(*evnp));
5006
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005007 devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
5009 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5010 evnp->ChainOffset = 0;
5011 evnp->MsgFlags = 0;
5012 evnp->Switch = EvSwitch;
5013
5014 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5015
5016 return 0;
5017}
5018
5019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5020/**
5021 * SendEventAck - Send EventAck request to MPT adapter.
5022 * @ioc: Pointer to MPT_ADAPTER structure
5023 * @evnp: Pointer to original EventNotification request
5024 */
5025static int
5026SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5027{
5028 EventAck_t *pAck;
5029
5030 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005031 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5032 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5033 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5034 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 return -1;
5036 }
5037 memset(pAck, 0, sizeof(*pAck));
5038
5039 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5040
5041 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5042 pAck->ChainOffset = 0;
5043 pAck->MsgFlags = 0;
5044 pAck->Event = evnp->Event;
5045 pAck->EventContext = evnp->EventContext;
5046
5047 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5048
5049 return 0;
5050}
5051
5052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5053/**
5054 * mpt_config - Generic function to issue config message
5055 * @ioc - Pointer to an adapter structure
5056 * @cfg - Pointer to a configuration structure. Struct contains
5057 * action, page address, direction, physical address
5058 * and pointer to a configuration page header
5059 * Page header is updated.
5060 *
5061 * Returns 0 for success
5062 * -EPERM if not allowed due to ISR context
5063 * -EAGAIN if no msg frames currently available
5064 * -EFAULT for non-successful reply or no reply (timeout)
5065 */
5066int
5067mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5068{
5069 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005070 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 MPT_FRAME_HDR *mf;
5072 unsigned long flags;
5073 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005074 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075 int in_isr;
5076
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005077 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 * to be in ISR context, because that is fatal!
5079 */
5080 in_isr = in_interrupt();
5081 if (in_isr) {
5082 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5083 ioc->name));
5084 return -EPERM;
5085 }
5086
5087 /* Get and Populate a free Frame
5088 */
5089 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5090 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5091 ioc->name));
5092 return -EAGAIN;
5093 }
5094 pReq = (Config_t *)mf;
5095 pReq->Action = pCfg->action;
5096 pReq->Reserved = 0;
5097 pReq->ChainOffset = 0;
5098 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005099
5100 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 pReq->ExtPageLength = 0;
5102 pReq->ExtPageType = 0;
5103 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005104
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 for (ii=0; ii < 8; ii++)
5106 pReq->Reserved2[ii] = 0;
5107
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005108 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5109 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5110 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5111 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5112
5113 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5114 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5115 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5116 pReq->ExtPageType = pExtHdr->ExtPageType;
5117 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5118
5119 /* Page Length must be treated as a reserved field for the extended header. */
5120 pReq->Header.PageLength = 0;
5121 }
5122
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5124
5125 /* Add a SGE to the config request.
5126 */
5127 if (pCfg->dir)
5128 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5129 else
5130 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5131
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005132 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5133 flagsLength |= pExtHdr->ExtPageLength * 4;
5134
5135 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5136 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5137 }
5138 else {
5139 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5140
5141 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5142 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144
5145 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5146
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 /* Append pCfg pointer to end of mf
5148 */
5149 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5150
5151 /* Initalize the timer
5152 */
5153 init_timer(&pCfg->timer);
5154 pCfg->timer.data = (unsigned long) ioc;
5155 pCfg->timer.function = mpt_timer_expired;
5156 pCfg->wait_done = 0;
5157
5158 /* Set the timer; ensure 10 second minimum */
5159 if (pCfg->timeout < 10)
5160 pCfg->timer.expires = jiffies + HZ*10;
5161 else
5162 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5163
5164 /* Add to end of Q, set timer and then issue this command */
5165 spin_lock_irqsave(&ioc->FreeQlock, flags);
5166 list_add_tail(&pCfg->linkage, &ioc->configQ);
5167 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5168
5169 add_timer(&pCfg->timer);
5170 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5171 wait_event(mpt_waitq, pCfg->wait_done);
5172
5173 /* mf has been freed - do not access */
5174
5175 rc = pCfg->status;
5176
5177 return rc;
5178}
5179
5180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5181/**
5182 * mpt_toolbox - Generic function to issue toolbox message
5183 * @ioc - Pointer to an adapter structure
5184 * @cfg - Pointer to a toolbox structure. Struct contains
5185 * action, page address, direction, physical address
5186 * and pointer to a configuration page header
5187 * Page header is updated.
5188 *
5189 * Returns 0 for success
5190 * -EPERM if not allowed due to ISR context
5191 * -EAGAIN if no msg frames currently available
5192 * -EFAULT for non-successful reply or no reply (timeout)
5193 */
5194int
5195mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5196{
5197 ToolboxIstwiReadWriteRequest_t *pReq;
5198 MPT_FRAME_HDR *mf;
5199 struct pci_dev *pdev;
5200 unsigned long flags;
5201 int rc;
5202 u32 flagsLength;
5203 int in_isr;
5204
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005205 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 * to be in ISR context, because that is fatal!
5207 */
5208 in_isr = in_interrupt();
5209 if (in_isr) {
5210 dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n",
5211 ioc->name));
5212 return -EPERM;
5213 }
5214
5215 /* Get and Populate a free Frame
5216 */
5217 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5218 dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n",
5219 ioc->name));
5220 return -EAGAIN;
5221 }
5222 pReq = (ToolboxIstwiReadWriteRequest_t *)mf;
5223 pReq->Tool = pCfg->action;
5224 pReq->Reserved = 0;
5225 pReq->ChainOffset = 0;
5226 pReq->Function = MPI_FUNCTION_TOOLBOX;
5227 pReq->Reserved1 = 0;
5228 pReq->Reserved2 = 0;
5229 pReq->MsgFlags = 0;
5230 pReq->Flags = pCfg->dir;
5231 pReq->BusNum = 0;
5232 pReq->Reserved3 = 0;
5233 pReq->NumAddressBytes = 0x01;
5234 pReq->Reserved4 = 0;
Christoph Hellwig637fa992005-08-18 16:25:44 +02005235 pReq->DataLength = cpu_to_le16(0x04);
5236 pdev = ioc->pcidev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 if (pdev->devfn & 1)
5238 pReq->DeviceAddr = 0xB2;
5239 else
5240 pReq->DeviceAddr = 0xB0;
5241 pReq->Addr1 = 0;
5242 pReq->Addr2 = 0;
5243 pReq->Addr3 = 0;
5244 pReq->Reserved5 = 0;
5245
5246 /* Add a SGE to the config request.
5247 */
5248
5249 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4;
5250
5251 mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr);
5252
5253 dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n",
5254 ioc->name, pReq->Tool));
5255
5256 /* Append pCfg pointer to end of mf
5257 */
5258 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5259
5260 /* Initalize the timer
5261 */
5262 init_timer(&pCfg->timer);
5263 pCfg->timer.data = (unsigned long) ioc;
5264 pCfg->timer.function = mpt_timer_expired;
5265 pCfg->wait_done = 0;
5266
5267 /* Set the timer; ensure 10 second minimum */
5268 if (pCfg->timeout < 10)
5269 pCfg->timer.expires = jiffies + HZ*10;
5270 else
5271 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5272
5273 /* Add to end of Q, set timer and then issue this command */
5274 spin_lock_irqsave(&ioc->FreeQlock, flags);
5275 list_add_tail(&pCfg->linkage, &ioc->configQ);
5276 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5277
5278 add_timer(&pCfg->timer);
5279 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5280 wait_event(mpt_waitq, pCfg->wait_done);
5281
5282 /* mf has been freed - do not access */
5283
5284 rc = pCfg->status;
5285
5286 return rc;
5287}
5288
5289/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5290/*
5291 * mpt_timer_expired - Call back for timer process.
5292 * Used only internal config functionality.
5293 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5294 */
5295static void
5296mpt_timer_expired(unsigned long data)
5297{
5298 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5299
5300 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5301
5302 /* Perform a FW reload */
5303 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5304 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5305
5306 /* No more processing.
5307 * Hard reset clean-up will wake up
5308 * process and free all resources.
5309 */
5310 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5311
5312 return;
5313}
5314
5315/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5316/*
5317 * mpt_ioc_reset - Base cleanup for hard reset
5318 * @ioc: Pointer to the adapter structure
5319 * @reset_phase: Indicates pre- or post-reset functionality
5320 *
5321 * Remark: Free's resources with internally generated commands.
5322 */
5323static int
5324mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5325{
5326 CONFIGPARMS *pCfg;
5327 unsigned long flags;
5328
5329 dprintk((KERN_WARNING MYNAM
5330 ": IOC %s_reset routed to MPT base driver!\n",
5331 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5332 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5333
5334 if (reset_phase == MPT_IOC_SETUP_RESET) {
5335 ;
5336 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5337 /* If the internal config Q is not empty -
5338 * delete timer. MF resources will be freed when
5339 * the FIFO's are primed.
5340 */
5341 spin_lock_irqsave(&ioc->FreeQlock, flags);
5342 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5343 del_timer(&pCfg->timer);
5344 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5345
5346 } else {
5347 CONFIGPARMS *pNext;
5348
5349 /* Search the configQ for internal commands.
5350 * Flush the Q, and wake up all suspended threads.
5351 */
5352 spin_lock_irqsave(&ioc->FreeQlock, flags);
5353 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5354 list_del(&pCfg->linkage);
5355
5356 pCfg->status = MPT_CONFIG_ERROR;
5357 pCfg->wait_done = 1;
5358 wake_up(&mpt_waitq);
5359 }
5360 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5361 }
5362
5363 return 1; /* currently means nothing really */
5364}
5365
5366
5367#ifdef CONFIG_PROC_FS /* { */
5368/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5369/*
5370 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5371 */
5372/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5373/*
5374 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5375 *
5376 * Returns 0 for success, non-zero for failure.
5377 */
5378static int
5379procmpt_create(void)
5380{
5381 struct proc_dir_entry *ent;
5382
5383 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5384 if (mpt_proc_root_dir == NULL)
5385 return -ENOTDIR;
5386
5387 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5388 if (ent)
5389 ent->read_proc = procmpt_summary_read;
5390
5391 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5392 if (ent)
5393 ent->read_proc = procmpt_version_read;
5394
5395 return 0;
5396}
5397
5398/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5399/*
5400 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5401 *
5402 * Returns 0 for success, non-zero for failure.
5403 */
5404static void
5405procmpt_destroy(void)
5406{
5407 remove_proc_entry("version", mpt_proc_root_dir);
5408 remove_proc_entry("summary", mpt_proc_root_dir);
5409 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5410}
5411
5412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5413/*
5414 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5415 * or from /proc/mpt/iocN/summary.
5416 * @buf: Pointer to area to write information
5417 * @start: Pointer to start pointer
5418 * @offset: Offset to start writing
5419 * @request:
5420 * @eof: Pointer to EOF integer
5421 * @data: Pointer
5422 *
5423 * Returns number of characters written to process performing the read.
5424 */
5425static int
5426procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5427{
5428 MPT_ADAPTER *ioc;
5429 char *out = buf;
5430 int len;
5431
5432 if (data) {
5433 int more = 0;
5434
5435 ioc = data;
5436 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5437
5438 out += more;
5439 } else {
5440 list_for_each_entry(ioc, &ioc_list, list) {
5441 int more = 0;
5442
5443 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5444
5445 out += more;
5446 if ((out-buf) >= request)
5447 break;
5448 }
5449 }
5450
5451 len = out - buf;
5452
5453 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5454}
5455
5456/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5457/*
5458 * procmpt_version_read - Handle read request from /proc/mpt/version.
5459 * @buf: Pointer to area to write information
5460 * @start: Pointer to start pointer
5461 * @offset: Offset to start writing
5462 * @request:
5463 * @eof: Pointer to EOF integer
5464 * @data: Pointer
5465 *
5466 * Returns number of characters written to process performing the read.
5467 */
5468static int
5469procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5470{
5471 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005472 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 char *drvname;
5474 int len;
5475
5476 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5477 len += sprintf(buf+len, " Fusion MPT base driver\n");
5478
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005479 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5481 drvname = NULL;
5482 if (MptCallbacks[ii]) {
5483 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005484 case MPTSPI_DRIVER:
5485 if (!scsi++) drvname = "SPI host";
5486 break;
5487 case MPTFC_DRIVER:
5488 if (!fc++) drvname = "FC host";
5489 break;
5490 case MPTSAS_DRIVER:
5491 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 break;
5493 case MPTLAN_DRIVER:
5494 if (!lan++) drvname = "LAN";
5495 break;
5496 case MPTSTM_DRIVER:
5497 if (!targ++) drvname = "SCSI target";
5498 break;
5499 case MPTCTL_DRIVER:
5500 if (!ctl++) drvname = "ioctl";
5501 break;
5502 }
5503
5504 if (drvname)
5505 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5506 }
5507 }
5508
5509 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5510}
5511
5512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5513/*
5514 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5515 * @buf: Pointer to area to write information
5516 * @start: Pointer to start pointer
5517 * @offset: Offset to start writing
5518 * @request:
5519 * @eof: Pointer to EOF integer
5520 * @data: Pointer
5521 *
5522 * Returns number of characters written to process performing the read.
5523 */
5524static int
5525procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5526{
5527 MPT_ADAPTER *ioc = data;
5528 int len;
5529 char expVer[32];
5530 int sz;
5531 int p;
5532
5533 mpt_get_fw_exp_ver(expVer, ioc);
5534
5535 len = sprintf(buf, "%s:", ioc->name);
5536 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5537 len += sprintf(buf+len, " (f/w download boot flag set)");
5538// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5539// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5540
5541 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5542 ioc->facts.ProductID,
5543 ioc->prod_name);
5544 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5545 if (ioc->facts.FWImageSize)
5546 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5547 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5548 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5549 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5550
5551 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5552 ioc->facts.CurrentHostMfaHighAddr);
5553 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5554 ioc->facts.CurrentSenseBufferHighAddr);
5555
5556 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5557 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5558
5559 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5560 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5561 /*
5562 * Rounding UP to nearest 4-kB boundary here...
5563 */
5564 sz = (ioc->req_sz * ioc->req_depth) + 128;
5565 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5566 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5567 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5568 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5569 4*ioc->facts.RequestFrameSize,
5570 ioc->facts.GlobalCredits);
5571
5572 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5573 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5574 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5575 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5576 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5577 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5578 ioc->facts.CurReplyFrameSize,
5579 ioc->facts.ReplyQueueDepth);
5580
5581 len += sprintf(buf+len, " MaxDevices = %d\n",
5582 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5583 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5584
5585 /* per-port info */
5586 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5587 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5588 p+1,
5589 ioc->facts.NumberOfPorts);
5590 if (ioc->bus_type == FC) {
5591 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5592 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5593 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5594 a[5], a[4], a[3], a[2], a[1], a[0]);
5595 }
5596 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5597 ioc->fc_port_page0[p].WWNN.High,
5598 ioc->fc_port_page0[p].WWNN.Low,
5599 ioc->fc_port_page0[p].WWPN.High,
5600 ioc->fc_port_page0[p].WWPN.Low);
5601 }
5602 }
5603
5604 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5605}
5606
5607#endif /* CONFIG_PROC_FS } */
5608
5609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5610static void
5611mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5612{
5613 buf[0] ='\0';
5614 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5615 sprintf(buf, " (Exp %02d%02d)",
5616 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5617 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5618
5619 /* insider hack! */
5620 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5621 strcat(buf, " [MDBG]");
5622 }
5623}
5624
5625/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5626/**
5627 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5628 * @ioc: Pointer to MPT_ADAPTER structure
5629 * @buffer: Pointer to buffer where IOC summary info should be written
5630 * @size: Pointer to number of bytes we wrote (set by this routine)
5631 * @len: Offset at which to start writing in buffer
5632 * @showlan: Display LAN stuff?
5633 *
5634 * This routine writes (english readable) ASCII text, which represents
5635 * a summary of IOC information, to a buffer.
5636 */
5637void
5638mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5639{
5640 char expVer[32];
5641 int y;
5642
5643 mpt_get_fw_exp_ver(expVer, ioc);
5644
5645 /*
5646 * Shorter summary of attached ioc's...
5647 */
5648 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5649 ioc->name,
5650 ioc->prod_name,
5651 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5652 ioc->facts.FWVersion.Word,
5653 expVer,
5654 ioc->facts.NumberOfPorts,
5655 ioc->req_depth);
5656
5657 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5658 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5659 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5660 a[5], a[4], a[3], a[2], a[1], a[0]);
5661 }
5662
5663#ifndef __sparc__
5664 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5665#else
5666 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5667#endif
5668
5669 if (!ioc->active)
5670 y += sprintf(buffer+len+y, " (disabled)");
5671
5672 y += sprintf(buffer+len+y, "\n");
5673
5674 *size = y;
5675}
5676
5677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5678/*
5679 * Reset Handling
5680 */
5681/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5682/**
5683 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5684 * Management call based on input arg values. If TaskMgmt fails,
5685 * return associated SCSI request.
5686 * @ioc: Pointer to MPT_ADAPTER structure
5687 * @sleepFlag: Indicates if sleep or schedule must be called.
5688 *
5689 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5690 * or a non-interrupt thread. In the former, must not call schedule().
5691 *
5692 * Remark: A return of -1 is a FATAL error case, as it means a
5693 * FW reload/initialization failed.
5694 *
5695 * Returns 0 for SUCCESS or -1 if FAILED.
5696 */
5697int
5698mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5699{
5700 int rc;
5701 unsigned long flags;
5702
5703 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5704#ifdef MFCNT
5705 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5706 printk("MF count 0x%x !\n", ioc->mfcnt);
5707#endif
5708
5709 /* Reset the adapter. Prevent more than 1 call to
5710 * mpt_do_ioc_recovery at any instant in time.
5711 */
5712 spin_lock_irqsave(&ioc->diagLock, flags);
5713 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5714 spin_unlock_irqrestore(&ioc->diagLock, flags);
5715 return 0;
5716 } else {
5717 ioc->diagPending = 1;
5718 }
5719 spin_unlock_irqrestore(&ioc->diagLock, flags);
5720
5721 /* FIXME: If do_ioc_recovery fails, repeat....
5722 */
5723
5724 /* The SCSI driver needs to adjust timeouts on all current
5725 * commands prior to the diagnostic reset being issued.
5726 * Prevents timeouts occuring during a diagnostic reset...very bad.
5727 * For all other protocol drivers, this is a no-op.
5728 */
5729 {
5730 int ii;
5731 int r = 0;
5732
5733 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5734 if (MptResetHandlers[ii]) {
5735 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5736 ioc->name, ii));
5737 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5738 if (ioc->alt_ioc) {
5739 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5740 ioc->name, ioc->alt_ioc->name, ii));
5741 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5742 }
5743 }
5744 }
5745 }
5746
5747 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5748 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5749 rc, ioc->name);
5750 }
5751 ioc->reload_fw = 0;
5752 if (ioc->alt_ioc)
5753 ioc->alt_ioc->reload_fw = 0;
5754
5755 spin_lock_irqsave(&ioc->diagLock, flags);
5756 ioc->diagPending = 0;
5757 if (ioc->alt_ioc)
5758 ioc->alt_ioc->diagPending = 0;
5759 spin_unlock_irqrestore(&ioc->diagLock, flags);
5760
5761 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5762
5763 return rc;
5764}
5765
5766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005767static void
5768EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769{
5770 char *ds;
5771
5772 switch(event) {
5773 case MPI_EVENT_NONE:
5774 ds = "None";
5775 break;
5776 case MPI_EVENT_LOG_DATA:
5777 ds = "Log Data";
5778 break;
5779 case MPI_EVENT_STATE_CHANGE:
5780 ds = "State Change";
5781 break;
5782 case MPI_EVENT_UNIT_ATTENTION:
5783 ds = "Unit Attention";
5784 break;
5785 case MPI_EVENT_IOC_BUS_RESET:
5786 ds = "IOC Bus Reset";
5787 break;
5788 case MPI_EVENT_EXT_BUS_RESET:
5789 ds = "External Bus Reset";
5790 break;
5791 case MPI_EVENT_RESCAN:
5792 ds = "Bus Rescan Event";
5793 /* Ok, do we need to do anything here? As far as
5794 I can tell, this is when a new device gets added
5795 to the loop. */
5796 break;
5797 case MPI_EVENT_LINK_STATUS_CHANGE:
5798 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5799 ds = "Link Status(FAILURE) Change";
5800 else
5801 ds = "Link Status(ACTIVE) Change";
5802 break;
5803 case MPI_EVENT_LOOP_STATE_CHANGE:
5804 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5805 ds = "Loop State(LIP) Change";
5806 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5807 ds = "Loop State(LPE) Change"; /* ??? */
5808 else
5809 ds = "Loop State(LPB) Change"; /* ??? */
5810 break;
5811 case MPI_EVENT_LOGOUT:
5812 ds = "Logout";
5813 break;
5814 case MPI_EVENT_EVENT_CHANGE:
5815 if (evData0)
5816 ds = "Events(ON) Change";
5817 else
5818 ds = "Events(OFF) Change";
5819 break;
5820 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005821 {
5822 u8 ReasonCode = (u8)(evData0 >> 16);
5823 switch (ReasonCode) {
5824 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5825 ds = "Integrated Raid: Volume Created";
5826 break;
5827 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5828 ds = "Integrated Raid: Volume Deleted";
5829 break;
5830 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5831 ds = "Integrated Raid: Volume Settings Changed";
5832 break;
5833 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5834 ds = "Integrated Raid: Volume Status Changed";
5835 break;
5836 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5837 ds = "Integrated Raid: Volume Physdisk Changed";
5838 break;
5839 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5840 ds = "Integrated Raid: Physdisk Created";
5841 break;
5842 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5843 ds = "Integrated Raid: Physdisk Deleted";
5844 break;
5845 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5846 ds = "Integrated Raid: Physdisk Settings Changed";
5847 break;
5848 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5849 ds = "Integrated Raid: Physdisk Status Changed";
5850 break;
5851 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5852 ds = "Integrated Raid: Domain Validation Needed";
5853 break;
5854 case MPI_EVENT_RAID_RC_SMART_DATA :
5855 ds = "Integrated Raid; Smart Data";
5856 break;
5857 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5858 ds = "Integrated Raid: Replace Action Started";
5859 break;
5860 default:
5861 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005863 }
5864 break;
5865 }
5866 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5867 ds = "SCSI Device Status Change";
5868 break;
5869 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5870 {
5871 u8 ReasonCode = (u8)(evData0 >> 16);
5872 switch (ReasonCode) {
5873 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
5874 ds = "SAS Device Status Change: Added";
5875 break;
5876 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
5877 ds = "SAS Device Status Change: Deleted";
5878 break;
5879 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
5880 ds = "SAS Device Status Change: SMART Data";
5881 break;
5882 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
5883 ds = "SAS Device Status Change: No Persistancy Added";
5884 break;
5885 default:
5886 ds = "SAS Device Status Change: Unknown";
5887 break;
5888 }
5889 break;
5890 }
5891 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5892 ds = "Bus Timer Expired";
5893 break;
5894 case MPI_EVENT_QUEUE_FULL:
5895 ds = "Queue Full";
5896 break;
5897 case MPI_EVENT_SAS_SES:
5898 ds = "SAS SES Event";
5899 break;
5900 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5901 ds = "Persistent Table Full";
5902 break;
5903 case MPI_EVENT_SAS_PHY_LINK_STATUS:
5904 ds = "SAS PHY Link Status";
5905 break;
5906 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5907 ds = "SAS Discovery Error";
5908 break;
5909
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 /*
5911 * MPT base "custom" events may be added here...
5912 */
5913 default:
5914 ds = "Unknown";
5915 break;
5916 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005917 strcpy(evStr,ds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918}
5919
5920/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5921/*
5922 * ProcessEventNotification - Route a received EventNotificationReply to
5923 * all currently regeistered event handlers.
5924 * @ioc: Pointer to MPT_ADAPTER structure
5925 * @pEventReply: Pointer to EventNotification reply frame
5926 * @evHandlers: Pointer to integer, number of event handlers
5927 *
5928 * Returns sum of event handlers return values.
5929 */
5930static int
5931ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5932{
5933 u16 evDataLen;
5934 u32 evData0 = 0;
5935// u32 evCtx;
5936 int ii;
5937 int r = 0;
5938 int handlers = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005939 char evStr[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 u8 event;
5941
5942 /*
5943 * Do platform normalization of values
5944 */
5945 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5946// evCtx = le32_to_cpu(pEventReply->EventContext);
5947 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5948 if (evDataLen) {
5949 evData0 = le32_to_cpu(pEventReply->Data[0]);
5950 }
5951
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005952 EventDescriptionStr(event, evData0, evStr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
5954 ioc->name,
5955 evStr,
5956 event));
5957
5958#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
5959 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5960 for (ii = 0; ii < evDataLen; ii++)
5961 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5962 printk("\n");
5963#endif
5964
5965 /*
5966 * Do general / base driver event processing
5967 */
5968 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 case MPI_EVENT_EVENT_CHANGE: /* 0A */
5970 if (evDataLen) {
5971 u8 evState = evData0 & 0xFF;
5972
5973 /* CHECKME! What if evState unexpectedly says OFF (0)? */
5974
5975 /* Update EventState field in cached IocFacts */
5976 if (ioc->facts.Function) {
5977 ioc->facts.EventState = evState;
5978 }
5979 }
5980 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005981 default:
5982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 }
5984
5985 /*
5986 * Should this event be logged? Events are written sequentially.
5987 * When buffer is full, start again at the top.
5988 */
5989 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
5990 int idx;
5991
5992 idx = ioc->eventContext % ioc->eventLogSize;
5993
5994 ioc->events[idx].event = event;
5995 ioc->events[idx].eventContext = ioc->eventContext;
5996
5997 for (ii = 0; ii < 2; ii++) {
5998 if (ii < evDataLen)
5999 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6000 else
6001 ioc->events[idx].data[ii] = 0;
6002 }
6003
6004 ioc->eventContext++;
6005 }
6006
6007
6008 /*
6009 * Call each currently registered protocol event handler.
6010 */
6011 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6012 if (MptEvHandlers[ii]) {
6013 devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
6014 ioc->name, ii));
6015 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6016 handlers++;
6017 }
6018 }
6019 /* FIXME? Examine results here? */
6020
6021 /*
6022 * If needed, send (a single) EventAck.
6023 */
6024 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006025 devtprintk((MYIOC_s_WARN_FMT
6026 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
6028 devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
6029 ioc->name, ii));
6030 }
6031 }
6032
6033 *evHandlers = handlers;
6034 return r;
6035}
6036
6037/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6038/*
6039 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6040 * @ioc: Pointer to MPT_ADAPTER structure
6041 * @log_info: U32 LogInfo reply word from the IOC
6042 *
6043 * Refer to lsi/fc_log.h.
6044 */
6045static void
6046mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6047{
6048 static char *subcl_str[8] = {
6049 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6050 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6051 };
6052 u8 subcl = (log_info >> 24) & 0x7;
6053
6054 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6055 ioc->name, log_info, subcl_str[subcl]);
6056}
6057
6058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6059/*
6060 * mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
6061 * @ioc: Pointer to MPT_ADAPTER structure
6062 * @mr: Pointer to MPT reply frame
6063 * @log_info: U32 LogInfo word from the IOC
6064 *
6065 * Refer to lsi/sp_log.h.
6066 */
6067static void
6068mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
6069{
6070 u32 info = log_info & 0x00FF0000;
6071 char *desc = "unknown";
6072
6073 switch (info) {
6074 case 0x00010000:
6075 desc = "bug! MID not found";
6076 if (ioc->reload_fw == 0)
6077 ioc->reload_fw++;
6078 break;
6079
6080 case 0x00020000:
6081 desc = "Parity Error";
6082 break;
6083
6084 case 0x00030000:
6085 desc = "ASYNC Outbound Overrun";
6086 break;
6087
6088 case 0x00040000:
6089 desc = "SYNC Offset Error";
6090 break;
6091
6092 case 0x00050000:
6093 desc = "BM Change";
6094 break;
6095
6096 case 0x00060000:
6097 desc = "Msg In Overflow";
6098 break;
6099
6100 case 0x00070000:
6101 desc = "DMA Error";
6102 break;
6103
6104 case 0x00080000:
6105 desc = "Outbound DMA Overrun";
6106 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006107
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 case 0x00090000:
6109 desc = "Task Management";
6110 break;
6111
6112 case 0x000A0000:
6113 desc = "Device Problem";
6114 break;
6115
6116 case 0x000B0000:
6117 desc = "Invalid Phase Change";
6118 break;
6119
6120 case 0x000C0000:
6121 desc = "Untagged Table Size";
6122 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006123
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 }
6125
6126 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6127}
6128
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006129/* strings for sas loginfo */
6130 static char *originator_str[] = {
6131 "IOP", /* 00h */
6132 "PL", /* 01h */
6133 "IR" /* 02h */
6134 };
6135 static char *iop_code_str[] = {
6136 NULL, /* 00h */
6137 "Invalid SAS Address", /* 01h */
6138 NULL, /* 02h */
6139 "Invalid Page", /* 03h */
6140 NULL, /* 04h */
6141 "Task Terminated" /* 05h */
6142 };
6143 static char *pl_code_str[] = {
6144 NULL, /* 00h */
6145 "Open Failure", /* 01h */
6146 "Invalid Scatter Gather List", /* 02h */
6147 "Wrong Relative Offset or Frame Length", /* 03h */
6148 "Frame Transfer Error", /* 04h */
6149 "Transmit Frame Connected Low", /* 05h */
6150 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6151 "SATA Read Log Receive Data Error", /* 07h */
6152 "SATA NCQ Fail All Commands After Error", /* 08h */
6153 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6154 "Receive Frame Invalid Message", /* 0Ah */
6155 "Receive Context Message Valid Error", /* 0Bh */
6156 "Receive Frame Current Frame Error", /* 0Ch */
6157 "SATA Link Down", /* 0Dh */
6158 "Discovery SATA Init W IOS", /* 0Eh */
6159 "Config Invalid Page", /* 0Fh */
6160 "Discovery SATA Init Timeout", /* 10h */
6161 "Reset", /* 11h */
6162 "Abort", /* 12h */
6163 "IO Not Yet Executed", /* 13h */
6164 "IO Executed", /* 14h */
6165 NULL, /* 15h */
6166 NULL, /* 16h */
6167 NULL, /* 17h */
6168 NULL, /* 18h */
6169 NULL, /* 19h */
6170 NULL, /* 1Ah */
6171 NULL, /* 1Bh */
6172 NULL, /* 1Ch */
6173 NULL, /* 1Dh */
6174 NULL, /* 1Eh */
6175 NULL, /* 1Fh */
6176 "Enclosure Management" /* 20h */
6177 };
6178
6179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6180/*
6181 * mpt_sas_log_info - Log information returned from SAS IOC.
6182 * @ioc: Pointer to MPT_ADAPTER structure
6183 * @log_info: U32 LogInfo reply word from the IOC
6184 *
6185 * Refer to lsi/mpi_log_sas.h.
6186 */
6187static void
6188mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6189{
6190union loginfo_type {
6191 u32 loginfo;
6192 struct {
6193 u32 subcode:16;
6194 u32 code:8;
6195 u32 originator:4;
6196 u32 bus_type:4;
6197 }dw;
6198};
6199 union loginfo_type sas_loginfo;
6200 char *code_desc = NULL;
6201
6202 sas_loginfo.loginfo = log_info;
6203 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6204 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6205 return;
6206 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6207 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6208 code_desc = iop_code_str[sas_loginfo.dw.code];
6209 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6210 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6211 code_desc = pl_code_str[sas_loginfo.dw.code];
6212 }
6213
6214 if (code_desc != NULL)
6215 printk(MYIOC_s_INFO_FMT
6216 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6217 " SubCode(0x%04x)\n",
6218 ioc->name,
6219 log_info,
6220 originator_str[sas_loginfo.dw.originator],
6221 code_desc,
6222 sas_loginfo.dw.subcode);
6223 else
6224 printk(MYIOC_s_INFO_FMT
6225 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6226 " SubCode(0x%04x)\n",
6227 ioc->name,
6228 log_info,
6229 originator_str[sas_loginfo.dw.originator],
6230 sas_loginfo.dw.code,
6231 sas_loginfo.dw.subcode);
6232}
6233
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6235/*
6236 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6237 * @ioc: Pointer to MPT_ADAPTER structure
6238 * @ioc_status: U32 IOCStatus word from IOC
6239 * @mf: Pointer to MPT request frame
6240 *
6241 * Refer to lsi/mpi.h.
6242 */
6243static void
6244mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6245{
6246 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6247 char *desc = "";
6248
6249 switch (status) {
6250 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6251 desc = "Invalid Function";
6252 break;
6253
6254 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6255 desc = "Busy";
6256 break;
6257
6258 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6259 desc = "Invalid SGL";
6260 break;
6261
6262 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6263 desc = "Internal Error";
6264 break;
6265
6266 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6267 desc = "Reserved";
6268 break;
6269
6270 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6271 desc = "Insufficient Resources";
6272 break;
6273
6274 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6275 desc = "Invalid Field";
6276 break;
6277
6278 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6279 desc = "Invalid State";
6280 break;
6281
6282 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6283 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6284 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6285 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6286 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6287 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6288 /* No message for Config IOCStatus values */
6289 break;
6290
6291 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6292 /* No message for recovered error
6293 desc = "SCSI Recovered Error";
6294 */
6295 break;
6296
6297 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6298 desc = "SCSI Invalid Bus";
6299 break;
6300
6301 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6302 desc = "SCSI Invalid TargetID";
6303 break;
6304
6305 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6306 {
6307 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6308 U8 cdb = pScsiReq->CDB[0];
6309 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6310 desc = "SCSI Device Not There";
6311 }
6312 break;
6313 }
6314
6315 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6316 desc = "SCSI Data Overrun";
6317 break;
6318
6319 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006320 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 desc = "SCSI Data Underrun";
6322 */
6323 break;
6324
6325 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6326 desc = "SCSI I/O Data Error";
6327 break;
6328
6329 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6330 desc = "SCSI Protocol Error";
6331 break;
6332
6333 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6334 desc = "SCSI Task Terminated";
6335 break;
6336
6337 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6338 desc = "SCSI Residual Mismatch";
6339 break;
6340
6341 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6342 desc = "SCSI Task Management Failed";
6343 break;
6344
6345 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6346 desc = "SCSI IOC Terminated";
6347 break;
6348
6349 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6350 desc = "SCSI Ext Terminated";
6351 break;
6352
6353 default:
6354 desc = "Others";
6355 break;
6356 }
6357 if (desc != "")
6358 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6359}
6360
6361/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006362EXPORT_SYMBOL(mpt_attach);
6363EXPORT_SYMBOL(mpt_detach);
6364#ifdef CONFIG_PM
6365EXPORT_SYMBOL(mpt_resume);
6366EXPORT_SYMBOL(mpt_suspend);
6367#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006369EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370EXPORT_SYMBOL(mpt_register);
6371EXPORT_SYMBOL(mpt_deregister);
6372EXPORT_SYMBOL(mpt_event_register);
6373EXPORT_SYMBOL(mpt_event_deregister);
6374EXPORT_SYMBOL(mpt_reset_register);
6375EXPORT_SYMBOL(mpt_reset_deregister);
6376EXPORT_SYMBOL(mpt_device_driver_register);
6377EXPORT_SYMBOL(mpt_device_driver_deregister);
6378EXPORT_SYMBOL(mpt_get_msg_frame);
6379EXPORT_SYMBOL(mpt_put_msg_frame);
6380EXPORT_SYMBOL(mpt_free_msg_frame);
6381EXPORT_SYMBOL(mpt_add_sge);
6382EXPORT_SYMBOL(mpt_send_handshake_request);
6383EXPORT_SYMBOL(mpt_verify_adapter);
6384EXPORT_SYMBOL(mpt_GetIocState);
6385EXPORT_SYMBOL(mpt_print_ioc_summary);
6386EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006387EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388EXPORT_SYMBOL(mpt_HardResetHandler);
6389EXPORT_SYMBOL(mpt_config);
6390EXPORT_SYMBOL(mpt_toolbox);
6391EXPORT_SYMBOL(mpt_findImVolumes);
6392EXPORT_SYMBOL(mpt_read_ioc_pg_3);
6393EXPORT_SYMBOL(mpt_alloc_fw_memory);
6394EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006395EXPORT_SYMBOL(mptbase_sas_persist_operation);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07006396EXPORT_SYMBOL(mpt_alt_ioc_wait);
Michael Reed05e8ec12006-01-13 14:31:54 -06006397EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
6400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6401/*
6402 * fusion_init - Fusion MPT base driver initialization routine.
6403 *
6404 * Returns 0 for success, non-zero for failure.
6405 */
6406static int __init
6407fusion_init(void)
6408{
6409 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410
6411 show_mptmod_ver(my_NAME, my_VERSION);
6412 printk(KERN_INFO COPYRIGHT "\n");
6413
6414 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6415 MptCallbacks[i] = NULL;
6416 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6417 MptEvHandlers[i] = NULL;
6418 MptResetHandlers[i] = NULL;
6419 }
6420
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006421 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422 * EventNotification handling.
6423 */
6424 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6425
6426 /* Register for hard reset handling callbacks.
6427 */
6428 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6429 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6430 } else {
6431 /* FIXME! */
6432 }
6433
6434#ifdef CONFIG_PROC_FS
6435 (void) procmpt_create();
6436#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006437 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438}
6439
6440/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6441/*
6442 * fusion_exit - Perform driver unload cleanup.
6443 *
6444 * This routine frees all resources associated with each MPT adapter
6445 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6446 */
6447static void __exit
6448fusion_exit(void)
6449{
6450
6451 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6452
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453 mpt_reset_deregister(mpt_base_index);
6454
6455#ifdef CONFIG_PROC_FS
6456 procmpt_destroy();
6457#endif
6458}
6459
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460module_init(fusion_init);
6461module_exit(fusion_exit);