blob: 5a10c87239c22f0a57072d5b351859ad81236f4f [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 *
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#ifdef MFCNT
91static int mfcounter = 0;
92#define PRINT_MF_COUNT 20000
93#endif
94
95/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
96/*
97 * Public data...
98 */
99int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Linus Torvaldsf7473072005-11-29 14:21:57 -0800102struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104#define WHOINIT_UNKNOWN 0xAA
105
106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
107/*
108 * Private data...
109 */
110 /* Adapter link list */
111LIST_HEAD(ioc_list);
112 /* Callback lookup table */
113static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Protocol driver class lookup table */
115static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Event handler lookup table */
117static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Reset handler lookup table */
119static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
120static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
121
122static int mpt_base_index = -1;
123static int last_drv_idx = -1;
124
125static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
126
127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
128/*
129 * Forward protos...
130 */
David Howells7d12e782006-10-05 14:55:46 +0100131static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
133static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
134 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
135 int sleepFlag);
136static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
137static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
138static void mpt_adapter_disable(MPT_ADAPTER *ioc);
139static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
140
141static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
142static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
144static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
146static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
147static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200148static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
150static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
151static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
152static int PrimeIocFifos(MPT_ADAPTER *ioc);
153static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
155static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
156static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200158int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
160static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
161static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
162static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
163static void mpt_timer_expired(unsigned long data);
164static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
165static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200166static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
167static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169#ifdef CONFIG_PROC_FS
170static int procmpt_summary_read(char *buf, char **start, off_t offset,
171 int request, int *eof, void *data);
172static int procmpt_version_read(char *buf, char **start, off_t offset,
173 int request, int *eof, void *data);
174static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
175 int request, int *eof, void *data);
176#endif
177static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
178
179//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
180static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700181#ifdef MPT_DEBUG_REPLY
182static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
183#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700185static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600186static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700187static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700188static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static int __init fusion_init (void);
192static void __exit fusion_exit (void);
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194#define CHIPREG_READ32(addr) readl_relaxed(addr)
195#define CHIPREG_READ32_dmasync(addr) readl(addr)
196#define CHIPREG_WRITE32(addr,val) writel(val, addr)
197#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
198#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
199
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600200static void
201pci_disable_io_access(struct pci_dev *pdev)
202{
203 u16 command_reg;
204
205 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
206 command_reg &= ~1;
207 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
208}
209
210static void
211pci_enable_io_access(struct pci_dev *pdev)
212{
213 u16 command_reg;
214
215 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
216 command_reg |= 1;
217 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
218}
219
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600220/*
221 * Process turbo (context) reply...
222 */
223static void
224mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
225{
226 MPT_FRAME_HDR *mf = NULL;
227 MPT_FRAME_HDR *mr = NULL;
228 int req_idx = 0;
229 int cb_idx;
230
231 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
232 ioc->name, pa));
233
234 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
235 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
236 req_idx = pa & 0x0000FFFF;
237 cb_idx = (pa & 0x00FF0000) >> 16;
238 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
239 break;
240 case MPI_CONTEXT_REPLY_TYPE_LAN:
241 cb_idx = mpt_lan_index;
242 /*
243 * Blind set of mf to NULL here was fatal
244 * after lan_reply says "freeme"
245 * Fix sort of combined with an optimization here;
246 * added explicit check for case where lan_reply
247 * was just returning 1 and doing nothing else.
248 * For this case skip the callback, but set up
249 * proper mf value first here:-)
250 */
251 if ((pa & 0x58000000) == 0x58000000) {
252 req_idx = pa & 0x0000FFFF;
253 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
254 mpt_free_msg_frame(ioc, mf);
255 mb();
256 return;
257 break;
258 }
259 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
260 break;
261 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
262 cb_idx = mpt_stm_index;
263 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
264 break;
265 default:
266 cb_idx = 0;
267 BUG();
268 }
269
270 /* Check for (valid) IO callback! */
271 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
272 MptCallbacks[cb_idx] == NULL) {
273 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
274 __FUNCTION__, ioc->name, cb_idx);
275 goto out;
276 }
277
278 if (MptCallbacks[cb_idx](ioc, mf, mr))
279 mpt_free_msg_frame(ioc, mf);
280 out:
281 mb();
282}
283
284static void
285mpt_reply(MPT_ADAPTER *ioc, u32 pa)
286{
287 MPT_FRAME_HDR *mf;
288 MPT_FRAME_HDR *mr;
289 int req_idx;
290 int cb_idx;
291 int freeme;
292
293 u32 reply_dma_low;
294 u16 ioc_stat;
295
296 /* non-TURBO reply! Hmmm, something may be up...
297 * Newest turbo reply mechanism; get address
298 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
299 */
300
301 /* Map DMA address of reply header to cpu address.
302 * pa is 32 bits - but the dma address may be 32 or 64 bits
303 * get offset based only only the low addresses
304 */
305
306 reply_dma_low = (pa <<= 1);
307 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
308 (reply_dma_low - ioc->reply_frames_low_dma));
309
310 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
311 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
312 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
313
314 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
315 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
316 DBG_DUMP_REPLY_FRAME(mr)
317
318 /* Check/log IOC log info
319 */
320 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
321 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
322 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
323 if (ioc->bus_type == FC)
324 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700325 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700326 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 else if (ioc->bus_type == SAS)
328 mpt_sas_log_info(ioc, log_info);
329 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600330
Eric Moorec6c727a2007-01-29 09:44:54 -0700331#ifdef MPT_DEBUG_REPLY
332 if (ioc_stat & MPI_IOCSTATUS_MASK)
333 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
334#endif
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600335
336 /* Check for (valid) IO callback! */
337 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
338 MptCallbacks[cb_idx] == NULL) {
339 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
340 __FUNCTION__, ioc->name, cb_idx);
341 freeme = 0;
342 goto out;
343 }
344
345 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
346
347 out:
348 /* Flush (non-TURBO) reply with a WRITE! */
349 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
350
351 if (freeme)
352 mpt_free_msg_frame(ioc, mf);
353 mb();
354}
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800357/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
359 * @irq: irq number (not used)
360 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 *
362 * This routine is registered via the request_irq() kernel API call,
363 * and handles all interrupts generated from a specific MPT adapter
364 * (also referred to as a IO Controller or IOC).
365 * This routine must clear the interrupt from the adapter and does
366 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200367 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 *
369 * This routine handles register-level access of the adapter but
370 * dispatches (calls) a protocol-specific callback routine to handle
371 * the protocol-specific details of the MPT request completion.
372 */
373static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100374mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600376 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600377 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
378
379 if (pa == 0xFFFFFFFF)
380 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 /*
383 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600385 do {
386 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600387 mpt_reply(ioc, pa);
388 else
389 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600390 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
391 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 return IRQ_HANDLED;
394}
395
396/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800397/**
398 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 * @ioc: Pointer to MPT_ADAPTER structure
400 * @mf: Pointer to original MPT request frame
401 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
402 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800403 * MPT base driver's callback routine; all base driver
404 * "internal" request/reply processing is routed here.
405 * Currently used for EventNotification and EventAck handling.
406 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200407 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 * should be freed, or 0 if it shouldn't.
409 */
410static int
411mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
412{
413 int freereq = 1;
414 u8 func;
415
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200416 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200418#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
420 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
421 DBG_DUMP_REQUEST_FRAME_HDR(mf)
422 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200423#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200426 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 ioc->name, func));
428
429 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
430 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
431 int evHandlers = 0;
432 int results;
433
434 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
435 if (results != evHandlers) {
436 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700437 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 ioc->name, evHandlers, results));
439 }
440
441 /*
442 * Hmmm... It seems that EventNotificationReply is an exception
443 * to the rule of one reply per request.
444 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200445 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200447 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700448 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200449 ioc->name, pEvReply));
450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452#ifdef CONFIG_PROC_FS
453// LogEvent(ioc, pEvReply);
454#endif
455
456 } else if (func == MPI_FUNCTION_EVENT_ACK) {
457 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
458 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700459 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 CONFIGPARMS *pCfg;
461 unsigned long flags;
462
463 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
464 ioc->name, mf, reply));
465
466 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
467
468 if (pCfg) {
469 /* disable timer and remove from linked list */
470 del_timer(&pCfg->timer);
471
472 spin_lock_irqsave(&ioc->FreeQlock, flags);
473 list_del(&pCfg->linkage);
474 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
475
476 /*
477 * If IOC Status is SUCCESS, save the header
478 * and set the status code to GOOD.
479 */
480 pCfg->status = MPT_CONFIG_ERROR;
481 if (reply) {
482 ConfigReply_t *pReply = (ConfigReply_t *)reply;
483 u16 status;
484
485 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
486 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
487 status, le32_to_cpu(pReply->IOCLogInfo)));
488
489 pCfg->status = status;
490 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200491 if ((pReply->Header.PageType &
492 MPI_CONFIG_PAGETYPE_MASK) ==
493 MPI_CONFIG_PAGETYPE_EXTENDED) {
494 pCfg->cfghdr.ehdr->ExtPageLength =
495 le16_to_cpu(pReply->ExtPageLength);
496 pCfg->cfghdr.ehdr->ExtPageType =
497 pReply->ExtPageType;
498 }
499 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
500
501 /* If this is a regular header, save PageLength. */
502 /* LMP Do this better so not using a reserved field! */
503 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
504 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
505 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
507 }
508
509 /*
510 * Wake up the original calling thread
511 */
512 pCfg->wait_done = 1;
513 wake_up(&mpt_waitq);
514 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200515 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
516 /* we should be always getting a reply frame */
517 memcpy(ioc->persist_reply_frame, reply,
518 min(MPT_DEFAULT_FRAME_SIZE,
519 4*reply->u.reply.MsgLength));
520 del_timer(&ioc->persist_timer);
521 ioc->persist_wait_done = 1;
522 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 } else {
524 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
525 ioc->name, func);
526 }
527
528 /*
529 * Conditionally tell caller to free the original
530 * EventNotification/EventAck/unexpected request frame!
531 */
532 return freereq;
533}
534
535/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
536/**
537 * mpt_register - Register protocol-specific main callback handler.
538 * @cbfunc: callback function pointer
539 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
540 *
541 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800542 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 * protocol-specific driver must do this before it will be able to
544 * use any IOC resources, such as obtaining request frames.
545 *
546 * NOTES: The SCSI protocol driver currently calls this routine thrice
547 * in order to register separate callbacks; one for "normal" SCSI IO;
548 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
549 *
550 * Returns a positive integer valued "handle" in the
551 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
552 * Any non-positive return value (including zero!) should be considered
553 * an error by the caller.
554 */
555int
556mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
557{
558 int i;
559
560 last_drv_idx = -1;
561
562 /*
563 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
564 * (slot/handle 0 is reserved!)
565 */
566 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
567 if (MptCallbacks[i] == NULL) {
568 MptCallbacks[i] = cbfunc;
569 MptDriverClass[i] = dclass;
570 MptEvHandlers[i] = NULL;
571 last_drv_idx = i;
572 break;
573 }
574 }
575
576 return last_drv_idx;
577}
578
579/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
580/**
581 * mpt_deregister - Deregister a protocol drivers resources.
582 * @cb_idx: previously registered callback handle
583 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800584 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 * module is unloaded.
586 */
587void
588mpt_deregister(int cb_idx)
589{
590 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
591 MptCallbacks[cb_idx] = NULL;
592 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
593 MptEvHandlers[cb_idx] = NULL;
594
595 last_drv_idx++;
596 }
597}
598
599/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
600/**
601 * mpt_event_register - Register protocol-specific event callback
602 * handler.
603 * @cb_idx: previously registered (via mpt_register) callback handle
604 * @ev_cbfunc: callback function
605 *
606 * This routine can be called by one or more protocol-specific drivers
607 * if/when they choose to be notified of MPT events.
608 *
609 * Returns 0 for success.
610 */
611int
612mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
613{
614 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
615 return -1;
616
617 MptEvHandlers[cb_idx] = ev_cbfunc;
618 return 0;
619}
620
621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
622/**
623 * mpt_event_deregister - Deregister protocol-specific event callback
624 * handler.
625 * @cb_idx: previously registered callback handle
626 *
627 * Each protocol-specific driver should call this routine
628 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800629 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 */
631void
632mpt_event_deregister(int cb_idx)
633{
634 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
635 return;
636
637 MptEvHandlers[cb_idx] = NULL;
638}
639
640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
641/**
642 * mpt_reset_register - Register protocol-specific IOC reset handler.
643 * @cb_idx: previously registered (via mpt_register) callback handle
644 * @reset_func: reset function
645 *
646 * This routine can be called by one or more protocol-specific drivers
647 * if/when they choose to be notified of IOC resets.
648 *
649 * Returns 0 for success.
650 */
651int
652mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
653{
654 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
655 return -1;
656
657 MptResetHandlers[cb_idx] = reset_func;
658 return 0;
659}
660
661/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
662/**
663 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
664 * @cb_idx: previously registered callback handle
665 *
666 * Each protocol-specific driver should call this routine
667 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800668 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 */
670void
671mpt_reset_deregister(int cb_idx)
672{
673 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
674 return;
675
676 MptResetHandlers[cb_idx] = NULL;
677}
678
679/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
680/**
681 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800682 * @dd_cbfunc: driver callbacks struct
683 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 */
685int
686mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
687{
688 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600689 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Eric Moored58b2722006-07-11 17:23:23 -0600691 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400692 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
695
696 /* call per pci device probe entry point */
697 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600698 id = ioc->pcidev->driver ?
699 ioc->pcidev->driver->id_table : NULL;
700 if (dd_cbfunc->probe)
701 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400704 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
707/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
708/**
709 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800710 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 */
712void
713mpt_device_driver_deregister(int cb_idx)
714{
715 struct mpt_pci_driver *dd_cbfunc;
716 MPT_ADAPTER *ioc;
717
718 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
719 return;
720
721 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
722
723 list_for_each_entry(ioc, &ioc_list, list) {
724 if (dd_cbfunc->remove)
725 dd_cbfunc->remove(ioc->pcidev);
726 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 MptDeviceDriverHandlers[cb_idx] = NULL;
729}
730
731
732/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
733/**
734 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
735 * allocated per MPT adapter.
736 * @handle: Handle of registered MPT protocol driver
737 * @ioc: Pointer to MPT adapter structure
738 *
739 * Returns pointer to a MPT request frame or %NULL if none are available
740 * or IOC is not active.
741 */
742MPT_FRAME_HDR*
743mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
744{
745 MPT_FRAME_HDR *mf;
746 unsigned long flags;
747 u16 req_idx; /* Request index */
748
749 /* validate handle and ioc identifier */
750
751#ifdef MFCNT
752 if (!ioc->active)
753 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
754#endif
755
756 /* If interrupts are not attached, do not return a request frame */
757 if (!ioc->active)
758 return NULL;
759
760 spin_lock_irqsave(&ioc->FreeQlock, flags);
761 if (!list_empty(&ioc->FreeQ)) {
762 int req_offset;
763
764 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
765 u.frame.linkage.list);
766 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200767 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
769 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
770 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500771 req_idx = req_offset / ioc->req_sz;
772 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
774 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
775#ifdef MFCNT
776 ioc->mfcnt++;
777#endif
778 }
779 else
780 mf = NULL;
781 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
782
783#ifdef MFCNT
784 if (mf == NULL)
785 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
786 mfcounter++;
787 if (mfcounter == PRINT_MF_COUNT)
788 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
789#endif
790
791 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
792 ioc->name, handle, ioc->id, mf));
793 return mf;
794}
795
796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
797/**
798 * mpt_put_msg_frame - Send a protocol specific MPT request frame
799 * to a IOC.
800 * @handle: Handle of registered MPT protocol driver
801 * @ioc: Pointer to MPT adapter structure
802 * @mf: Pointer to MPT request frame
803 *
804 * This routine posts a MPT request frame to the request post FIFO of a
805 * specific MPT adapter.
806 */
807void
808mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
809{
810 u32 mf_dma_addr;
811 int req_offset;
812 u16 req_idx; /* Request index */
813
814 /* ensure values are reset properly! */
815 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
816 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
817 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500818 req_idx = req_offset / ioc->req_sz;
819 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
821
822#ifdef MPT_DEBUG_MSG_FRAME
823 {
824 u32 *m = mf->u.frame.hwhdr.__hdr;
825 int ii, n;
826
827 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
828 ioc->name, m);
829 n = ioc->req_sz/4 - 1;
830 while (m[n] == 0)
831 n--;
832 for (ii=0; ii<=n; ii++) {
833 if (ii && ((ii%8)==0))
834 printk("\n" KERN_INFO " ");
835 printk(" %08x", le32_to_cpu(m[ii]));
836 }
837 printk("\n");
838 }
839#endif
840
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200841 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 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]));
843 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
844}
845
846/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
847/**
848 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
849 * @handle: Handle of registered MPT protocol driver
850 * @ioc: Pointer to MPT adapter structure
851 * @mf: Pointer to MPT request frame
852 *
853 * This routine places a MPT request frame back on the MPT adapter's
854 * FreeQ.
855 */
856void
857mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
858{
859 unsigned long flags;
860
861 /* Put Request back on FreeQ! */
862 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200863 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
865#ifdef MFCNT
866 ioc->mfcnt--;
867#endif
868 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
869}
870
871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
872/**
873 * mpt_add_sge - Place a simple SGE at address pAddr.
874 * @pAddr: virtual address for SGE
875 * @flagslength: SGE flags and data transfer length
876 * @dma_addr: Physical address
877 *
878 * This routine places a MPT request frame back on the MPT adapter's
879 * FreeQ.
880 */
881void
882mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
883{
884 if (sizeof(dma_addr_t) == sizeof(u64)) {
885 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
886 u32 tmp = dma_addr & 0xFFFFFFFF;
887
888 pSge->FlagsLength = cpu_to_le32(flagslength);
889 pSge->Address.Low = cpu_to_le32(tmp);
890 tmp = (u32) ((u64)dma_addr >> 32);
891 pSge->Address.High = cpu_to_le32(tmp);
892
893 } else {
894 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
895 pSge->FlagsLength = cpu_to_le32(flagslength);
896 pSge->Address = cpu_to_le32(dma_addr);
897 }
898}
899
900/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
901/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800902 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 * @handle: Handle of registered MPT protocol driver
904 * @ioc: Pointer to MPT adapter structure
905 * @reqBytes: Size of the request in bytes
906 * @req: Pointer to MPT request frame
907 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
908 *
909 * This routine is used exclusively to send MptScsiTaskMgmt
910 * requests since they are required to be sent via doorbell handshake.
911 *
912 * NOTE: It is the callers responsibility to byte-swap fields in the
913 * request which are greater than 1 byte in size.
914 *
915 * Returns 0 for success, non-zero for failure.
916 */
917int
918mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
919{
Eric Moorecd2c6192007-01-29 09:47:47 -0700920 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 u8 *req_as_bytes;
922 int ii;
923
924 /* State is known to be good upon entering
925 * this function so issue the bus reset
926 * request.
927 */
928
929 /*
930 * Emulate what mpt_put_msg_frame() does /wrt to sanity
931 * setting cb_idx/req_idx. But ONLY if this request
932 * is in proper (pre-alloc'd) request buffer range...
933 */
934 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
935 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
936 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
937 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
938 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
939 }
940
941 /* Make sure there are no doorbells */
942 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 CHIPREG_WRITE32(&ioc->chip->Doorbell,
945 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
946 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
947
948 /* Wait for IOC doorbell int */
949 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
950 return ii;
951 }
952
953 /* Read doorbell and check for active bit */
954 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
955 return -5;
956
957 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200958 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
961
962 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
963 return -2;
964 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* Send request via doorbell handshake */
967 req_as_bytes = (u8 *) req;
968 for (ii = 0; ii < reqBytes/4; ii++) {
969 u32 word;
970
971 word = ((req_as_bytes[(ii*4) + 0] << 0) |
972 (req_as_bytes[(ii*4) + 1] << 8) |
973 (req_as_bytes[(ii*4) + 2] << 16) |
974 (req_as_bytes[(ii*4) + 3] << 24));
975 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
976 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
977 r = -3;
978 break;
979 }
980 }
981
982 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
983 r = 0;
984 else
985 r = -4;
986
987 /* Make sure there are no doorbells */
988 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return r;
991}
992
993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
994/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800995 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200996 * @ioc: Pointer to MPT adapter structure
997 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800998 * @sleepFlag: Specifies whether the process can sleep
999 *
1000 * Provides mechanism for the host driver to control the IOC's
1001 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001002 *
1003 * Access Control Value - bits[15:12]
1004 * 0h Reserved
1005 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1006 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1007 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1008 *
1009 * Returns 0 for success, non-zero for failure.
1010 */
1011
1012static int
1013mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1014{
1015 int r = 0;
1016
1017 /* return if in use */
1018 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1019 & MPI_DOORBELL_ACTIVE)
1020 return -1;
1021
1022 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1023
1024 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1025 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1026 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1027 (access_control_value<<12)));
1028
1029 /* Wait for IOC to clear Doorbell Status bit */
1030 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1031 return -2;
1032 }else
1033 return 0;
1034}
1035
1036/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1037/**
1038 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001039 * @ioc: Pointer to pointer to IOC adapter
1040 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001041 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001042 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001043 * Returns 0 for success, non-zero for failure.
1044 */
1045static int
1046mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1047{
1048 char *psge;
1049 int flags_length;
1050 u32 host_page_buffer_sz=0;
1051
1052 if(!ioc->HostPageBuffer) {
1053
1054 host_page_buffer_sz =
1055 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1056
1057 if(!host_page_buffer_sz)
1058 return 0; /* fw doesn't need any host buffers */
1059
1060 /* spin till we get enough memory */
1061 while(host_page_buffer_sz > 0) {
1062
1063 if((ioc->HostPageBuffer = pci_alloc_consistent(
1064 ioc->pcidev,
1065 host_page_buffer_sz,
1066 &ioc->HostPageBuffer_dma)) != NULL) {
1067
1068 dinitprintk((MYIOC_s_INFO_FMT
1069 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001070 ioc->name, ioc->HostPageBuffer,
1071 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001072 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001073 ioc->alloc_total += host_page_buffer_sz;
1074 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1075 break;
1076 }
1077
1078 host_page_buffer_sz -= (4*1024);
1079 }
1080 }
1081
1082 if(!ioc->HostPageBuffer) {
1083 printk(MYIOC_s_ERR_FMT
1084 "Failed to alloc memory for host_page_buffer!\n",
1085 ioc->name);
1086 return -999;
1087 }
1088
1089 psge = (char *)&ioc_init->HostPageBufferSGE;
1090 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1091 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1092 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1093 MPI_SGE_FLAGS_HOST_TO_IOC |
1094 MPI_SGE_FLAGS_END_OF_BUFFER;
1095 if (sizeof(dma_addr_t) == sizeof(u64)) {
1096 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1097 }
1098 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1099 flags_length |= ioc->HostPageBuffer_sz;
1100 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1101 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1102
1103return 0;
1104}
1105
1106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001108 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 * @iocid: IOC unique identifier (integer)
1110 * @iocpp: Pointer to pointer to IOC adapter
1111 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001112 * Given a unique IOC identifier, set pointer to the associated MPT
1113 * adapter structure.
1114 *
1115 * Returns iocid and sets iocpp if iocid is found.
1116 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 */
1118int
1119mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1120{
1121 MPT_ADAPTER *ioc;
1122
1123 list_for_each_entry(ioc,&ioc_list,list) {
1124 if (ioc->id == iocid) {
1125 *iocpp =ioc;
1126 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 *iocpp = NULL;
1131 return -1;
1132}
1133
1134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001135/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001136 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001138 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 *
1140 * This routine performs all the steps necessary to bring the IOC of
1141 * a MPT adapter to a OPERATIONAL state. This includes registering
1142 * memory regions, registering the interrupt, and allocating request
1143 * and reply memory pools.
1144 *
1145 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1146 * MPT adapter.
1147 *
1148 * Returns 0 for success, non-zero for failure.
1149 *
1150 * TODO: Add support for polled controllers
1151 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001152int
1153mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154{
1155 MPT_ADAPTER *ioc;
1156 u8 __iomem *mem;
1157 unsigned long mem_phys;
1158 unsigned long port;
1159 u32 msize;
1160 u32 psize;
1161 int ii;
1162 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 u8 revision;
1164 u8 pcixcmd;
1165 static int mpt_ids = 0;
1166#ifdef CONFIG_PROC_FS
1167 struct proc_dir_entry *dent, *ent;
1168#endif
1169
1170 if (pci_enable_device(pdev))
1171 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001175 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 dprintk((KERN_INFO MYNAM
1177 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001178 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1180 return r;
1181 }
1182
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001183 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 dprintk((KERN_INFO MYNAM
1185 ": Using 64 bit consistent mask\n"));
1186 else
1187 dprintk((KERN_INFO MYNAM
1188 ": Not using 64 bit consistent mask\n"));
1189
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001190 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (ioc == NULL) {
1192 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1193 return -ENOMEM;
1194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 ioc->alloc_total = sizeof(MPT_ADAPTER);
1196 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1197 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 ioc->pcidev = pdev;
1200 ioc->diagPending = 0;
1201 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001202 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 /* Initialize the event logging.
1205 */
1206 ioc->eventTypes = 0; /* None */
1207 ioc->eventContext = 0;
1208 ioc->eventLogSize = 0;
1209 ioc->events = NULL;
1210
1211#ifdef MFCNT
1212 ioc->mfcnt = 0;
1213#endif
1214
1215 ioc->cached_fw = NULL;
1216
1217 /* Initilize SCSI Config Data structure
1218 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001219 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 /* Initialize the running configQ head.
1222 */
1223 INIT_LIST_HEAD(&ioc->configQ);
1224
Michael Reed05e8ec12006-01-13 14:31:54 -06001225 /* Initialize the fc rport list head.
1226 */
1227 INIT_LIST_HEAD(&ioc->fc_rports);
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 /* Find lookup slot. */
1230 INIT_LIST_HEAD(&ioc->list);
1231 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 mem_phys = msize = 0;
1234 port = psize = 0;
1235 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1236 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001237 if (psize)
1238 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Get I/O space! */
1240 port = pci_resource_start(pdev, ii);
1241 psize = pci_resource_len(pdev,ii);
1242 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001243 if (msize)
1244 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 /* Get memmap */
1246 mem_phys = pci_resource_start(pdev, ii);
1247 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
1249 }
1250 ioc->mem_size = msize;
1251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 mem = NULL;
1253 /* Get logical ptr for PciMem0 space */
1254 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001255 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (mem == NULL) {
1257 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1258 kfree(ioc);
1259 return -EINVAL;
1260 }
1261 ioc->memmap = mem;
1262 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1263
1264 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1265 &ioc->facts, &ioc->pfacts[0]));
1266
1267 ioc->mem_phys = mem_phys;
1268 ioc->chip = (SYSIF_REGS __iomem *)mem;
1269
1270 /* Save Port IO values in case we need to do downloadboot */
1271 {
1272 u8 *pmem = (u8*)port;
1273 ioc->pio_mem_phys = port;
1274 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1275 }
1276
1277 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1278 ioc->prod_name = "LSIFC909";
1279 ioc->bus_type = FC;
1280 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001281 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 ioc->prod_name = "LSIFC929";
1283 ioc->bus_type = FC;
1284 }
1285 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1286 ioc->prod_name = "LSIFC919";
1287 ioc->bus_type = FC;
1288 }
1289 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1290 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1291 ioc->bus_type = FC;
1292 if (revision < XL_929) {
1293 ioc->prod_name = "LSIFC929X";
1294 /* 929X Chip Fix. Set Split transactions level
1295 * for PCIX. Set MOST bits to zero.
1296 */
1297 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1298 pcixcmd &= 0x8F;
1299 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1300 } else {
1301 ioc->prod_name = "LSIFC929XL";
1302 /* 929XL Chip Fix. Set MMRBC to 0x08.
1303 */
1304 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1305 pcixcmd |= 0x08;
1306 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1307 }
1308 }
1309 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1310 ioc->prod_name = "LSIFC919X";
1311 ioc->bus_type = FC;
1312 /* 919X Chip Fix. Set Split transactions level
1313 * for PCIX. Set MOST bits to zero.
1314 */
1315 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1316 pcixcmd &= 0x8F;
1317 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1318 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001319 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1320 ioc->prod_name = "LSIFC939X";
1321 ioc->bus_type = FC;
1322 ioc->errata_flag_1064 = 1;
1323 }
1324 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1325 ioc->prod_name = "LSIFC949X";
1326 ioc->bus_type = FC;
1327 ioc->errata_flag_1064 = 1;
1328 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001329 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1330 ioc->prod_name = "LSIFC949E";
1331 ioc->bus_type = FC;
1332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1334 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001335 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 /* 1030 Chip Fix. Disable Split transactions
1337 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1338 */
1339 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1340 if (revision < C0_1030) {
1341 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1342 pcixcmd &= 0x8F;
1343 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1344 }
1345 }
1346 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1347 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001348 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001350 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1351 ioc->prod_name = "LSISAS1064";
1352 ioc->bus_type = SAS;
1353 ioc->errata_flag_1064 = 1;
1354 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001355 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1356 ioc->prod_name = "LSISAS1068";
1357 ioc->bus_type = SAS;
1358 ioc->errata_flag_1064 = 1;
1359 }
1360 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1361 ioc->prod_name = "LSISAS1064E";
1362 ioc->bus_type = SAS;
1363 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001364 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1365 ioc->prod_name = "LSISAS1068E";
1366 ioc->bus_type = SAS;
1367 }
Eric Moore87cf8982006-06-27 16:09:26 -06001368 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1369 ioc->prod_name = "LSISAS1078";
1370 ioc->bus_type = SAS;
1371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001373 if (ioc->errata_flag_1064)
1374 pci_disable_io_access(pdev);
1375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 sprintf(ioc->name, "ioc%d", ioc->id);
1377
1378 spin_lock_init(&ioc->FreeQlock);
1379
1380 /* Disable all! */
1381 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1382 ioc->active = 0;
1383 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1384
1385 /* Set lookup ptr. */
1386 list_add_tail(&ioc->list, &ioc_list);
1387
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001388 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 */
1390 mpt_detect_bound_ports(ioc, pdev);
1391
James Bottomleyc92f2222006-03-01 09:02:49 -06001392 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1393 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 printk(KERN_WARNING MYNAM
1395 ": WARNING - %s did not initialize properly! (%d)\n",
1396 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001399 if (ioc->alt_ioc)
1400 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 iounmap(mem);
1402 kfree(ioc);
1403 pci_set_drvdata(pdev, NULL);
1404 return r;
1405 }
1406
1407 /* call per device driver probe entry point */
1408 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1409 if(MptDeviceDriverHandlers[ii] &&
1410 MptDeviceDriverHandlers[ii]->probe) {
1411 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1412 }
1413 }
1414
1415#ifdef CONFIG_PROC_FS
1416 /*
1417 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1418 */
1419 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1420 if (dent) {
1421 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1422 if (ent) {
1423 ent->read_proc = procmpt_iocinfo_read;
1424 ent->data = ioc;
1425 }
1426 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1427 if (ent) {
1428 ent->read_proc = procmpt_summary_read;
1429 ent->data = ioc;
1430 }
1431 }
1432#endif
1433
1434 return 0;
1435}
1436
1437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001438/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001439 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 */
1442
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001443void
1444mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445{
1446 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1447 char pname[32];
1448 int ii;
1449
1450 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1451 remove_proc_entry(pname, NULL);
1452 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1453 remove_proc_entry(pname, NULL);
1454 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1455 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 /* call per device driver remove entry point */
1458 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1459 if(MptDeviceDriverHandlers[ii] &&
1460 MptDeviceDriverHandlers[ii]->remove) {
1461 MptDeviceDriverHandlers[ii]->remove(pdev);
1462 }
1463 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 /* Disable interrupts! */
1466 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1467
1468 ioc->active = 0;
1469 synchronize_irq(pdev->irq);
1470
1471 /* Clear any lingering interrupt */
1472 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1473
1474 CHIPREG_READ32(&ioc->chip->IntStatus);
1475
1476 mpt_adapter_dispose(ioc);
1477
1478 pci_set_drvdata(pdev, NULL);
1479}
1480
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481/**************************************************************************
1482 * Power Management
1483 */
1484#ifdef CONFIG_PM
1485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001486/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001487 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001488 * @pdev: Pointer to pci_dev structure
1489 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001491int
1492mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 u32 device_state;
1495 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496
Pavel Machek2a569572005-07-07 17:56:40 -07001497 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 printk(MYIOC_s_INFO_FMT
1500 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1501 ioc->name, pdev, pci_name(pdev), device_state);
1502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 pci_save_state(pdev);
1504
1505 /* put ioc into READY_STATE */
1506 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1507 printk(MYIOC_s_ERR_FMT
1508 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1509 }
1510
1511 /* disable interrupts */
1512 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1513 ioc->active = 0;
1514
1515 /* Clear any lingering interrupt */
1516 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1517
1518 pci_disable_device(pdev);
1519 pci_set_power_state(pdev, device_state);
1520
1521 return 0;
1522}
1523
1524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001525/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001526 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001527 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001529int
1530mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531{
1532 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1533 u32 device_state = pdev->current_state;
1534 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001535 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 printk(MYIOC_s_INFO_FMT
1538 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1539 ioc->name, pdev, pci_name(pdev), device_state);
1540
1541 pci_set_power_state(pdev, 0);
1542 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001543 err = pci_enable_device(pdev);
1544 if (err)
1545 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001548 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 ioc->active = 1;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 printk(MYIOC_s_INFO_FMT
1552 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1553 ioc->name,
1554 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1555 CHIPREG_READ32(&ioc->chip->Doorbell));
1556
1557 /* bring ioc to operational state */
1558 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1559 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1560 printk(MYIOC_s_INFO_FMT
1561 "pci-resume: Cannot recover, error:[%x]\n",
1562 ioc->name, recovery_state);
1563 } else {
1564 printk(MYIOC_s_INFO_FMT
1565 "pci-resume: success\n", ioc->name);
1566 }
1567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 return 0;
1569}
1570#endif
1571
James Bottomley4ff42a62006-05-17 18:06:52 -05001572static int
1573mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1574{
1575 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1576 ioc->bus_type != SPI) ||
1577 (MptDriverClass[index] == MPTFC_DRIVER &&
1578 ioc->bus_type != FC) ||
1579 (MptDriverClass[index] == MPTSAS_DRIVER &&
1580 ioc->bus_type != SAS))
1581 /* make sure we only call the relevant reset handler
1582 * for the bus */
1583 return 0;
1584 return (MptResetHandlers[index])(ioc, reset_phase);
1585}
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001588/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1590 * @ioc: Pointer to MPT adapter structure
1591 * @reason: Event word / reason
1592 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1593 *
1594 * This routine performs all the steps necessary to bring the IOC
1595 * to a OPERATIONAL state.
1596 *
1597 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1598 * MPT adapter.
1599 *
1600 * Returns:
1601 * 0 for success
1602 * -1 if failed to get board READY
1603 * -2 if READY but IOCFacts Failed
1604 * -3 if READY but PrimeIOCFifos Failed
1605 * -4 if READY but IOCInit Failed
1606 */
1607static int
1608mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1609{
1610 int hard_reset_done = 0;
1611 int alt_ioc_ready = 0;
1612 int hard;
1613 int rc=0;
1614 int ii;
1615 int handlers;
1616 int ret = 0;
1617 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001618 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1621 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1622
1623 /* Disable reply interrupts (also blocks FreeQ) */
1624 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1625 ioc->active = 0;
1626
1627 if (ioc->alt_ioc) {
1628 if (ioc->alt_ioc->active)
1629 reset_alt_ioc_active = 1;
1630
1631 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1632 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1633 ioc->alt_ioc->active = 0;
1634 }
1635
1636 hard = 1;
1637 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1638 hard = 0;
1639
1640 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1641 if (hard_reset_done == -4) {
1642 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1643 ioc->name);
1644
1645 if (reset_alt_ioc_active && ioc->alt_ioc) {
1646 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1647 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1648 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001649 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 ioc->alt_ioc->active = 1;
1651 }
1652
1653 } else {
1654 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1655 ioc->name);
1656 }
1657 return -1;
1658 }
1659
1660 /* hard_reset_done = 0 if a soft reset was performed
1661 * and 1 if a hard reset was performed.
1662 */
1663 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1664 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1665 alt_ioc_ready = 1;
1666 else
1667 printk(KERN_WARNING MYNAM
1668 ": alt-%s: Not ready WARNING!\n",
1669 ioc->alt_ioc->name);
1670 }
1671
1672 for (ii=0; ii<5; ii++) {
1673 /* Get IOC facts! Allow 5 retries */
1674 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1675 break;
1676 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 if (ii == 5) {
1680 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1681 ret = -2;
1682 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1683 MptDisplayIocCapabilities(ioc);
1684 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (alt_ioc_ready) {
1687 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1688 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1689 /* Retry - alt IOC was initialized once
1690 */
1691 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1692 }
1693 if (rc) {
1694 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1695 alt_ioc_ready = 0;
1696 reset_alt_ioc_active = 0;
1697 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1698 MptDisplayIocCapabilities(ioc->alt_ioc);
1699 }
1700 }
1701
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001702 /*
1703 * Device is reset now. It must have de-asserted the interrupt line
1704 * (if it was asserted) and it should be safe to register for the
1705 * interrupt now.
1706 */
1707 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1708 ioc->pci_irq = -1;
1709 if (ioc->pcidev->irq) {
1710 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1711 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1712 ioc->name);
1713 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001714 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001715 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001716 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1717 "interrupt %d!\n", ioc->name,
1718 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001719 if (mpt_msi_enable)
1720 pci_disable_msi(ioc->pcidev);
1721 return -EBUSY;
1722 }
1723 irq_allocated = 1;
1724 ioc->pci_irq = ioc->pcidev->irq;
1725 pci_set_master(ioc->pcidev); /* ?? */
1726 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001727 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1728 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001729 }
1730 }
1731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 /* Prime reply & request queues!
1733 * (mucho alloc's) Must be done prior to
1734 * init as upper addresses are needed for init.
1735 * If fails, continue with alt-ioc processing
1736 */
1737 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1738 ret = -3;
1739
1740 /* May need to check/upload firmware & data here!
1741 * If fails, continue with alt-ioc processing
1742 */
1743 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1744 ret = -4;
1745// NEW!
1746 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1747 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1748 ioc->alt_ioc->name, rc);
1749 alt_ioc_ready = 0;
1750 reset_alt_ioc_active = 0;
1751 }
1752
1753 if (alt_ioc_ready) {
1754 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1755 alt_ioc_ready = 0;
1756 reset_alt_ioc_active = 0;
1757 printk(KERN_WARNING MYNAM
1758 ": alt-%s: (%d) init failure WARNING!\n",
1759 ioc->alt_ioc->name, rc);
1760 }
1761 }
1762
1763 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1764 if (ioc->upload_fw) {
1765 ddlprintk((MYIOC_s_INFO_FMT
1766 "firmware upload required!\n", ioc->name));
1767
1768 /* Controller is not operational, cannot do upload
1769 */
1770 if (ret == 0) {
1771 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001772 if (rc == 0) {
1773 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1774 /*
1775 * Maintain only one pointer to FW memory
1776 * so there will not be two attempt to
1777 * downloadboot onboard dual function
1778 * chips (mpt_adapter_disable,
1779 * mpt_diag_reset)
1780 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001781 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1782 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06001783 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001784 }
1785 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001787 ret = -5;
1788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 }
1790 }
1791 }
1792
1793 if (ret == 0) {
1794 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001795 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 ioc->active = 1;
1797 }
1798
1799 if (reset_alt_ioc_active && ioc->alt_ioc) {
1800 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001801 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001803 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 ioc->alt_ioc->active = 1;
1805 }
1806
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001807 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 * and EventAck handling.
1809 */
1810 if ((ret == 0) && (!ioc->facts.EventState))
1811 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1812
1813 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1814 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1815
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001816 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1818 * recursive scenario; GetLanConfigPages times out, timer expired
1819 * routine calls HardResetHandler, which calls into here again,
1820 * and we try GetLanConfigPages again...
1821 */
1822 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07001823
1824 /*
1825 * Initalize link list for inactive raid volumes.
1826 */
1827 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
1828 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
1829
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001830 if (ioc->bus_type == SAS) {
1831
1832 /* clear persistency table */
1833 if(ioc->facts.IOCExceptions &
1834 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1835 ret = mptbase_sas_persist_operation(ioc,
1836 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1837 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001838 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001839 }
1840
1841 /* Find IM volumes
1842 */
1843 mpt_findImVolumes(ioc);
1844
1845 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1847 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1848 /*
1849 * Pre-fetch the ports LAN MAC address!
1850 * (LANPage1_t stuff)
1851 */
1852 (void) GetLanConfigPages(ioc);
1853#ifdef MPT_DEBUG
1854 {
1855 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1856 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1857 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1858 }
1859#endif
1860 }
1861 } else {
1862 /* Get NVRAM and adapter maximums from SPP 0 and 2
1863 */
1864 mpt_GetScsiPortSettings(ioc, 0);
1865
1866 /* Get version and length of SDP 1
1867 */
1868 mpt_readScsiDevicePageHeaders(ioc, 0);
1869
1870 /* Find IM volumes
1871 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001872 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 mpt_findImVolumes(ioc);
1874
1875 /* Check, and possibly reset, the coalescing value
1876 */
1877 mpt_read_ioc_pg_1(ioc);
1878
1879 mpt_read_ioc_pg_4(ioc);
1880 }
1881
1882 GetIoUnitPage2(ioc);
1883 }
1884
1885 /*
1886 * Call each currently registered protocol IOC reset handler
1887 * with post-reset indication.
1888 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1889 * MptResetHandlers[] registered yet.
1890 */
1891 if (hard_reset_done) {
1892 rc = handlers = 0;
1893 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1894 if ((ret == 0) && MptResetHandlers[ii]) {
1895 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1896 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001897 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 handlers++;
1899 }
1900
1901 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001902 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001904 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 handlers++;
1906 }
1907 }
1908 /* FIXME? Examine results here? */
1909 }
1910
Eric Moore0ccdb002006-07-11 17:33:13 -06001911 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001912 if ((ret != 0) && irq_allocated) {
1913 free_irq(ioc->pci_irq, ioc);
1914 if (mpt_msi_enable)
1915 pci_disable_msi(ioc->pcidev);
1916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 return ret;
1918}
1919
1920/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001921/**
1922 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 * @ioc: Pointer to MPT adapter structure
1924 * @pdev: Pointer to (struct pci_dev) structure
1925 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001926 * Search for PCI bus/dev_function which matches
1927 * PCI bus/dev_function (+/-1) for newly discovered 929,
1928 * 929X, 1030 or 1035.
1929 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1931 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1932 */
1933static void
1934mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1935{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001936 struct pci_dev *peer=NULL;
1937 unsigned int slot = PCI_SLOT(pdev->devfn);
1938 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 MPT_ADAPTER *ioc_srch;
1940
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001941 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1942 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001943 ioc->name, pci_name(pdev), pdev->bus->number,
1944 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001945
1946 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1947 if (!peer) {
1948 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1949 if (!peer)
1950 return;
1951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
1953 list_for_each_entry(ioc_srch, &ioc_list, list) {
1954 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001955 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 /* Paranoia checks */
1957 if (ioc->alt_ioc != NULL) {
1958 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001959 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961 } else if (ioc_srch->alt_ioc != NULL) {
1962 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001963 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 break;
1965 }
1966 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001967 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 ioc_srch->alt_ioc = ioc;
1969 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001972 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973}
1974
1975/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001976/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001978 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 */
1980static void
1981mpt_adapter_disable(MPT_ADAPTER *ioc)
1982{
1983 int sz;
1984 int ret;
1985
1986 if (ioc->cached_fw != NULL) {
1987 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001988 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 printk(KERN_WARNING MYNAM
1990 ": firmware downloadboot failure (%d)!\n", ret);
1991 }
1992 }
1993
1994 /* Disable adapter interrupts! */
1995 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1996 ioc->active = 0;
1997 /* Clear any lingering interrupt */
1998 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1999
2000 if (ioc->alloc != NULL) {
2001 sz = ioc->alloc_sz;
2002 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2003 ioc->name, ioc->alloc, ioc->alloc_sz));
2004 pci_free_consistent(ioc->pcidev, sz,
2005 ioc->alloc, ioc->alloc_dma);
2006 ioc->reply_frames = NULL;
2007 ioc->req_frames = NULL;
2008 ioc->alloc = NULL;
2009 ioc->alloc_total -= sz;
2010 }
2011
2012 if (ioc->sense_buf_pool != NULL) {
2013 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2014 pci_free_consistent(ioc->pcidev, sz,
2015 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2016 ioc->sense_buf_pool = NULL;
2017 ioc->alloc_total -= sz;
2018 }
2019
2020 if (ioc->events != NULL){
2021 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2022 kfree(ioc->events);
2023 ioc->events = NULL;
2024 ioc->alloc_total -= sz;
2025 }
2026
2027 if (ioc->cached_fw != NULL) {
2028 sz = ioc->facts.FWImageSize;
2029 pci_free_consistent(ioc->pcidev, sz,
2030 ioc->cached_fw, ioc->cached_fw_dma);
2031 ioc->cached_fw = NULL;
2032 ioc->alloc_total -= sz;
2033 }
2034
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002035 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002036 mpt_inactive_raid_list_free(ioc);
2037 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002038 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002039 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002040 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041
2042 if (ioc->spi_data.pIocPg4 != NULL) {
2043 sz = ioc->spi_data.IocPg4Sz;
2044 pci_free_consistent(ioc->pcidev, sz,
2045 ioc->spi_data.pIocPg4,
2046 ioc->spi_data.IocPg4_dma);
2047 ioc->spi_data.pIocPg4 = NULL;
2048 ioc->alloc_total -= sz;
2049 }
2050
2051 if (ioc->ReqToChain != NULL) {
2052 kfree(ioc->ReqToChain);
2053 kfree(ioc->RequestNB);
2054 ioc->ReqToChain = NULL;
2055 }
2056
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002057 kfree(ioc->ChainToChain);
2058 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002059
2060 if (ioc->HostPageBuffer != NULL) {
2061 if((ret = mpt_host_page_access_control(ioc,
2062 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2063 printk(KERN_ERR MYNAM
2064 ": %s: host page buffers free failed (%d)!\n",
2065 __FUNCTION__, ret);
2066 }
2067 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2068 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2069 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2070 ioc->HostPageBuffer,
2071 ioc->HostPageBuffer_dma);
2072 ioc->HostPageBuffer = NULL;
2073 ioc->HostPageBuffer_sz = 0;
2074 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076}
2077
2078/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002079/**
2080 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 * @ioc: Pointer to MPT adapter structure
2082 *
2083 * This routine unregisters h/w resources and frees all alloc'd memory
2084 * associated with a MPT adapter structure.
2085 */
2086static void
2087mpt_adapter_dispose(MPT_ADAPTER *ioc)
2088{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002089 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002091 if (ioc == NULL)
2092 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002094 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002096 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002098 if (ioc->pci_irq != -1) {
2099 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002100 if (mpt_msi_enable)
2101 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102 ioc->pci_irq = -1;
2103 }
2104
2105 if (ioc->memmap != NULL) {
2106 iounmap(ioc->memmap);
2107 ioc->memmap = NULL;
2108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
2110#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002111 if (ioc->mtrr_reg > 0) {
2112 mtrr_del(ioc->mtrr_reg, 0, 0);
2113 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115#endif
2116
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117 /* Zap the adapter lookup ptr! */
2118 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002120 sz_last = ioc->alloc_total;
2121 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2122 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002123
2124 if (ioc->alt_ioc)
2125 ioc->alt_ioc->alt_ioc = NULL;
2126
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002127 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}
2129
2130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002131/**
2132 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 * @ioc: Pointer to MPT adapter structure
2134 */
2135static void
2136MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2137{
2138 int i = 0;
2139
2140 printk(KERN_INFO "%s: ", ioc->name);
2141 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2142 printk("%s: ", ioc->prod_name+3);
2143 printk("Capabilities={");
2144
2145 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2146 printk("Initiator");
2147 i++;
2148 }
2149
2150 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2151 printk("%sTarget", i ? "," : "");
2152 i++;
2153 }
2154
2155 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2156 printk("%sLAN", i ? "," : "");
2157 i++;
2158 }
2159
2160#if 0
2161 /*
2162 * This would probably evoke more questions than it's worth
2163 */
2164 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2165 printk("%sLogBusAddr", i ? "," : "");
2166 i++;
2167 }
2168#endif
2169
2170 printk("}\n");
2171}
2172
2173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002174/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2176 * @ioc: Pointer to MPT_ADAPTER structure
2177 * @force: Force hard KickStart of IOC
2178 * @sleepFlag: Specifies whether the process can sleep
2179 *
2180 * Returns:
2181 * 1 - DIAG reset and READY
2182 * 0 - READY initially OR soft reset and READY
2183 * -1 - Any failure on KickStart
2184 * -2 - Msg Unit Reset Failed
2185 * -3 - IO Unit Reset Failed
2186 * -4 - IOC owned by a PEER
2187 */
2188static int
2189MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2190{
2191 u32 ioc_state;
2192 int statefault = 0;
2193 int cntdn;
2194 int hard_reset_done = 0;
2195 int r;
2196 int ii;
2197 int whoinit;
2198
2199 /* Get current [raw] IOC state */
2200 ioc_state = mpt_GetIocState(ioc, 0);
2201 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2202
2203 /*
2204 * Check to see if IOC got left/stuck in doorbell handshake
2205 * grip of death. If so, hard reset the IOC.
2206 */
2207 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2208 statefault = 1;
2209 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2210 ioc->name);
2211 }
2212
2213 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002214 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 return 0;
2216
2217 /*
2218 * Check to see if IOC is in FAULT state.
2219 */
2220 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2221 statefault = 2;
2222 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2223 ioc->name);
2224 printk(KERN_WARNING " FAULT code = %04xh\n",
2225 ioc_state & MPI_DOORBELL_DATA_MASK);
2226 }
2227
2228 /*
2229 * Hmmm... Did it get left operational?
2230 */
2231 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002232 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 ioc->name));
2234
2235 /* Check WhoInit.
2236 * If PCI Peer, exit.
2237 * Else, if no fault conditions are present, issue a MessageUnitReset
2238 * Else, fall through to KickStart case
2239 */
2240 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002241 dinitprintk((KERN_INFO MYNAM
2242 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 whoinit, statefault, force));
2244 if (whoinit == MPI_WHOINIT_PCI_PEER)
2245 return -4;
2246 else {
2247 if ((statefault == 0 ) && (force == 0)) {
2248 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2249 return 0;
2250 }
2251 statefault = 3;
2252 }
2253 }
2254
2255 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2256 if (hard_reset_done < 0)
2257 return -1;
2258
2259 /*
2260 * Loop here waiting for IOC to come READY.
2261 */
2262 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002263 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
2265 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2266 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2267 /*
2268 * BIOS or previous driver load left IOC in OP state.
2269 * Reset messaging FIFOs.
2270 */
2271 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2272 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2273 return -2;
2274 }
2275 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2276 /*
2277 * Something is wrong. Try to get IOC back
2278 * to a known state.
2279 */
2280 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2281 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2282 return -3;
2283 }
2284 }
2285
2286 ii++; cntdn--;
2287 if (!cntdn) {
2288 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2289 ioc->name, (int)((ii+5)/HZ));
2290 return -ETIME;
2291 }
2292
2293 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002294 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 } else {
2296 mdelay (1); /* 1 msec delay */
2297 }
2298
2299 }
2300
2301 if (statefault < 3) {
2302 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2303 ioc->name,
2304 statefault==1 ? "stuck handshake" : "IOC FAULT");
2305 }
2306
2307 return hard_reset_done;
2308}
2309
2310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002311/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 * mpt_GetIocState - Get the current state of a MPT adapter.
2313 * @ioc: Pointer to MPT_ADAPTER structure
2314 * @cooked: Request raw or cooked IOC state
2315 *
2316 * Returns all IOC Doorbell register bits if cooked==0, else just the
2317 * Doorbell bits in MPI_IOC_STATE_MASK.
2318 */
2319u32
2320mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2321{
2322 u32 s, sc;
2323
2324 /* Get! */
2325 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2326// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2327 sc = s & MPI_IOC_STATE_MASK;
2328
2329 /* Save! */
2330 ioc->last_state = sc;
2331
2332 return cooked ? sc : s;
2333}
2334
2335/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002336/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 * GetIocFacts - Send IOCFacts request to MPT adapter.
2338 * @ioc: Pointer to MPT_ADAPTER structure
2339 * @sleepFlag: Specifies whether the process can sleep
2340 * @reason: If recovery, only update facts.
2341 *
2342 * Returns 0 for success, non-zero for failure.
2343 */
2344static int
2345GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2346{
2347 IOCFacts_t get_facts;
2348 IOCFactsReply_t *facts;
2349 int r;
2350 int req_sz;
2351 int reply_sz;
2352 int sz;
2353 u32 status, vv;
2354 u8 shiftFactor=1;
2355
2356 /* IOC *must* NOT be in RESET state! */
2357 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2358 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2359 ioc->name,
2360 ioc->last_state );
2361 return -44;
2362 }
2363
2364 facts = &ioc->facts;
2365
2366 /* Destination (reply area)... */
2367 reply_sz = sizeof(*facts);
2368 memset(facts, 0, reply_sz);
2369
2370 /* Request area (get_facts on the stack right now!) */
2371 req_sz = sizeof(get_facts);
2372 memset(&get_facts, 0, req_sz);
2373
2374 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2375 /* Assert: All other get_facts fields are zero! */
2376
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002377 dinitprintk((MYIOC_s_INFO_FMT
2378 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 ioc->name, req_sz, reply_sz));
2380
2381 /* No non-zero fields in the get_facts request are greater than
2382 * 1 byte in size, so we can just fire it off as is.
2383 */
2384 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2385 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2386 if (r != 0)
2387 return r;
2388
2389 /*
2390 * Now byte swap (GRRR) the necessary fields before any further
2391 * inspection of reply contents.
2392 *
2393 * But need to do some sanity checks on MsgLength (byte) field
2394 * to make sure we don't zero IOC's req_sz!
2395 */
2396 /* Did we get a valid reply? */
2397 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2398 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2399 /*
2400 * If not been here, done that, save off first WhoInit value
2401 */
2402 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2403 ioc->FirstWhoInit = facts->WhoInit;
2404 }
2405
2406 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2407 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2408 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2409 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2410 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002411 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /* CHECKME! IOCStatus, IOCLogInfo */
2413
2414 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2415 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2416
2417 /*
2418 * FC f/w version changed between 1.1 and 1.2
2419 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2420 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2421 */
2422 if (facts->MsgVersion < 0x0102) {
2423 /*
2424 * Handle old FC f/w style, convert to new...
2425 */
2426 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2427 facts->FWVersion.Word =
2428 ((oldv<<12) & 0xFF000000) |
2429 ((oldv<<8) & 0x000FFF00);
2430 } else
2431 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2432
2433 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002434 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2435 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2436 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 facts->CurrentHostMfaHighAddr =
2438 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2439 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2440 facts->CurrentSenseBufferHighAddr =
2441 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2442 facts->CurReplyFrameSize =
2443 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002444 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446 /*
2447 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2448 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2449 * to 14 in MPI-1.01.0x.
2450 */
2451 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2452 facts->MsgVersion > 0x0100) {
2453 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2454 }
2455
2456 sz = facts->FWImageSize;
2457 if ( sz & 0x01 )
2458 sz += 1;
2459 if ( sz & 0x02 )
2460 sz += 2;
2461 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002462
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 if (!facts->RequestFrameSize) {
2464 /* Something is wrong! */
2465 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2466 ioc->name);
2467 return -55;
2468 }
2469
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002470 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 vv = ((63 / (sz * 4)) + 1) & 0x03;
2472 ioc->NB_for_64_byte_frame = vv;
2473 while ( sz )
2474 {
2475 shiftFactor++;
2476 sz = sz >> 1;
2477 }
2478 ioc->NBShiftFactor = shiftFactor;
2479 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2480 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002481
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2483 /*
2484 * Set values for this IOC's request & reply frame sizes,
2485 * and request & reply queue depths...
2486 */
2487 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2488 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2489 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2490 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2491
2492 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2493 ioc->name, ioc->reply_sz, ioc->reply_depth));
2494 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2495 ioc->name, ioc->req_sz, ioc->req_depth));
2496
2497 /* Get port facts! */
2498 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2499 return r;
2500 }
2501 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002502 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2504 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2505 RequestFrameSize)/sizeof(u32)));
2506 return -66;
2507 }
2508
2509 return 0;
2510}
2511
2512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002513/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 * GetPortFacts - Send PortFacts request to MPT adapter.
2515 * @ioc: Pointer to MPT_ADAPTER structure
2516 * @portnum: Port number
2517 * @sleepFlag: Specifies whether the process can sleep
2518 *
2519 * Returns 0 for success, non-zero for failure.
2520 */
2521static int
2522GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2523{
2524 PortFacts_t get_pfacts;
2525 PortFactsReply_t *pfacts;
2526 int ii;
2527 int req_sz;
2528 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002529 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
2531 /* IOC *must* NOT be in RESET state! */
2532 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2533 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2534 ioc->name,
2535 ioc->last_state );
2536 return -4;
2537 }
2538
2539 pfacts = &ioc->pfacts[portnum];
2540
2541 /* Destination (reply area)... */
2542 reply_sz = sizeof(*pfacts);
2543 memset(pfacts, 0, reply_sz);
2544
2545 /* Request area (get_pfacts on the stack right now!) */
2546 req_sz = sizeof(get_pfacts);
2547 memset(&get_pfacts, 0, req_sz);
2548
2549 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2550 get_pfacts.PortNumber = portnum;
2551 /* Assert: All other get_pfacts fields are zero! */
2552
2553 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2554 ioc->name, portnum));
2555
2556 /* No non-zero fields in the get_pfacts request are greater than
2557 * 1 byte in size, so we can just fire it off as is.
2558 */
2559 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2560 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2561 if (ii != 0)
2562 return ii;
2563
2564 /* Did we get a valid reply? */
2565
2566 /* Now byte swap the necessary fields in the response. */
2567 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2568 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2569 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2570 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2571 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2572 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2573 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2574 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2575 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2576
Eric Moore793955f2007-01-29 09:42:20 -07002577 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2578 pfacts->MaxDevices;
2579 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2580 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2581
2582 /*
2583 * Place all the devices on channels
2584 *
2585 * (for debuging)
2586 */
2587 if (mpt_channel_mapping) {
2588 ioc->devices_per_bus = 1;
2589 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2590 }
2591
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 return 0;
2593}
2594
2595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002596/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 * SendIocInit - Send IOCInit request to MPT adapter.
2598 * @ioc: Pointer to MPT_ADAPTER structure
2599 * @sleepFlag: Specifies whether the process can sleep
2600 *
2601 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2602 *
2603 * Returns 0 for success, non-zero for failure.
2604 */
2605static int
2606SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2607{
2608 IOCInit_t ioc_init;
2609 MPIDefaultReply_t init_reply;
2610 u32 state;
2611 int r;
2612 int count;
2613 int cntdn;
2614
2615 memset(&ioc_init, 0, sizeof(ioc_init));
2616 memset(&init_reply, 0, sizeof(init_reply));
2617
2618 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2619 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2620
2621 /* If we are in a recovery mode and we uploaded the FW image,
2622 * then this pointer is not NULL. Skip the upload a second time.
2623 * Set this flag if cached_fw set for either IOC.
2624 */
2625 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2626 ioc->upload_fw = 1;
2627 else
2628 ioc->upload_fw = 0;
2629 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2630 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2631
Eric Moore793955f2007-01-29 09:42:20 -07002632 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2633 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002634 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2635 ioc->name, ioc->facts.MsgVersion));
2636 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2637 // set MsgVersion and HeaderVersion host driver was built with
2638 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2639 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002641 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2642 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2643 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2644 return -99;
2645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2647
2648 if (sizeof(dma_addr_t) == sizeof(u64)) {
2649 /* Save the upper 32-bits of the request
2650 * (reply) and sense buffers.
2651 */
2652 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2653 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2654 } else {
2655 /* Force 32-bit addressing */
2656 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2657 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2658 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2661 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002662 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2663 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
2665 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2666 ioc->name, &ioc_init));
2667
2668 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2669 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002670 if (r != 0) {
2671 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
2675 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002676 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 */
2678
2679 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2680 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002681
2682 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2683 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
2687 /* YIKES! SUPER IMPORTANT!!!
2688 * Poll IocState until _OPERATIONAL while IOC is doing
2689 * LoopInit and TargetDiscovery!
2690 */
2691 count = 0;
2692 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2693 state = mpt_GetIocState(ioc, 1);
2694 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2695 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002696 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 } else {
2698 mdelay(1);
2699 }
2700
2701 if (!cntdn) {
2702 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2703 ioc->name, (int)((count+5)/HZ));
2704 return -9;
2705 }
2706
2707 state = mpt_GetIocState(ioc, 1);
2708 count++;
2709 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002710 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 ioc->name, count));
2712
Eric Mooreba856d32006-07-11 17:34:01 -06002713 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 return r;
2715}
2716
2717/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002718/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 * SendPortEnable - Send PortEnable request to MPT adapter port.
2720 * @ioc: Pointer to MPT_ADAPTER structure
2721 * @portnum: Port number to enable
2722 * @sleepFlag: Specifies whether the process can sleep
2723 *
2724 * Send PortEnable to bring IOC to OPERATIONAL state.
2725 *
2726 * Returns 0 for success, non-zero for failure.
2727 */
2728static int
2729SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2730{
2731 PortEnable_t port_enable;
2732 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002733 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 int req_sz;
2735 int reply_sz;
2736
2737 /* Destination... */
2738 reply_sz = sizeof(MPIDefaultReply_t);
2739 memset(&reply_buf, 0, reply_sz);
2740
2741 req_sz = sizeof(PortEnable_t);
2742 memset(&port_enable, 0, req_sz);
2743
2744 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2745 port_enable.PortNumber = portnum;
2746/* port_enable.ChainOffset = 0; */
2747/* port_enable.MsgFlags = 0; */
2748/* port_enable.MsgContext = 0; */
2749
2750 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2751 ioc->name, portnum, &port_enable));
2752
2753 /* RAID FW may take a long time to enable
2754 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002755 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07002756 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2757 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2758 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002759 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002760 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2761 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2762 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002764 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765}
2766
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002767/**
2768 * mpt_alloc_fw_memory - allocate firmware memory
2769 * @ioc: Pointer to MPT_ADAPTER structure
2770 * @size: total FW bytes
2771 *
2772 * If memory has already been allocated, the same (cached) value
2773 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 */
2775void
2776mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2777{
2778 if (ioc->cached_fw)
2779 return; /* use already allocated memory */
2780 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2781 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2782 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06002783 ioc->alloc_total += size;
2784 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 } else {
2786 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2787 ioc->alloc_total += size;
2788 }
2789}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002790/**
2791 * mpt_free_fw_memory - free firmware memory
2792 * @ioc: Pointer to MPT_ADAPTER structure
2793 *
2794 * If alt_img is NULL, delete from ioc structure.
2795 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 */
2797void
2798mpt_free_fw_memory(MPT_ADAPTER *ioc)
2799{
2800 int sz;
2801
2802 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002803 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2805 pci_free_consistent(ioc->pcidev, sz,
2806 ioc->cached_fw, ioc->cached_fw_dma);
2807 ioc->cached_fw = NULL;
2808
2809 return;
2810}
2811
2812
2813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002814/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2816 * @ioc: Pointer to MPT_ADAPTER structure
2817 * @sleepFlag: Specifies whether the process can sleep
2818 *
2819 * Returns 0 for success, >0 for handshake failure
2820 * <0 for fw upload failure.
2821 *
2822 * Remark: If bound IOC and a successful FWUpload was performed
2823 * on the bound IOC, the second image is discarded
2824 * and memory is free'd. Both channels must upload to prevent
2825 * IOC from running in degraded mode.
2826 */
2827static int
2828mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2829{
2830 u8 request[ioc->req_sz];
2831 u8 reply[sizeof(FWUploadReply_t)];
2832 FWUpload_t *prequest;
2833 FWUploadReply_t *preply;
2834 FWUploadTCSGE_t *ptcsge;
2835 int sgeoffset;
2836 u32 flagsLength;
2837 int ii, sz, reply_sz;
2838 int cmdStatus;
2839
2840 /* If the image size is 0, we are done.
2841 */
2842 if ((sz = ioc->facts.FWImageSize) == 0)
2843 return 0;
2844
2845 mpt_alloc_fw_memory(ioc, sz);
2846
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002847 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002849
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 if (ioc->cached_fw == NULL) {
2851 /* Major Failure.
2852 */
2853 return -ENOMEM;
2854 }
2855
2856 prequest = (FWUpload_t *)&request;
2857 preply = (FWUploadReply_t *)&reply;
2858
2859 /* Destination... */
2860 memset(prequest, 0, ioc->req_sz);
2861
2862 reply_sz = sizeof(reply);
2863 memset(preply, 0, reply_sz);
2864
2865 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2866 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2867
2868 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2869 ptcsge->DetailsLength = 12;
2870 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2871 ptcsge->ImageSize = cpu_to_le32(sz);
2872
2873 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2874
2875 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2876 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2877
2878 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002879 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 prequest, sgeoffset));
2881 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2882
2883 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2884 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2885
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002886 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 cmdStatus = -EFAULT;
2889 if (ii == 0) {
2890 /* Handshake transfer was complete and successful.
2891 * Check the Reply Frame.
2892 */
2893 int status, transfer_sz;
2894 status = le16_to_cpu(preply->IOCStatus);
2895 if (status == MPI_IOCSTATUS_SUCCESS) {
2896 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2897 if (transfer_sz == sz)
2898 cmdStatus = 0;
2899 }
2900 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002901 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 ioc->name, cmdStatus));
2903
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 if (cmdStatus) {
2906
2907 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2908 ioc->name));
2909 mpt_free_fw_memory(ioc);
2910 }
2911
2912 return cmdStatus;
2913}
2914
2915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002916/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 * mpt_downloadboot - DownloadBoot code
2918 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002919 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 * @sleepFlag: Specifies whether the process can sleep
2921 *
2922 * FwDownloadBoot requires Programmed IO access.
2923 *
2924 * Returns 0 for success
2925 * -1 FW Image size is 0
2926 * -2 No valid cached_fw Pointer
2927 * <0 for fw upload failure.
2928 */
2929static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002930mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 MpiExtImageHeader_t *pExtImage;
2933 u32 fwSize;
2934 u32 diag0val;
2935 int count;
2936 u32 *ptrFw;
2937 u32 diagRwData;
2938 u32 nextImage;
2939 u32 load_addr;
2940 u32 ioc_state=0;
2941
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002942 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2943 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002944
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2946 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2947 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2948 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2949 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2950 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2951
2952 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2953
2954 /* wait 1 msec */
2955 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002956 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 } else {
2958 mdelay (1);
2959 }
2960
2961 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2962 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2963
2964 for (count = 0; count < 30; count ++) {
2965 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2966 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2967 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2968 ioc->name, count));
2969 break;
2970 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002971 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002973 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002975 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977 }
2978
2979 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002980 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2981 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 ioc->name, diag0val));
2983 return -3;
2984 }
2985
2986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2988 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2989 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2990 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2991 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2992
2993 /* Set the DiagRwEn and Disable ARM bits */
2994 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2995
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 fwSize = (pFwHeader->ImageSize + 3)/4;
2997 ptrFw = (u32 *) pFwHeader;
2998
2999 /* Write the LoadStartAddress to the DiagRw Address Register
3000 * using Programmed IO
3001 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003002 if (ioc->errata_flag_1064)
3003 pci_enable_io_access(ioc->pcidev);
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3006 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3007 ioc->name, pFwHeader->LoadStartAddress));
3008
3009 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3010 ioc->name, fwSize*4, ptrFw));
3011 while (fwSize--) {
3012 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3013 }
3014
3015 nextImage = pFwHeader->NextImageHeaderOffset;
3016 while (nextImage) {
3017 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3018
3019 load_addr = pExtImage->LoadStartAddress;
3020
3021 fwSize = (pExtImage->ImageSize + 3) >> 2;
3022 ptrFw = (u32 *)pExtImage;
3023
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003024 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3025 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3027
3028 while (fwSize--) {
3029 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3030 }
3031 nextImage = pExtImage->NextImageHeaderOffset;
3032 }
3033
3034 /* Write the IopResetVectorRegAddr */
3035 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3036 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3037
3038 /* Write the IopResetVectorValue */
3039 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3040 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3041
3042 /* Clear the internal flash bad bit - autoincrementing register,
3043 * so must do two writes.
3044 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003045 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003046 /*
3047 * 1030 and 1035 H/W errata, workaround to access
3048 * the ClearFlashBadSignatureBit
3049 */
3050 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3051 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3052 diagRwData |= 0x40000000;
3053 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3054 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3055
3056 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3057 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3058 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3059 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3060
3061 /* wait 1 msec */
3062 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003063 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003064 } else {
3065 mdelay (1);
3066 }
3067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003069 if (ioc->errata_flag_1064)
3070 pci_disable_io_access(ioc->pcidev);
3071
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003073 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3074 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003076 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3078 ioc->name, diag0val));
3079 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3080
3081 /* Write 0xFF to reset the sequencer */
3082 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3083
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003084 if (ioc->bus_type == SAS) {
3085 ioc_state = mpt_GetIocState(ioc, 0);
3086 if ( (GetIocFacts(ioc, sleepFlag,
3087 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3088 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3089 ioc->name, ioc_state));
3090 return -EFAULT;
3091 }
3092 }
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 for (count=0; count<HZ*20; count++) {
3095 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3096 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3097 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003098 if (ioc->bus_type == SAS) {
3099 return 0;
3100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3102 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3103 ioc->name));
3104 return -EFAULT;
3105 }
3106 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3107 ioc->name));
3108 return 0;
3109 }
3110 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003111 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 } else {
3113 mdelay (10);
3114 }
3115 }
3116 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3117 ioc->name, ioc_state));
3118 return -EFAULT;
3119}
3120
3121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003122/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 * KickStart - Perform hard reset of MPT adapter.
3124 * @ioc: Pointer to MPT_ADAPTER structure
3125 * @force: Force hard reset
3126 * @sleepFlag: Specifies whether the process can sleep
3127 *
3128 * This routine places MPT adapter in diagnostic mode via the
3129 * WriteSequence register, and then performs a hard reset of adapter
3130 * via the Diagnostic register.
3131 *
3132 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3133 * or NO_SLEEP (interrupt thread, use mdelay)
3134 * force - 1 if doorbell active, board fault state
3135 * board operational, IOC_RECOVERY or
3136 * IOC_BRINGUP and there is an alt_ioc.
3137 * 0 else
3138 *
3139 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003140 * 1 - hard reset, READY
3141 * 0 - no reset due to History bit, READY
3142 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 * OR reset but failed to come READY
3144 * -2 - no reset, could not enter DIAG mode
3145 * -3 - reset but bad FW bit
3146 */
3147static int
3148KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3149{
3150 int hard_reset_done = 0;
3151 u32 ioc_state=0;
3152 int cnt,cntdn;
3153
3154 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003155 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 /* Always issue a Msg Unit Reset first. This will clear some
3157 * SCSI bus hang conditions.
3158 */
3159 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3160
3161 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003162 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 } else {
3164 mdelay (1000);
3165 }
3166 }
3167
3168 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3169 if (hard_reset_done < 0)
3170 return hard_reset_done;
3171
3172 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3173 ioc->name));
3174
3175 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3176 for (cnt=0; cnt<cntdn; cnt++) {
3177 ioc_state = mpt_GetIocState(ioc, 1);
3178 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3179 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3180 ioc->name, cnt));
3181 return hard_reset_done;
3182 }
3183 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003184 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 } else {
3186 mdelay (10);
3187 }
3188 }
3189
3190 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3191 ioc->name, ioc_state);
3192 return -1;
3193}
3194
3195/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003196/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 * mpt_diag_reset - Perform hard reset of the adapter.
3198 * @ioc: Pointer to MPT_ADAPTER structure
3199 * @ignore: Set if to honor and clear to ignore
3200 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003201 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 * else set to NO_SLEEP (use mdelay instead)
3203 *
3204 * This routine places the adapter in diagnostic mode via the
3205 * WriteSequence register and then performs a hard reset of adapter
3206 * via the Diagnostic register. Adapter should be in ready state
3207 * upon successful completion.
3208 *
3209 * Returns: 1 hard reset successful
3210 * 0 no reset performed because reset history bit set
3211 * -2 enabling diagnostic mode failed
3212 * -3 diagnostic reset failed
3213 */
3214static int
3215mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3216{
Eric Moore0ccdb002006-07-11 17:33:13 -06003217 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 u32 diag0val;
3219 u32 doorbell;
3220 int hard_reset_done = 0;
3221 int count = 0;
3222#ifdef MPT_DEBUG
3223 u32 diag1val = 0;
3224#endif
3225
Eric Moorecd2c6192007-01-29 09:47:47 -07003226 /* Clear any existing interrupts */
3227 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3228
Eric Moore87cf8982006-06-27 16:09:26 -06003229 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3230 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3231 "address=%p\n", ioc->name, __FUNCTION__,
3232 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3233 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3234 if (sleepFlag == CAN_SLEEP)
3235 msleep(1);
3236 else
3237 mdelay(1);
3238
3239 for (count = 0; count < 60; count ++) {
3240 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3241 doorbell &= MPI_IOC_STATE_MASK;
3242
3243 drsprintk((MYIOC_s_INFO_FMT
3244 "looking for READY STATE: doorbell=%x"
3245 " count=%d\n",
3246 ioc->name, doorbell, count));
3247 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003248 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003249 }
3250
3251 /* wait 1 sec */
3252 if (sleepFlag == CAN_SLEEP)
3253 msleep(1000);
3254 else
3255 mdelay(1000);
3256 }
3257 return -1;
3258 }
3259
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 /* Use "Diagnostic reset" method! (only thing available!) */
3261 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3262
3263#ifdef MPT_DEBUG
3264 if (ioc->alt_ioc)
3265 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3266 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3267 ioc->name, diag0val, diag1val));
3268#endif
3269
3270 /* Do the reset if we are told to ignore the reset history
3271 * or if the reset history is 0
3272 */
3273 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3274 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3275 /* Write magic sequence to WriteSequence register
3276 * Loop until in diagnostic mode
3277 */
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3279 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3280 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3281 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3282 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3283 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3284
3285 /* wait 100 msec */
3286 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003287 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 } else {
3289 mdelay (100);
3290 }
3291
3292 count++;
3293 if (count > 20) {
3294 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3295 ioc->name, diag0val);
3296 return -2;
3297
3298 }
3299
3300 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3301
3302 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3303 ioc->name, diag0val));
3304 }
3305
3306#ifdef MPT_DEBUG
3307 if (ioc->alt_ioc)
3308 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3309 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3310 ioc->name, diag0val, diag1val));
3311#endif
3312 /*
3313 * Disable the ARM (Bug fix)
3314 *
3315 */
3316 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003317 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
3319 /*
3320 * Now hit the reset bit in the Diagnostic register
3321 * (THE BIG HAMMER!) (Clears DRWE bit).
3322 */
3323 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3324 hard_reset_done = 1;
3325 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3326 ioc->name));
3327
3328 /*
3329 * Call each currently registered protocol IOC reset handler
3330 * with pre-reset indication.
3331 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3332 * MptResetHandlers[] registered yet.
3333 */
3334 {
3335 int ii;
3336 int r = 0;
3337
3338 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3339 if (MptResetHandlers[ii]) {
3340 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3341 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003342 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 if (ioc->alt_ioc) {
3344 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3345 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003346 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 }
3348 }
3349 }
3350 /* FIXME? Examine results here? */
3351 }
3352
Eric Moore0ccdb002006-07-11 17:33:13 -06003353 if (ioc->cached_fw)
3354 iocp = ioc;
3355 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3356 iocp = ioc->alt_ioc;
3357 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 /* If the DownloadBoot operation fails, the
3359 * IOC will be left unusable. This is a fatal error
3360 * case. _diag_reset will return < 0
3361 */
3362 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003363 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3365 break;
3366 }
3367
Eric Moore0ccdb002006-07-11 17:33:13 -06003368 dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
3369 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 /* wait 1 sec */
3371 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003372 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 } else {
3374 mdelay (1000);
3375 }
3376 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003377 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003378 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 printk(KERN_WARNING MYNAM
3380 ": firmware downloadboot failure (%d)!\n", count);
3381 }
3382
3383 } else {
3384 /* Wait for FW to reload and for board
3385 * to go to the READY state.
3386 * Maximum wait is 60 seconds.
3387 * If fail, no error will check again
3388 * with calling program.
3389 */
3390 for (count = 0; count < 60; count ++) {
3391 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3392 doorbell &= MPI_IOC_STATE_MASK;
3393
3394 if (doorbell == MPI_IOC_STATE_READY) {
3395 break;
3396 }
3397
3398 /* wait 1 sec */
3399 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003400 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 } else {
3402 mdelay (1000);
3403 }
3404 }
3405 }
3406 }
3407
3408 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3409#ifdef MPT_DEBUG
3410 if (ioc->alt_ioc)
3411 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3412 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3413 ioc->name, diag0val, diag1val));
3414#endif
3415
3416 /* Clear RESET_HISTORY bit! Place board in the
3417 * diagnostic mode to update the diag register.
3418 */
3419 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3420 count = 0;
3421 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3422 /* Write magic sequence to WriteSequence register
3423 * Loop until in diagnostic mode
3424 */
3425 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3426 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3427 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3428 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3429 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3430 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3431
3432 /* wait 100 msec */
3433 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003434 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 } else {
3436 mdelay (100);
3437 }
3438
3439 count++;
3440 if (count > 20) {
3441 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3442 ioc->name, diag0val);
3443 break;
3444 }
3445 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3446 }
3447 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3448 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3449 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3450 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3451 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3452 ioc->name);
3453 }
3454
3455 /* Disable Diagnostic Mode
3456 */
3457 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3458
3459 /* Check FW reload status flags.
3460 */
3461 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3462 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3463 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3464 ioc->name, diag0val);
3465 return -3;
3466 }
3467
3468#ifdef MPT_DEBUG
3469 if (ioc->alt_ioc)
3470 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3471 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3472 ioc->name, diag0val, diag1val));
3473#endif
3474
3475 /*
3476 * Reset flag that says we've enabled event notification
3477 */
3478 ioc->facts.EventState = 0;
3479
3480 if (ioc->alt_ioc)
3481 ioc->alt_ioc->facts.EventState = 0;
3482
3483 return hard_reset_done;
3484}
3485
3486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003487/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 * SendIocReset - Send IOCReset request to MPT adapter.
3489 * @ioc: Pointer to MPT_ADAPTER structure
3490 * @reset_type: reset type, expected values are
3491 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003492 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 *
3494 * Send IOCReset request to the MPT adapter.
3495 *
3496 * Returns 0 for success, non-zero for failure.
3497 */
3498static int
3499SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3500{
3501 int r;
3502 u32 state;
3503 int cntdn, count;
3504
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003505 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 ioc->name, reset_type));
3507 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3508 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3509 return r;
3510
3511 /* FW ACK'd request, wait for READY state
3512 */
3513 count = 0;
3514 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3515
3516 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3517 cntdn--;
3518 count++;
3519 if (!cntdn) {
3520 if (sleepFlag != CAN_SLEEP)
3521 count *= 10;
3522
3523 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3524 ioc->name, (int)((count+5)/HZ));
3525 return -ETIME;
3526 }
3527
3528 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003529 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 } else {
3531 mdelay (1); /* 1 msec delay */
3532 }
3533 }
3534
3535 /* TODO!
3536 * Cleanup all event stuff for this IOC; re-issue EventNotification
3537 * request if needed.
3538 */
3539 if (ioc->facts.Function)
3540 ioc->facts.EventState = 0;
3541
3542 return 0;
3543}
3544
3545/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003546/**
3547 * initChainBuffers - Allocate memory for and initialize chain buffers
3548 * @ioc: Pointer to MPT_ADAPTER structure
3549 *
3550 * Allocates memory for and initializes chain buffers,
3551 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 */
3553static int
3554initChainBuffers(MPT_ADAPTER *ioc)
3555{
3556 u8 *mem;
3557 int sz, ii, num_chain;
3558 int scale, num_sge, numSGE;
3559
3560 /* ReqToChain size must equal the req_depth
3561 * index = req_idx
3562 */
3563 if (ioc->ReqToChain == NULL) {
3564 sz = ioc->req_depth * sizeof(int);
3565 mem = kmalloc(sz, GFP_ATOMIC);
3566 if (mem == NULL)
3567 return -1;
3568
3569 ioc->ReqToChain = (int *) mem;
3570 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3571 ioc->name, mem, sz));
3572 mem = kmalloc(sz, GFP_ATOMIC);
3573 if (mem == NULL)
3574 return -1;
3575
3576 ioc->RequestNB = (int *) mem;
3577 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3578 ioc->name, mem, sz));
3579 }
3580 for (ii = 0; ii < ioc->req_depth; ii++) {
3581 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3582 }
3583
3584 /* ChainToChain size must equal the total number
3585 * of chain buffers to be allocated.
3586 * index = chain_idx
3587 *
3588 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003589 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 *
3591 * num_sge = num sge in request frame + last chain buffer
3592 * scale = num sge per chain buffer if no chain element
3593 */
3594 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3595 if (sizeof(dma_addr_t) == sizeof(u64))
3596 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3597 else
3598 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3599
3600 if (sizeof(dma_addr_t) == sizeof(u64)) {
3601 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3602 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3603 } else {
3604 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3605 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3606 }
3607 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3608 ioc->name, num_sge, numSGE));
3609
3610 if ( numSGE > MPT_SCSI_SG_DEPTH )
3611 numSGE = MPT_SCSI_SG_DEPTH;
3612
3613 num_chain = 1;
3614 while (numSGE - num_sge > 0) {
3615 num_chain++;
3616 num_sge += (scale - 1);
3617 }
3618 num_chain++;
3619
3620 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3621 ioc->name, numSGE, num_sge, num_chain));
3622
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003623 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 num_chain *= MPT_SCSI_CAN_QUEUE;
3625 else
3626 num_chain *= MPT_FC_CAN_QUEUE;
3627
3628 ioc->num_chain = num_chain;
3629
3630 sz = num_chain * sizeof(int);
3631 if (ioc->ChainToChain == NULL) {
3632 mem = kmalloc(sz, GFP_ATOMIC);
3633 if (mem == NULL)
3634 return -1;
3635
3636 ioc->ChainToChain = (int *) mem;
3637 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3638 ioc->name, mem, sz));
3639 } else {
3640 mem = (u8 *) ioc->ChainToChain;
3641 }
3642 memset(mem, 0xFF, sz);
3643 return num_chain;
3644}
3645
3646/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003647/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3649 * @ioc: Pointer to MPT_ADAPTER structure
3650 *
3651 * This routine allocates memory for the MPT reply and request frame
3652 * pools (if necessary), and primes the IOC reply FIFO with
3653 * reply frames.
3654 *
3655 * Returns 0 for success, non-zero for failure.
3656 */
3657static int
3658PrimeIocFifos(MPT_ADAPTER *ioc)
3659{
3660 MPT_FRAME_HDR *mf;
3661 unsigned long flags;
3662 dma_addr_t alloc_dma;
3663 u8 *mem;
3664 int i, reply_sz, sz, total_size, num_chain;
3665
3666 /* Prime reply FIFO... */
3667
3668 if (ioc->reply_frames == NULL) {
3669 if ( (num_chain = initChainBuffers(ioc)) < 0)
3670 return -1;
3671
3672 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3673 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3674 ioc->name, ioc->reply_sz, ioc->reply_depth));
3675 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3676 ioc->name, reply_sz, reply_sz));
3677
3678 sz = (ioc->req_sz * ioc->req_depth);
3679 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3680 ioc->name, ioc->req_sz, ioc->req_depth));
3681 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3682 ioc->name, sz, sz));
3683 total_size += sz;
3684
3685 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3686 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3687 ioc->name, ioc->req_sz, num_chain));
3688 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3689 ioc->name, sz, sz, num_chain));
3690
3691 total_size += sz;
3692 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3693 if (mem == NULL) {
3694 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3695 ioc->name);
3696 goto out_fail;
3697 }
3698
3699 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3700 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3701
3702 memset(mem, 0, total_size);
3703 ioc->alloc_total += total_size;
3704 ioc->alloc = mem;
3705 ioc->alloc_dma = alloc_dma;
3706 ioc->alloc_sz = total_size;
3707 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3708 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3709
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003710 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3711 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3712
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 alloc_dma += reply_sz;
3714 mem += reply_sz;
3715
3716 /* Request FIFO - WE manage this! */
3717
3718 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3719 ioc->req_frames_dma = alloc_dma;
3720
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003721 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 ioc->name, mem, (void *)(ulong)alloc_dma));
3723
3724 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3725
3726#if defined(CONFIG_MTRR) && 0
3727 /*
3728 * Enable Write Combining MTRR for IOC's memory region.
3729 * (at least as much as we can; "size and base must be
3730 * multiples of 4 kiB"
3731 */
3732 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3733 sz,
3734 MTRR_TYPE_WRCOMB, 1);
3735 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3736 ioc->name, ioc->req_frames_dma, sz));
3737#endif
3738
3739 for (i = 0; i < ioc->req_depth; i++) {
3740 alloc_dma += ioc->req_sz;
3741 mem += ioc->req_sz;
3742 }
3743
3744 ioc->ChainBuffer = mem;
3745 ioc->ChainBufferDMA = alloc_dma;
3746
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003747 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3749
3750 /* Initialize the free chain Q.
3751 */
3752
3753 INIT_LIST_HEAD(&ioc->FreeChainQ);
3754
3755 /* Post the chain buffers to the FreeChainQ.
3756 */
3757 mem = (u8 *)ioc->ChainBuffer;
3758 for (i=0; i < num_chain; i++) {
3759 mf = (MPT_FRAME_HDR *) mem;
3760 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3761 mem += ioc->req_sz;
3762 }
3763
3764 /* Initialize Request frames linked list
3765 */
3766 alloc_dma = ioc->req_frames_dma;
3767 mem = (u8 *) ioc->req_frames;
3768
3769 spin_lock_irqsave(&ioc->FreeQlock, flags);
3770 INIT_LIST_HEAD(&ioc->FreeQ);
3771 for (i = 0; i < ioc->req_depth; i++) {
3772 mf = (MPT_FRAME_HDR *) mem;
3773
3774 /* Queue REQUESTs *internally*! */
3775 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3776
3777 mem += ioc->req_sz;
3778 }
3779 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3780
3781 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3782 ioc->sense_buf_pool =
3783 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3784 if (ioc->sense_buf_pool == NULL) {
3785 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3786 ioc->name);
3787 goto out_fail;
3788 }
3789
3790 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3791 ioc->alloc_total += sz;
3792 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3793 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3794
3795 }
3796
3797 /* Post Reply frames to FIFO
3798 */
3799 alloc_dma = ioc->alloc_dma;
3800 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3801 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3802
3803 for (i = 0; i < ioc->reply_depth; i++) {
3804 /* Write each address to the IOC! */
3805 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3806 alloc_dma += ioc->reply_sz;
3807 }
3808
3809 return 0;
3810
3811out_fail:
3812 if (ioc->alloc != NULL) {
3813 sz = ioc->alloc_sz;
3814 pci_free_consistent(ioc->pcidev,
3815 sz,
3816 ioc->alloc, ioc->alloc_dma);
3817 ioc->reply_frames = NULL;
3818 ioc->req_frames = NULL;
3819 ioc->alloc_total -= sz;
3820 }
3821 if (ioc->sense_buf_pool != NULL) {
3822 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3823 pci_free_consistent(ioc->pcidev,
3824 sz,
3825 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3826 ioc->sense_buf_pool = NULL;
3827 }
3828 return -1;
3829}
3830
3831/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3832/**
3833 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3834 * from IOC via doorbell handshake method.
3835 * @ioc: Pointer to MPT_ADAPTER structure
3836 * @reqBytes: Size of the request in bytes
3837 * @req: Pointer to MPT request frame
3838 * @replyBytes: Expected size of the reply in bytes
3839 * @u16reply: Pointer to area where reply should be written
3840 * @maxwait: Max wait time for a reply (in seconds)
3841 * @sleepFlag: Specifies whether the process can sleep
3842 *
3843 * NOTES: It is the callers responsibility to byte-swap fields in the
3844 * request which are greater than 1 byte in size. It is also the
3845 * callers responsibility to byte-swap response fields which are
3846 * greater than 1 byte in size.
3847 *
3848 * Returns 0 for success, non-zero for failure.
3849 */
3850static int
3851mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003852 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853{
3854 MPIDefaultReply_t *mptReply;
3855 int failcnt = 0;
3856 int t;
3857
3858 /*
3859 * Get ready to cache a handshake reply
3860 */
3861 ioc->hs_reply_idx = 0;
3862 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3863 mptReply->MsgLength = 0;
3864
3865 /*
3866 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3867 * then tell IOC that we want to handshake a request of N words.
3868 * (WRITE u32val to Doorbell reg).
3869 */
3870 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3871 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3872 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3873 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3874
3875 /*
3876 * Wait for IOC's doorbell handshake int
3877 */
3878 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3879 failcnt++;
3880
3881 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3882 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3883
3884 /* Read doorbell and check for active bit */
3885 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3886 return -1;
3887
3888 /*
3889 * Clear doorbell int (WRITE 0 to IntStatus reg),
3890 * then wait for IOC to ACKnowledge that it's ready for
3891 * our handshake request.
3892 */
3893 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3894 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3895 failcnt++;
3896
3897 if (!failcnt) {
3898 int ii;
3899 u8 *req_as_bytes = (u8 *) req;
3900
3901 /*
3902 * Stuff request words via doorbell handshake,
3903 * with ACK from IOC for each.
3904 */
3905 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3906 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3907 (req_as_bytes[(ii*4) + 1] << 8) |
3908 (req_as_bytes[(ii*4) + 2] << 16) |
3909 (req_as_bytes[(ii*4) + 3] << 24));
3910
3911 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3912 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3913 failcnt++;
3914 }
3915
3916 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3917 DBG_DUMP_REQUEST_FRAME_HDR(req)
3918
3919 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3920 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3921
3922 /*
3923 * Wait for completion of doorbell handshake reply from the IOC
3924 */
3925 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3926 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3929 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3930
3931 /*
3932 * Copy out the cached reply...
3933 */
3934 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3935 u16reply[ii] = ioc->hs_reply[ii];
3936 } else {
3937 return -99;
3938 }
3939
3940 return -failcnt;
3941}
3942
3943/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003944/**
3945 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 * @ioc: Pointer to MPT_ADAPTER structure
3947 * @howlong: How long to wait (in seconds)
3948 * @sleepFlag: Specifies whether the process can sleep
3949 *
3950 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003951 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
3952 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 *
3954 * Returns a negative value on failure, else wait loop count.
3955 */
3956static int
3957WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3958{
3959 int cntdn;
3960 int count = 0;
3961 u32 intstat=0;
3962
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003963 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964
3965 if (sleepFlag == CAN_SLEEP) {
3966 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003967 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3969 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3970 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 count++;
3972 }
3973 } else {
3974 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003975 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3977 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3978 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 count++;
3980 }
3981 }
3982
3983 if (cntdn) {
3984 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3985 ioc->name, count));
3986 return count;
3987 }
3988
3989 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3990 ioc->name, count, intstat);
3991 return -1;
3992}
3993
3994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003995/**
3996 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 * @ioc: Pointer to MPT_ADAPTER structure
3998 * @howlong: How long to wait (in seconds)
3999 * @sleepFlag: Specifies whether the process can sleep
4000 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004001 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4002 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 *
4004 * Returns a negative value on failure, else wait loop count.
4005 */
4006static int
4007WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4008{
4009 int cntdn;
4010 int count = 0;
4011 u32 intstat=0;
4012
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004013 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 if (sleepFlag == CAN_SLEEP) {
4015 while (--cntdn) {
4016 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4017 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4018 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004019 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 count++;
4021 }
4022 } else {
4023 while (--cntdn) {
4024 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4025 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4026 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004027 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 count++;
4029 }
4030 }
4031
4032 if (cntdn) {
4033 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4034 ioc->name, count, howlong));
4035 return count;
4036 }
4037
4038 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4039 ioc->name, count, intstat);
4040 return -1;
4041}
4042
4043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004044/**
4045 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 * @ioc: Pointer to MPT_ADAPTER structure
4047 * @howlong: How long to wait (in seconds)
4048 * @sleepFlag: Specifies whether the process can sleep
4049 *
4050 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4051 * Reply is cached to IOC private area large enough to hold a maximum
4052 * of 128 bytes of reply data.
4053 *
4054 * Returns a negative value on failure, else size of reply in WORDS.
4055 */
4056static int
4057WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4058{
4059 int u16cnt = 0;
4060 int failcnt = 0;
4061 int t;
4062 u16 *hs_reply = ioc->hs_reply;
4063 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4064 u16 hword;
4065
4066 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4067
4068 /*
4069 * Get first two u16's so we can look at IOC's intended reply MsgLength
4070 */
4071 u16cnt=0;
4072 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4073 failcnt++;
4074 } else {
4075 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4076 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4077 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4078 failcnt++;
4079 else {
4080 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4081 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4082 }
4083 }
4084
4085 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004086 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4088
4089 /*
4090 * If no error (and IOC said MsgLength is > 0), piece together
4091 * reply 16 bits at a time.
4092 */
4093 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4094 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4095 failcnt++;
4096 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4097 /* don't overflow our IOC hs_reply[] buffer! */
4098 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4099 hs_reply[u16cnt] = hword;
4100 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4101 }
4102
4103 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4104 failcnt++;
4105 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4106
4107 if (failcnt) {
4108 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4109 ioc->name);
4110 return -failcnt;
4111 }
4112#if 0
4113 else if (u16cnt != (2 * mptReply->MsgLength)) {
4114 return -101;
4115 }
4116 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4117 return -102;
4118 }
4119#endif
4120
4121 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4122 DBG_DUMP_REPLY_FRAME(mptReply)
4123
4124 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4125 ioc->name, t, u16cnt/2));
4126 return u16cnt/2;
4127}
4128
4129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004130/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 * GetLanConfigPages - Fetch LANConfig pages.
4132 * @ioc: Pointer to MPT_ADAPTER structure
4133 *
4134 * Return: 0 for success
4135 * -ENOMEM if no memory available
4136 * -EPERM if not allowed due to ISR context
4137 * -EAGAIN if no msg frames currently available
4138 * -EFAULT for non-successful reply or no reply (timeout)
4139 */
4140static int
4141GetLanConfigPages(MPT_ADAPTER *ioc)
4142{
4143 ConfigPageHeader_t hdr;
4144 CONFIGPARMS cfg;
4145 LANPage0_t *ppage0_alloc;
4146 dma_addr_t page0_dma;
4147 LANPage1_t *ppage1_alloc;
4148 dma_addr_t page1_dma;
4149 int rc = 0;
4150 int data_sz;
4151 int copy_sz;
4152
4153 /* Get LAN Page 0 header */
4154 hdr.PageVersion = 0;
4155 hdr.PageLength = 0;
4156 hdr.PageNumber = 0;
4157 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004158 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 cfg.physAddr = -1;
4160 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4161 cfg.dir = 0;
4162 cfg.pageAddr = 0;
4163 cfg.timeout = 0;
4164
4165 if ((rc = mpt_config(ioc, &cfg)) != 0)
4166 return rc;
4167
4168 if (hdr.PageLength > 0) {
4169 data_sz = hdr.PageLength * 4;
4170 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4171 rc = -ENOMEM;
4172 if (ppage0_alloc) {
4173 memset((u8 *)ppage0_alloc, 0, data_sz);
4174 cfg.physAddr = page0_dma;
4175 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4176
4177 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4178 /* save the data */
4179 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4180 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4181
4182 }
4183
4184 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4185
4186 /* FIXME!
4187 * Normalize endianness of structure data,
4188 * by byte-swapping all > 1 byte fields!
4189 */
4190
4191 }
4192
4193 if (rc)
4194 return rc;
4195 }
4196
4197 /* Get LAN Page 1 header */
4198 hdr.PageVersion = 0;
4199 hdr.PageLength = 0;
4200 hdr.PageNumber = 1;
4201 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004202 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 cfg.physAddr = -1;
4204 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4205 cfg.dir = 0;
4206 cfg.pageAddr = 0;
4207
4208 if ((rc = mpt_config(ioc, &cfg)) != 0)
4209 return rc;
4210
4211 if (hdr.PageLength == 0)
4212 return 0;
4213
4214 data_sz = hdr.PageLength * 4;
4215 rc = -ENOMEM;
4216 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4217 if (ppage1_alloc) {
4218 memset((u8 *)ppage1_alloc, 0, data_sz);
4219 cfg.physAddr = page1_dma;
4220 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4221
4222 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4223 /* save the data */
4224 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4225 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4226 }
4227
4228 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4229
4230 /* FIXME!
4231 * Normalize endianness of structure data,
4232 * by byte-swapping all > 1 byte fields!
4233 */
4234
4235 }
4236
4237 return rc;
4238}
4239
4240/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004241/**
4242 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004243 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004244 * @persist_opcode: see below
4245 *
4246 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4247 * devices not currently present.
4248 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4249 *
4250 * NOTE: Don't use not this function during interrupt time.
4251 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004252 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004253 */
4254
4255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4256int
4257mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4258{
4259 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4260 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4261 MPT_FRAME_HDR *mf = NULL;
4262 MPIHeader_t *mpi_hdr;
4263
4264
4265 /* insure garbage is not sent to fw */
4266 switch(persist_opcode) {
4267
4268 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4269 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4270 break;
4271
4272 default:
4273 return -1;
4274 break;
4275 }
4276
4277 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4278
4279 /* Get a MF for this command.
4280 */
4281 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4282 printk("%s: no msg frames!\n",__FUNCTION__);
4283 return -1;
4284 }
4285
4286 mpi_hdr = (MPIHeader_t *) mf;
4287 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4288 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4289 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4290 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4291 sasIoUnitCntrReq->Operation = persist_opcode;
4292
4293 init_timer(&ioc->persist_timer);
4294 ioc->persist_timer.data = (unsigned long) ioc;
4295 ioc->persist_timer.function = mpt_timer_expired;
4296 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4297 ioc->persist_wait_done=0;
4298 add_timer(&ioc->persist_timer);
4299 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4300 wait_event(mpt_waitq, ioc->persist_wait_done);
4301
4302 sasIoUnitCntrReply =
4303 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4304 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4305 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4306 __FUNCTION__,
4307 sasIoUnitCntrReply->IOCStatus,
4308 sasIoUnitCntrReply->IOCLogInfo);
4309 return -1;
4310 }
4311
4312 printk("%s: success\n",__FUNCTION__);
4313 return 0;
4314}
4315
4316/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004317
4318static void
4319mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4320 MpiEventDataRaid_t * pRaidEventData)
4321{
4322 int volume;
4323 int reason;
4324 int disk;
4325 int status;
4326 int flags;
4327 int state;
4328
4329 volume = pRaidEventData->VolumeID;
4330 reason = pRaidEventData->ReasonCode;
4331 disk = pRaidEventData->PhysDiskNum;
4332 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4333 flags = (status >> 0) & 0xff;
4334 state = (status >> 8) & 0xff;
4335
4336 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4337 return;
4338 }
4339
4340 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4341 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4342 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004343 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4344 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004345 } else {
4346 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4347 ioc->name, volume);
4348 }
4349
4350 switch(reason) {
4351 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4352 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4353 ioc->name);
4354 break;
4355
4356 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4357
4358 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4359 ioc->name);
4360 break;
4361
4362 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4363 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4364 ioc->name);
4365 break;
4366
4367 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4368 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4369 ioc->name,
4370 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4371 ? "optimal"
4372 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4373 ? "degraded"
4374 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4375 ? "failed"
4376 : "state unknown",
4377 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4378 ? ", enabled" : "",
4379 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4380 ? ", quiesced" : "",
4381 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4382 ? ", resync in progress" : "" );
4383 break;
4384
4385 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4386 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4387 ioc->name, disk);
4388 break;
4389
4390 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4391 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4392 ioc->name);
4393 break;
4394
4395 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4396 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4397 ioc->name);
4398 break;
4399
4400 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4401 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4402 ioc->name);
4403 break;
4404
4405 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4406 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4407 ioc->name,
4408 state == MPI_PHYSDISK0_STATUS_ONLINE
4409 ? "online"
4410 : state == MPI_PHYSDISK0_STATUS_MISSING
4411 ? "missing"
4412 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4413 ? "not compatible"
4414 : state == MPI_PHYSDISK0_STATUS_FAILED
4415 ? "failed"
4416 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4417 ? "initializing"
4418 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4419 ? "offline requested"
4420 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4421 ? "failed requested"
4422 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4423 ? "offline"
4424 : "state unknown",
4425 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4426 ? ", out of sync" : "",
4427 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4428 ? ", quiesced" : "" );
4429 break;
4430
4431 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4432 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4433 ioc->name, disk);
4434 break;
4435
4436 case MPI_EVENT_RAID_RC_SMART_DATA:
4437 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4438 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4439 break;
4440
4441 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4442 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4443 ioc->name, disk);
4444 break;
4445 }
4446}
4447
4448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004449/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4451 * @ioc: Pointer to MPT_ADAPTER structure
4452 *
4453 * Returns: 0 for success
4454 * -ENOMEM if no memory available
4455 * -EPERM if not allowed due to ISR context
4456 * -EAGAIN if no msg frames currently available
4457 * -EFAULT for non-successful reply or no reply (timeout)
4458 */
4459static int
4460GetIoUnitPage2(MPT_ADAPTER *ioc)
4461{
4462 ConfigPageHeader_t hdr;
4463 CONFIGPARMS cfg;
4464 IOUnitPage2_t *ppage_alloc;
4465 dma_addr_t page_dma;
4466 int data_sz;
4467 int rc;
4468
4469 /* Get the page header */
4470 hdr.PageVersion = 0;
4471 hdr.PageLength = 0;
4472 hdr.PageNumber = 2;
4473 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004474 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 cfg.physAddr = -1;
4476 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4477 cfg.dir = 0;
4478 cfg.pageAddr = 0;
4479 cfg.timeout = 0;
4480
4481 if ((rc = mpt_config(ioc, &cfg)) != 0)
4482 return rc;
4483
4484 if (hdr.PageLength == 0)
4485 return 0;
4486
4487 /* Read the config page */
4488 data_sz = hdr.PageLength * 4;
4489 rc = -ENOMEM;
4490 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4491 if (ppage_alloc) {
4492 memset((u8 *)ppage_alloc, 0, data_sz);
4493 cfg.physAddr = page_dma;
4494 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4495
4496 /* If Good, save data */
4497 if ((rc = mpt_config(ioc, &cfg)) == 0)
4498 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4499
4500 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4501 }
4502
4503 return rc;
4504}
4505
4506/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004507/**
4508 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 * @ioc: Pointer to a Adapter Strucutre
4510 * @portnum: IOC port number
4511 *
4512 * Return: -EFAULT if read of config page header fails
4513 * or if no nvram
4514 * If read of SCSI Port Page 0 fails,
4515 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4516 * Adapter settings: async, narrow
4517 * Return 1
4518 * If read of SCSI Port Page 2 fails,
4519 * Adapter settings valid
4520 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4521 * Return 1
4522 * Else
4523 * Both valid
4524 * Return 0
4525 * CHECK - what type of locking mechanisms should be used????
4526 */
4527static int
4528mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4529{
4530 u8 *pbuf;
4531 dma_addr_t buf_dma;
4532 CONFIGPARMS cfg;
4533 ConfigPageHeader_t header;
4534 int ii;
4535 int data, rc = 0;
4536
4537 /* Allocate memory
4538 */
4539 if (!ioc->spi_data.nvram) {
4540 int sz;
4541 u8 *mem;
4542 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4543 mem = kmalloc(sz, GFP_ATOMIC);
4544 if (mem == NULL)
4545 return -EFAULT;
4546
4547 ioc->spi_data.nvram = (int *) mem;
4548
4549 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4550 ioc->name, ioc->spi_data.nvram, sz));
4551 }
4552
4553 /* Invalidate NVRAM information
4554 */
4555 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4556 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4557 }
4558
4559 /* Read SPP0 header, allocate memory, then read page.
4560 */
4561 header.PageVersion = 0;
4562 header.PageLength = 0;
4563 header.PageNumber = 0;
4564 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004565 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 cfg.physAddr = -1;
4567 cfg.pageAddr = portnum;
4568 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4569 cfg.dir = 0;
4570 cfg.timeout = 0; /* use default */
4571 if (mpt_config(ioc, &cfg) != 0)
4572 return -EFAULT;
4573
4574 if (header.PageLength > 0) {
4575 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4576 if (pbuf) {
4577 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4578 cfg.physAddr = buf_dma;
4579 if (mpt_config(ioc, &cfg) != 0) {
4580 ioc->spi_data.maxBusWidth = MPT_NARROW;
4581 ioc->spi_data.maxSyncOffset = 0;
4582 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4583 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4584 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004585 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4586 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 } else {
4588 /* Save the Port Page 0 data
4589 */
4590 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4591 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4592 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4593
4594 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4595 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004596 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 ioc->name, pPP0->Capabilities));
4598 }
4599 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4600 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4601 if (data) {
4602 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4603 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4604 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004605 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4606 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 } else {
4608 ioc->spi_data.maxSyncOffset = 0;
4609 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4610 }
4611
4612 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4613
4614 /* Update the minSyncFactor based on bus type.
4615 */
4616 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4617 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4618
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004619 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004621 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4622 ioc->name, ioc->spi_data.minSyncFactor));
4623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 }
4625 }
4626 if (pbuf) {
4627 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4628 }
4629 }
4630 }
4631
4632 /* SCSI Port Page 2 - Read the header then the page.
4633 */
4634 header.PageVersion = 0;
4635 header.PageLength = 0;
4636 header.PageNumber = 2;
4637 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004638 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 cfg.physAddr = -1;
4640 cfg.pageAddr = portnum;
4641 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4642 cfg.dir = 0;
4643 if (mpt_config(ioc, &cfg) != 0)
4644 return -EFAULT;
4645
4646 if (header.PageLength > 0) {
4647 /* Allocate memory and read SCSI Port Page 2
4648 */
4649 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4650 if (pbuf) {
4651 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4652 cfg.physAddr = buf_dma;
4653 if (mpt_config(ioc, &cfg) != 0) {
4654 /* Nvram data is left with INVALID mark
4655 */
4656 rc = 1;
4657 } else {
4658 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4659 MpiDeviceInfo_t *pdevice = NULL;
4660
Moore, Ericd8e925d2006-01-16 18:53:06 -07004661 /*
4662 * Save "Set to Avoid SCSI Bus Resets" flag
4663 */
4664 ioc->spi_data.bus_reset =
4665 (le32_to_cpu(pPP2->PortFlags) &
4666 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4667 0 : 1 ;
4668
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 /* Save the Port Page 2 data
4670 * (reformat into a 32bit quantity)
4671 */
4672 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4673 ioc->spi_data.PortFlags = data;
4674 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4675 pdevice = &pPP2->DeviceSettings[ii];
4676 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4677 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4678 ioc->spi_data.nvram[ii] = data;
4679 }
4680 }
4681
4682 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4683 }
4684 }
4685
4686 /* Update Adapter limits with those from NVRAM
4687 * Comment: Don't need to do this. Target performance
4688 * parameters will never exceed the adapters limits.
4689 */
4690
4691 return rc;
4692}
4693
4694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004695/**
4696 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 * @ioc: Pointer to a Adapter Strucutre
4698 * @portnum: IOC port number
4699 *
4700 * Return: -EFAULT if read of config page header fails
4701 * or 0 if success.
4702 */
4703static int
4704mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4705{
4706 CONFIGPARMS cfg;
4707 ConfigPageHeader_t header;
4708
4709 /* Read the SCSI Device Page 1 header
4710 */
4711 header.PageVersion = 0;
4712 header.PageLength = 0;
4713 header.PageNumber = 1;
4714 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004715 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 cfg.physAddr = -1;
4717 cfg.pageAddr = portnum;
4718 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4719 cfg.dir = 0;
4720 cfg.timeout = 0;
4721 if (mpt_config(ioc, &cfg) != 0)
4722 return -EFAULT;
4723
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004724 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4725 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
4727 header.PageVersion = 0;
4728 header.PageLength = 0;
4729 header.PageNumber = 0;
4730 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4731 if (mpt_config(ioc, &cfg) != 0)
4732 return -EFAULT;
4733
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004734 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4735 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
4737 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4738 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4739
4740 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4741 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4742 return 0;
4743}
4744
Eric Mooreb506ade2007-01-29 09:45:37 -07004745/**
Randy Dunlap1544d672007-02-20 11:17:03 -08004746 * mpt_inactive_raid_list_free - This clears this link list.
4747 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07004748 **/
4749static void
4750mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
4751{
4752 struct inactive_raid_component_info *component_info, *pNext;
4753
4754 if (list_empty(&ioc->raid_data.inactive_list))
4755 return;
4756
4757 down(&ioc->raid_data.inactive_list_mutex);
4758 list_for_each_entry_safe(component_info, pNext,
4759 &ioc->raid_data.inactive_list, list) {
4760 list_del(&component_info->list);
4761 kfree(component_info);
4762 }
4763 up(&ioc->raid_data.inactive_list_mutex);
4764}
4765
4766/**
Randy Dunlap1544d672007-02-20 11:17:03 -08004767 * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
Eric Mooreb506ade2007-01-29 09:45:37 -07004768 *
Randy Dunlap1544d672007-02-20 11:17:03 -08004769 * @ioc : pointer to per adapter structure
4770 * @channel : volume channel
4771 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07004772 **/
4773static void
4774mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
4775{
4776 CONFIGPARMS cfg;
4777 ConfigPageHeader_t hdr;
4778 dma_addr_t dma_handle;
4779 pRaidVolumePage0_t buffer = NULL;
4780 int i;
4781 RaidPhysDiskPage0_t phys_disk;
4782 struct inactive_raid_component_info *component_info;
4783 int handle_inactive_volumes;
4784
4785 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4786 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4787 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4788 cfg.pageAddr = (channel << 8) + id;
4789 cfg.cfghdr.hdr = &hdr;
4790 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4791
4792 if (mpt_config(ioc, &cfg) != 0)
4793 goto out;
4794
4795 if (!hdr.PageLength)
4796 goto out;
4797
4798 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4799 &dma_handle);
4800
4801 if (!buffer)
4802 goto out;
4803
4804 cfg.physAddr = dma_handle;
4805 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4806
4807 if (mpt_config(ioc, &cfg) != 0)
4808 goto out;
4809
4810 if (!buffer->NumPhysDisks)
4811 goto out;
4812
4813 handle_inactive_volumes =
4814 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
4815 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
4816 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
4817 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
4818
4819 if (!handle_inactive_volumes)
4820 goto out;
4821
4822 down(&ioc->raid_data.inactive_list_mutex);
4823 for (i = 0; i < buffer->NumPhysDisks; i++) {
4824 if(mpt_raid_phys_disk_pg0(ioc,
4825 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4826 continue;
4827
4828 if ((component_info = kmalloc(sizeof (*component_info),
4829 GFP_KERNEL)) == NULL)
4830 continue;
4831
4832 component_info->volumeID = id;
4833 component_info->volumeBus = channel;
4834 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
4835 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
4836 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
4837 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
4838
4839 list_add_tail(&component_info->list,
4840 &ioc->raid_data.inactive_list);
4841 }
4842 up(&ioc->raid_data.inactive_list_mutex);
4843
4844 out:
4845 if (buffer)
4846 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4847 dma_handle);
4848}
4849
4850/**
4851 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
4852 * @ioc: Pointer to a Adapter Structure
4853 * @phys_disk_num: io unit unique phys disk num generated by the ioc
4854 * @phys_disk: requested payload data returned
4855 *
4856 * Return:
4857 * 0 on success
4858 * -EFAULT if read of config page header fails or data pointer not NULL
4859 * -ENOMEM if pci_alloc failed
4860 **/
4861int
4862mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
4863{
4864 CONFIGPARMS cfg;
4865 ConfigPageHeader_t hdr;
4866 dma_addr_t dma_handle;
4867 pRaidPhysDiskPage0_t buffer = NULL;
4868 int rc;
4869
4870 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4871 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4872
4873 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
4874 cfg.cfghdr.hdr = &hdr;
4875 cfg.physAddr = -1;
4876 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4877
4878 if (mpt_config(ioc, &cfg) != 0) {
4879 rc = -EFAULT;
4880 goto out;
4881 }
4882
4883 if (!hdr.PageLength) {
4884 rc = -EFAULT;
4885 goto out;
4886 }
4887
4888 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4889 &dma_handle);
4890
4891 if (!buffer) {
4892 rc = -ENOMEM;
4893 goto out;
4894 }
4895
4896 cfg.physAddr = dma_handle;
4897 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4898 cfg.pageAddr = phys_disk_num;
4899
4900 if (mpt_config(ioc, &cfg) != 0) {
4901 rc = -EFAULT;
4902 goto out;
4903 }
4904
4905 rc = 0;
4906 memcpy(phys_disk, buffer, sizeof(*buffer));
4907 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
4908
4909 out:
4910
4911 if (buffer)
4912 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4913 dma_handle);
4914
4915 return rc;
4916}
4917
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918/**
4919 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4920 * @ioc: Pointer to a Adapter Strucutre
4921 * @portnum: IOC port number
4922 *
4923 * Return:
4924 * 0 on success
4925 * -EFAULT if read of config page header fails or data pointer not NULL
4926 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07004927 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928int
4929mpt_findImVolumes(MPT_ADAPTER *ioc)
4930{
4931 IOCPage2_t *pIoc2;
4932 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 dma_addr_t ioc2_dma;
4934 CONFIGPARMS cfg;
4935 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 int rc = 0;
4937 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07004938 int i;
4939
4940 if (!ioc->ir_firmware)
4941 return 0;
4942
4943 /* Free the old page
4944 */
4945 kfree(ioc->raid_data.pIocPg2);
4946 ioc->raid_data.pIocPg2 = NULL;
4947 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
4949 /* Read IOCP2 header then the page.
4950 */
4951 header.PageVersion = 0;
4952 header.PageLength = 0;
4953 header.PageNumber = 2;
4954 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004955 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 cfg.physAddr = -1;
4957 cfg.pageAddr = 0;
4958 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4959 cfg.dir = 0;
4960 cfg.timeout = 0;
4961 if (mpt_config(ioc, &cfg) != 0)
4962 return -EFAULT;
4963
4964 if (header.PageLength == 0)
4965 return -EFAULT;
4966
4967 iocpage2sz = header.PageLength * 4;
4968 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4969 if (!pIoc2)
4970 return -ENOMEM;
4971
4972 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4973 cfg.physAddr = ioc2_dma;
4974 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07004975 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976
Eric Mooreb506ade2007-01-29 09:45:37 -07004977 mem = kmalloc(iocpage2sz, GFP_KERNEL);
4978 if (!mem)
4979 goto out;
4980
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07004982 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
Eric Mooreb506ade2007-01-29 09:45:37 -07004984 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985
Eric Mooreb506ade2007-01-29 09:45:37 -07004986 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
4987 mpt_inactive_raid_volumes(ioc,
4988 pIoc2->RaidVolume[i].VolumeBus,
4989 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
Eric Mooreb506ade2007-01-29 09:45:37 -07004991 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4993
4994 return rc;
4995}
4996
Moore, Ericc972c702006-03-14 09:14:06 -07004997static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4999{
5000 IOCPage3_t *pIoc3;
5001 u8 *mem;
5002 CONFIGPARMS cfg;
5003 ConfigPageHeader_t header;
5004 dma_addr_t ioc3_dma;
5005 int iocpage3sz = 0;
5006
5007 /* Free the old page
5008 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005009 kfree(ioc->raid_data.pIocPg3);
5010 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
5012 /* There is at least one physical disk.
5013 * Read and save IOC Page 3
5014 */
5015 header.PageVersion = 0;
5016 header.PageLength = 0;
5017 header.PageNumber = 3;
5018 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005019 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 cfg.physAddr = -1;
5021 cfg.pageAddr = 0;
5022 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5023 cfg.dir = 0;
5024 cfg.timeout = 0;
5025 if (mpt_config(ioc, &cfg) != 0)
5026 return 0;
5027
5028 if (header.PageLength == 0)
5029 return 0;
5030
5031 /* Read Header good, alloc memory
5032 */
5033 iocpage3sz = header.PageLength * 4;
5034 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5035 if (!pIoc3)
5036 return 0;
5037
5038 /* Read the Page and save the data
5039 * into malloc'd memory.
5040 */
5041 cfg.physAddr = ioc3_dma;
5042 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5043 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005044 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 if (mem) {
5046 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005047 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 }
5049 }
5050
5051 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5052
5053 return 0;
5054}
5055
5056static void
5057mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5058{
5059 IOCPage4_t *pIoc4;
5060 CONFIGPARMS cfg;
5061 ConfigPageHeader_t header;
5062 dma_addr_t ioc4_dma;
5063 int iocpage4sz;
5064
5065 /* Read and save IOC Page 4
5066 */
5067 header.PageVersion = 0;
5068 header.PageLength = 0;
5069 header.PageNumber = 4;
5070 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005071 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 cfg.physAddr = -1;
5073 cfg.pageAddr = 0;
5074 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5075 cfg.dir = 0;
5076 cfg.timeout = 0;
5077 if (mpt_config(ioc, &cfg) != 0)
5078 return;
5079
5080 if (header.PageLength == 0)
5081 return;
5082
5083 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5084 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5085 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5086 if (!pIoc4)
5087 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005088 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 } else {
5090 ioc4_dma = ioc->spi_data.IocPg4_dma;
5091 iocpage4sz = ioc->spi_data.IocPg4Sz;
5092 }
5093
5094 /* Read the Page into dma memory.
5095 */
5096 cfg.physAddr = ioc4_dma;
5097 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5098 if (mpt_config(ioc, &cfg) == 0) {
5099 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5100 ioc->spi_data.IocPg4_dma = ioc4_dma;
5101 ioc->spi_data.IocPg4Sz = iocpage4sz;
5102 } else {
5103 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5104 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005105 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 }
5107}
5108
5109static void
5110mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5111{
5112 IOCPage1_t *pIoc1;
5113 CONFIGPARMS cfg;
5114 ConfigPageHeader_t header;
5115 dma_addr_t ioc1_dma;
5116 int iocpage1sz = 0;
5117 u32 tmp;
5118
5119 /* Check the Coalescing Timeout in IOC Page 1
5120 */
5121 header.PageVersion = 0;
5122 header.PageLength = 0;
5123 header.PageNumber = 1;
5124 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005125 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 cfg.physAddr = -1;
5127 cfg.pageAddr = 0;
5128 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5129 cfg.dir = 0;
5130 cfg.timeout = 0;
5131 if (mpt_config(ioc, &cfg) != 0)
5132 return;
5133
5134 if (header.PageLength == 0)
5135 return;
5136
5137 /* Read Header good, alloc memory
5138 */
5139 iocpage1sz = header.PageLength * 4;
5140 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5141 if (!pIoc1)
5142 return;
5143
5144 /* Read the Page and check coalescing timeout
5145 */
5146 cfg.physAddr = ioc1_dma;
5147 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5148 if (mpt_config(ioc, &cfg) == 0) {
5149
5150 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5151 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5152 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5153
5154 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5155 ioc->name, tmp));
5156
5157 if (tmp > MPT_COALESCING_TIMEOUT) {
5158 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5159
5160 /* Write NVRAM and current
5161 */
5162 cfg.dir = 1;
5163 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5164 if (mpt_config(ioc, &cfg) == 0) {
5165 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5166 ioc->name, MPT_COALESCING_TIMEOUT));
5167
5168 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5169 if (mpt_config(ioc, &cfg) == 0) {
5170 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5171 ioc->name, MPT_COALESCING_TIMEOUT));
5172 } else {
5173 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5174 ioc->name));
5175 }
5176
5177 } else {
5178 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5179 ioc->name));
5180 }
5181 }
5182
5183 } else {
5184 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5185 }
5186 }
5187
5188 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5189
5190 return;
5191}
5192
5193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005194/**
5195 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 * @ioc: Pointer to MPT_ADAPTER structure
5197 * @EvSwitch: Event switch flags
5198 */
5199static int
5200SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5201{
5202 EventNotification_t *evnp;
5203
5204 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5205 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005206 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 ioc->name));
5208 return 0;
5209 }
5210 memset(evnp, 0, sizeof(*evnp));
5211
Moore, Eric3a892be2006-03-14 09:14:03 -07005212 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213
5214 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5215 evnp->ChainOffset = 0;
5216 evnp->MsgFlags = 0;
5217 evnp->Switch = EvSwitch;
5218
5219 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5220
5221 return 0;
5222}
5223
5224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5225/**
5226 * SendEventAck - Send EventAck request to MPT adapter.
5227 * @ioc: Pointer to MPT_ADAPTER structure
5228 * @evnp: Pointer to original EventNotification request
5229 */
5230static int
5231SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5232{
5233 EventAck_t *pAck;
5234
5235 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005236 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5237 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 return -1;
5239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240
Eric Moore4f766dc2006-07-11 17:24:07 -06005241 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242
5243 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5244 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005245 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005247 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 pAck->Event = evnp->Event;
5249 pAck->EventContext = evnp->EventContext;
5250
5251 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5252
5253 return 0;
5254}
5255
5256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5257/**
5258 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005259 * @ioc: Pointer to an adapter structure
5260 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 * action, page address, direction, physical address
5262 * and pointer to a configuration page header
5263 * Page header is updated.
5264 *
5265 * Returns 0 for success
5266 * -EPERM if not allowed due to ISR context
5267 * -EAGAIN if no msg frames currently available
5268 * -EFAULT for non-successful reply or no reply (timeout)
5269 */
5270int
5271mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5272{
5273 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005274 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 MPT_FRAME_HDR *mf;
5276 unsigned long flags;
5277 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005278 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 int in_isr;
5280
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005281 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 * to be in ISR context, because that is fatal!
5283 */
5284 in_isr = in_interrupt();
5285 if (in_isr) {
5286 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5287 ioc->name));
5288 return -EPERM;
5289 }
5290
5291 /* Get and Populate a free Frame
5292 */
5293 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5294 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5295 ioc->name));
5296 return -EAGAIN;
5297 }
5298 pReq = (Config_t *)mf;
5299 pReq->Action = pCfg->action;
5300 pReq->Reserved = 0;
5301 pReq->ChainOffset = 0;
5302 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005303
5304 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 pReq->ExtPageLength = 0;
5306 pReq->ExtPageType = 0;
5307 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005308
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 for (ii=0; ii < 8; ii++)
5310 pReq->Reserved2[ii] = 0;
5311
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005312 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5313 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5314 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5315 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5316
5317 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5318 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5319 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5320 pReq->ExtPageType = pExtHdr->ExtPageType;
5321 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5322
5323 /* Page Length must be treated as a reserved field for the extended header. */
5324 pReq->Header.PageLength = 0;
5325 }
5326
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5328
5329 /* Add a SGE to the config request.
5330 */
5331 if (pCfg->dir)
5332 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5333 else
5334 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5335
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005336 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5337 flagsLength |= pExtHdr->ExtPageLength * 4;
5338
5339 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5340 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5341 }
5342 else {
5343 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5344
5345 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5346 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348
5349 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5350
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 /* Append pCfg pointer to end of mf
5352 */
5353 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5354
5355 /* Initalize the timer
5356 */
5357 init_timer(&pCfg->timer);
5358 pCfg->timer.data = (unsigned long) ioc;
5359 pCfg->timer.function = mpt_timer_expired;
5360 pCfg->wait_done = 0;
5361
5362 /* Set the timer; ensure 10 second minimum */
5363 if (pCfg->timeout < 10)
5364 pCfg->timer.expires = jiffies + HZ*10;
5365 else
5366 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5367
5368 /* Add to end of Q, set timer and then issue this command */
5369 spin_lock_irqsave(&ioc->FreeQlock, flags);
5370 list_add_tail(&pCfg->linkage, &ioc->configQ);
5371 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5372
5373 add_timer(&pCfg->timer);
5374 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5375 wait_event(mpt_waitq, pCfg->wait_done);
5376
5377 /* mf has been freed - do not access */
5378
5379 rc = pCfg->status;
5380
5381 return rc;
5382}
5383
5384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005385/**
5386 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 * Used only internal config functionality.
5388 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5389 */
5390static void
5391mpt_timer_expired(unsigned long data)
5392{
5393 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5394
5395 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5396
5397 /* Perform a FW reload */
5398 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5399 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5400
5401 /* No more processing.
5402 * Hard reset clean-up will wake up
5403 * process and free all resources.
5404 */
5405 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5406
5407 return;
5408}
5409
5410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005411/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 * mpt_ioc_reset - Base cleanup for hard reset
5413 * @ioc: Pointer to the adapter structure
5414 * @reset_phase: Indicates pre- or post-reset functionality
5415 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005416 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 */
5418static int
5419mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5420{
5421 CONFIGPARMS *pCfg;
5422 unsigned long flags;
5423
5424 dprintk((KERN_WARNING MYNAM
5425 ": IOC %s_reset routed to MPT base driver!\n",
5426 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5427 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5428
5429 if (reset_phase == MPT_IOC_SETUP_RESET) {
5430 ;
5431 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5432 /* If the internal config Q is not empty -
5433 * delete timer. MF resources will be freed when
5434 * the FIFO's are primed.
5435 */
5436 spin_lock_irqsave(&ioc->FreeQlock, flags);
5437 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5438 del_timer(&pCfg->timer);
5439 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5440
5441 } else {
5442 CONFIGPARMS *pNext;
5443
5444 /* Search the configQ for internal commands.
5445 * Flush the Q, and wake up all suspended threads.
5446 */
5447 spin_lock_irqsave(&ioc->FreeQlock, flags);
5448 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5449 list_del(&pCfg->linkage);
5450
5451 pCfg->status = MPT_CONFIG_ERROR;
5452 pCfg->wait_done = 1;
5453 wake_up(&mpt_waitq);
5454 }
5455 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5456 }
5457
5458 return 1; /* currently means nothing really */
5459}
5460
5461
5462#ifdef CONFIG_PROC_FS /* { */
5463/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5464/*
5465 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5466 */
5467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005468/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5470 *
5471 * Returns 0 for success, non-zero for failure.
5472 */
5473static int
5474procmpt_create(void)
5475{
5476 struct proc_dir_entry *ent;
5477
5478 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5479 if (mpt_proc_root_dir == NULL)
5480 return -ENOTDIR;
5481
5482 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5483 if (ent)
5484 ent->read_proc = procmpt_summary_read;
5485
5486 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5487 if (ent)
5488 ent->read_proc = procmpt_version_read;
5489
5490 return 0;
5491}
5492
5493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005494/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5496 *
5497 * Returns 0 for success, non-zero for failure.
5498 */
5499static void
5500procmpt_destroy(void)
5501{
5502 remove_proc_entry("version", mpt_proc_root_dir);
5503 remove_proc_entry("summary", mpt_proc_root_dir);
5504 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5505}
5506
5507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005508/**
5509 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 * @buf: Pointer to area to write information
5511 * @start: Pointer to start pointer
5512 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005513 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 * @eof: Pointer to EOF integer
5515 * @data: Pointer
5516 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005517 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 * Returns number of characters written to process performing the read.
5519 */
5520static int
5521procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5522{
5523 MPT_ADAPTER *ioc;
5524 char *out = buf;
5525 int len;
5526
5527 if (data) {
5528 int more = 0;
5529
5530 ioc = data;
5531 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5532
5533 out += more;
5534 } else {
5535 list_for_each_entry(ioc, &ioc_list, list) {
5536 int more = 0;
5537
5538 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5539
5540 out += more;
5541 if ((out-buf) >= request)
5542 break;
5543 }
5544 }
5545
5546 len = out - buf;
5547
5548 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5549}
5550
5551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005552/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 * procmpt_version_read - Handle read request from /proc/mpt/version.
5554 * @buf: Pointer to area to write information
5555 * @start: Pointer to start pointer
5556 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005557 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 * @eof: Pointer to EOF integer
5559 * @data: Pointer
5560 *
5561 * Returns number of characters written to process performing the read.
5562 */
5563static int
5564procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5565{
5566 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005567 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 char *drvname;
5569 int len;
5570
5571 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5572 len += sprintf(buf+len, " Fusion MPT base driver\n");
5573
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005574 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5576 drvname = NULL;
5577 if (MptCallbacks[ii]) {
5578 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005579 case MPTSPI_DRIVER:
5580 if (!scsi++) drvname = "SPI host";
5581 break;
5582 case MPTFC_DRIVER:
5583 if (!fc++) drvname = "FC host";
5584 break;
5585 case MPTSAS_DRIVER:
5586 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 break;
5588 case MPTLAN_DRIVER:
5589 if (!lan++) drvname = "LAN";
5590 break;
5591 case MPTSTM_DRIVER:
5592 if (!targ++) drvname = "SCSI target";
5593 break;
5594 case MPTCTL_DRIVER:
5595 if (!ctl++) drvname = "ioctl";
5596 break;
5597 }
5598
5599 if (drvname)
5600 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5601 }
5602 }
5603
5604 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5605}
5606
5607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005608/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5610 * @buf: Pointer to area to write information
5611 * @start: Pointer to start pointer
5612 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005613 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 * @eof: Pointer to EOF integer
5615 * @data: Pointer
5616 *
5617 * Returns number of characters written to process performing the read.
5618 */
5619static int
5620procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5621{
5622 MPT_ADAPTER *ioc = data;
5623 int len;
5624 char expVer[32];
5625 int sz;
5626 int p;
5627
5628 mpt_get_fw_exp_ver(expVer, ioc);
5629
5630 len = sprintf(buf, "%s:", ioc->name);
5631 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5632 len += sprintf(buf+len, " (f/w download boot flag set)");
5633// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5634// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5635
5636 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5637 ioc->facts.ProductID,
5638 ioc->prod_name);
5639 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5640 if (ioc->facts.FWImageSize)
5641 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5642 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5643 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5644 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5645
5646 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5647 ioc->facts.CurrentHostMfaHighAddr);
5648 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5649 ioc->facts.CurrentSenseBufferHighAddr);
5650
5651 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5652 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5653
5654 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5655 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5656 /*
5657 * Rounding UP to nearest 4-kB boundary here...
5658 */
5659 sz = (ioc->req_sz * ioc->req_depth) + 128;
5660 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5661 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5662 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5663 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5664 4*ioc->facts.RequestFrameSize,
5665 ioc->facts.GlobalCredits);
5666
5667 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5668 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5669 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5670 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5671 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5672 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5673 ioc->facts.CurReplyFrameSize,
5674 ioc->facts.ReplyQueueDepth);
5675
5676 len += sprintf(buf+len, " MaxDevices = %d\n",
5677 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5678 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5679
5680 /* per-port info */
5681 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5682 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5683 p+1,
5684 ioc->facts.NumberOfPorts);
5685 if (ioc->bus_type == FC) {
5686 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5687 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5688 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5689 a[5], a[4], a[3], a[2], a[1], a[0]);
5690 }
5691 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5692 ioc->fc_port_page0[p].WWNN.High,
5693 ioc->fc_port_page0[p].WWNN.Low,
5694 ioc->fc_port_page0[p].WWPN.High,
5695 ioc->fc_port_page0[p].WWPN.Low);
5696 }
5697 }
5698
5699 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5700}
5701
5702#endif /* CONFIG_PROC_FS } */
5703
5704/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5705static void
5706mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5707{
5708 buf[0] ='\0';
5709 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5710 sprintf(buf, " (Exp %02d%02d)",
5711 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5712 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5713
5714 /* insider hack! */
5715 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5716 strcat(buf, " [MDBG]");
5717 }
5718}
5719
5720/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5721/**
5722 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5723 * @ioc: Pointer to MPT_ADAPTER structure
5724 * @buffer: Pointer to buffer where IOC summary info should be written
5725 * @size: Pointer to number of bytes we wrote (set by this routine)
5726 * @len: Offset at which to start writing in buffer
5727 * @showlan: Display LAN stuff?
5728 *
5729 * This routine writes (english readable) ASCII text, which represents
5730 * a summary of IOC information, to a buffer.
5731 */
5732void
5733mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5734{
5735 char expVer[32];
5736 int y;
5737
5738 mpt_get_fw_exp_ver(expVer, ioc);
5739
5740 /*
5741 * Shorter summary of attached ioc's...
5742 */
5743 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5744 ioc->name,
5745 ioc->prod_name,
5746 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5747 ioc->facts.FWVersion.Word,
5748 expVer,
5749 ioc->facts.NumberOfPorts,
5750 ioc->req_depth);
5751
5752 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5753 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5754 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5755 a[5], a[4], a[3], a[2], a[1], a[0]);
5756 }
5757
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759
5760 if (!ioc->active)
5761 y += sprintf(buffer+len+y, " (disabled)");
5762
5763 y += sprintf(buffer+len+y, "\n");
5764
5765 *size = y;
5766}
5767
5768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5769/*
5770 * Reset Handling
5771 */
5772/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5773/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005774 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 * @ioc: Pointer to MPT_ADAPTER structure
5776 * @sleepFlag: Indicates if sleep or schedule must be called.
5777 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005778 * Issues SCSI Task Management call based on input arg values.
5779 * If TaskMgmt fails, returns associated SCSI request.
5780 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5782 * or a non-interrupt thread. In the former, must not call schedule().
5783 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005784 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 * FW reload/initialization failed.
5786 *
5787 * Returns 0 for SUCCESS or -1 if FAILED.
5788 */
5789int
5790mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5791{
5792 int rc;
5793 unsigned long flags;
5794
5795 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5796#ifdef MFCNT
5797 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5798 printk("MF count 0x%x !\n", ioc->mfcnt);
5799#endif
5800
5801 /* Reset the adapter. Prevent more than 1 call to
5802 * mpt_do_ioc_recovery at any instant in time.
5803 */
5804 spin_lock_irqsave(&ioc->diagLock, flags);
5805 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5806 spin_unlock_irqrestore(&ioc->diagLock, flags);
5807 return 0;
5808 } else {
5809 ioc->diagPending = 1;
5810 }
5811 spin_unlock_irqrestore(&ioc->diagLock, flags);
5812
5813 /* FIXME: If do_ioc_recovery fails, repeat....
5814 */
5815
5816 /* The SCSI driver needs to adjust timeouts on all current
5817 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02005818 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 * For all other protocol drivers, this is a no-op.
5820 */
5821 {
5822 int ii;
5823 int r = 0;
5824
5825 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5826 if (MptResetHandlers[ii]) {
5827 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5828 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005829 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 if (ioc->alt_ioc) {
5831 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5832 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005833 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 }
5835 }
5836 }
5837 }
5838
5839 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5840 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5841 rc, ioc->name);
5842 }
5843 ioc->reload_fw = 0;
5844 if (ioc->alt_ioc)
5845 ioc->alt_ioc->reload_fw = 0;
5846
5847 spin_lock_irqsave(&ioc->diagLock, flags);
5848 ioc->diagPending = 0;
5849 if (ioc->alt_ioc)
5850 ioc->alt_ioc->diagPending = 0;
5851 spin_unlock_irqrestore(&ioc->diagLock, flags);
5852
5853 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5854
5855 return rc;
5856}
5857
5858/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005859static void
5860EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861{
Eric Moore509e5e52006-04-26 13:22:37 -06005862 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863
5864 switch(event) {
5865 case MPI_EVENT_NONE:
5866 ds = "None";
5867 break;
5868 case MPI_EVENT_LOG_DATA:
5869 ds = "Log Data";
5870 break;
5871 case MPI_EVENT_STATE_CHANGE:
5872 ds = "State Change";
5873 break;
5874 case MPI_EVENT_UNIT_ATTENTION:
5875 ds = "Unit Attention";
5876 break;
5877 case MPI_EVENT_IOC_BUS_RESET:
5878 ds = "IOC Bus Reset";
5879 break;
5880 case MPI_EVENT_EXT_BUS_RESET:
5881 ds = "External Bus Reset";
5882 break;
5883 case MPI_EVENT_RESCAN:
5884 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 break;
5886 case MPI_EVENT_LINK_STATUS_CHANGE:
5887 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5888 ds = "Link Status(FAILURE) Change";
5889 else
5890 ds = "Link Status(ACTIVE) Change";
5891 break;
5892 case MPI_EVENT_LOOP_STATE_CHANGE:
5893 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5894 ds = "Loop State(LIP) Change";
5895 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005896 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 else
Eric Moore509e5e52006-04-26 13:22:37 -06005898 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 break;
5900 case MPI_EVENT_LOGOUT:
5901 ds = "Logout";
5902 break;
5903 case MPI_EVENT_EVENT_CHANGE:
5904 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06005905 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 else
Eric Moore4f766dc2006-07-11 17:24:07 -06005907 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 break;
5909 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005910 {
5911 u8 ReasonCode = (u8)(evData0 >> 16);
5912 switch (ReasonCode) {
5913 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5914 ds = "Integrated Raid: Volume Created";
5915 break;
5916 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5917 ds = "Integrated Raid: Volume Deleted";
5918 break;
5919 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5920 ds = "Integrated Raid: Volume Settings Changed";
5921 break;
5922 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5923 ds = "Integrated Raid: Volume Status Changed";
5924 break;
5925 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5926 ds = "Integrated Raid: Volume Physdisk Changed";
5927 break;
5928 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5929 ds = "Integrated Raid: Physdisk Created";
5930 break;
5931 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5932 ds = "Integrated Raid: Physdisk Deleted";
5933 break;
5934 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5935 ds = "Integrated Raid: Physdisk Settings Changed";
5936 break;
5937 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5938 ds = "Integrated Raid: Physdisk Status Changed";
5939 break;
5940 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5941 ds = "Integrated Raid: Domain Validation Needed";
5942 break;
5943 case MPI_EVENT_RAID_RC_SMART_DATA :
5944 ds = "Integrated Raid; Smart Data";
5945 break;
5946 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5947 ds = "Integrated Raid: Replace Action Started";
5948 break;
5949 default:
5950 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005952 }
5953 break;
5954 }
5955 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5956 ds = "SCSI Device Status Change";
5957 break;
5958 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5959 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005960 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07005961 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005962 u8 ReasonCode = (u8)(evData0 >> 16);
5963 switch (ReasonCode) {
5964 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005965 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005966 "SAS Device Status Change: Added: "
5967 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005968 break;
5969 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005970 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005971 "SAS Device Status Change: Deleted: "
5972 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005973 break;
5974 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005975 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005976 "SAS Device Status Change: SMART Data: "
5977 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005978 break;
5979 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005980 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005981 "SAS Device Status Change: No Persistancy: "
5982 "id=%d channel=%d", id, channel);
5983 break;
5984 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
5985 snprintf(evStr, EVENT_DESCR_STR_SZ,
5986 "SAS Device Status Change: Unsupported Device "
5987 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06005988 break;
5989 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5990 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005991 "SAS Device Status Change: Internal Device "
5992 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06005993 break;
5994 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5995 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07005996 "SAS Device Status Change: Internal Task "
5997 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06005998 break;
5999 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6000 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006001 "SAS Device Status Change: Internal Abort "
6002 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006003 break;
6004 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6005 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006006 "SAS Device Status Change: Internal Clear "
6007 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006008 break;
6009 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6010 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006011 "SAS Device Status Change: Internal Query "
6012 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006013 break;
6014 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006015 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006016 "SAS Device Status Change: Unknown: "
6017 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006018 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006019 }
6020 break;
6021 }
6022 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6023 ds = "Bus Timer Expired";
6024 break;
6025 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006026 {
6027 u16 curr_depth = (u16)(evData0 >> 16);
6028 u8 channel = (u8)(evData0 >> 8);
6029 u8 id = (u8)(evData0);
6030
6031 snprintf(evStr, EVENT_DESCR_STR_SZ,
6032 "Queue Full: channel=%d id=%d depth=%d",
6033 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006034 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006035 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006036 case MPI_EVENT_SAS_SES:
6037 ds = "SAS SES Event";
6038 break;
6039 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6040 ds = "Persistent Table Full";
6041 break;
6042 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006043 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006044 u8 LinkRates = (u8)(evData0 >> 8);
6045 u8 PhyNumber = (u8)(evData0);
6046 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6047 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6048 switch (LinkRates) {
6049 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006050 snprintf(evStr, EVENT_DESCR_STR_SZ,
6051 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006052 " Rate Unknown",PhyNumber);
6053 break;
6054 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006055 snprintf(evStr, EVENT_DESCR_STR_SZ,
6056 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006057 " Phy Disabled",PhyNumber);
6058 break;
6059 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006060 snprintf(evStr, EVENT_DESCR_STR_SZ,
6061 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006062 " Failed Speed Nego",PhyNumber);
6063 break;
6064 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006065 snprintf(evStr, EVENT_DESCR_STR_SZ,
6066 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006067 " Sata OOB Completed",PhyNumber);
6068 break;
6069 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006070 snprintf(evStr, EVENT_DESCR_STR_SZ,
6071 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006072 " Rate 1.5 Gbps",PhyNumber);
6073 break;
6074 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006075 snprintf(evStr, EVENT_DESCR_STR_SZ,
6076 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006077 " Rate 3.0 Gpbs",PhyNumber);
6078 break;
6079 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006080 snprintf(evStr, EVENT_DESCR_STR_SZ,
6081 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006082 break;
6083 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006084 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006085 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006086 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6087 ds = "SAS Discovery Error";
6088 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006089 case MPI_EVENT_IR_RESYNC_UPDATE:
6090 {
6091 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006092 snprintf(evStr, EVENT_DESCR_STR_SZ,
6093 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006094 break;
6095 }
6096 case MPI_EVENT_IR2:
6097 {
6098 u8 ReasonCode = (u8)(evData0 >> 16);
6099 switch (ReasonCode) {
6100 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6101 ds = "IR2: LD State Changed";
6102 break;
6103 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6104 ds = "IR2: PD State Changed";
6105 break;
6106 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6107 ds = "IR2: Bad Block Table Full";
6108 break;
6109 case MPI_EVENT_IR2_RC_PD_INSERTED:
6110 ds = "IR2: PD Inserted";
6111 break;
6112 case MPI_EVENT_IR2_RC_PD_REMOVED:
6113 ds = "IR2: PD Removed";
6114 break;
6115 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6116 ds = "IR2: Foreign CFG Detected";
6117 break;
6118 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6119 ds = "IR2: Rebuild Medium Error";
6120 break;
6121 default:
6122 ds = "IR2";
6123 break;
6124 }
6125 break;
6126 }
6127 case MPI_EVENT_SAS_DISCOVERY:
6128 {
6129 if (evData0)
6130 ds = "SAS Discovery: Start";
6131 else
6132 ds = "SAS Discovery: Stop";
6133 break;
6134 }
6135 case MPI_EVENT_LOG_ENTRY_ADDED:
6136 ds = "SAS Log Entry Added";
6137 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006138
Eric Moorec6c727a2007-01-29 09:44:54 -07006139 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6140 {
6141 u8 phy_num = (u8)(evData0);
6142 u8 port_num = (u8)(evData0 >> 8);
6143 u8 port_width = (u8)(evData0 >> 16);
6144 u8 primative = (u8)(evData0 >> 24);
6145 snprintf(evStr, EVENT_DESCR_STR_SZ,
6146 "SAS Broadcase Primative: phy=%d port=%d "
6147 "width=%d primative=0x%02x",
6148 phy_num, port_num, port_width, primative);
6149 break;
6150 }
6151
6152 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6153 {
6154 u8 reason = (u8)(evData0);
6155 u8 port_num = (u8)(evData0 >> 8);
6156 u16 handle = le16_to_cpu(evData0 >> 16);
6157
6158 snprintf(evStr, EVENT_DESCR_STR_SZ,
6159 "SAS Initiator Device Status Change: reason=0x%02x "
6160 "port=%d handle=0x%04x",
6161 reason, port_num, handle);
6162 break;
6163 }
6164
6165 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6166 {
6167 u8 max_init = (u8)(evData0);
6168 u8 current_init = (u8)(evData0 >> 8);
6169
6170 snprintf(evStr, EVENT_DESCR_STR_SZ,
6171 "SAS Initiator Device Table Overflow: max initiators=%02d "
6172 "current initators=%02d",
6173 max_init, current_init);
6174 break;
6175 }
6176 case MPI_EVENT_SAS_SMP_ERROR:
6177 {
6178 u8 status = (u8)(evData0);
6179 u8 port_num = (u8)(evData0 >> 8);
6180 u8 result = (u8)(evData0 >> 16);
6181
6182 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6183 snprintf(evStr, EVENT_DESCR_STR_SZ,
6184 "SAS SMP Error: port=%d result=0x%02x",
6185 port_num, result);
6186 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6187 snprintf(evStr, EVENT_DESCR_STR_SZ,
6188 "SAS SMP Error: port=%d : CRC Error",
6189 port_num);
6190 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6191 snprintf(evStr, EVENT_DESCR_STR_SZ,
6192 "SAS SMP Error: port=%d : Timeout",
6193 port_num);
6194 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6195 snprintf(evStr, EVENT_DESCR_STR_SZ,
6196 "SAS SMP Error: port=%d : No Destination",
6197 port_num);
6198 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6199 snprintf(evStr, EVENT_DESCR_STR_SZ,
6200 "SAS SMP Error: port=%d : Bad Destination",
6201 port_num);
6202 else
6203 snprintf(evStr, EVENT_DESCR_STR_SZ,
6204 "SAS SMP Error: port=%d : status=0x%02x",
6205 port_num, status);
6206 break;
6207 }
6208
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 /*
6210 * MPT base "custom" events may be added here...
6211 */
6212 default:
6213 ds = "Unknown";
6214 break;
6215 }
Eric Moore509e5e52006-04-26 13:22:37 -06006216 if (ds)
6217 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218}
6219
6220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006221/**
6222 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 * @ioc: Pointer to MPT_ADAPTER structure
6224 * @pEventReply: Pointer to EventNotification reply frame
6225 * @evHandlers: Pointer to integer, number of event handlers
6226 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006227 * Routes a received EventNotificationReply to all currently registered
6228 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 * Returns sum of event handlers return values.
6230 */
6231static int
6232ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6233{
6234 u16 evDataLen;
6235 u32 evData0 = 0;
6236// u32 evCtx;
6237 int ii;
6238 int r = 0;
6239 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006240 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 u8 event;
6242
6243 /*
6244 * Do platform normalization of values
6245 */
6246 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6247// evCtx = le32_to_cpu(pEventReply->EventContext);
6248 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6249 if (evDataLen) {
6250 evData0 = le32_to_cpu(pEventReply->Data[0]);
6251 }
6252
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006253 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006254 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006256 event,
6257 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Moore, Eric3a892be2006-03-14 09:14:03 -07006259#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6261 for (ii = 0; ii < evDataLen; ii++)
6262 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6263 printk("\n");
6264#endif
6265
6266 /*
6267 * Do general / base driver event processing
6268 */
6269 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6271 if (evDataLen) {
6272 u8 evState = evData0 & 0xFF;
6273
6274 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6275
6276 /* Update EventState field in cached IocFacts */
6277 if (ioc->facts.Function) {
6278 ioc->facts.EventState = evState;
6279 }
6280 }
6281 break;
Moore, Ericece50912006-01-16 18:53:19 -07006282 case MPI_EVENT_INTEGRATED_RAID:
6283 mptbase_raid_process_event_data(ioc,
6284 (MpiEventDataRaid_t *)pEventReply->Data);
6285 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006286 default:
6287 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288 }
6289
6290 /*
6291 * Should this event be logged? Events are written sequentially.
6292 * When buffer is full, start again at the top.
6293 */
6294 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6295 int idx;
6296
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006297 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298
6299 ioc->events[idx].event = event;
6300 ioc->events[idx].eventContext = ioc->eventContext;
6301
6302 for (ii = 0; ii < 2; ii++) {
6303 if (ii < evDataLen)
6304 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6305 else
6306 ioc->events[idx].data[ii] = 0;
6307 }
6308
6309 ioc->eventContext++;
6310 }
6311
6312
6313 /*
6314 * Call each currently registered protocol event handler.
6315 */
6316 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6317 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006318 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 ioc->name, ii));
6320 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6321 handlers++;
6322 }
6323 }
6324 /* FIXME? Examine results here? */
6325
6326 /*
6327 * If needed, send (a single) EventAck.
6328 */
6329 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006330 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006331 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006333 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 ioc->name, ii));
6335 }
6336 }
6337
6338 *evHandlers = handlers;
6339 return r;
6340}
6341
6342/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006343/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6345 * @ioc: Pointer to MPT_ADAPTER structure
6346 * @log_info: U32 LogInfo reply word from the IOC
6347 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006348 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 */
6350static void
6351mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6352{
Eric Moore7c431e52007-06-13 16:34:36 -06006353 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354
Eric Moore7c431e52007-06-13 16:34:36 -06006355 switch (log_info & 0xFF000000) {
6356 case MPI_IOCLOGINFO_FC_INIT_BASE:
6357 desc = "FCP Initiator";
6358 break;
6359 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6360 desc = "FCP Target";
6361 break;
6362 case MPI_IOCLOGINFO_FC_LAN_BASE:
6363 desc = "LAN";
6364 break;
6365 case MPI_IOCLOGINFO_FC_MSG_BASE:
6366 desc = "MPI Message Layer";
6367 break;
6368 case MPI_IOCLOGINFO_FC_LINK_BASE:
6369 desc = "FC Link";
6370 break;
6371 case MPI_IOCLOGINFO_FC_CTX_BASE:
6372 desc = "Context Manager";
6373 break;
6374 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6375 desc = "Invalid Field Offset";
6376 break;
6377 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6378 desc = "State Change Info";
6379 break;
6380 }
6381
6382 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6383 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384}
6385
6386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006387/**
Moore, Eric335a9412006-01-17 17:06:23 -07006388 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 * @ioc: Pointer to MPT_ADAPTER structure
6390 * @mr: Pointer to MPT reply frame
6391 * @log_info: U32 LogInfo word from the IOC
6392 *
6393 * Refer to lsi/sp_log.h.
6394 */
6395static void
Moore, Eric335a9412006-01-17 17:06:23 -07006396mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397{
6398 u32 info = log_info & 0x00FF0000;
6399 char *desc = "unknown";
6400
6401 switch (info) {
6402 case 0x00010000:
6403 desc = "bug! MID not found";
6404 if (ioc->reload_fw == 0)
6405 ioc->reload_fw++;
6406 break;
6407
6408 case 0x00020000:
6409 desc = "Parity Error";
6410 break;
6411
6412 case 0x00030000:
6413 desc = "ASYNC Outbound Overrun";
6414 break;
6415
6416 case 0x00040000:
6417 desc = "SYNC Offset Error";
6418 break;
6419
6420 case 0x00050000:
6421 desc = "BM Change";
6422 break;
6423
6424 case 0x00060000:
6425 desc = "Msg In Overflow";
6426 break;
6427
6428 case 0x00070000:
6429 desc = "DMA Error";
6430 break;
6431
6432 case 0x00080000:
6433 desc = "Outbound DMA Overrun";
6434 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006435
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436 case 0x00090000:
6437 desc = "Task Management";
6438 break;
6439
6440 case 0x000A0000:
6441 desc = "Device Problem";
6442 break;
6443
6444 case 0x000B0000:
6445 desc = "Invalid Phase Change";
6446 break;
6447
6448 case 0x000C0000:
6449 desc = "Untagged Table Size";
6450 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006451
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452 }
6453
6454 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6455}
6456
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006457/* strings for sas loginfo */
6458 static char *originator_str[] = {
6459 "IOP", /* 00h */
6460 "PL", /* 01h */
6461 "IR" /* 02h */
6462 };
6463 static char *iop_code_str[] = {
6464 NULL, /* 00h */
6465 "Invalid SAS Address", /* 01h */
6466 NULL, /* 02h */
6467 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006468 "Diag Message Error", /* 04h */
6469 "Task Terminated", /* 05h */
6470 "Enclosure Management", /* 06h */
6471 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006472 };
6473 static char *pl_code_str[] = {
6474 NULL, /* 00h */
6475 "Open Failure", /* 01h */
6476 "Invalid Scatter Gather List", /* 02h */
6477 "Wrong Relative Offset or Frame Length", /* 03h */
6478 "Frame Transfer Error", /* 04h */
6479 "Transmit Frame Connected Low", /* 05h */
6480 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6481 "SATA Read Log Receive Data Error", /* 07h */
6482 "SATA NCQ Fail All Commands After Error", /* 08h */
6483 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6484 "Receive Frame Invalid Message", /* 0Ah */
6485 "Receive Context Message Valid Error", /* 0Bh */
6486 "Receive Frame Current Frame Error", /* 0Ch */
6487 "SATA Link Down", /* 0Dh */
6488 "Discovery SATA Init W IOS", /* 0Eh */
6489 "Config Invalid Page", /* 0Fh */
6490 "Discovery SATA Init Timeout", /* 10h */
6491 "Reset", /* 11h */
6492 "Abort", /* 12h */
6493 "IO Not Yet Executed", /* 13h */
6494 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006495 "Persistent Reservation Out Not Affiliation "
6496 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006497 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006498 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006499 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006500 NULL, /* 19h */
6501 NULL, /* 1Ah */
6502 NULL, /* 1Bh */
6503 NULL, /* 1Ch */
6504 NULL, /* 1Dh */
6505 NULL, /* 1Eh */
6506 NULL, /* 1Fh */
6507 "Enclosure Management" /* 20h */
6508 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006509 static char *ir_code_str[] = {
6510 "Raid Action Error", /* 00h */
6511 NULL, /* 00h */
6512 NULL, /* 01h */
6513 NULL, /* 02h */
6514 NULL, /* 03h */
6515 NULL, /* 04h */
6516 NULL, /* 05h */
6517 NULL, /* 06h */
6518 NULL /* 07h */
6519 };
6520 static char *raid_sub_code_str[] = {
6521 NULL, /* 00h */
6522 "Volume Creation Failed: Data Passed too "
6523 "Large", /* 01h */
6524 "Volume Creation Failed: Duplicate Volumes "
6525 "Attempted", /* 02h */
6526 "Volume Creation Failed: Max Number "
6527 "Supported Volumes Exceeded", /* 03h */
6528 "Volume Creation Failed: DMA Error", /* 04h */
6529 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6530 "Volume Creation Failed: Error Reading "
6531 "MFG Page 4", /* 06h */
6532 "Volume Creation Failed: Creating Internal "
6533 "Structures", /* 07h */
6534 NULL, /* 08h */
6535 NULL, /* 09h */
6536 NULL, /* 0Ah */
6537 NULL, /* 0Bh */
6538 NULL, /* 0Ch */
6539 NULL, /* 0Dh */
6540 NULL, /* 0Eh */
6541 NULL, /* 0Fh */
6542 "Activation failed: Already Active Volume", /* 10h */
6543 "Activation failed: Unsupported Volume Type", /* 11h */
6544 "Activation failed: Too Many Active Volumes", /* 12h */
6545 "Activation failed: Volume ID in Use", /* 13h */
6546 "Activation failed: Reported Failure", /* 14h */
6547 "Activation failed: Importing a Volume", /* 15h */
6548 NULL, /* 16h */
6549 NULL, /* 17h */
6550 NULL, /* 18h */
6551 NULL, /* 19h */
6552 NULL, /* 1Ah */
6553 NULL, /* 1Bh */
6554 NULL, /* 1Ch */
6555 NULL, /* 1Dh */
6556 NULL, /* 1Eh */
6557 NULL, /* 1Fh */
6558 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6559 "Phys Disk failed: Data Passed too Large", /* 21h */
6560 "Phys Disk failed: DMA Error", /* 22h */
6561 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6562 "Phys Disk failed: Creating Phys Disk Config "
6563 "Page", /* 24h */
6564 NULL, /* 25h */
6565 NULL, /* 26h */
6566 NULL, /* 27h */
6567 NULL, /* 28h */
6568 NULL, /* 29h */
6569 NULL, /* 2Ah */
6570 NULL, /* 2Bh */
6571 NULL, /* 2Ch */
6572 NULL, /* 2Dh */
6573 NULL, /* 2Eh */
6574 NULL, /* 2Fh */
6575 "Compatibility Error: IR Disabled", /* 30h */
6576 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6577 "Compatibility Error: Device not Direct Access "
6578 "Device ", /* 32h */
6579 "Compatibility Error: Removable Device Found", /* 33h */
6580 "Compatibility Error: Device SCSI Version not "
6581 "2 or Higher", /* 34h */
6582 "Compatibility Error: SATA Device, 48 BIT LBA "
6583 "not Supported", /* 35h */
6584 "Compatibility Error: Device doesn't have "
6585 "512 Byte Block Sizes", /* 36h */
6586 "Compatibility Error: Volume Type Check Failed", /* 37h */
6587 "Compatibility Error: Volume Type is "
6588 "Unsupported by FW", /* 38h */
6589 "Compatibility Error: Disk Drive too Small for "
6590 "use in Volume", /* 39h */
6591 "Compatibility Error: Phys Disk for Create "
6592 "Volume not Found", /* 3Ah */
6593 "Compatibility Error: Too Many or too Few "
6594 "Disks for Volume Type", /* 3Bh */
6595 "Compatibility Error: Disk stripe Sizes "
6596 "Must be 64KB", /* 3Ch */
6597 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6598 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006599
6600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006601/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006602 * mpt_sas_log_info - Log information returned from SAS IOC.
6603 * @ioc: Pointer to MPT_ADAPTER structure
6604 * @log_info: U32 LogInfo reply word from the IOC
6605 *
6606 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006607 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006608static void
6609mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6610{
6611union loginfo_type {
6612 u32 loginfo;
6613 struct {
6614 u32 subcode:16;
6615 u32 code:8;
6616 u32 originator:4;
6617 u32 bus_type:4;
6618 }dw;
6619};
6620 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006621 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006622 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006623 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006624
6625 sas_loginfo.loginfo = log_info;
6626 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6627 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6628 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006629
6630 originator_desc = originator_str[sas_loginfo.dw.originator];
6631
6632 switch (sas_loginfo.dw.originator) {
6633
6634 case 0: /* IOP */
6635 if (sas_loginfo.dw.code <
6636 sizeof(iop_code_str)/sizeof(char*))
6637 code_desc = iop_code_str[sas_loginfo.dw.code];
6638 break;
6639 case 1: /* PL */
6640 if (sas_loginfo.dw.code <
6641 sizeof(pl_code_str)/sizeof(char*))
6642 code_desc = pl_code_str[sas_loginfo.dw.code];
6643 break;
6644 case 2: /* IR */
6645 if (sas_loginfo.dw.code >=
6646 sizeof(ir_code_str)/sizeof(char*))
6647 break;
6648 code_desc = ir_code_str[sas_loginfo.dw.code];
6649 if (sas_loginfo.dw.subcode >=
6650 sizeof(raid_sub_code_str)/sizeof(char*))
6651 break;
6652 if (sas_loginfo.dw.code == 0)
6653 sub_code_desc =
6654 raid_sub_code_str[sas_loginfo.dw.subcode];
6655 break;
6656 default:
6657 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006658 }
6659
Eric Moorec6c727a2007-01-29 09:44:54 -07006660 if (sub_code_desc != NULL)
6661 printk(MYIOC_s_INFO_FMT
6662 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6663 " SubCode={%s}\n",
6664 ioc->name, log_info, originator_desc, code_desc,
6665 sub_code_desc);
6666 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006667 printk(MYIOC_s_INFO_FMT
6668 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6669 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006670 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006671 sas_loginfo.dw.subcode);
6672 else
6673 printk(MYIOC_s_INFO_FMT
6674 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6675 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006676 ioc->name, log_info, originator_desc,
6677 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006678}
6679
Eric Moorec6c727a2007-01-29 09:44:54 -07006680#ifdef MPT_DEBUG_REPLY
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006682/**
Eric Moorec6c727a2007-01-29 09:44:54 -07006683 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
6684 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08006685 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07006686 * @mf: Pointer to MPT request frame
6687 *
6688 * Refer to lsi/mpi.h.
6689 **/
6690static void
6691mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6692{
6693 Config_t *pReq = (Config_t *)mf;
6694 char extend_desc[EVENT_DESCR_STR_SZ];
6695 char *desc = NULL;
6696 u32 form;
6697 u8 page_type;
6698
6699 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
6700 page_type = pReq->ExtPageType;
6701 else
6702 page_type = pReq->Header.PageType;
6703
6704 /*
6705 * ignore invalid page messages for GET_NEXT_HANDLE
6706 */
6707 form = le32_to_cpu(pReq->PageAddress);
6708 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
6709 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
6710 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
6711 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
6712 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
6713 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
6714 return;
6715 }
6716 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
6717 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
6718 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
6719 return;
6720 }
6721
6722 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
6723 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
6724 page_type, pReq->Header.PageNumber, pReq->Action, form);
6725
6726 switch (ioc_status) {
6727
6728 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6729 desc = "Config Page Invalid Action";
6730 break;
6731
6732 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6733 desc = "Config Page Invalid Type";
6734 break;
6735
6736 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6737 desc = "Config Page Invalid Page";
6738 break;
6739
6740 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6741 desc = "Config Page Invalid Data";
6742 break;
6743
6744 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6745 desc = "Config Page No Defaults";
6746 break;
6747
6748 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6749 desc = "Config Page Can't Commit";
6750 break;
6751 }
6752
6753 if (!desc)
6754 return;
6755
6756 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
6757 ioc->name, ioc_status, desc, extend_desc);
6758}
6759
6760/**
6761 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762 * @ioc: Pointer to MPT_ADAPTER structure
6763 * @ioc_status: U32 IOCStatus word from IOC
6764 * @mf: Pointer to MPT request frame
6765 *
6766 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006767 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768static void
Eric Moorec6c727a2007-01-29 09:44:54 -07006769mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006770{
6771 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06006772 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006773
6774 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07006775
6776/****************************************************************************/
6777/* Common IOCStatus values for all replies */
6778/****************************************************************************/
6779
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6781 desc = "Invalid Function";
6782 break;
6783
6784 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6785 desc = "Busy";
6786 break;
6787
6788 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6789 desc = "Invalid SGL";
6790 break;
6791
6792 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6793 desc = "Internal Error";
6794 break;
6795
6796 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6797 desc = "Reserved";
6798 break;
6799
6800 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6801 desc = "Insufficient Resources";
6802 break;
6803
6804 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6805 desc = "Invalid Field";
6806 break;
6807
6808 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6809 desc = "Invalid State";
6810 break;
6811
Eric Moorec6c727a2007-01-29 09:44:54 -07006812/****************************************************************************/
6813/* Config IOCStatus values */
6814/****************************************************************************/
6815
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6817 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6818 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6819 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6820 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6821 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07006822 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823 break;
6824
Eric Moorec6c727a2007-01-29 09:44:54 -07006825/****************************************************************************/
6826/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
6827/* */
6828/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
6829/* */
6830/****************************************************************************/
6831
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07006834 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6835 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6836 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6837 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006838 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006842 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07006844 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006845 break;
6846
Eric Moorec6c727a2007-01-29 09:44:54 -07006847/****************************************************************************/
6848/* SCSI Target values */
6849/****************************************************************************/
6850
6851 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
6852 desc = "Target: Priority IO";
6853 break;
6854
6855 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
6856 desc = "Target: Invalid Port";
6857 break;
6858
6859 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
6860 desc = "Target Invalid IO Index:";
6861 break;
6862
6863 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
6864 desc = "Target: Aborted";
6865 break;
6866
6867 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
6868 desc = "Target: No Conn Retryable";
6869 break;
6870
6871 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
6872 desc = "Target: No Connection";
6873 break;
6874
6875 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
6876 desc = "Target: Transfer Count Mismatch";
6877 break;
6878
6879 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
6880 desc = "Target: STS Data not Sent";
6881 break;
6882
6883 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
6884 desc = "Target: Data Offset Error";
6885 break;
6886
6887 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
6888 desc = "Target: Too Much Write Data";
6889 break;
6890
6891 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
6892 desc = "Target: IU Too Short";
6893 break;
6894
6895 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
6896 desc = "Target: ACK NAK Timeout";
6897 break;
6898
6899 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
6900 desc = "Target: Nak Received";
6901 break;
6902
6903/****************************************************************************/
6904/* Fibre Channel Direct Access values */
6905/****************************************************************************/
6906
6907 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
6908 desc = "FC: Aborted";
6909 break;
6910
6911 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
6912 desc = "FC: RX ID Invalid";
6913 break;
6914
6915 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
6916 desc = "FC: DID Invalid";
6917 break;
6918
6919 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
6920 desc = "FC: Node Logged Out";
6921 break;
6922
6923 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
6924 desc = "FC: Exchange Canceled";
6925 break;
6926
6927/****************************************************************************/
6928/* LAN values */
6929/****************************************************************************/
6930
6931 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
6932 desc = "LAN: Device not Found";
6933 break;
6934
6935 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
6936 desc = "LAN: Device Failure";
6937 break;
6938
6939 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
6940 desc = "LAN: Transmit Error";
6941 break;
6942
6943 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
6944 desc = "LAN: Transmit Aborted";
6945 break;
6946
6947 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
6948 desc = "LAN: Receive Error";
6949 break;
6950
6951 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
6952 desc = "LAN: Receive Aborted";
6953 break;
6954
6955 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
6956 desc = "LAN: Partial Packet";
6957 break;
6958
6959 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
6960 desc = "LAN: Canceled";
6961 break;
6962
6963/****************************************************************************/
6964/* Serial Attached SCSI values */
6965/****************************************************************************/
6966
6967 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
6968 desc = "SAS: SMP Request Failed";
6969 break;
6970
6971 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
6972 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006973 break;
6974
6975 default:
6976 desc = "Others";
6977 break;
6978 }
Eric Moorec6c727a2007-01-29 09:44:54 -07006979
6980 if (!desc)
6981 return;
6982
6983 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006984}
Eric Moorec6c727a2007-01-29 09:44:54 -07006985#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986
6987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006988EXPORT_SYMBOL(mpt_attach);
6989EXPORT_SYMBOL(mpt_detach);
6990#ifdef CONFIG_PM
6991EXPORT_SYMBOL(mpt_resume);
6992EXPORT_SYMBOL(mpt_suspend);
6993#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006995EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996EXPORT_SYMBOL(mpt_register);
6997EXPORT_SYMBOL(mpt_deregister);
6998EXPORT_SYMBOL(mpt_event_register);
6999EXPORT_SYMBOL(mpt_event_deregister);
7000EXPORT_SYMBOL(mpt_reset_register);
7001EXPORT_SYMBOL(mpt_reset_deregister);
7002EXPORT_SYMBOL(mpt_device_driver_register);
7003EXPORT_SYMBOL(mpt_device_driver_deregister);
7004EXPORT_SYMBOL(mpt_get_msg_frame);
7005EXPORT_SYMBOL(mpt_put_msg_frame);
7006EXPORT_SYMBOL(mpt_free_msg_frame);
7007EXPORT_SYMBOL(mpt_add_sge);
7008EXPORT_SYMBOL(mpt_send_handshake_request);
7009EXPORT_SYMBOL(mpt_verify_adapter);
7010EXPORT_SYMBOL(mpt_GetIocState);
7011EXPORT_SYMBOL(mpt_print_ioc_summary);
7012EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007013EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014EXPORT_SYMBOL(mpt_HardResetHandler);
7015EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007016EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017EXPORT_SYMBOL(mpt_alloc_fw_memory);
7018EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007019EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007020EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007021
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007023/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024 * fusion_init - Fusion MPT base driver initialization routine.
7025 *
7026 * Returns 0 for success, non-zero for failure.
7027 */
7028static int __init
7029fusion_init(void)
7030{
7031 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
7033 show_mptmod_ver(my_NAME, my_VERSION);
7034 printk(KERN_INFO COPYRIGHT "\n");
7035
7036 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
7037 MptCallbacks[i] = NULL;
7038 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
7039 MptEvHandlers[i] = NULL;
7040 MptResetHandlers[i] = NULL;
7041 }
7042
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007043 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044 * EventNotification handling.
7045 */
7046 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7047
7048 /* Register for hard reset handling callbacks.
7049 */
7050 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
7051 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
7052 } else {
7053 /* FIXME! */
7054 }
7055
7056#ifdef CONFIG_PROC_FS
7057 (void) procmpt_create();
7058#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007059 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060}
7061
7062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007063/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064 * fusion_exit - Perform driver unload cleanup.
7065 *
7066 * This routine frees all resources associated with each MPT adapter
7067 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7068 */
7069static void __exit
7070fusion_exit(void)
7071{
7072
7073 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
7074
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075 mpt_reset_deregister(mpt_base_index);
7076
7077#ifdef CONFIG_PROC_FS
7078 procmpt_destroy();
7079#endif
7080}
7081
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082module_init(fusion_init);
7083module_exit(fusion_exit);