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