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