blob: b3f28a03b6a99f247648c9f12dc19f348d26213f [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
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
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"
67
68/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
69#define my_NAME "Fusion MPT base driver"
70#define my_VERSION MPT_LINUX_VERSION_COMMON
71#define MYNAM "mptbase"
72
73MODULE_AUTHOR(MODULEAUTHOR);
74MODULE_DESCRIPTION(my_NAME);
75MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070076MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78/*
79 * cmd line parameters
80 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000081static int mpt_msi_enable;
82module_param(mpt_msi_enable, int, 0);
83MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#ifdef MFCNT
86static int mfcounter = 0;
87#define PRINT_MF_COUNT 20000
88#endif
89
90/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
91/*
92 * Public data...
93 */
94int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080095int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvaldsf7473072005-11-29 14:21:57 -080097struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99#define WHOINIT_UNKNOWN 0xAA
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Private data...
104 */
105 /* Adapter link list */
106LIST_HEAD(ioc_list);
107 /* Callback lookup table */
108static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
109 /* Protocol driver class lookup table */
110static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
111 /* Event handler lookup table */
112static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Reset handler lookup table */
114static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116
117static int mpt_base_index = -1;
118static int last_drv_idx = -1;
119
120static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Forward protos...
125 */
David Howells7d12e782006-10-05 14:55:46 +0100126static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
128static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
129 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
130 int sleepFlag);
131static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
132static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
133static void mpt_adapter_disable(MPT_ADAPTER *ioc);
134static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
135
136static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
137static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
139static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
140static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
141static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
142static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200143static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
146static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
147static int PrimeIocFifos(MPT_ADAPTER *ioc);
148static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
151static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200153int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
155static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
156static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
157static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
158static void mpt_timer_expired(unsigned long data);
159static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
160static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200161static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
162static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#ifdef CONFIG_PROC_FS
165static int procmpt_summary_read(char *buf, char **start, off_t offset,
166 int request, int *eof, void *data);
167static int procmpt_version_read(char *buf, char **start, off_t offset,
168 int request, int *eof, void *data);
169static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
170 int request, int *eof, void *data);
171#endif
172static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
173
174//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
175static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
176static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
177static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700178static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600179static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700180static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static int __init fusion_init (void);
184static void __exit fusion_exit (void);
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define CHIPREG_READ32(addr) readl_relaxed(addr)
187#define CHIPREG_READ32_dmasync(addr) readl(addr)
188#define CHIPREG_WRITE32(addr,val) writel(val, addr)
189#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
190#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
191
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600192static void
193pci_disable_io_access(struct pci_dev *pdev)
194{
195 u16 command_reg;
196
197 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
198 command_reg &= ~1;
199 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
200}
201
202static void
203pci_enable_io_access(struct pci_dev *pdev)
204{
205 u16 command_reg;
206
207 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
208 command_reg |= 1;
209 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
210}
211
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600212/*
213 * Process turbo (context) reply...
214 */
215static void
216mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
217{
218 MPT_FRAME_HDR *mf = NULL;
219 MPT_FRAME_HDR *mr = NULL;
220 int req_idx = 0;
221 int cb_idx;
222
223 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
224 ioc->name, pa));
225
226 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
227 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
228 req_idx = pa & 0x0000FFFF;
229 cb_idx = (pa & 0x00FF0000) >> 16;
230 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
231 break;
232 case MPI_CONTEXT_REPLY_TYPE_LAN:
233 cb_idx = mpt_lan_index;
234 /*
235 * Blind set of mf to NULL here was fatal
236 * after lan_reply says "freeme"
237 * Fix sort of combined with an optimization here;
238 * added explicit check for case where lan_reply
239 * was just returning 1 and doing nothing else.
240 * For this case skip the callback, but set up
241 * proper mf value first here:-)
242 */
243 if ((pa & 0x58000000) == 0x58000000) {
244 req_idx = pa & 0x0000FFFF;
245 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
246 mpt_free_msg_frame(ioc, mf);
247 mb();
248 return;
249 break;
250 }
251 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
252 break;
253 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
254 cb_idx = mpt_stm_index;
255 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
256 break;
257 default:
258 cb_idx = 0;
259 BUG();
260 }
261
262 /* Check for (valid) IO callback! */
263 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
264 MptCallbacks[cb_idx] == NULL) {
265 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
266 __FUNCTION__, ioc->name, cb_idx);
267 goto out;
268 }
269
270 if (MptCallbacks[cb_idx](ioc, mf, mr))
271 mpt_free_msg_frame(ioc, mf);
272 out:
273 mb();
274}
275
276static void
277mpt_reply(MPT_ADAPTER *ioc, u32 pa)
278{
279 MPT_FRAME_HDR *mf;
280 MPT_FRAME_HDR *mr;
281 int req_idx;
282 int cb_idx;
283 int freeme;
284
285 u32 reply_dma_low;
286 u16 ioc_stat;
287
288 /* non-TURBO reply! Hmmm, something may be up...
289 * Newest turbo reply mechanism; get address
290 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
291 */
292
293 /* Map DMA address of reply header to cpu address.
294 * pa is 32 bits - but the dma address may be 32 or 64 bits
295 * get offset based only only the low addresses
296 */
297
298 reply_dma_low = (pa <<= 1);
299 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
300 (reply_dma_low - ioc->reply_frames_low_dma));
301
302 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
303 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
304 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
305
306 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
307 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
308 DBG_DUMP_REPLY_FRAME(mr)
309
310 /* Check/log IOC log info
311 */
312 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
313 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
314 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
315 if (ioc->bus_type == FC)
316 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700317 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700318 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600319 else if (ioc->bus_type == SAS)
320 mpt_sas_log_info(ioc, log_info);
321 }
322 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700323 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600324 cb_idx != mpt_stm_index &&
325 cb_idx != mpt_lan_index)
326 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
327 }
328
329
330 /* Check for (valid) IO callback! */
331 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
332 MptCallbacks[cb_idx] == NULL) {
333 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
334 __FUNCTION__, ioc->name, cb_idx);
335 freeme = 0;
336 goto out;
337 }
338
339 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
340
341 out:
342 /* Flush (non-TURBO) reply with a WRITE! */
343 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
344
345 if (freeme)
346 mpt_free_msg_frame(ioc, mf);
347 mb();
348}
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800351/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
353 * @irq: irq number (not used)
354 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 *
356 * This routine is registered via the request_irq() kernel API call,
357 * and handles all interrupts generated from a specific MPT adapter
358 * (also referred to as a IO Controller or IOC).
359 * This routine must clear the interrupt from the adapter and does
360 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200361 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 *
363 * This routine handles register-level access of the adapter but
364 * dispatches (calls) a protocol-specific callback routine to handle
365 * the protocol-specific details of the MPT request completion.
366 */
367static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100368mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600370 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600371 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
372
373 if (pa == 0xFFFFFFFF)
374 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /*
377 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600379 do {
380 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 mpt_reply(ioc, pa);
382 else
383 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600384 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
385 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 return IRQ_HANDLED;
388}
389
390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800391/**
392 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 * @ioc: Pointer to MPT_ADAPTER structure
394 * @mf: Pointer to original MPT request frame
395 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
396 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800397 * MPT base driver's callback routine; all base driver
398 * "internal" request/reply processing is routed here.
399 * Currently used for EventNotification and EventAck handling.
400 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 * should be freed, or 0 if it shouldn't.
403 */
404static int
405mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
406{
407 int freereq = 1;
408 u8 func;
409
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200410 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200412#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
414 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
415 DBG_DUMP_REQUEST_FRAME_HDR(mf)
416 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200417#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200420 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ioc->name, func));
422
423 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
424 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
425 int evHandlers = 0;
426 int results;
427
428 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
429 if (results != evHandlers) {
430 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700431 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 ioc->name, evHandlers, results));
433 }
434
435 /*
436 * Hmmm... It seems that EventNotificationReply is an exception
437 * to the rule of one reply per request.
438 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200439 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700442 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200443 ioc->name, pEvReply));
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446#ifdef CONFIG_PROC_FS
447// LogEvent(ioc, pEvReply);
448#endif
449
450 } else if (func == MPI_FUNCTION_EVENT_ACK) {
451 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
452 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700453 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 CONFIGPARMS *pCfg;
455 unsigned long flags;
456
457 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
458 ioc->name, mf, reply));
459
460 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
461
462 if (pCfg) {
463 /* disable timer and remove from linked list */
464 del_timer(&pCfg->timer);
465
466 spin_lock_irqsave(&ioc->FreeQlock, flags);
467 list_del(&pCfg->linkage);
468 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
469
470 /*
471 * If IOC Status is SUCCESS, save the header
472 * and set the status code to GOOD.
473 */
474 pCfg->status = MPT_CONFIG_ERROR;
475 if (reply) {
476 ConfigReply_t *pReply = (ConfigReply_t *)reply;
477 u16 status;
478
479 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
480 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
481 status, le32_to_cpu(pReply->IOCLogInfo)));
482
483 pCfg->status = status;
484 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200485 if ((pReply->Header.PageType &
486 MPI_CONFIG_PAGETYPE_MASK) ==
487 MPI_CONFIG_PAGETYPE_EXTENDED) {
488 pCfg->cfghdr.ehdr->ExtPageLength =
489 le16_to_cpu(pReply->ExtPageLength);
490 pCfg->cfghdr.ehdr->ExtPageType =
491 pReply->ExtPageType;
492 }
493 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
494
495 /* If this is a regular header, save PageLength. */
496 /* LMP Do this better so not using a reserved field! */
497 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
498 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
499 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 }
502
503 /*
504 * Wake up the original calling thread
505 */
506 pCfg->wait_done = 1;
507 wake_up(&mpt_waitq);
508 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200509 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
510 /* we should be always getting a reply frame */
511 memcpy(ioc->persist_reply_frame, reply,
512 min(MPT_DEFAULT_FRAME_SIZE,
513 4*reply->u.reply.MsgLength));
514 del_timer(&ioc->persist_timer);
515 ioc->persist_wait_done = 1;
516 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 } else {
518 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
519 ioc->name, func);
520 }
521
522 /*
523 * Conditionally tell caller to free the original
524 * EventNotification/EventAck/unexpected request frame!
525 */
526 return freereq;
527}
528
529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
530/**
531 * mpt_register - Register protocol-specific main callback handler.
532 * @cbfunc: callback function pointer
533 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
534 *
535 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800536 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 * protocol-specific driver must do this before it will be able to
538 * use any IOC resources, such as obtaining request frames.
539 *
540 * NOTES: The SCSI protocol driver currently calls this routine thrice
541 * in order to register separate callbacks; one for "normal" SCSI IO;
542 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
543 *
544 * Returns a positive integer valued "handle" in the
545 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
546 * Any non-positive return value (including zero!) should be considered
547 * an error by the caller.
548 */
549int
550mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
551{
552 int i;
553
554 last_drv_idx = -1;
555
556 /*
557 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
558 * (slot/handle 0 is reserved!)
559 */
560 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
561 if (MptCallbacks[i] == NULL) {
562 MptCallbacks[i] = cbfunc;
563 MptDriverClass[i] = dclass;
564 MptEvHandlers[i] = NULL;
565 last_drv_idx = i;
566 break;
567 }
568 }
569
570 return last_drv_idx;
571}
572
573/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
574/**
575 * mpt_deregister - Deregister a protocol drivers resources.
576 * @cb_idx: previously registered callback handle
577 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800578 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 * module is unloaded.
580 */
581void
582mpt_deregister(int cb_idx)
583{
584 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
585 MptCallbacks[cb_idx] = NULL;
586 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
587 MptEvHandlers[cb_idx] = NULL;
588
589 last_drv_idx++;
590 }
591}
592
593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
594/**
595 * mpt_event_register - Register protocol-specific event callback
596 * handler.
597 * @cb_idx: previously registered (via mpt_register) callback handle
598 * @ev_cbfunc: callback function
599 *
600 * This routine can be called by one or more protocol-specific drivers
601 * if/when they choose to be notified of MPT events.
602 *
603 * Returns 0 for success.
604 */
605int
606mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
607{
608 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
609 return -1;
610
611 MptEvHandlers[cb_idx] = ev_cbfunc;
612 return 0;
613}
614
615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
616/**
617 * mpt_event_deregister - Deregister protocol-specific event callback
618 * handler.
619 * @cb_idx: previously registered callback handle
620 *
621 * Each protocol-specific driver should call this routine
622 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800623 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 */
625void
626mpt_event_deregister(int cb_idx)
627{
628 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
629 return;
630
631 MptEvHandlers[cb_idx] = NULL;
632}
633
634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
635/**
636 * mpt_reset_register - Register protocol-specific IOC reset handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @reset_func: reset function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of IOC resets.
642 *
643 * Returns 0 for success.
644 */
645int
646mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
647{
648 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
649 return -1;
650
651 MptResetHandlers[cb_idx] = reset_func;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
658 * @cb_idx: previously registered callback handle
659 *
660 * Each protocol-specific driver should call this routine
661 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800662 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 */
664void
665mpt_reset_deregister(int cb_idx)
666{
667 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
668 return;
669
670 MptResetHandlers[cb_idx] = NULL;
671}
672
673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
674/**
675 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800676 * @dd_cbfunc: driver callbacks struct
677 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 */
679int
680mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
681{
682 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600683 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Eric Moored58b2722006-07-11 17:23:23 -0600685 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400686 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
689
690 /* call per pci device probe entry point */
691 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600692 id = ioc->pcidev->driver ?
693 ioc->pcidev->driver->id_table : NULL;
694 if (dd_cbfunc->probe)
695 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
697
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400698 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
701/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
702/**
703 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800704 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 */
706void
707mpt_device_driver_deregister(int cb_idx)
708{
709 struct mpt_pci_driver *dd_cbfunc;
710 MPT_ADAPTER *ioc;
711
712 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
713 return;
714
715 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
716
717 list_for_each_entry(ioc, &ioc_list, list) {
718 if (dd_cbfunc->remove)
719 dd_cbfunc->remove(ioc->pcidev);
720 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 MptDeviceDriverHandlers[cb_idx] = NULL;
723}
724
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
728 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
729 * allocated per MPT adapter.
730 * @handle: Handle of registered MPT protocol driver
731 * @ioc: Pointer to MPT adapter structure
732 *
733 * Returns pointer to a MPT request frame or %NULL if none are available
734 * or IOC is not active.
735 */
736MPT_FRAME_HDR*
737mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
738{
739 MPT_FRAME_HDR *mf;
740 unsigned long flags;
741 u16 req_idx; /* Request index */
742
743 /* validate handle and ioc identifier */
744
745#ifdef MFCNT
746 if (!ioc->active)
747 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
748#endif
749
750 /* If interrupts are not attached, do not return a request frame */
751 if (!ioc->active)
752 return NULL;
753
754 spin_lock_irqsave(&ioc->FreeQlock, flags);
755 if (!list_empty(&ioc->FreeQ)) {
756 int req_offset;
757
758 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
759 u.frame.linkage.list);
760 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200761 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
763 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
764 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500765 req_idx = req_offset / ioc->req_sz;
766 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
768 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
769#ifdef MFCNT
770 ioc->mfcnt++;
771#endif
772 }
773 else
774 mf = NULL;
775 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
776
777#ifdef MFCNT
778 if (mf == NULL)
779 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
780 mfcounter++;
781 if (mfcounter == PRINT_MF_COUNT)
782 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
783#endif
784
785 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
786 ioc->name, handle, ioc->id, mf));
787 return mf;
788}
789
790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
791/**
792 * mpt_put_msg_frame - Send a protocol specific MPT request frame
793 * to a IOC.
794 * @handle: Handle of registered MPT protocol driver
795 * @ioc: Pointer to MPT adapter structure
796 * @mf: Pointer to MPT request frame
797 *
798 * This routine posts a MPT request frame to the request post FIFO of a
799 * specific MPT adapter.
800 */
801void
802mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
803{
804 u32 mf_dma_addr;
805 int req_offset;
806 u16 req_idx; /* Request index */
807
808 /* ensure values are reset properly! */
809 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
810 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
811 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500812 req_idx = req_offset / ioc->req_sz;
813 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
815
816#ifdef MPT_DEBUG_MSG_FRAME
817 {
818 u32 *m = mf->u.frame.hwhdr.__hdr;
819 int ii, n;
820
821 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
822 ioc->name, m);
823 n = ioc->req_sz/4 - 1;
824 while (m[n] == 0)
825 n--;
826 for (ii=0; ii<=n; ii++) {
827 if (ii && ((ii%8)==0))
828 printk("\n" KERN_INFO " ");
829 printk(" %08x", le32_to_cpu(m[ii]));
830 }
831 printk("\n");
832 }
833#endif
834
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200835 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 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]));
837 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
838}
839
840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
841/**
842 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
843 * @handle: Handle of registered MPT protocol driver
844 * @ioc: Pointer to MPT adapter structure
845 * @mf: Pointer to MPT request frame
846 *
847 * This routine places a MPT request frame back on the MPT adapter's
848 * FreeQ.
849 */
850void
851mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
852{
853 unsigned long flags;
854
855 /* Put Request back on FreeQ! */
856 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
859#ifdef MFCNT
860 ioc->mfcnt--;
861#endif
862 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
863}
864
865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
866/**
867 * mpt_add_sge - Place a simple SGE at address pAddr.
868 * @pAddr: virtual address for SGE
869 * @flagslength: SGE flags and data transfer length
870 * @dma_addr: Physical address
871 *
872 * This routine places a MPT request frame back on the MPT adapter's
873 * FreeQ.
874 */
875void
876mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
877{
878 if (sizeof(dma_addr_t) == sizeof(u64)) {
879 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
880 u32 tmp = dma_addr & 0xFFFFFFFF;
881
882 pSge->FlagsLength = cpu_to_le32(flagslength);
883 pSge->Address.Low = cpu_to_le32(tmp);
884 tmp = (u32) ((u64)dma_addr >> 32);
885 pSge->Address.High = cpu_to_le32(tmp);
886
887 } else {
888 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
889 pSge->FlagsLength = cpu_to_le32(flagslength);
890 pSge->Address = cpu_to_le32(dma_addr);
891 }
892}
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800896 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 * @handle: Handle of registered MPT protocol driver
898 * @ioc: Pointer to MPT adapter structure
899 * @reqBytes: Size of the request in bytes
900 * @req: Pointer to MPT request frame
901 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
902 *
903 * This routine is used exclusively to send MptScsiTaskMgmt
904 * requests since they are required to be sent via doorbell handshake.
905 *
906 * NOTE: It is the callers responsibility to byte-swap fields in the
907 * request which are greater than 1 byte in size.
908 *
909 * Returns 0 for success, non-zero for failure.
910 */
911int
912mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
913{
914 int r = 0;
915 u8 *req_as_bytes;
916 int ii;
917
918 /* State is known to be good upon entering
919 * this function so issue the bus reset
920 * request.
921 */
922
923 /*
924 * Emulate what mpt_put_msg_frame() does /wrt to sanity
925 * setting cb_idx/req_idx. But ONLY if this request
926 * is in proper (pre-alloc'd) request buffer range...
927 */
928 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
929 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
930 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
931 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
932 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
933 }
934
935 /* Make sure there are no doorbells */
936 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 CHIPREG_WRITE32(&ioc->chip->Doorbell,
939 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
940 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
941
942 /* Wait for IOC doorbell int */
943 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
944 return ii;
945 }
946
947 /* Read doorbell and check for active bit */
948 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
949 return -5;
950
951 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200952 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
955
956 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
957 return -2;
958 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 /* Send request via doorbell handshake */
961 req_as_bytes = (u8 *) req;
962 for (ii = 0; ii < reqBytes/4; ii++) {
963 u32 word;
964
965 word = ((req_as_bytes[(ii*4) + 0] << 0) |
966 (req_as_bytes[(ii*4) + 1] << 8) |
967 (req_as_bytes[(ii*4) + 2] << 16) |
968 (req_as_bytes[(ii*4) + 3] << 24));
969 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
970 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
971 r = -3;
972 break;
973 }
974 }
975
976 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
977 r = 0;
978 else
979 r = -4;
980
981 /* Make sure there are no doorbells */
982 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return r;
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
988/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800989 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200990 * @ioc: Pointer to MPT adapter structure
991 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800992 * @sleepFlag: Specifies whether the process can sleep
993 *
994 * Provides mechanism for the host driver to control the IOC's
995 * Host Page Buffer access.
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200996 *
997 * Access Control Value - bits[15:12]
998 * 0h Reserved
999 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1000 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1001 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1002 *
1003 * Returns 0 for success, non-zero for failure.
1004 */
1005
1006static int
1007mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1008{
1009 int r = 0;
1010
1011 /* return if in use */
1012 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1013 & MPI_DOORBELL_ACTIVE)
1014 return -1;
1015
1016 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1017
1018 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1019 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1020 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1021 (access_control_value<<12)));
1022
1023 /* Wait for IOC to clear Doorbell Status bit */
1024 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1025 return -2;
1026 }else
1027 return 0;
1028}
1029
1030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1031/**
1032 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001033 * @ioc: Pointer to pointer to IOC adapter
1034 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001035 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001036 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001037 * Returns 0 for success, non-zero for failure.
1038 */
1039static int
1040mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1041{
1042 char *psge;
1043 int flags_length;
1044 u32 host_page_buffer_sz=0;
1045
1046 if(!ioc->HostPageBuffer) {
1047
1048 host_page_buffer_sz =
1049 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1050
1051 if(!host_page_buffer_sz)
1052 return 0; /* fw doesn't need any host buffers */
1053
1054 /* spin till we get enough memory */
1055 while(host_page_buffer_sz > 0) {
1056
1057 if((ioc->HostPageBuffer = pci_alloc_consistent(
1058 ioc->pcidev,
1059 host_page_buffer_sz,
1060 &ioc->HostPageBuffer_dma)) != NULL) {
1061
1062 dinitprintk((MYIOC_s_INFO_FMT
1063 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001064 ioc->name, ioc->HostPageBuffer,
1065 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001066 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001067 ioc->alloc_total += host_page_buffer_sz;
1068 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1069 break;
1070 }
1071
1072 host_page_buffer_sz -= (4*1024);
1073 }
1074 }
1075
1076 if(!ioc->HostPageBuffer) {
1077 printk(MYIOC_s_ERR_FMT
1078 "Failed to alloc memory for host_page_buffer!\n",
1079 ioc->name);
1080 return -999;
1081 }
1082
1083 psge = (char *)&ioc_init->HostPageBufferSGE;
1084 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1085 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1086 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1087 MPI_SGE_FLAGS_HOST_TO_IOC |
1088 MPI_SGE_FLAGS_END_OF_BUFFER;
1089 if (sizeof(dma_addr_t) == sizeof(u64)) {
1090 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1091 }
1092 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1093 flags_length |= ioc->HostPageBuffer_sz;
1094 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1095 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1096
1097return 0;
1098}
1099
1100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1101/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001102 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 * @iocid: IOC unique identifier (integer)
1104 * @iocpp: Pointer to pointer to IOC adapter
1105 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001106 * Given a unique IOC identifier, set pointer to the associated MPT
1107 * adapter structure.
1108 *
1109 * Returns iocid and sets iocpp if iocid is found.
1110 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 */
1112int
1113mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1114{
1115 MPT_ADAPTER *ioc;
1116
1117 list_for_each_entry(ioc,&ioc_list,list) {
1118 if (ioc->id == iocid) {
1119 *iocpp =ioc;
1120 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 *iocpp = NULL;
1125 return -1;
1126}
1127
1128/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001129/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001130 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001132 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 *
1134 * This routine performs all the steps necessary to bring the IOC of
1135 * a MPT adapter to a OPERATIONAL state. This includes registering
1136 * memory regions, registering the interrupt, and allocating request
1137 * and reply memory pools.
1138 *
1139 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1140 * MPT adapter.
1141 *
1142 * Returns 0 for success, non-zero for failure.
1143 *
1144 * TODO: Add support for polled controllers
1145 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001146int
1147mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148{
1149 MPT_ADAPTER *ioc;
1150 u8 __iomem *mem;
1151 unsigned long mem_phys;
1152 unsigned long port;
1153 u32 msize;
1154 u32 psize;
1155 int ii;
1156 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 u8 revision;
1158 u8 pcixcmd;
1159 static int mpt_ids = 0;
1160#ifdef CONFIG_PROC_FS
1161 struct proc_dir_entry *dent, *ent;
1162#endif
1163
1164 if (pci_enable_device(pdev))
1165 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001166
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001168
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001169 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 dprintk((KERN_INFO MYNAM
1171 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001172 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1174 return r;
1175 }
1176
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001177 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 dprintk((KERN_INFO MYNAM
1179 ": Using 64 bit consistent mask\n"));
1180 else
1181 dprintk((KERN_INFO MYNAM
1182 ": Not using 64 bit consistent mask\n"));
1183
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001184 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (ioc == NULL) {
1186 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1187 return -ENOMEM;
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 ioc->alloc_total = sizeof(MPT_ADAPTER);
1190 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1191 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 ioc->pcidev = pdev;
1194 ioc->diagPending = 0;
1195 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001196 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
1198 /* Initialize the event logging.
1199 */
1200 ioc->eventTypes = 0; /* None */
1201 ioc->eventContext = 0;
1202 ioc->eventLogSize = 0;
1203 ioc->events = NULL;
1204
1205#ifdef MFCNT
1206 ioc->mfcnt = 0;
1207#endif
1208
1209 ioc->cached_fw = NULL;
1210
1211 /* Initilize SCSI Config Data structure
1212 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001213 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
1215 /* Initialize the running configQ head.
1216 */
1217 INIT_LIST_HEAD(&ioc->configQ);
1218
Michael Reed05e8ec12006-01-13 14:31:54 -06001219 /* Initialize the fc rport list head.
1220 */
1221 INIT_LIST_HEAD(&ioc->fc_rports);
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 /* Find lookup slot. */
1224 INIT_LIST_HEAD(&ioc->list);
1225 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 mem_phys = msize = 0;
1228 port = psize = 0;
1229 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1230 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001231 if (psize)
1232 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 /* Get I/O space! */
1234 port = pci_resource_start(pdev, ii);
1235 psize = pci_resource_len(pdev,ii);
1236 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001237 if (msize)
1238 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Get memmap */
1240 mem_phys = pci_resource_start(pdev, ii);
1241 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243 }
1244 ioc->mem_size = msize;
1245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 mem = NULL;
1247 /* Get logical ptr for PciMem0 space */
1248 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001249 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 if (mem == NULL) {
1251 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1252 kfree(ioc);
1253 return -EINVAL;
1254 }
1255 ioc->memmap = mem;
1256 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1257
1258 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1259 &ioc->facts, &ioc->pfacts[0]));
1260
1261 ioc->mem_phys = mem_phys;
1262 ioc->chip = (SYSIF_REGS __iomem *)mem;
1263
1264 /* Save Port IO values in case we need to do downloadboot */
1265 {
1266 u8 *pmem = (u8*)port;
1267 ioc->pio_mem_phys = port;
1268 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1269 }
1270
1271 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1272 ioc->prod_name = "LSIFC909";
1273 ioc->bus_type = FC;
1274 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001275 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 ioc->prod_name = "LSIFC929";
1277 ioc->bus_type = FC;
1278 }
1279 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1280 ioc->prod_name = "LSIFC919";
1281 ioc->bus_type = FC;
1282 }
1283 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1284 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1285 ioc->bus_type = FC;
1286 if (revision < XL_929) {
1287 ioc->prod_name = "LSIFC929X";
1288 /* 929X Chip Fix. Set Split transactions level
1289 * for PCIX. Set MOST bits to zero.
1290 */
1291 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1292 pcixcmd &= 0x8F;
1293 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1294 } else {
1295 ioc->prod_name = "LSIFC929XL";
1296 /* 929XL Chip Fix. Set MMRBC to 0x08.
1297 */
1298 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1299 pcixcmd |= 0x08;
1300 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1301 }
1302 }
1303 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1304 ioc->prod_name = "LSIFC919X";
1305 ioc->bus_type = FC;
1306 /* 919X Chip Fix. Set Split transactions level
1307 * for PCIX. Set MOST bits to zero.
1308 */
1309 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1310 pcixcmd &= 0x8F;
1311 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1312 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001313 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1314 ioc->prod_name = "LSIFC939X";
1315 ioc->bus_type = FC;
1316 ioc->errata_flag_1064 = 1;
1317 }
1318 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1319 ioc->prod_name = "LSIFC949X";
1320 ioc->bus_type = FC;
1321 ioc->errata_flag_1064 = 1;
1322 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001323 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1324 ioc->prod_name = "LSIFC949E";
1325 ioc->bus_type = FC;
1326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1328 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001329 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 /* 1030 Chip Fix. Disable Split transactions
1331 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1332 */
1333 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1334 if (revision < C0_1030) {
1335 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1336 pcixcmd &= 0x8F;
1337 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1338 }
1339 }
1340 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1341 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001342 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001344 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1345 ioc->prod_name = "LSISAS1064";
1346 ioc->bus_type = SAS;
1347 ioc->errata_flag_1064 = 1;
1348 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001349 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1350 ioc->prod_name = "LSISAS1068";
1351 ioc->bus_type = SAS;
1352 ioc->errata_flag_1064 = 1;
1353 }
1354 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1355 ioc->prod_name = "LSISAS1064E";
1356 ioc->bus_type = SAS;
1357 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001358 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1359 ioc->prod_name = "LSISAS1068E";
1360 ioc->bus_type = SAS;
1361 }
Eric Moore87cf8982006-06-27 16:09:26 -06001362 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
1363 ioc->prod_name = "LSISAS1078";
1364 ioc->bus_type = SAS;
1365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001367 if (ioc->errata_flag_1064)
1368 pci_disable_io_access(pdev);
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 sprintf(ioc->name, "ioc%d", ioc->id);
1371
1372 spin_lock_init(&ioc->FreeQlock);
1373
1374 /* Disable all! */
1375 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1376 ioc->active = 0;
1377 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1378
1379 /* Set lookup ptr. */
1380 list_add_tail(&ioc->list, &ioc_list);
1381
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001382 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 */
1384 mpt_detect_bound_ports(ioc, pdev);
1385
James Bottomleyc92f2222006-03-01 09:02:49 -06001386 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1387 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 printk(KERN_WARNING MYNAM
1389 ": WARNING - %s did not initialize properly! (%d)\n",
1390 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001393 if (ioc->alt_ioc)
1394 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 iounmap(mem);
1396 kfree(ioc);
1397 pci_set_drvdata(pdev, NULL);
1398 return r;
1399 }
1400
1401 /* call per device driver probe entry point */
1402 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1403 if(MptDeviceDriverHandlers[ii] &&
1404 MptDeviceDriverHandlers[ii]->probe) {
1405 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1406 }
1407 }
1408
1409#ifdef CONFIG_PROC_FS
1410 /*
1411 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1412 */
1413 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1414 if (dent) {
1415 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1416 if (ent) {
1417 ent->read_proc = procmpt_iocinfo_read;
1418 ent->data = ioc;
1419 }
1420 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1421 if (ent) {
1422 ent->read_proc = procmpt_summary_read;
1423 ent->data = ioc;
1424 }
1425 }
1426#endif
1427
1428 return 0;
1429}
1430
1431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001432/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001433 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 */
1436
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001437void
1438mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439{
1440 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1441 char pname[32];
1442 int ii;
1443
1444 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1445 remove_proc_entry(pname, NULL);
1446 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1447 remove_proc_entry(pname, NULL);
1448 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1449 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 /* call per device driver remove entry point */
1452 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1453 if(MptDeviceDriverHandlers[ii] &&
1454 MptDeviceDriverHandlers[ii]->remove) {
1455 MptDeviceDriverHandlers[ii]->remove(pdev);
1456 }
1457 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 /* Disable interrupts! */
1460 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1461
1462 ioc->active = 0;
1463 synchronize_irq(pdev->irq);
1464
1465 /* Clear any lingering interrupt */
1466 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1467
1468 CHIPREG_READ32(&ioc->chip->IntStatus);
1469
1470 mpt_adapter_dispose(ioc);
1471
1472 pci_set_drvdata(pdev, NULL);
1473}
1474
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475/**************************************************************************
1476 * Power Management
1477 */
1478#ifdef CONFIG_PM
1479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001480/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001481 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001482 * @pdev: Pointer to pci_dev structure
1483 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001485int
1486mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 u32 device_state;
1489 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
Pavel Machek2a569572005-07-07 17:56:40 -07001491 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 printk(MYIOC_s_INFO_FMT
1494 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1495 ioc->name, pdev, pci_name(pdev), device_state);
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 pci_save_state(pdev);
1498
1499 /* put ioc into READY_STATE */
1500 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1501 printk(MYIOC_s_ERR_FMT
1502 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1503 }
1504
1505 /* disable interrupts */
1506 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1507 ioc->active = 0;
1508
1509 /* Clear any lingering interrupt */
1510 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1511
1512 pci_disable_device(pdev);
1513 pci_set_power_state(pdev, device_state);
1514
1515 return 0;
1516}
1517
1518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001519/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001520 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001521 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001523int
1524mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525{
1526 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1527 u32 device_state = pdev->current_state;
1528 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 printk(MYIOC_s_INFO_FMT
1531 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1532 ioc->name, pdev, pci_name(pdev), device_state);
1533
1534 pci_set_power_state(pdev, 0);
1535 pci_restore_state(pdev);
1536 pci_enable_device(pdev);
1537
1538 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001539 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 ioc->active = 1;
1541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 printk(MYIOC_s_INFO_FMT
1543 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1544 ioc->name,
1545 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1546 CHIPREG_READ32(&ioc->chip->Doorbell));
1547
1548 /* bring ioc to operational state */
1549 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1550 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1551 printk(MYIOC_s_INFO_FMT
1552 "pci-resume: Cannot recover, error:[%x]\n",
1553 ioc->name, recovery_state);
1554 } else {
1555 printk(MYIOC_s_INFO_FMT
1556 "pci-resume: success\n", ioc->name);
1557 }
1558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return 0;
1560}
1561#endif
1562
James Bottomley4ff42a62006-05-17 18:06:52 -05001563static int
1564mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1565{
1566 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1567 ioc->bus_type != SPI) ||
1568 (MptDriverClass[index] == MPTFC_DRIVER &&
1569 ioc->bus_type != FC) ||
1570 (MptDriverClass[index] == MPTSAS_DRIVER &&
1571 ioc->bus_type != SAS))
1572 /* make sure we only call the relevant reset handler
1573 * for the bus */
1574 return 0;
1575 return (MptResetHandlers[index])(ioc, reset_phase);
1576}
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001579/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1581 * @ioc: Pointer to MPT adapter structure
1582 * @reason: Event word / reason
1583 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1584 *
1585 * This routine performs all the steps necessary to bring the IOC
1586 * to a OPERATIONAL state.
1587 *
1588 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1589 * MPT adapter.
1590 *
1591 * Returns:
1592 * 0 for success
1593 * -1 if failed to get board READY
1594 * -2 if READY but IOCFacts Failed
1595 * -3 if READY but PrimeIOCFifos Failed
1596 * -4 if READY but IOCInit Failed
1597 */
1598static int
1599mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1600{
1601 int hard_reset_done = 0;
1602 int alt_ioc_ready = 0;
1603 int hard;
1604 int rc=0;
1605 int ii;
1606 int handlers;
1607 int ret = 0;
1608 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001609 int irq_allocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1612 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1613
1614 /* Disable reply interrupts (also blocks FreeQ) */
1615 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1616 ioc->active = 0;
1617
1618 if (ioc->alt_ioc) {
1619 if (ioc->alt_ioc->active)
1620 reset_alt_ioc_active = 1;
1621
1622 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1623 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1624 ioc->alt_ioc->active = 0;
1625 }
1626
1627 hard = 1;
1628 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1629 hard = 0;
1630
1631 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1632 if (hard_reset_done == -4) {
1633 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1634 ioc->name);
1635
1636 if (reset_alt_ioc_active && ioc->alt_ioc) {
1637 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1638 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1639 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001640 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 ioc->alt_ioc->active = 1;
1642 }
1643
1644 } else {
1645 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1646 ioc->name);
1647 }
1648 return -1;
1649 }
1650
1651 /* hard_reset_done = 0 if a soft reset was performed
1652 * and 1 if a hard reset was performed.
1653 */
1654 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1655 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1656 alt_ioc_ready = 1;
1657 else
1658 printk(KERN_WARNING MYNAM
1659 ": alt-%s: Not ready WARNING!\n",
1660 ioc->alt_ioc->name);
1661 }
1662
1663 for (ii=0; ii<5; ii++) {
1664 /* Get IOC facts! Allow 5 retries */
1665 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1666 break;
1667 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
1670 if (ii == 5) {
1671 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1672 ret = -2;
1673 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1674 MptDisplayIocCapabilities(ioc);
1675 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 if (alt_ioc_ready) {
1678 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1679 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1680 /* Retry - alt IOC was initialized once
1681 */
1682 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1683 }
1684 if (rc) {
1685 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1686 alt_ioc_ready = 0;
1687 reset_alt_ioc_active = 0;
1688 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1689 MptDisplayIocCapabilities(ioc->alt_ioc);
1690 }
1691 }
1692
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001693 /*
1694 * Device is reset now. It must have de-asserted the interrupt line
1695 * (if it was asserted) and it should be safe to register for the
1696 * interrupt now.
1697 */
1698 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1699 ioc->pci_irq = -1;
1700 if (ioc->pcidev->irq) {
1701 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1702 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1703 ioc->name);
1704 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001705 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001706 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001707 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1708 "interrupt %d!\n", ioc->name,
1709 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001710 if (mpt_msi_enable)
1711 pci_disable_msi(ioc->pcidev);
1712 return -EBUSY;
1713 }
1714 irq_allocated = 1;
1715 ioc->pci_irq = ioc->pcidev->irq;
1716 pci_set_master(ioc->pcidev); /* ?? */
1717 pci_set_drvdata(ioc->pcidev, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001718 dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
1719 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001720 }
1721 }
1722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 /* Prime reply & request queues!
1724 * (mucho alloc's) Must be done prior to
1725 * init as upper addresses are needed for init.
1726 * If fails, continue with alt-ioc processing
1727 */
1728 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1729 ret = -3;
1730
1731 /* May need to check/upload firmware & data here!
1732 * If fails, continue with alt-ioc processing
1733 */
1734 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1735 ret = -4;
1736// NEW!
1737 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1738 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1739 ioc->alt_ioc->name, rc);
1740 alt_ioc_ready = 0;
1741 reset_alt_ioc_active = 0;
1742 }
1743
1744 if (alt_ioc_ready) {
1745 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1746 alt_ioc_ready = 0;
1747 reset_alt_ioc_active = 0;
1748 printk(KERN_WARNING MYNAM
1749 ": alt-%s: (%d) init failure WARNING!\n",
1750 ioc->alt_ioc->name, rc);
1751 }
1752 }
1753
1754 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1755 if (ioc->upload_fw) {
1756 ddlprintk((MYIOC_s_INFO_FMT
1757 "firmware upload required!\n", ioc->name));
1758
1759 /* Controller is not operational, cannot do upload
1760 */
1761 if (ret == 0) {
1762 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001763 if (rc == 0) {
1764 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1765 /*
1766 * Maintain only one pointer to FW memory
1767 * so there will not be two attempt to
1768 * downloadboot onboard dual function
1769 * chips (mpt_adapter_disable,
1770 * mpt_diag_reset)
1771 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001772 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1773 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06001774 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001775 }
1776 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001778 ret = -5;
1779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
1781 }
1782 }
1783
1784 if (ret == 0) {
1785 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001786 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 ioc->active = 1;
1788 }
1789
1790 if (reset_alt_ioc_active && ioc->alt_ioc) {
1791 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001792 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001794 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ioc->alt_ioc->active = 1;
1796 }
1797
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001798 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 * and EventAck handling.
1800 */
1801 if ((ret == 0) && (!ioc->facts.EventState))
1802 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1803
1804 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1805 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1806
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001807 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1809 * recursive scenario; GetLanConfigPages times out, timer expired
1810 * routine calls HardResetHandler, which calls into here again,
1811 * and we try GetLanConfigPages again...
1812 */
1813 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001814 if (ioc->bus_type == SAS) {
1815
1816 /* clear persistency table */
1817 if(ioc->facts.IOCExceptions &
1818 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1819 ret = mptbase_sas_persist_operation(ioc,
1820 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1821 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001822 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001823 }
1824
1825 /* Find IM volumes
1826 */
1827 mpt_findImVolumes(ioc);
1828
1829 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1831 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1832 /*
1833 * Pre-fetch the ports LAN MAC address!
1834 * (LANPage1_t stuff)
1835 */
1836 (void) GetLanConfigPages(ioc);
1837#ifdef MPT_DEBUG
1838 {
1839 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1840 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1841 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1842 }
1843#endif
1844 }
1845 } else {
1846 /* Get NVRAM and adapter maximums from SPP 0 and 2
1847 */
1848 mpt_GetScsiPortSettings(ioc, 0);
1849
1850 /* Get version and length of SDP 1
1851 */
1852 mpt_readScsiDevicePageHeaders(ioc, 0);
1853
1854 /* Find IM volumes
1855 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001856 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 mpt_findImVolumes(ioc);
1858
1859 /* Check, and possibly reset, the coalescing value
1860 */
1861 mpt_read_ioc_pg_1(ioc);
1862
1863 mpt_read_ioc_pg_4(ioc);
1864 }
1865
1866 GetIoUnitPage2(ioc);
1867 }
1868
1869 /*
1870 * Call each currently registered protocol IOC reset handler
1871 * with post-reset indication.
1872 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1873 * MptResetHandlers[] registered yet.
1874 */
1875 if (hard_reset_done) {
1876 rc = handlers = 0;
1877 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1878 if ((ret == 0) && MptResetHandlers[ii]) {
1879 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1880 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001881 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 handlers++;
1883 }
1884
1885 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001886 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001888 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 handlers++;
1890 }
1891 }
1892 /* FIXME? Examine results here? */
1893 }
1894
Eric Moore0ccdb002006-07-11 17:33:13 -06001895 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001896 if ((ret != 0) && irq_allocated) {
1897 free_irq(ioc->pci_irq, ioc);
1898 if (mpt_msi_enable)
1899 pci_disable_msi(ioc->pcidev);
1900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 return ret;
1902}
1903
1904/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001905/**
1906 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 * @ioc: Pointer to MPT adapter structure
1908 * @pdev: Pointer to (struct pci_dev) structure
1909 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001910 * Search for PCI bus/dev_function which matches
1911 * PCI bus/dev_function (+/-1) for newly discovered 929,
1912 * 929X, 1030 or 1035.
1913 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1915 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1916 */
1917static void
1918mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1919{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001920 struct pci_dev *peer=NULL;
1921 unsigned int slot = PCI_SLOT(pdev->devfn);
1922 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 MPT_ADAPTER *ioc_srch;
1924
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001925 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1926 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001927 ioc->name, pci_name(pdev), pdev->bus->number,
1928 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001929
1930 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1931 if (!peer) {
1932 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1933 if (!peer)
1934 return;
1935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937 list_for_each_entry(ioc_srch, &ioc_list, list) {
1938 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001939 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 /* Paranoia checks */
1941 if (ioc->alt_ioc != NULL) {
1942 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001943 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 break;
1945 } else if (ioc_srch->alt_ioc != NULL) {
1946 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001947 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
1949 }
1950 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001951 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 ioc_srch->alt_ioc = ioc;
1953 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 }
1955 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001956 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001960/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001962 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 */
1964static void
1965mpt_adapter_disable(MPT_ADAPTER *ioc)
1966{
1967 int sz;
1968 int ret;
1969
1970 if (ioc->cached_fw != NULL) {
1971 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001972 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 printk(KERN_WARNING MYNAM
1974 ": firmware downloadboot failure (%d)!\n", ret);
1975 }
1976 }
1977
1978 /* Disable adapter interrupts! */
1979 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1980 ioc->active = 0;
1981 /* Clear any lingering interrupt */
1982 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1983
1984 if (ioc->alloc != NULL) {
1985 sz = ioc->alloc_sz;
1986 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1987 ioc->name, ioc->alloc, ioc->alloc_sz));
1988 pci_free_consistent(ioc->pcidev, sz,
1989 ioc->alloc, ioc->alloc_dma);
1990 ioc->reply_frames = NULL;
1991 ioc->req_frames = NULL;
1992 ioc->alloc = NULL;
1993 ioc->alloc_total -= sz;
1994 }
1995
1996 if (ioc->sense_buf_pool != NULL) {
1997 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
1998 pci_free_consistent(ioc->pcidev, sz,
1999 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2000 ioc->sense_buf_pool = NULL;
2001 ioc->alloc_total -= sz;
2002 }
2003
2004 if (ioc->events != NULL){
2005 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2006 kfree(ioc->events);
2007 ioc->events = NULL;
2008 ioc->alloc_total -= sz;
2009 }
2010
2011 if (ioc->cached_fw != NULL) {
2012 sz = ioc->facts.FWImageSize;
2013 pci_free_consistent(ioc->pcidev, sz,
2014 ioc->cached_fw, ioc->cached_fw_dma);
2015 ioc->cached_fw = NULL;
2016 ioc->alloc_total -= sz;
2017 }
2018
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002019 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002020 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002021 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002022 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 if (ioc->spi_data.pIocPg4 != NULL) {
2025 sz = ioc->spi_data.IocPg4Sz;
2026 pci_free_consistent(ioc->pcidev, sz,
2027 ioc->spi_data.pIocPg4,
2028 ioc->spi_data.IocPg4_dma);
2029 ioc->spi_data.pIocPg4 = NULL;
2030 ioc->alloc_total -= sz;
2031 }
2032
2033 if (ioc->ReqToChain != NULL) {
2034 kfree(ioc->ReqToChain);
2035 kfree(ioc->RequestNB);
2036 ioc->ReqToChain = NULL;
2037 }
2038
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002039 kfree(ioc->ChainToChain);
2040 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002041
2042 if (ioc->HostPageBuffer != NULL) {
2043 if((ret = mpt_host_page_access_control(ioc,
2044 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2045 printk(KERN_ERR MYNAM
2046 ": %s: host page buffers free failed (%d)!\n",
2047 __FUNCTION__, ret);
2048 }
2049 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2050 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2051 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2052 ioc->HostPageBuffer,
2053 ioc->HostPageBuffer_dma);
2054 ioc->HostPageBuffer = NULL;
2055 ioc->HostPageBuffer_sz = 0;
2056 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058}
2059
2060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002061/**
2062 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 * @ioc: Pointer to MPT adapter structure
2064 *
2065 * This routine unregisters h/w resources and frees all alloc'd memory
2066 * associated with a MPT adapter structure.
2067 */
2068static void
2069mpt_adapter_dispose(MPT_ADAPTER *ioc)
2070{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002071 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002073 if (ioc == NULL)
2074 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002076 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002078 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002080 if (ioc->pci_irq != -1) {
2081 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002082 if (mpt_msi_enable)
2083 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002084 ioc->pci_irq = -1;
2085 }
2086
2087 if (ioc->memmap != NULL) {
2088 iounmap(ioc->memmap);
2089 ioc->memmap = NULL;
2090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
2092#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002093 if (ioc->mtrr_reg > 0) {
2094 mtrr_del(ioc->mtrr_reg, 0, 0);
2095 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097#endif
2098
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002099 /* Zap the adapter lookup ptr! */
2100 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102 sz_last = ioc->alloc_total;
2103 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2104 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002105
2106 if (ioc->alt_ioc)
2107 ioc->alt_ioc->alt_ioc = NULL;
2108
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002109 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110}
2111
2112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002113/**
2114 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 * @ioc: Pointer to MPT adapter structure
2116 */
2117static void
2118MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2119{
2120 int i = 0;
2121
2122 printk(KERN_INFO "%s: ", ioc->name);
2123 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2124 printk("%s: ", ioc->prod_name+3);
2125 printk("Capabilities={");
2126
2127 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2128 printk("Initiator");
2129 i++;
2130 }
2131
2132 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2133 printk("%sTarget", i ? "," : "");
2134 i++;
2135 }
2136
2137 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2138 printk("%sLAN", i ? "," : "");
2139 i++;
2140 }
2141
2142#if 0
2143 /*
2144 * This would probably evoke more questions than it's worth
2145 */
2146 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2147 printk("%sLogBusAddr", i ? "," : "");
2148 i++;
2149 }
2150#endif
2151
2152 printk("}\n");
2153}
2154
2155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002156/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2158 * @ioc: Pointer to MPT_ADAPTER structure
2159 * @force: Force hard KickStart of IOC
2160 * @sleepFlag: Specifies whether the process can sleep
2161 *
2162 * Returns:
2163 * 1 - DIAG reset and READY
2164 * 0 - READY initially OR soft reset and READY
2165 * -1 - Any failure on KickStart
2166 * -2 - Msg Unit Reset Failed
2167 * -3 - IO Unit Reset Failed
2168 * -4 - IOC owned by a PEER
2169 */
2170static int
2171MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2172{
2173 u32 ioc_state;
2174 int statefault = 0;
2175 int cntdn;
2176 int hard_reset_done = 0;
2177 int r;
2178 int ii;
2179 int whoinit;
2180
2181 /* Get current [raw] IOC state */
2182 ioc_state = mpt_GetIocState(ioc, 0);
2183 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2184
2185 /*
2186 * Check to see if IOC got left/stuck in doorbell handshake
2187 * grip of death. If so, hard reset the IOC.
2188 */
2189 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2190 statefault = 1;
2191 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2192 ioc->name);
2193 }
2194
2195 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002196 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 return 0;
2198
2199 /*
2200 * Check to see if IOC is in FAULT state.
2201 */
2202 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2203 statefault = 2;
2204 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2205 ioc->name);
2206 printk(KERN_WARNING " FAULT code = %04xh\n",
2207 ioc_state & MPI_DOORBELL_DATA_MASK);
2208 }
2209
2210 /*
2211 * Hmmm... Did it get left operational?
2212 */
2213 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002214 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 ioc->name));
2216
2217 /* Check WhoInit.
2218 * If PCI Peer, exit.
2219 * Else, if no fault conditions are present, issue a MessageUnitReset
2220 * Else, fall through to KickStart case
2221 */
2222 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002223 dinitprintk((KERN_INFO MYNAM
2224 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 whoinit, statefault, force));
2226 if (whoinit == MPI_WHOINIT_PCI_PEER)
2227 return -4;
2228 else {
2229 if ((statefault == 0 ) && (force == 0)) {
2230 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2231 return 0;
2232 }
2233 statefault = 3;
2234 }
2235 }
2236
2237 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2238 if (hard_reset_done < 0)
2239 return -1;
2240
2241 /*
2242 * Loop here waiting for IOC to come READY.
2243 */
2244 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002245 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2248 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2249 /*
2250 * BIOS or previous driver load left IOC in OP state.
2251 * Reset messaging FIFOs.
2252 */
2253 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2254 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2255 return -2;
2256 }
2257 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2258 /*
2259 * Something is wrong. Try to get IOC back
2260 * to a known state.
2261 */
2262 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2263 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2264 return -3;
2265 }
2266 }
2267
2268 ii++; cntdn--;
2269 if (!cntdn) {
2270 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2271 ioc->name, (int)((ii+5)/HZ));
2272 return -ETIME;
2273 }
2274
2275 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002276 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 } else {
2278 mdelay (1); /* 1 msec delay */
2279 }
2280
2281 }
2282
2283 if (statefault < 3) {
2284 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2285 ioc->name,
2286 statefault==1 ? "stuck handshake" : "IOC FAULT");
2287 }
2288
2289 return hard_reset_done;
2290}
2291
2292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002293/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 * mpt_GetIocState - Get the current state of a MPT adapter.
2295 * @ioc: Pointer to MPT_ADAPTER structure
2296 * @cooked: Request raw or cooked IOC state
2297 *
2298 * Returns all IOC Doorbell register bits if cooked==0, else just the
2299 * Doorbell bits in MPI_IOC_STATE_MASK.
2300 */
2301u32
2302mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2303{
2304 u32 s, sc;
2305
2306 /* Get! */
2307 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2308// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2309 sc = s & MPI_IOC_STATE_MASK;
2310
2311 /* Save! */
2312 ioc->last_state = sc;
2313
2314 return cooked ? sc : s;
2315}
2316
2317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002318/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 * GetIocFacts - Send IOCFacts request to MPT adapter.
2320 * @ioc: Pointer to MPT_ADAPTER structure
2321 * @sleepFlag: Specifies whether the process can sleep
2322 * @reason: If recovery, only update facts.
2323 *
2324 * Returns 0 for success, non-zero for failure.
2325 */
2326static int
2327GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2328{
2329 IOCFacts_t get_facts;
2330 IOCFactsReply_t *facts;
2331 int r;
2332 int req_sz;
2333 int reply_sz;
2334 int sz;
2335 u32 status, vv;
2336 u8 shiftFactor=1;
2337
2338 /* IOC *must* NOT be in RESET state! */
2339 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2340 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2341 ioc->name,
2342 ioc->last_state );
2343 return -44;
2344 }
2345
2346 facts = &ioc->facts;
2347
2348 /* Destination (reply area)... */
2349 reply_sz = sizeof(*facts);
2350 memset(facts, 0, reply_sz);
2351
2352 /* Request area (get_facts on the stack right now!) */
2353 req_sz = sizeof(get_facts);
2354 memset(&get_facts, 0, req_sz);
2355
2356 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2357 /* Assert: All other get_facts fields are zero! */
2358
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002359 dinitprintk((MYIOC_s_INFO_FMT
2360 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 ioc->name, req_sz, reply_sz));
2362
2363 /* No non-zero fields in the get_facts request are greater than
2364 * 1 byte in size, so we can just fire it off as is.
2365 */
2366 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2367 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2368 if (r != 0)
2369 return r;
2370
2371 /*
2372 * Now byte swap (GRRR) the necessary fields before any further
2373 * inspection of reply contents.
2374 *
2375 * But need to do some sanity checks on MsgLength (byte) field
2376 * to make sure we don't zero IOC's req_sz!
2377 */
2378 /* Did we get a valid reply? */
2379 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2380 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2381 /*
2382 * If not been here, done that, save off first WhoInit value
2383 */
2384 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2385 ioc->FirstWhoInit = facts->WhoInit;
2386 }
2387
2388 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2389 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2390 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2391 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2392 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002393 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 /* CHECKME! IOCStatus, IOCLogInfo */
2395
2396 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2397 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2398
2399 /*
2400 * FC f/w version changed between 1.1 and 1.2
2401 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2402 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2403 */
2404 if (facts->MsgVersion < 0x0102) {
2405 /*
2406 * Handle old FC f/w style, convert to new...
2407 */
2408 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2409 facts->FWVersion.Word =
2410 ((oldv<<12) & 0xFF000000) |
2411 ((oldv<<8) & 0x000FFF00);
2412 } else
2413 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2414
2415 facts->ProductID = le16_to_cpu(facts->ProductID);
2416 facts->CurrentHostMfaHighAddr =
2417 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2418 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2419 facts->CurrentSenseBufferHighAddr =
2420 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2421 facts->CurReplyFrameSize =
2422 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002423 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 /*
2426 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2427 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2428 * to 14 in MPI-1.01.0x.
2429 */
2430 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2431 facts->MsgVersion > 0x0100) {
2432 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2433 }
2434
2435 sz = facts->FWImageSize;
2436 if ( sz & 0x01 )
2437 sz += 1;
2438 if ( sz & 0x02 )
2439 sz += 2;
2440 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if (!facts->RequestFrameSize) {
2443 /* Something is wrong! */
2444 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2445 ioc->name);
2446 return -55;
2447 }
2448
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002449 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 vv = ((63 / (sz * 4)) + 1) & 0x03;
2451 ioc->NB_for_64_byte_frame = vv;
2452 while ( sz )
2453 {
2454 shiftFactor++;
2455 sz = sz >> 1;
2456 }
2457 ioc->NBShiftFactor = shiftFactor;
2458 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2459 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2462 /*
2463 * Set values for this IOC's request & reply frame sizes,
2464 * and request & reply queue depths...
2465 */
2466 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2467 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2468 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2469 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2470
2471 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2472 ioc->name, ioc->reply_sz, ioc->reply_depth));
2473 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2474 ioc->name, ioc->req_sz, ioc->req_depth));
2475
2476 /* Get port facts! */
2477 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2478 return r;
2479 }
2480 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002481 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2483 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2484 RequestFrameSize)/sizeof(u32)));
2485 return -66;
2486 }
2487
2488 return 0;
2489}
2490
2491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002492/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 * GetPortFacts - Send PortFacts request to MPT adapter.
2494 * @ioc: Pointer to MPT_ADAPTER structure
2495 * @portnum: Port number
2496 * @sleepFlag: Specifies whether the process can sleep
2497 *
2498 * Returns 0 for success, non-zero for failure.
2499 */
2500static int
2501GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2502{
2503 PortFacts_t get_pfacts;
2504 PortFactsReply_t *pfacts;
2505 int ii;
2506 int req_sz;
2507 int reply_sz;
2508
2509 /* IOC *must* NOT be in RESET state! */
2510 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2511 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2512 ioc->name,
2513 ioc->last_state );
2514 return -4;
2515 }
2516
2517 pfacts = &ioc->pfacts[portnum];
2518
2519 /* Destination (reply area)... */
2520 reply_sz = sizeof(*pfacts);
2521 memset(pfacts, 0, reply_sz);
2522
2523 /* Request area (get_pfacts on the stack right now!) */
2524 req_sz = sizeof(get_pfacts);
2525 memset(&get_pfacts, 0, req_sz);
2526
2527 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2528 get_pfacts.PortNumber = portnum;
2529 /* Assert: All other get_pfacts fields are zero! */
2530
2531 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2532 ioc->name, portnum));
2533
2534 /* No non-zero fields in the get_pfacts request are greater than
2535 * 1 byte in size, so we can just fire it off as is.
2536 */
2537 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2538 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2539 if (ii != 0)
2540 return ii;
2541
2542 /* Did we get a valid reply? */
2543
2544 /* Now byte swap the necessary fields in the response. */
2545 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2546 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2547 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2548 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2549 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2550 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2551 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2552 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2553 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2554
2555 return 0;
2556}
2557
2558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002559/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 * SendIocInit - Send IOCInit request to MPT adapter.
2561 * @ioc: Pointer to MPT_ADAPTER structure
2562 * @sleepFlag: Specifies whether the process can sleep
2563 *
2564 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2565 *
2566 * Returns 0 for success, non-zero for failure.
2567 */
2568static int
2569SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2570{
2571 IOCInit_t ioc_init;
2572 MPIDefaultReply_t init_reply;
2573 u32 state;
2574 int r;
2575 int count;
2576 int cntdn;
2577
2578 memset(&ioc_init, 0, sizeof(ioc_init));
2579 memset(&init_reply, 0, sizeof(init_reply));
2580
2581 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2582 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2583
2584 /* If we are in a recovery mode and we uploaded the FW image,
2585 * then this pointer is not NULL. Skip the upload a second time.
2586 * Set this flag if cached_fw set for either IOC.
2587 */
2588 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2589 ioc->upload_fw = 1;
2590 else
2591 ioc->upload_fw = 0;
2592 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2593 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2594
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002595 if(ioc->bus_type == SAS)
2596 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2597 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2599 else
2600 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002602 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2603 ioc->name, ioc->facts.MsgVersion));
2604 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2605 // set MsgVersion and HeaderVersion host driver was built with
2606 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2607 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002609 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2610 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2611 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2612 return -99;
2613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2615
2616 if (sizeof(dma_addr_t) == sizeof(u64)) {
2617 /* Save the upper 32-bits of the request
2618 * (reply) and sense buffers.
2619 */
2620 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2621 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2622 } else {
2623 /* Force 32-bit addressing */
2624 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2625 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2626 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002627
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2629 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002630 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2631 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2634 ioc->name, &ioc_init));
2635
2636 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2637 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002638 if (r != 0) {
2639 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002644 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 */
2646
2647 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2648 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002649
2650 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2651 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655 /* YIKES! SUPER IMPORTANT!!!
2656 * Poll IocState until _OPERATIONAL while IOC is doing
2657 * LoopInit and TargetDiscovery!
2658 */
2659 count = 0;
2660 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2661 state = mpt_GetIocState(ioc, 1);
2662 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2663 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002664 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 } else {
2666 mdelay(1);
2667 }
2668
2669 if (!cntdn) {
2670 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2671 ioc->name, (int)((count+5)/HZ));
2672 return -9;
2673 }
2674
2675 state = mpt_GetIocState(ioc, 1);
2676 count++;
2677 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002678 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 ioc->name, count));
2680
Eric Mooreba856d32006-07-11 17:34:01 -06002681 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return r;
2683}
2684
2685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002686/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 * SendPortEnable - Send PortEnable request to MPT adapter port.
2688 * @ioc: Pointer to MPT_ADAPTER structure
2689 * @portnum: Port number to enable
2690 * @sleepFlag: Specifies whether the process can sleep
2691 *
2692 * Send PortEnable to bring IOC to OPERATIONAL state.
2693 *
2694 * Returns 0 for success, non-zero for failure.
2695 */
2696static int
2697SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2698{
2699 PortEnable_t port_enable;
2700 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002701 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 int req_sz;
2703 int reply_sz;
2704
2705 /* Destination... */
2706 reply_sz = sizeof(MPIDefaultReply_t);
2707 memset(&reply_buf, 0, reply_sz);
2708
2709 req_sz = sizeof(PortEnable_t);
2710 memset(&port_enable, 0, req_sz);
2711
2712 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2713 port_enable.PortNumber = portnum;
2714/* port_enable.ChainOffset = 0; */
2715/* port_enable.MsgFlags = 0; */
2716/* port_enable.MsgContext = 0; */
2717
2718 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2719 ioc->name, portnum, &port_enable));
2720
2721 /* RAID FW may take a long time to enable
2722 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002723 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2724 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2725 (ioc->bus_type == SAS)) {
2726 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2727 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2728 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002729 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002730 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2731 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2732 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002734 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735}
2736
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002737/**
2738 * mpt_alloc_fw_memory - allocate firmware memory
2739 * @ioc: Pointer to MPT_ADAPTER structure
2740 * @size: total FW bytes
2741 *
2742 * If memory has already been allocated, the same (cached) value
2743 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 */
2745void
2746mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2747{
2748 if (ioc->cached_fw)
2749 return; /* use already allocated memory */
2750 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2751 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2752 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06002753 ioc->alloc_total += size;
2754 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 } else {
2756 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2757 ioc->alloc_total += size;
2758 }
2759}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002760/**
2761 * mpt_free_fw_memory - free firmware memory
2762 * @ioc: Pointer to MPT_ADAPTER structure
2763 *
2764 * If alt_img is NULL, delete from ioc structure.
2765 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 */
2767void
2768mpt_free_fw_memory(MPT_ADAPTER *ioc)
2769{
2770 int sz;
2771
2772 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002773 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2775 pci_free_consistent(ioc->pcidev, sz,
2776 ioc->cached_fw, ioc->cached_fw_dma);
2777 ioc->cached_fw = NULL;
2778
2779 return;
2780}
2781
2782
2783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002784/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2786 * @ioc: Pointer to MPT_ADAPTER structure
2787 * @sleepFlag: Specifies whether the process can sleep
2788 *
2789 * Returns 0 for success, >0 for handshake failure
2790 * <0 for fw upload failure.
2791 *
2792 * Remark: If bound IOC and a successful FWUpload was performed
2793 * on the bound IOC, the second image is discarded
2794 * and memory is free'd. Both channels must upload to prevent
2795 * IOC from running in degraded mode.
2796 */
2797static int
2798mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2799{
2800 u8 request[ioc->req_sz];
2801 u8 reply[sizeof(FWUploadReply_t)];
2802 FWUpload_t *prequest;
2803 FWUploadReply_t *preply;
2804 FWUploadTCSGE_t *ptcsge;
2805 int sgeoffset;
2806 u32 flagsLength;
2807 int ii, sz, reply_sz;
2808 int cmdStatus;
2809
2810 /* If the image size is 0, we are done.
2811 */
2812 if ((sz = ioc->facts.FWImageSize) == 0)
2813 return 0;
2814
2815 mpt_alloc_fw_memory(ioc, sz);
2816
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002817 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002819
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 if (ioc->cached_fw == NULL) {
2821 /* Major Failure.
2822 */
2823 return -ENOMEM;
2824 }
2825
2826 prequest = (FWUpload_t *)&request;
2827 preply = (FWUploadReply_t *)&reply;
2828
2829 /* Destination... */
2830 memset(prequest, 0, ioc->req_sz);
2831
2832 reply_sz = sizeof(reply);
2833 memset(preply, 0, reply_sz);
2834
2835 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2836 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2837
2838 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2839 ptcsge->DetailsLength = 12;
2840 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2841 ptcsge->ImageSize = cpu_to_le32(sz);
2842
2843 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2844
2845 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2846 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2847
2848 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002849 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 prequest, sgeoffset));
2851 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2852
2853 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2854 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2855
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002856 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
2858 cmdStatus = -EFAULT;
2859 if (ii == 0) {
2860 /* Handshake transfer was complete and successful.
2861 * Check the Reply Frame.
2862 */
2863 int status, transfer_sz;
2864 status = le16_to_cpu(preply->IOCStatus);
2865 if (status == MPI_IOCSTATUS_SUCCESS) {
2866 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2867 if (transfer_sz == sz)
2868 cmdStatus = 0;
2869 }
2870 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002871 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 ioc->name, cmdStatus));
2873
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002874
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (cmdStatus) {
2876
2877 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2878 ioc->name));
2879 mpt_free_fw_memory(ioc);
2880 }
2881
2882 return cmdStatus;
2883}
2884
2885/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002886/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 * mpt_downloadboot - DownloadBoot code
2888 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002889 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 * @sleepFlag: Specifies whether the process can sleep
2891 *
2892 * FwDownloadBoot requires Programmed IO access.
2893 *
2894 * Returns 0 for success
2895 * -1 FW Image size is 0
2896 * -2 No valid cached_fw Pointer
2897 * <0 for fw upload failure.
2898 */
2899static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002900mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 MpiExtImageHeader_t *pExtImage;
2903 u32 fwSize;
2904 u32 diag0val;
2905 int count;
2906 u32 *ptrFw;
2907 u32 diagRwData;
2908 u32 nextImage;
2909 u32 load_addr;
2910 u32 ioc_state=0;
2911
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002912 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2913 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002914
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2916 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2917 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2918 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2919 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2920 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2921
2922 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2923
2924 /* wait 1 msec */
2925 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002926 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 } else {
2928 mdelay (1);
2929 }
2930
2931 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2932 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2933
2934 for (count = 0; count < 30; count ++) {
2935 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2936 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2937 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2938 ioc->name, count));
2939 break;
2940 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002941 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002943 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002945 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 }
2947 }
2948
2949 if ( count == 30 ) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002950 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2951 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 ioc->name, diag0val));
2953 return -3;
2954 }
2955
2956 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2957 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2958 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2959 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2960 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2961 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2962
2963 /* Set the DiagRwEn and Disable ARM bits */
2964 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2965
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 fwSize = (pFwHeader->ImageSize + 3)/4;
2967 ptrFw = (u32 *) pFwHeader;
2968
2969 /* Write the LoadStartAddress to the DiagRw Address Register
2970 * using Programmed IO
2971 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002972 if (ioc->errata_flag_1064)
2973 pci_enable_io_access(ioc->pcidev);
2974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2976 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2977 ioc->name, pFwHeader->LoadStartAddress));
2978
2979 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2980 ioc->name, fwSize*4, ptrFw));
2981 while (fwSize--) {
2982 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2983 }
2984
2985 nextImage = pFwHeader->NextImageHeaderOffset;
2986 while (nextImage) {
2987 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2988
2989 load_addr = pExtImage->LoadStartAddress;
2990
2991 fwSize = (pExtImage->ImageSize + 3) >> 2;
2992 ptrFw = (u32 *)pExtImage;
2993
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002994 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2995 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2997
2998 while (fwSize--) {
2999 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3000 }
3001 nextImage = pExtImage->NextImageHeaderOffset;
3002 }
3003
3004 /* Write the IopResetVectorRegAddr */
3005 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3006 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3007
3008 /* Write the IopResetVectorValue */
3009 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3010 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3011
3012 /* Clear the internal flash bad bit - autoincrementing register,
3013 * so must do two writes.
3014 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003015 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003016 /*
3017 * 1030 and 1035 H/W errata, workaround to access
3018 * the ClearFlashBadSignatureBit
3019 */
3020 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3021 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3022 diagRwData |= 0x40000000;
3023 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3024 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3025
3026 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3027 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3028 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3029 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3030
3031 /* wait 1 msec */
3032 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003033 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003034 } else {
3035 mdelay (1);
3036 }
3037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003039 if (ioc->errata_flag_1064)
3040 pci_disable_io_access(ioc->pcidev);
3041
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003043 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3044 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003046 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3048 ioc->name, diag0val));
3049 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3050
3051 /* Write 0xFF to reset the sequencer */
3052 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3053
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003054 if (ioc->bus_type == SAS) {
3055 ioc_state = mpt_GetIocState(ioc, 0);
3056 if ( (GetIocFacts(ioc, sleepFlag,
3057 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3058 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3059 ioc->name, ioc_state));
3060 return -EFAULT;
3061 }
3062 }
3063
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 for (count=0; count<HZ*20; count++) {
3065 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3066 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3067 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003068 if (ioc->bus_type == SAS) {
3069 return 0;
3070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3072 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3073 ioc->name));
3074 return -EFAULT;
3075 }
3076 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3077 ioc->name));
3078 return 0;
3079 }
3080 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003081 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 } else {
3083 mdelay (10);
3084 }
3085 }
3086 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3087 ioc->name, ioc_state));
3088 return -EFAULT;
3089}
3090
3091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003092/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 * KickStart - Perform hard reset of MPT adapter.
3094 * @ioc: Pointer to MPT_ADAPTER structure
3095 * @force: Force hard reset
3096 * @sleepFlag: Specifies whether the process can sleep
3097 *
3098 * This routine places MPT adapter in diagnostic mode via the
3099 * WriteSequence register, and then performs a hard reset of adapter
3100 * via the Diagnostic register.
3101 *
3102 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3103 * or NO_SLEEP (interrupt thread, use mdelay)
3104 * force - 1 if doorbell active, board fault state
3105 * board operational, IOC_RECOVERY or
3106 * IOC_BRINGUP and there is an alt_ioc.
3107 * 0 else
3108 *
3109 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003110 * 1 - hard reset, READY
3111 * 0 - no reset due to History bit, READY
3112 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 * OR reset but failed to come READY
3114 * -2 - no reset, could not enter DIAG mode
3115 * -3 - reset but bad FW bit
3116 */
3117static int
3118KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3119{
3120 int hard_reset_done = 0;
3121 u32 ioc_state=0;
3122 int cnt,cntdn;
3123
3124 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003125 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 /* Always issue a Msg Unit Reset first. This will clear some
3127 * SCSI bus hang conditions.
3128 */
3129 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3130
3131 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003132 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 } else {
3134 mdelay (1000);
3135 }
3136 }
3137
3138 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3139 if (hard_reset_done < 0)
3140 return hard_reset_done;
3141
3142 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3143 ioc->name));
3144
3145 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3146 for (cnt=0; cnt<cntdn; cnt++) {
3147 ioc_state = mpt_GetIocState(ioc, 1);
3148 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3149 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3150 ioc->name, cnt));
3151 return hard_reset_done;
3152 }
3153 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003154 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 } else {
3156 mdelay (10);
3157 }
3158 }
3159
3160 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3161 ioc->name, ioc_state);
3162 return -1;
3163}
3164
3165/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003166/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 * mpt_diag_reset - Perform hard reset of the adapter.
3168 * @ioc: Pointer to MPT_ADAPTER structure
3169 * @ignore: Set if to honor and clear to ignore
3170 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003171 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 * else set to NO_SLEEP (use mdelay instead)
3173 *
3174 * This routine places the adapter in diagnostic mode via the
3175 * WriteSequence register and then performs a hard reset of adapter
3176 * via the Diagnostic register. Adapter should be in ready state
3177 * upon successful completion.
3178 *
3179 * Returns: 1 hard reset successful
3180 * 0 no reset performed because reset history bit set
3181 * -2 enabling diagnostic mode failed
3182 * -3 diagnostic reset failed
3183 */
3184static int
3185mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3186{
Eric Moore0ccdb002006-07-11 17:33:13 -06003187 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 u32 diag0val;
3189 u32 doorbell;
3190 int hard_reset_done = 0;
3191 int count = 0;
3192#ifdef MPT_DEBUG
3193 u32 diag1val = 0;
3194#endif
3195
Eric Moore87cf8982006-06-27 16:09:26 -06003196 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
3197 drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
3198 "address=%p\n", ioc->name, __FUNCTION__,
3199 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3200 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3201 if (sleepFlag == CAN_SLEEP)
3202 msleep(1);
3203 else
3204 mdelay(1);
3205
3206 for (count = 0; count < 60; count ++) {
3207 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3208 doorbell &= MPI_IOC_STATE_MASK;
3209
3210 drsprintk((MYIOC_s_INFO_FMT
3211 "looking for READY STATE: doorbell=%x"
3212 " count=%d\n",
3213 ioc->name, doorbell, count));
3214 if (doorbell == MPI_IOC_STATE_READY) {
3215 return 0;
3216 }
3217
3218 /* wait 1 sec */
3219 if (sleepFlag == CAN_SLEEP)
3220 msleep(1000);
3221 else
3222 mdelay(1000);
3223 }
3224 return -1;
3225 }
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 /* Clear any existing interrupts */
3228 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3229
3230 /* Use "Diagnostic reset" method! (only thing available!) */
3231 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3232
3233#ifdef MPT_DEBUG
3234 if (ioc->alt_ioc)
3235 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3236 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3237 ioc->name, diag0val, diag1val));
3238#endif
3239
3240 /* Do the reset if we are told to ignore the reset history
3241 * or if the reset history is 0
3242 */
3243 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3244 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3245 /* Write magic sequence to WriteSequence register
3246 * Loop until in diagnostic mode
3247 */
3248 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3249 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3250 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3251 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3252 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3253 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3254
3255 /* wait 100 msec */
3256 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003257 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 } else {
3259 mdelay (100);
3260 }
3261
3262 count++;
3263 if (count > 20) {
3264 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3265 ioc->name, diag0val);
3266 return -2;
3267
3268 }
3269
3270 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3271
3272 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3273 ioc->name, diag0val));
3274 }
3275
3276#ifdef MPT_DEBUG
3277 if (ioc->alt_ioc)
3278 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3279 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3280 ioc->name, diag0val, diag1val));
3281#endif
3282 /*
3283 * Disable the ARM (Bug fix)
3284 *
3285 */
3286 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003287 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
3289 /*
3290 * Now hit the reset bit in the Diagnostic register
3291 * (THE BIG HAMMER!) (Clears DRWE bit).
3292 */
3293 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3294 hard_reset_done = 1;
3295 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3296 ioc->name));
3297
3298 /*
3299 * Call each currently registered protocol IOC reset handler
3300 * with pre-reset indication.
3301 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3302 * MptResetHandlers[] registered yet.
3303 */
3304 {
3305 int ii;
3306 int r = 0;
3307
3308 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3309 if (MptResetHandlers[ii]) {
3310 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3311 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003312 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 if (ioc->alt_ioc) {
3314 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3315 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003316 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 }
3318 }
3319 }
3320 /* FIXME? Examine results here? */
3321 }
3322
Eric Moore0ccdb002006-07-11 17:33:13 -06003323 if (ioc->cached_fw)
3324 iocp = ioc;
3325 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3326 iocp = ioc->alt_ioc;
3327 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 /* If the DownloadBoot operation fails, the
3329 * IOC will be left unusable. This is a fatal error
3330 * case. _diag_reset will return < 0
3331 */
3332 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003333 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3335 break;
3336 }
3337
Eric Moore0ccdb002006-07-11 17:33:13 -06003338 dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
3339 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 /* wait 1 sec */
3341 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003342 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 } else {
3344 mdelay (1000);
3345 }
3346 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003347 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003348 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 printk(KERN_WARNING MYNAM
3350 ": firmware downloadboot failure (%d)!\n", count);
3351 }
3352
3353 } else {
3354 /* Wait for FW to reload and for board
3355 * to go to the READY state.
3356 * Maximum wait is 60 seconds.
3357 * If fail, no error will check again
3358 * with calling program.
3359 */
3360 for (count = 0; count < 60; count ++) {
3361 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3362 doorbell &= MPI_IOC_STATE_MASK;
3363
3364 if (doorbell == MPI_IOC_STATE_READY) {
3365 break;
3366 }
3367
3368 /* wait 1 sec */
3369 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003370 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 } else {
3372 mdelay (1000);
3373 }
3374 }
3375 }
3376 }
3377
3378 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3379#ifdef MPT_DEBUG
3380 if (ioc->alt_ioc)
3381 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3382 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3383 ioc->name, diag0val, diag1val));
3384#endif
3385
3386 /* Clear RESET_HISTORY bit! Place board in the
3387 * diagnostic mode to update the diag register.
3388 */
3389 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3390 count = 0;
3391 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3392 /* Write magic sequence to WriteSequence register
3393 * Loop until in diagnostic mode
3394 */
3395 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3396 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3397 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3398 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3399 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3400 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3401
3402 /* wait 100 msec */
3403 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003404 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 } else {
3406 mdelay (100);
3407 }
3408
3409 count++;
3410 if (count > 20) {
3411 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3412 ioc->name, diag0val);
3413 break;
3414 }
3415 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3416 }
3417 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3418 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3419 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3420 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3421 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3422 ioc->name);
3423 }
3424
3425 /* Disable Diagnostic Mode
3426 */
3427 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3428
3429 /* Check FW reload status flags.
3430 */
3431 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3432 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3433 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3434 ioc->name, diag0val);
3435 return -3;
3436 }
3437
3438#ifdef MPT_DEBUG
3439 if (ioc->alt_ioc)
3440 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3441 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3442 ioc->name, diag0val, diag1val));
3443#endif
3444
3445 /*
3446 * Reset flag that says we've enabled event notification
3447 */
3448 ioc->facts.EventState = 0;
3449
3450 if (ioc->alt_ioc)
3451 ioc->alt_ioc->facts.EventState = 0;
3452
3453 return hard_reset_done;
3454}
3455
3456/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003457/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 * SendIocReset - Send IOCReset request to MPT adapter.
3459 * @ioc: Pointer to MPT_ADAPTER structure
3460 * @reset_type: reset type, expected values are
3461 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003462 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 *
3464 * Send IOCReset request to the MPT adapter.
3465 *
3466 * Returns 0 for success, non-zero for failure.
3467 */
3468static int
3469SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3470{
3471 int r;
3472 u32 state;
3473 int cntdn, count;
3474
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003475 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 ioc->name, reset_type));
3477 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3478 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3479 return r;
3480
3481 /* FW ACK'd request, wait for READY state
3482 */
3483 count = 0;
3484 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3485
3486 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3487 cntdn--;
3488 count++;
3489 if (!cntdn) {
3490 if (sleepFlag != CAN_SLEEP)
3491 count *= 10;
3492
3493 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3494 ioc->name, (int)((count+5)/HZ));
3495 return -ETIME;
3496 }
3497
3498 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003499 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 } else {
3501 mdelay (1); /* 1 msec delay */
3502 }
3503 }
3504
3505 /* TODO!
3506 * Cleanup all event stuff for this IOC; re-issue EventNotification
3507 * request if needed.
3508 */
3509 if (ioc->facts.Function)
3510 ioc->facts.EventState = 0;
3511
3512 return 0;
3513}
3514
3515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003516/**
3517 * initChainBuffers - Allocate memory for and initialize chain buffers
3518 * @ioc: Pointer to MPT_ADAPTER structure
3519 *
3520 * Allocates memory for and initializes chain buffers,
3521 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 */
3523static int
3524initChainBuffers(MPT_ADAPTER *ioc)
3525{
3526 u8 *mem;
3527 int sz, ii, num_chain;
3528 int scale, num_sge, numSGE;
3529
3530 /* ReqToChain size must equal the req_depth
3531 * index = req_idx
3532 */
3533 if (ioc->ReqToChain == NULL) {
3534 sz = ioc->req_depth * sizeof(int);
3535 mem = kmalloc(sz, GFP_ATOMIC);
3536 if (mem == NULL)
3537 return -1;
3538
3539 ioc->ReqToChain = (int *) mem;
3540 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3541 ioc->name, mem, sz));
3542 mem = kmalloc(sz, GFP_ATOMIC);
3543 if (mem == NULL)
3544 return -1;
3545
3546 ioc->RequestNB = (int *) mem;
3547 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3548 ioc->name, mem, sz));
3549 }
3550 for (ii = 0; ii < ioc->req_depth; ii++) {
3551 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3552 }
3553
3554 /* ChainToChain size must equal the total number
3555 * of chain buffers to be allocated.
3556 * index = chain_idx
3557 *
3558 * Calculate the number of chain buffers needed(plus 1) per I/O
3559 * then multiply the the maximum number of simultaneous cmds
3560 *
3561 * num_sge = num sge in request frame + last chain buffer
3562 * scale = num sge per chain buffer if no chain element
3563 */
3564 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3565 if (sizeof(dma_addr_t) == sizeof(u64))
3566 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3567 else
3568 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3569
3570 if (sizeof(dma_addr_t) == sizeof(u64)) {
3571 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3572 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3573 } else {
3574 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3575 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3576 }
3577 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3578 ioc->name, num_sge, numSGE));
3579
3580 if ( numSGE > MPT_SCSI_SG_DEPTH )
3581 numSGE = MPT_SCSI_SG_DEPTH;
3582
3583 num_chain = 1;
3584 while (numSGE - num_sge > 0) {
3585 num_chain++;
3586 num_sge += (scale - 1);
3587 }
3588 num_chain++;
3589
3590 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3591 ioc->name, numSGE, num_sge, num_chain));
3592
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003593 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 num_chain *= MPT_SCSI_CAN_QUEUE;
3595 else
3596 num_chain *= MPT_FC_CAN_QUEUE;
3597
3598 ioc->num_chain = num_chain;
3599
3600 sz = num_chain * sizeof(int);
3601 if (ioc->ChainToChain == NULL) {
3602 mem = kmalloc(sz, GFP_ATOMIC);
3603 if (mem == NULL)
3604 return -1;
3605
3606 ioc->ChainToChain = (int *) mem;
3607 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3608 ioc->name, mem, sz));
3609 } else {
3610 mem = (u8 *) ioc->ChainToChain;
3611 }
3612 memset(mem, 0xFF, sz);
3613 return num_chain;
3614}
3615
3616/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003617/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3619 * @ioc: Pointer to MPT_ADAPTER structure
3620 *
3621 * This routine allocates memory for the MPT reply and request frame
3622 * pools (if necessary), and primes the IOC reply FIFO with
3623 * reply frames.
3624 *
3625 * Returns 0 for success, non-zero for failure.
3626 */
3627static int
3628PrimeIocFifos(MPT_ADAPTER *ioc)
3629{
3630 MPT_FRAME_HDR *mf;
3631 unsigned long flags;
3632 dma_addr_t alloc_dma;
3633 u8 *mem;
3634 int i, reply_sz, sz, total_size, num_chain;
3635
3636 /* Prime reply FIFO... */
3637
3638 if (ioc->reply_frames == NULL) {
3639 if ( (num_chain = initChainBuffers(ioc)) < 0)
3640 return -1;
3641
3642 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3643 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3644 ioc->name, ioc->reply_sz, ioc->reply_depth));
3645 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3646 ioc->name, reply_sz, reply_sz));
3647
3648 sz = (ioc->req_sz * ioc->req_depth);
3649 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3650 ioc->name, ioc->req_sz, ioc->req_depth));
3651 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3652 ioc->name, sz, sz));
3653 total_size += sz;
3654
3655 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3656 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3657 ioc->name, ioc->req_sz, num_chain));
3658 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3659 ioc->name, sz, sz, num_chain));
3660
3661 total_size += sz;
3662 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3663 if (mem == NULL) {
3664 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3665 ioc->name);
3666 goto out_fail;
3667 }
3668
3669 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3670 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3671
3672 memset(mem, 0, total_size);
3673 ioc->alloc_total += total_size;
3674 ioc->alloc = mem;
3675 ioc->alloc_dma = alloc_dma;
3676 ioc->alloc_sz = total_size;
3677 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3678 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3679
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003680 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3681 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3682
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 alloc_dma += reply_sz;
3684 mem += reply_sz;
3685
3686 /* Request FIFO - WE manage this! */
3687
3688 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3689 ioc->req_frames_dma = alloc_dma;
3690
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003691 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ioc->name, mem, (void *)(ulong)alloc_dma));
3693
3694 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3695
3696#if defined(CONFIG_MTRR) && 0
3697 /*
3698 * Enable Write Combining MTRR for IOC's memory region.
3699 * (at least as much as we can; "size and base must be
3700 * multiples of 4 kiB"
3701 */
3702 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3703 sz,
3704 MTRR_TYPE_WRCOMB, 1);
3705 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3706 ioc->name, ioc->req_frames_dma, sz));
3707#endif
3708
3709 for (i = 0; i < ioc->req_depth; i++) {
3710 alloc_dma += ioc->req_sz;
3711 mem += ioc->req_sz;
3712 }
3713
3714 ioc->ChainBuffer = mem;
3715 ioc->ChainBufferDMA = alloc_dma;
3716
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003717 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3719
3720 /* Initialize the free chain Q.
3721 */
3722
3723 INIT_LIST_HEAD(&ioc->FreeChainQ);
3724
3725 /* Post the chain buffers to the FreeChainQ.
3726 */
3727 mem = (u8 *)ioc->ChainBuffer;
3728 for (i=0; i < num_chain; i++) {
3729 mf = (MPT_FRAME_HDR *) mem;
3730 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3731 mem += ioc->req_sz;
3732 }
3733
3734 /* Initialize Request frames linked list
3735 */
3736 alloc_dma = ioc->req_frames_dma;
3737 mem = (u8 *) ioc->req_frames;
3738
3739 spin_lock_irqsave(&ioc->FreeQlock, flags);
3740 INIT_LIST_HEAD(&ioc->FreeQ);
3741 for (i = 0; i < ioc->req_depth; i++) {
3742 mf = (MPT_FRAME_HDR *) mem;
3743
3744 /* Queue REQUESTs *internally*! */
3745 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3746
3747 mem += ioc->req_sz;
3748 }
3749 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3750
3751 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3752 ioc->sense_buf_pool =
3753 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3754 if (ioc->sense_buf_pool == NULL) {
3755 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3756 ioc->name);
3757 goto out_fail;
3758 }
3759
3760 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3761 ioc->alloc_total += sz;
3762 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3763 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3764
3765 }
3766
3767 /* Post Reply frames to FIFO
3768 */
3769 alloc_dma = ioc->alloc_dma;
3770 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3771 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3772
3773 for (i = 0; i < ioc->reply_depth; i++) {
3774 /* Write each address to the IOC! */
3775 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3776 alloc_dma += ioc->reply_sz;
3777 }
3778
3779 return 0;
3780
3781out_fail:
3782 if (ioc->alloc != NULL) {
3783 sz = ioc->alloc_sz;
3784 pci_free_consistent(ioc->pcidev,
3785 sz,
3786 ioc->alloc, ioc->alloc_dma);
3787 ioc->reply_frames = NULL;
3788 ioc->req_frames = NULL;
3789 ioc->alloc_total -= sz;
3790 }
3791 if (ioc->sense_buf_pool != NULL) {
3792 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3793 pci_free_consistent(ioc->pcidev,
3794 sz,
3795 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3796 ioc->sense_buf_pool = NULL;
3797 }
3798 return -1;
3799}
3800
3801/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3802/**
3803 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3804 * from IOC via doorbell handshake method.
3805 * @ioc: Pointer to MPT_ADAPTER structure
3806 * @reqBytes: Size of the request in bytes
3807 * @req: Pointer to MPT request frame
3808 * @replyBytes: Expected size of the reply in bytes
3809 * @u16reply: Pointer to area where reply should be written
3810 * @maxwait: Max wait time for a reply (in seconds)
3811 * @sleepFlag: Specifies whether the process can sleep
3812 *
3813 * NOTES: It is the callers responsibility to byte-swap fields in the
3814 * request which are greater than 1 byte in size. It is also the
3815 * callers responsibility to byte-swap response fields which are
3816 * greater than 1 byte in size.
3817 *
3818 * Returns 0 for success, non-zero for failure.
3819 */
3820static int
3821mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003822 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823{
3824 MPIDefaultReply_t *mptReply;
3825 int failcnt = 0;
3826 int t;
3827
3828 /*
3829 * Get ready to cache a handshake reply
3830 */
3831 ioc->hs_reply_idx = 0;
3832 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3833 mptReply->MsgLength = 0;
3834
3835 /*
3836 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3837 * then tell IOC that we want to handshake a request of N words.
3838 * (WRITE u32val to Doorbell reg).
3839 */
3840 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3841 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3842 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3843 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3844
3845 /*
3846 * Wait for IOC's doorbell handshake int
3847 */
3848 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3849 failcnt++;
3850
3851 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3852 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3853
3854 /* Read doorbell and check for active bit */
3855 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3856 return -1;
3857
3858 /*
3859 * Clear doorbell int (WRITE 0 to IntStatus reg),
3860 * then wait for IOC to ACKnowledge that it's ready for
3861 * our handshake request.
3862 */
3863 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3864 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3865 failcnt++;
3866
3867 if (!failcnt) {
3868 int ii;
3869 u8 *req_as_bytes = (u8 *) req;
3870
3871 /*
3872 * Stuff request words via doorbell handshake,
3873 * with ACK from IOC for each.
3874 */
3875 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3876 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3877 (req_as_bytes[(ii*4) + 1] << 8) |
3878 (req_as_bytes[(ii*4) + 2] << 16) |
3879 (req_as_bytes[(ii*4) + 3] << 24));
3880
3881 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3882 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3883 failcnt++;
3884 }
3885
3886 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3887 DBG_DUMP_REQUEST_FRAME_HDR(req)
3888
3889 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3890 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3891
3892 /*
3893 * Wait for completion of doorbell handshake reply from the IOC
3894 */
3895 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3896 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003897
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3899 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3900
3901 /*
3902 * Copy out the cached reply...
3903 */
3904 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3905 u16reply[ii] = ioc->hs_reply[ii];
3906 } else {
3907 return -99;
3908 }
3909
3910 return -failcnt;
3911}
3912
3913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003914/**
3915 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 * @ioc: Pointer to MPT_ADAPTER structure
3917 * @howlong: How long to wait (in seconds)
3918 * @sleepFlag: Specifies whether the process can sleep
3919 *
3920 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003921 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
3922 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 *
3924 * Returns a negative value on failure, else wait loop count.
3925 */
3926static int
3927WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3928{
3929 int cntdn;
3930 int count = 0;
3931 u32 intstat=0;
3932
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003933 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
3935 if (sleepFlag == CAN_SLEEP) {
3936 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003937 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3939 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3940 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 count++;
3942 }
3943 } else {
3944 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003945 mdelay (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3947 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3948 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 count++;
3950 }
3951 }
3952
3953 if (cntdn) {
3954 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3955 ioc->name, count));
3956 return count;
3957 }
3958
3959 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3960 ioc->name, count, intstat);
3961 return -1;
3962}
3963
3964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003965/**
3966 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 * @ioc: Pointer to MPT_ADAPTER structure
3968 * @howlong: How long to wait (in seconds)
3969 * @sleepFlag: Specifies whether the process can sleep
3970 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003971 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
3972 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 *
3974 * Returns a negative value on failure, else wait loop count.
3975 */
3976static int
3977WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3978{
3979 int cntdn;
3980 int count = 0;
3981 u32 intstat=0;
3982
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003983 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 if (sleepFlag == CAN_SLEEP) {
3985 while (--cntdn) {
3986 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3987 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3988 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05003989 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 count++;
3991 }
3992 } else {
3993 while (--cntdn) {
3994 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3995 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3996 break;
3997 mdelay(1);
3998 count++;
3999 }
4000 }
4001
4002 if (cntdn) {
4003 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4004 ioc->name, count, howlong));
4005 return count;
4006 }
4007
4008 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4009 ioc->name, count, intstat);
4010 return -1;
4011}
4012
4013/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004014/**
4015 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 * @ioc: Pointer to MPT_ADAPTER structure
4017 * @howlong: How long to wait (in seconds)
4018 * @sleepFlag: Specifies whether the process can sleep
4019 *
4020 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4021 * Reply is cached to IOC private area large enough to hold a maximum
4022 * of 128 bytes of reply data.
4023 *
4024 * Returns a negative value on failure, else size of reply in WORDS.
4025 */
4026static int
4027WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4028{
4029 int u16cnt = 0;
4030 int failcnt = 0;
4031 int t;
4032 u16 *hs_reply = ioc->hs_reply;
4033 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4034 u16 hword;
4035
4036 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4037
4038 /*
4039 * Get first two u16's so we can look at IOC's intended reply MsgLength
4040 */
4041 u16cnt=0;
4042 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4043 failcnt++;
4044 } else {
4045 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4046 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4047 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4048 failcnt++;
4049 else {
4050 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4051 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4052 }
4053 }
4054
4055 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004056 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4058
4059 /*
4060 * If no error (and IOC said MsgLength is > 0), piece together
4061 * reply 16 bits at a time.
4062 */
4063 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4064 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4065 failcnt++;
4066 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4067 /* don't overflow our IOC hs_reply[] buffer! */
4068 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4069 hs_reply[u16cnt] = hword;
4070 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4071 }
4072
4073 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4074 failcnt++;
4075 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4076
4077 if (failcnt) {
4078 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4079 ioc->name);
4080 return -failcnt;
4081 }
4082#if 0
4083 else if (u16cnt != (2 * mptReply->MsgLength)) {
4084 return -101;
4085 }
4086 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4087 return -102;
4088 }
4089#endif
4090
4091 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4092 DBG_DUMP_REPLY_FRAME(mptReply)
4093
4094 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4095 ioc->name, t, u16cnt/2));
4096 return u16cnt/2;
4097}
4098
4099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004100/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 * GetLanConfigPages - Fetch LANConfig pages.
4102 * @ioc: Pointer to MPT_ADAPTER structure
4103 *
4104 * Return: 0 for success
4105 * -ENOMEM if no memory available
4106 * -EPERM if not allowed due to ISR context
4107 * -EAGAIN if no msg frames currently available
4108 * -EFAULT for non-successful reply or no reply (timeout)
4109 */
4110static int
4111GetLanConfigPages(MPT_ADAPTER *ioc)
4112{
4113 ConfigPageHeader_t hdr;
4114 CONFIGPARMS cfg;
4115 LANPage0_t *ppage0_alloc;
4116 dma_addr_t page0_dma;
4117 LANPage1_t *ppage1_alloc;
4118 dma_addr_t page1_dma;
4119 int rc = 0;
4120 int data_sz;
4121 int copy_sz;
4122
4123 /* Get LAN Page 0 header */
4124 hdr.PageVersion = 0;
4125 hdr.PageLength = 0;
4126 hdr.PageNumber = 0;
4127 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004128 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 cfg.physAddr = -1;
4130 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4131 cfg.dir = 0;
4132 cfg.pageAddr = 0;
4133 cfg.timeout = 0;
4134
4135 if ((rc = mpt_config(ioc, &cfg)) != 0)
4136 return rc;
4137
4138 if (hdr.PageLength > 0) {
4139 data_sz = hdr.PageLength * 4;
4140 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4141 rc = -ENOMEM;
4142 if (ppage0_alloc) {
4143 memset((u8 *)ppage0_alloc, 0, data_sz);
4144 cfg.physAddr = page0_dma;
4145 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4146
4147 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4148 /* save the data */
4149 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4150 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4151
4152 }
4153
4154 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4155
4156 /* FIXME!
4157 * Normalize endianness of structure data,
4158 * by byte-swapping all > 1 byte fields!
4159 */
4160
4161 }
4162
4163 if (rc)
4164 return rc;
4165 }
4166
4167 /* Get LAN Page 1 header */
4168 hdr.PageVersion = 0;
4169 hdr.PageLength = 0;
4170 hdr.PageNumber = 1;
4171 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004172 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 cfg.physAddr = -1;
4174 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4175 cfg.dir = 0;
4176 cfg.pageAddr = 0;
4177
4178 if ((rc = mpt_config(ioc, &cfg)) != 0)
4179 return rc;
4180
4181 if (hdr.PageLength == 0)
4182 return 0;
4183
4184 data_sz = hdr.PageLength * 4;
4185 rc = -ENOMEM;
4186 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4187 if (ppage1_alloc) {
4188 memset((u8 *)ppage1_alloc, 0, data_sz);
4189 cfg.physAddr = page1_dma;
4190 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4191
4192 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4193 /* save the data */
4194 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4195 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4196 }
4197
4198 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4199
4200 /* FIXME!
4201 * Normalize endianness of structure data,
4202 * by byte-swapping all > 1 byte fields!
4203 */
4204
4205 }
4206
4207 return rc;
4208}
4209
4210/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004211/**
4212 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004213 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004214 * @persist_opcode: see below
4215 *
4216 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4217 * devices not currently present.
4218 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4219 *
4220 * NOTE: Don't use not this function during interrupt time.
4221 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004222 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004223 */
4224
4225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4226int
4227mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4228{
4229 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4230 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4231 MPT_FRAME_HDR *mf = NULL;
4232 MPIHeader_t *mpi_hdr;
4233
4234
4235 /* insure garbage is not sent to fw */
4236 switch(persist_opcode) {
4237
4238 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4239 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4240 break;
4241
4242 default:
4243 return -1;
4244 break;
4245 }
4246
4247 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4248
4249 /* Get a MF for this command.
4250 */
4251 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4252 printk("%s: no msg frames!\n",__FUNCTION__);
4253 return -1;
4254 }
4255
4256 mpi_hdr = (MPIHeader_t *) mf;
4257 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4258 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4259 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4260 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4261 sasIoUnitCntrReq->Operation = persist_opcode;
4262
4263 init_timer(&ioc->persist_timer);
4264 ioc->persist_timer.data = (unsigned long) ioc;
4265 ioc->persist_timer.function = mpt_timer_expired;
4266 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4267 ioc->persist_wait_done=0;
4268 add_timer(&ioc->persist_timer);
4269 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4270 wait_event(mpt_waitq, ioc->persist_wait_done);
4271
4272 sasIoUnitCntrReply =
4273 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4274 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4275 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4276 __FUNCTION__,
4277 sasIoUnitCntrReply->IOCStatus,
4278 sasIoUnitCntrReply->IOCLogInfo);
4279 return -1;
4280 }
4281
4282 printk("%s: success\n",__FUNCTION__);
4283 return 0;
4284}
4285
4286/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004287
4288static void
4289mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4290 MpiEventDataRaid_t * pRaidEventData)
4291{
4292 int volume;
4293 int reason;
4294 int disk;
4295 int status;
4296 int flags;
4297 int state;
4298
4299 volume = pRaidEventData->VolumeID;
4300 reason = pRaidEventData->ReasonCode;
4301 disk = pRaidEventData->PhysDiskNum;
4302 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4303 flags = (status >> 0) & 0xff;
4304 state = (status >> 8) & 0xff;
4305
4306 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4307 return;
4308 }
4309
4310 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4311 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4312 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4313 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4314 ioc->name, disk);
4315 } else {
4316 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4317 ioc->name, volume);
4318 }
4319
4320 switch(reason) {
4321 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4322 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4323 ioc->name);
4324 break;
4325
4326 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4327
4328 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4329 ioc->name);
4330 break;
4331
4332 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4333 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4334 ioc->name);
4335 break;
4336
4337 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4338 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4339 ioc->name,
4340 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4341 ? "optimal"
4342 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4343 ? "degraded"
4344 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4345 ? "failed"
4346 : "state unknown",
4347 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4348 ? ", enabled" : "",
4349 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4350 ? ", quiesced" : "",
4351 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4352 ? ", resync in progress" : "" );
4353 break;
4354
4355 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4356 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4357 ioc->name, disk);
4358 break;
4359
4360 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4361 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4362 ioc->name);
4363 break;
4364
4365 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4366 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4367 ioc->name);
4368 break;
4369
4370 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4371 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4372 ioc->name);
4373 break;
4374
4375 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4376 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4377 ioc->name,
4378 state == MPI_PHYSDISK0_STATUS_ONLINE
4379 ? "online"
4380 : state == MPI_PHYSDISK0_STATUS_MISSING
4381 ? "missing"
4382 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4383 ? "not compatible"
4384 : state == MPI_PHYSDISK0_STATUS_FAILED
4385 ? "failed"
4386 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4387 ? "initializing"
4388 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4389 ? "offline requested"
4390 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4391 ? "failed requested"
4392 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4393 ? "offline"
4394 : "state unknown",
4395 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4396 ? ", out of sync" : "",
4397 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4398 ? ", quiesced" : "" );
4399 break;
4400
4401 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4402 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4403 ioc->name, disk);
4404 break;
4405
4406 case MPI_EVENT_RAID_RC_SMART_DATA:
4407 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4408 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4409 break;
4410
4411 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4412 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4413 ioc->name, disk);
4414 break;
4415 }
4416}
4417
4418/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004419/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4421 * @ioc: Pointer to MPT_ADAPTER structure
4422 *
4423 * Returns: 0 for success
4424 * -ENOMEM if no memory available
4425 * -EPERM if not allowed due to ISR context
4426 * -EAGAIN if no msg frames currently available
4427 * -EFAULT for non-successful reply or no reply (timeout)
4428 */
4429static int
4430GetIoUnitPage2(MPT_ADAPTER *ioc)
4431{
4432 ConfigPageHeader_t hdr;
4433 CONFIGPARMS cfg;
4434 IOUnitPage2_t *ppage_alloc;
4435 dma_addr_t page_dma;
4436 int data_sz;
4437 int rc;
4438
4439 /* Get the page header */
4440 hdr.PageVersion = 0;
4441 hdr.PageLength = 0;
4442 hdr.PageNumber = 2;
4443 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004444 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 cfg.physAddr = -1;
4446 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4447 cfg.dir = 0;
4448 cfg.pageAddr = 0;
4449 cfg.timeout = 0;
4450
4451 if ((rc = mpt_config(ioc, &cfg)) != 0)
4452 return rc;
4453
4454 if (hdr.PageLength == 0)
4455 return 0;
4456
4457 /* Read the config page */
4458 data_sz = hdr.PageLength * 4;
4459 rc = -ENOMEM;
4460 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4461 if (ppage_alloc) {
4462 memset((u8 *)ppage_alloc, 0, data_sz);
4463 cfg.physAddr = page_dma;
4464 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4465
4466 /* If Good, save data */
4467 if ((rc = mpt_config(ioc, &cfg)) == 0)
4468 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4469
4470 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4471 }
4472
4473 return rc;
4474}
4475
4476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004477/**
4478 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 * @ioc: Pointer to a Adapter Strucutre
4480 * @portnum: IOC port number
4481 *
4482 * Return: -EFAULT if read of config page header fails
4483 * or if no nvram
4484 * If read of SCSI Port Page 0 fails,
4485 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4486 * Adapter settings: async, narrow
4487 * Return 1
4488 * If read of SCSI Port Page 2 fails,
4489 * Adapter settings valid
4490 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4491 * Return 1
4492 * Else
4493 * Both valid
4494 * Return 0
4495 * CHECK - what type of locking mechanisms should be used????
4496 */
4497static int
4498mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4499{
4500 u8 *pbuf;
4501 dma_addr_t buf_dma;
4502 CONFIGPARMS cfg;
4503 ConfigPageHeader_t header;
4504 int ii;
4505 int data, rc = 0;
4506
4507 /* Allocate memory
4508 */
4509 if (!ioc->spi_data.nvram) {
4510 int sz;
4511 u8 *mem;
4512 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4513 mem = kmalloc(sz, GFP_ATOMIC);
4514 if (mem == NULL)
4515 return -EFAULT;
4516
4517 ioc->spi_data.nvram = (int *) mem;
4518
4519 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4520 ioc->name, ioc->spi_data.nvram, sz));
4521 }
4522
4523 /* Invalidate NVRAM information
4524 */
4525 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4526 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4527 }
4528
4529 /* Read SPP0 header, allocate memory, then read page.
4530 */
4531 header.PageVersion = 0;
4532 header.PageLength = 0;
4533 header.PageNumber = 0;
4534 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004535 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 cfg.physAddr = -1;
4537 cfg.pageAddr = portnum;
4538 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4539 cfg.dir = 0;
4540 cfg.timeout = 0; /* use default */
4541 if (mpt_config(ioc, &cfg) != 0)
4542 return -EFAULT;
4543
4544 if (header.PageLength > 0) {
4545 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4546 if (pbuf) {
4547 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4548 cfg.physAddr = buf_dma;
4549 if (mpt_config(ioc, &cfg) != 0) {
4550 ioc->spi_data.maxBusWidth = MPT_NARROW;
4551 ioc->spi_data.maxSyncOffset = 0;
4552 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4553 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4554 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004555 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4556 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 } else {
4558 /* Save the Port Page 0 data
4559 */
4560 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4561 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4562 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4563
4564 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4565 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004566 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 ioc->name, pPP0->Capabilities));
4568 }
4569 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4570 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4571 if (data) {
4572 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4573 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4574 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004575 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4576 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 } else {
4578 ioc->spi_data.maxSyncOffset = 0;
4579 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4580 }
4581
4582 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4583
4584 /* Update the minSyncFactor based on bus type.
4585 */
4586 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4587 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4588
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004589 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004591 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4592 ioc->name, ioc->spi_data.minSyncFactor));
4593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 }
4595 }
4596 if (pbuf) {
4597 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4598 }
4599 }
4600 }
4601
4602 /* SCSI Port Page 2 - Read the header then the page.
4603 */
4604 header.PageVersion = 0;
4605 header.PageLength = 0;
4606 header.PageNumber = 2;
4607 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004608 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 cfg.physAddr = -1;
4610 cfg.pageAddr = portnum;
4611 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4612 cfg.dir = 0;
4613 if (mpt_config(ioc, &cfg) != 0)
4614 return -EFAULT;
4615
4616 if (header.PageLength > 0) {
4617 /* Allocate memory and read SCSI Port Page 2
4618 */
4619 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4620 if (pbuf) {
4621 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4622 cfg.physAddr = buf_dma;
4623 if (mpt_config(ioc, &cfg) != 0) {
4624 /* Nvram data is left with INVALID mark
4625 */
4626 rc = 1;
4627 } else {
4628 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4629 MpiDeviceInfo_t *pdevice = NULL;
4630
Moore, Ericd8e925d2006-01-16 18:53:06 -07004631 /*
4632 * Save "Set to Avoid SCSI Bus Resets" flag
4633 */
4634 ioc->spi_data.bus_reset =
4635 (le32_to_cpu(pPP2->PortFlags) &
4636 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4637 0 : 1 ;
4638
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 /* Save the Port Page 2 data
4640 * (reformat into a 32bit quantity)
4641 */
4642 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4643 ioc->spi_data.PortFlags = data;
4644 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4645 pdevice = &pPP2->DeviceSettings[ii];
4646 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4647 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4648 ioc->spi_data.nvram[ii] = data;
4649 }
4650 }
4651
4652 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4653 }
4654 }
4655
4656 /* Update Adapter limits with those from NVRAM
4657 * Comment: Don't need to do this. Target performance
4658 * parameters will never exceed the adapters limits.
4659 */
4660
4661 return rc;
4662}
4663
4664/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004665/**
4666 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 * @ioc: Pointer to a Adapter Strucutre
4668 * @portnum: IOC port number
4669 *
4670 * Return: -EFAULT if read of config page header fails
4671 * or 0 if success.
4672 */
4673static int
4674mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4675{
4676 CONFIGPARMS cfg;
4677 ConfigPageHeader_t header;
4678
4679 /* Read the SCSI Device Page 1 header
4680 */
4681 header.PageVersion = 0;
4682 header.PageLength = 0;
4683 header.PageNumber = 1;
4684 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004685 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 cfg.physAddr = -1;
4687 cfg.pageAddr = portnum;
4688 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4689 cfg.dir = 0;
4690 cfg.timeout = 0;
4691 if (mpt_config(ioc, &cfg) != 0)
4692 return -EFAULT;
4693
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004694 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4695 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696
4697 header.PageVersion = 0;
4698 header.PageLength = 0;
4699 header.PageNumber = 0;
4700 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4701 if (mpt_config(ioc, &cfg) != 0)
4702 return -EFAULT;
4703
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004704 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4705 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
4707 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4708 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4709
4710 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4711 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4712 return 0;
4713}
4714
4715/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4716/**
4717 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4718 * @ioc: Pointer to a Adapter Strucutre
4719 * @portnum: IOC port number
4720 *
4721 * Return:
4722 * 0 on success
4723 * -EFAULT if read of config page header fails or data pointer not NULL
4724 * -ENOMEM if pci_alloc failed
4725 */
4726int
4727mpt_findImVolumes(MPT_ADAPTER *ioc)
4728{
4729 IOCPage2_t *pIoc2;
4730 u8 *mem;
4731 ConfigPageIoc2RaidVol_t *pIocRv;
4732 dma_addr_t ioc2_dma;
4733 CONFIGPARMS cfg;
4734 ConfigPageHeader_t header;
4735 int jj;
4736 int rc = 0;
4737 int iocpage2sz;
4738 u8 nVols, nPhys;
4739 u8 vid, vbus, vioc;
4740
4741 /* Read IOCP2 header then the page.
4742 */
4743 header.PageVersion = 0;
4744 header.PageLength = 0;
4745 header.PageNumber = 2;
4746 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004747 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 cfg.physAddr = -1;
4749 cfg.pageAddr = 0;
4750 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4751 cfg.dir = 0;
4752 cfg.timeout = 0;
4753 if (mpt_config(ioc, &cfg) != 0)
4754 return -EFAULT;
4755
4756 if (header.PageLength == 0)
4757 return -EFAULT;
4758
4759 iocpage2sz = header.PageLength * 4;
4760 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4761 if (!pIoc2)
4762 return -ENOMEM;
4763
4764 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4765 cfg.physAddr = ioc2_dma;
4766 if (mpt_config(ioc, &cfg) != 0)
4767 goto done_and_free;
4768
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004769 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4771 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004772 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 } else {
4774 goto done_and_free;
4775 }
4776 }
4777 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4778
4779 /* Identify RAID Volume Id's */
4780 nVols = pIoc2->NumActiveVolumes;
4781 if ( nVols == 0) {
4782 /* No RAID Volume.
4783 */
4784 goto done_and_free;
4785 } else {
4786 /* At least 1 RAID Volume
4787 */
4788 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004789 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4791 vid = pIocRv->VolumeID;
4792 vbus = pIocRv->VolumeBus;
4793 vioc = pIocRv->VolumeIOC;
4794
4795 /* find the match
4796 */
4797 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004798 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 } else {
4800 /* Error! Always bus 0
4801 */
4802 }
4803 }
4804 }
4805
4806 /* Identify Hidden Physical Disk Id's */
4807 nPhys = pIoc2->NumActivePhysDisks;
4808 if (nPhys == 0) {
4809 /* No physical disks.
4810 */
4811 } else {
4812 mpt_read_ioc_pg_3(ioc);
4813 }
4814
4815done_and_free:
4816 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4817
4818 return rc;
4819}
4820
Moore, Ericc972c702006-03-14 09:14:06 -07004821static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4823{
4824 IOCPage3_t *pIoc3;
4825 u8 *mem;
4826 CONFIGPARMS cfg;
4827 ConfigPageHeader_t header;
4828 dma_addr_t ioc3_dma;
4829 int iocpage3sz = 0;
4830
4831 /* Free the old page
4832 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004833 kfree(ioc->raid_data.pIocPg3);
4834 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835
4836 /* There is at least one physical disk.
4837 * Read and save IOC Page 3
4838 */
4839 header.PageVersion = 0;
4840 header.PageLength = 0;
4841 header.PageNumber = 3;
4842 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004843 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 cfg.physAddr = -1;
4845 cfg.pageAddr = 0;
4846 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4847 cfg.dir = 0;
4848 cfg.timeout = 0;
4849 if (mpt_config(ioc, &cfg) != 0)
4850 return 0;
4851
4852 if (header.PageLength == 0)
4853 return 0;
4854
4855 /* Read Header good, alloc memory
4856 */
4857 iocpage3sz = header.PageLength * 4;
4858 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4859 if (!pIoc3)
4860 return 0;
4861
4862 /* Read the Page and save the data
4863 * into malloc'd memory.
4864 */
4865 cfg.physAddr = ioc3_dma;
4866 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4867 if (mpt_config(ioc, &cfg) == 0) {
4868 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4869 if (mem) {
4870 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004871 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 }
4873 }
4874
4875 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4876
4877 return 0;
4878}
4879
4880static void
4881mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4882{
4883 IOCPage4_t *pIoc4;
4884 CONFIGPARMS cfg;
4885 ConfigPageHeader_t header;
4886 dma_addr_t ioc4_dma;
4887 int iocpage4sz;
4888
4889 /* Read and save IOC Page 4
4890 */
4891 header.PageVersion = 0;
4892 header.PageLength = 0;
4893 header.PageNumber = 4;
4894 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004895 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 cfg.physAddr = -1;
4897 cfg.pageAddr = 0;
4898 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4899 cfg.dir = 0;
4900 cfg.timeout = 0;
4901 if (mpt_config(ioc, &cfg) != 0)
4902 return;
4903
4904 if (header.PageLength == 0)
4905 return;
4906
4907 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4908 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4909 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4910 if (!pIoc4)
4911 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06004912 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 } else {
4914 ioc4_dma = ioc->spi_data.IocPg4_dma;
4915 iocpage4sz = ioc->spi_data.IocPg4Sz;
4916 }
4917
4918 /* Read the Page into dma memory.
4919 */
4920 cfg.physAddr = ioc4_dma;
4921 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4922 if (mpt_config(ioc, &cfg) == 0) {
4923 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4924 ioc->spi_data.IocPg4_dma = ioc4_dma;
4925 ioc->spi_data.IocPg4Sz = iocpage4sz;
4926 } else {
4927 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4928 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06004929 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 }
4931}
4932
4933static void
4934mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4935{
4936 IOCPage1_t *pIoc1;
4937 CONFIGPARMS cfg;
4938 ConfigPageHeader_t header;
4939 dma_addr_t ioc1_dma;
4940 int iocpage1sz = 0;
4941 u32 tmp;
4942
4943 /* Check the Coalescing Timeout in IOC Page 1
4944 */
4945 header.PageVersion = 0;
4946 header.PageLength = 0;
4947 header.PageNumber = 1;
4948 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004949 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 cfg.physAddr = -1;
4951 cfg.pageAddr = 0;
4952 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4953 cfg.dir = 0;
4954 cfg.timeout = 0;
4955 if (mpt_config(ioc, &cfg) != 0)
4956 return;
4957
4958 if (header.PageLength == 0)
4959 return;
4960
4961 /* Read Header good, alloc memory
4962 */
4963 iocpage1sz = header.PageLength * 4;
4964 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
4965 if (!pIoc1)
4966 return;
4967
4968 /* Read the Page and check coalescing timeout
4969 */
4970 cfg.physAddr = ioc1_dma;
4971 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4972 if (mpt_config(ioc, &cfg) == 0) {
4973
4974 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
4975 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
4976 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
4977
4978 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
4979 ioc->name, tmp));
4980
4981 if (tmp > MPT_COALESCING_TIMEOUT) {
4982 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
4983
4984 /* Write NVRAM and current
4985 */
4986 cfg.dir = 1;
4987 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
4988 if (mpt_config(ioc, &cfg) == 0) {
4989 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
4990 ioc->name, MPT_COALESCING_TIMEOUT));
4991
4992 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
4993 if (mpt_config(ioc, &cfg) == 0) {
4994 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
4995 ioc->name, MPT_COALESCING_TIMEOUT));
4996 } else {
4997 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
4998 ioc->name));
4999 }
5000
5001 } else {
5002 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5003 ioc->name));
5004 }
5005 }
5006
5007 } else {
5008 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5009 }
5010 }
5011
5012 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5013
5014 return;
5015}
5016
5017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005018/**
5019 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 * @ioc: Pointer to MPT_ADAPTER structure
5021 * @EvSwitch: Event switch flags
5022 */
5023static int
5024SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5025{
5026 EventNotification_t *evnp;
5027
5028 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5029 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005030 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 ioc->name));
5032 return 0;
5033 }
5034 memset(evnp, 0, sizeof(*evnp));
5035
Moore, Eric3a892be2006-03-14 09:14:03 -07005036 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
5038 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5039 evnp->ChainOffset = 0;
5040 evnp->MsgFlags = 0;
5041 evnp->Switch = EvSwitch;
5042
5043 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5044
5045 return 0;
5046}
5047
5048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5049/**
5050 * SendEventAck - Send EventAck request to MPT adapter.
5051 * @ioc: Pointer to MPT_ADAPTER structure
5052 * @evnp: Pointer to original EventNotification request
5053 */
5054static int
5055SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5056{
5057 EventAck_t *pAck;
5058
5059 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Eric Moore4f766dc2006-07-11 17:24:07 -06005060 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
5061 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 return -1;
5063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064
Eric Moore4f766dc2006-07-11 17:24:07 -06005065 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066
5067 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5068 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005069 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005071 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 pAck->Event = evnp->Event;
5073 pAck->EventContext = evnp->EventContext;
5074
5075 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5076
5077 return 0;
5078}
5079
5080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5081/**
5082 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005083 * @ioc: Pointer to an adapter structure
5084 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 * action, page address, direction, physical address
5086 * and pointer to a configuration page header
5087 * Page header is updated.
5088 *
5089 * Returns 0 for success
5090 * -EPERM if not allowed due to ISR context
5091 * -EAGAIN if no msg frames currently available
5092 * -EFAULT for non-successful reply or no reply (timeout)
5093 */
5094int
5095mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5096{
5097 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005098 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 MPT_FRAME_HDR *mf;
5100 unsigned long flags;
5101 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005102 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 int in_isr;
5104
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005105 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 * to be in ISR context, because that is fatal!
5107 */
5108 in_isr = in_interrupt();
5109 if (in_isr) {
5110 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5111 ioc->name));
5112 return -EPERM;
5113 }
5114
5115 /* Get and Populate a free Frame
5116 */
5117 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5118 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5119 ioc->name));
5120 return -EAGAIN;
5121 }
5122 pReq = (Config_t *)mf;
5123 pReq->Action = pCfg->action;
5124 pReq->Reserved = 0;
5125 pReq->ChainOffset = 0;
5126 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005127
5128 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pReq->ExtPageLength = 0;
5130 pReq->ExtPageType = 0;
5131 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005132
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 for (ii=0; ii < 8; ii++)
5134 pReq->Reserved2[ii] = 0;
5135
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005136 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5137 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5138 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5139 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5140
5141 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5142 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5143 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5144 pReq->ExtPageType = pExtHdr->ExtPageType;
5145 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5146
5147 /* Page Length must be treated as a reserved field for the extended header. */
5148 pReq->Header.PageLength = 0;
5149 }
5150
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5152
5153 /* Add a SGE to the config request.
5154 */
5155 if (pCfg->dir)
5156 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5157 else
5158 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5159
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005160 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5161 flagsLength |= pExtHdr->ExtPageLength * 4;
5162
5163 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5164 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5165 }
5166 else {
5167 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5168
5169 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5170 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172
5173 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5174
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 /* Append pCfg pointer to end of mf
5176 */
5177 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5178
5179 /* Initalize the timer
5180 */
5181 init_timer(&pCfg->timer);
5182 pCfg->timer.data = (unsigned long) ioc;
5183 pCfg->timer.function = mpt_timer_expired;
5184 pCfg->wait_done = 0;
5185
5186 /* Set the timer; ensure 10 second minimum */
5187 if (pCfg->timeout < 10)
5188 pCfg->timer.expires = jiffies + HZ*10;
5189 else
5190 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5191
5192 /* Add to end of Q, set timer and then issue this command */
5193 spin_lock_irqsave(&ioc->FreeQlock, flags);
5194 list_add_tail(&pCfg->linkage, &ioc->configQ);
5195 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5196
5197 add_timer(&pCfg->timer);
5198 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5199 wait_event(mpt_waitq, pCfg->wait_done);
5200
5201 /* mf has been freed - do not access */
5202
5203 rc = pCfg->status;
5204
5205 return rc;
5206}
5207
5208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005209/**
5210 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 * Used only internal config functionality.
5212 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5213 */
5214static void
5215mpt_timer_expired(unsigned long data)
5216{
5217 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5218
5219 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5220
5221 /* Perform a FW reload */
5222 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5223 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5224
5225 /* No more processing.
5226 * Hard reset clean-up will wake up
5227 * process and free all resources.
5228 */
5229 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5230
5231 return;
5232}
5233
5234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005235/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 * mpt_ioc_reset - Base cleanup for hard reset
5237 * @ioc: Pointer to the adapter structure
5238 * @reset_phase: Indicates pre- or post-reset functionality
5239 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005240 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 */
5242static int
5243mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5244{
5245 CONFIGPARMS *pCfg;
5246 unsigned long flags;
5247
5248 dprintk((KERN_WARNING MYNAM
5249 ": IOC %s_reset routed to MPT base driver!\n",
5250 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5251 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5252
5253 if (reset_phase == MPT_IOC_SETUP_RESET) {
5254 ;
5255 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5256 /* If the internal config Q is not empty -
5257 * delete timer. MF resources will be freed when
5258 * the FIFO's are primed.
5259 */
5260 spin_lock_irqsave(&ioc->FreeQlock, flags);
5261 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5262 del_timer(&pCfg->timer);
5263 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5264
5265 } else {
5266 CONFIGPARMS *pNext;
5267
5268 /* Search the configQ for internal commands.
5269 * Flush the Q, and wake up all suspended threads.
5270 */
5271 spin_lock_irqsave(&ioc->FreeQlock, flags);
5272 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5273 list_del(&pCfg->linkage);
5274
5275 pCfg->status = MPT_CONFIG_ERROR;
5276 pCfg->wait_done = 1;
5277 wake_up(&mpt_waitq);
5278 }
5279 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5280 }
5281
5282 return 1; /* currently means nothing really */
5283}
5284
5285
5286#ifdef CONFIG_PROC_FS /* { */
5287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5288/*
5289 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5290 */
5291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005292/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5294 *
5295 * Returns 0 for success, non-zero for failure.
5296 */
5297static int
5298procmpt_create(void)
5299{
5300 struct proc_dir_entry *ent;
5301
5302 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5303 if (mpt_proc_root_dir == NULL)
5304 return -ENOTDIR;
5305
5306 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5307 if (ent)
5308 ent->read_proc = procmpt_summary_read;
5309
5310 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5311 if (ent)
5312 ent->read_proc = procmpt_version_read;
5313
5314 return 0;
5315}
5316
5317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005318/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5320 *
5321 * Returns 0 for success, non-zero for failure.
5322 */
5323static void
5324procmpt_destroy(void)
5325{
5326 remove_proc_entry("version", mpt_proc_root_dir);
5327 remove_proc_entry("summary", mpt_proc_root_dir);
5328 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5329}
5330
5331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005332/**
5333 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 * @buf: Pointer to area to write information
5335 * @start: Pointer to start pointer
5336 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005337 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 * @eof: Pointer to EOF integer
5339 * @data: Pointer
5340 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005341 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 * Returns number of characters written to process performing the read.
5343 */
5344static int
5345procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5346{
5347 MPT_ADAPTER *ioc;
5348 char *out = buf;
5349 int len;
5350
5351 if (data) {
5352 int more = 0;
5353
5354 ioc = data;
5355 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5356
5357 out += more;
5358 } else {
5359 list_for_each_entry(ioc, &ioc_list, list) {
5360 int more = 0;
5361
5362 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5363
5364 out += more;
5365 if ((out-buf) >= request)
5366 break;
5367 }
5368 }
5369
5370 len = out - buf;
5371
5372 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5373}
5374
5375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005376/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 * procmpt_version_read - Handle read request from /proc/mpt/version.
5378 * @buf: Pointer to area to write information
5379 * @start: Pointer to start pointer
5380 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005381 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 * @eof: Pointer to EOF integer
5383 * @data: Pointer
5384 *
5385 * Returns number of characters written to process performing the read.
5386 */
5387static int
5388procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5389{
5390 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005391 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 char *drvname;
5393 int len;
5394
5395 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5396 len += sprintf(buf+len, " Fusion MPT base driver\n");
5397
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005398 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5400 drvname = NULL;
5401 if (MptCallbacks[ii]) {
5402 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005403 case MPTSPI_DRIVER:
5404 if (!scsi++) drvname = "SPI host";
5405 break;
5406 case MPTFC_DRIVER:
5407 if (!fc++) drvname = "FC host";
5408 break;
5409 case MPTSAS_DRIVER:
5410 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 break;
5412 case MPTLAN_DRIVER:
5413 if (!lan++) drvname = "LAN";
5414 break;
5415 case MPTSTM_DRIVER:
5416 if (!targ++) drvname = "SCSI target";
5417 break;
5418 case MPTCTL_DRIVER:
5419 if (!ctl++) drvname = "ioctl";
5420 break;
5421 }
5422
5423 if (drvname)
5424 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5425 }
5426 }
5427
5428 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5429}
5430
5431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005432/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5434 * @buf: Pointer to area to write information
5435 * @start: Pointer to start pointer
5436 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005437 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 * @eof: Pointer to EOF integer
5439 * @data: Pointer
5440 *
5441 * Returns number of characters written to process performing the read.
5442 */
5443static int
5444procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5445{
5446 MPT_ADAPTER *ioc = data;
5447 int len;
5448 char expVer[32];
5449 int sz;
5450 int p;
5451
5452 mpt_get_fw_exp_ver(expVer, ioc);
5453
5454 len = sprintf(buf, "%s:", ioc->name);
5455 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5456 len += sprintf(buf+len, " (f/w download boot flag set)");
5457// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5458// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5459
5460 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5461 ioc->facts.ProductID,
5462 ioc->prod_name);
5463 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5464 if (ioc->facts.FWImageSize)
5465 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5466 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5467 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5468 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5469
5470 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5471 ioc->facts.CurrentHostMfaHighAddr);
5472 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5473 ioc->facts.CurrentSenseBufferHighAddr);
5474
5475 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5476 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5477
5478 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5479 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5480 /*
5481 * Rounding UP to nearest 4-kB boundary here...
5482 */
5483 sz = (ioc->req_sz * ioc->req_depth) + 128;
5484 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5485 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5486 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5487 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5488 4*ioc->facts.RequestFrameSize,
5489 ioc->facts.GlobalCredits);
5490
5491 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5492 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5493 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5494 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5495 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5496 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5497 ioc->facts.CurReplyFrameSize,
5498 ioc->facts.ReplyQueueDepth);
5499
5500 len += sprintf(buf+len, " MaxDevices = %d\n",
5501 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5502 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5503
5504 /* per-port info */
5505 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5506 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5507 p+1,
5508 ioc->facts.NumberOfPorts);
5509 if (ioc->bus_type == FC) {
5510 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5511 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5512 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5513 a[5], a[4], a[3], a[2], a[1], a[0]);
5514 }
5515 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5516 ioc->fc_port_page0[p].WWNN.High,
5517 ioc->fc_port_page0[p].WWNN.Low,
5518 ioc->fc_port_page0[p].WWPN.High,
5519 ioc->fc_port_page0[p].WWPN.Low);
5520 }
5521 }
5522
5523 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5524}
5525
5526#endif /* CONFIG_PROC_FS } */
5527
5528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5529static void
5530mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5531{
5532 buf[0] ='\0';
5533 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5534 sprintf(buf, " (Exp %02d%02d)",
5535 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5536 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5537
5538 /* insider hack! */
5539 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5540 strcat(buf, " [MDBG]");
5541 }
5542}
5543
5544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5545/**
5546 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5547 * @ioc: Pointer to MPT_ADAPTER structure
5548 * @buffer: Pointer to buffer where IOC summary info should be written
5549 * @size: Pointer to number of bytes we wrote (set by this routine)
5550 * @len: Offset at which to start writing in buffer
5551 * @showlan: Display LAN stuff?
5552 *
5553 * This routine writes (english readable) ASCII text, which represents
5554 * a summary of IOC information, to a buffer.
5555 */
5556void
5557mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5558{
5559 char expVer[32];
5560 int y;
5561
5562 mpt_get_fw_exp_ver(expVer, ioc);
5563
5564 /*
5565 * Shorter summary of attached ioc's...
5566 */
5567 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5568 ioc->name,
5569 ioc->prod_name,
5570 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5571 ioc->facts.FWVersion.Word,
5572 expVer,
5573 ioc->facts.NumberOfPorts,
5574 ioc->req_depth);
5575
5576 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5577 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5578 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5579 a[5], a[4], a[3], a[2], a[1], a[0]);
5580 }
5581
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
5584 if (!ioc->active)
5585 y += sprintf(buffer+len+y, " (disabled)");
5586
5587 y += sprintf(buffer+len+y, "\n");
5588
5589 *size = y;
5590}
5591
5592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5593/*
5594 * Reset Handling
5595 */
5596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5597/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005598 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 * @ioc: Pointer to MPT_ADAPTER structure
5600 * @sleepFlag: Indicates if sleep or schedule must be called.
5601 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005602 * Issues SCSI Task Management call based on input arg values.
5603 * If TaskMgmt fails, returns associated SCSI request.
5604 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5606 * or a non-interrupt thread. In the former, must not call schedule().
5607 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005608 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 * FW reload/initialization failed.
5610 *
5611 * Returns 0 for SUCCESS or -1 if FAILED.
5612 */
5613int
5614mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5615{
5616 int rc;
5617 unsigned long flags;
5618
5619 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5620#ifdef MFCNT
5621 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5622 printk("MF count 0x%x !\n", ioc->mfcnt);
5623#endif
5624
5625 /* Reset the adapter. Prevent more than 1 call to
5626 * mpt_do_ioc_recovery at any instant in time.
5627 */
5628 spin_lock_irqsave(&ioc->diagLock, flags);
5629 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5630 spin_unlock_irqrestore(&ioc->diagLock, flags);
5631 return 0;
5632 } else {
5633 ioc->diagPending = 1;
5634 }
5635 spin_unlock_irqrestore(&ioc->diagLock, flags);
5636
5637 /* FIXME: If do_ioc_recovery fails, repeat....
5638 */
5639
5640 /* The SCSI driver needs to adjust timeouts on all current
5641 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02005642 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 * For all other protocol drivers, this is a no-op.
5644 */
5645 {
5646 int ii;
5647 int r = 0;
5648
5649 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5650 if (MptResetHandlers[ii]) {
5651 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5652 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005653 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 if (ioc->alt_ioc) {
5655 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5656 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005657 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 }
5659 }
5660 }
5661 }
5662
5663 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5664 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5665 rc, ioc->name);
5666 }
5667 ioc->reload_fw = 0;
5668 if (ioc->alt_ioc)
5669 ioc->alt_ioc->reload_fw = 0;
5670
5671 spin_lock_irqsave(&ioc->diagLock, flags);
5672 ioc->diagPending = 0;
5673 if (ioc->alt_ioc)
5674 ioc->alt_ioc->diagPending = 0;
5675 spin_unlock_irqrestore(&ioc->diagLock, flags);
5676
5677 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5678
5679 return rc;
5680}
5681
Eric Moore509e5e52006-04-26 13:22:37 -06005682# define EVENT_DESCR_STR_SZ 100
5683
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005685static void
5686EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687{
Eric Moore509e5e52006-04-26 13:22:37 -06005688 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
5690 switch(event) {
5691 case MPI_EVENT_NONE:
5692 ds = "None";
5693 break;
5694 case MPI_EVENT_LOG_DATA:
5695 ds = "Log Data";
5696 break;
5697 case MPI_EVENT_STATE_CHANGE:
5698 ds = "State Change";
5699 break;
5700 case MPI_EVENT_UNIT_ATTENTION:
5701 ds = "Unit Attention";
5702 break;
5703 case MPI_EVENT_IOC_BUS_RESET:
5704 ds = "IOC Bus Reset";
5705 break;
5706 case MPI_EVENT_EXT_BUS_RESET:
5707 ds = "External Bus Reset";
5708 break;
5709 case MPI_EVENT_RESCAN:
5710 ds = "Bus Rescan Event";
5711 /* Ok, do we need to do anything here? As far as
5712 I can tell, this is when a new device gets added
5713 to the loop. */
5714 break;
5715 case MPI_EVENT_LINK_STATUS_CHANGE:
5716 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5717 ds = "Link Status(FAILURE) Change";
5718 else
5719 ds = "Link Status(ACTIVE) Change";
5720 break;
5721 case MPI_EVENT_LOOP_STATE_CHANGE:
5722 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5723 ds = "Loop State(LIP) Change";
5724 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005725 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 else
Eric Moore509e5e52006-04-26 13:22:37 -06005727 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 break;
5729 case MPI_EVENT_LOGOUT:
5730 ds = "Logout";
5731 break;
5732 case MPI_EVENT_EVENT_CHANGE:
5733 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06005734 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 else
Eric Moore4f766dc2006-07-11 17:24:07 -06005736 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 break;
5738 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005739 {
5740 u8 ReasonCode = (u8)(evData0 >> 16);
5741 switch (ReasonCode) {
5742 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5743 ds = "Integrated Raid: Volume Created";
5744 break;
5745 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5746 ds = "Integrated Raid: Volume Deleted";
5747 break;
5748 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5749 ds = "Integrated Raid: Volume Settings Changed";
5750 break;
5751 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5752 ds = "Integrated Raid: Volume Status Changed";
5753 break;
5754 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5755 ds = "Integrated Raid: Volume Physdisk Changed";
5756 break;
5757 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5758 ds = "Integrated Raid: Physdisk Created";
5759 break;
5760 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5761 ds = "Integrated Raid: Physdisk Deleted";
5762 break;
5763 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5764 ds = "Integrated Raid: Physdisk Settings Changed";
5765 break;
5766 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5767 ds = "Integrated Raid: Physdisk Status Changed";
5768 break;
5769 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5770 ds = "Integrated Raid: Domain Validation Needed";
5771 break;
5772 case MPI_EVENT_RAID_RC_SMART_DATA :
5773 ds = "Integrated Raid; Smart Data";
5774 break;
5775 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5776 ds = "Integrated Raid: Replace Action Started";
5777 break;
5778 default:
5779 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005781 }
5782 break;
5783 }
5784 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5785 ds = "SCSI Device Status Change";
5786 break;
5787 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5788 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005789 u8 id = (u8)(evData0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005790 u8 ReasonCode = (u8)(evData0 >> 16);
5791 switch (ReasonCode) {
5792 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005793 snprintf(evStr, EVENT_DESCR_STR_SZ,
5794 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005795 break;
5796 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005797 snprintf(evStr, EVENT_DESCR_STR_SZ,
5798 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005799 break;
5800 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005801 snprintf(evStr, EVENT_DESCR_STR_SZ,
5802 "SAS Device Status Change: SMART Data: id=%d",
5803 id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005804 break;
5805 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005806 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moore4f766dc2006-07-11 17:24:07 -06005807 "SAS Device Status Change: No Persistancy: id=%d", id);
5808 break;
5809 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5810 snprintf(evStr, EVENT_DESCR_STR_SZ,
5811 "SAS Device Status Change: Internal Device Reset : id=%d", id);
5812 break;
5813 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5814 snprintf(evStr, EVENT_DESCR_STR_SZ,
5815 "SAS Device Status Change: Internal Task Abort : id=%d", id);
5816 break;
5817 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5818 snprintf(evStr, EVENT_DESCR_STR_SZ,
5819 "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
5820 break;
5821 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5822 snprintf(evStr, EVENT_DESCR_STR_SZ,
5823 "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
5824 break;
5825 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5826 snprintf(evStr, EVENT_DESCR_STR_SZ,
5827 "SAS Device Status Change: Internal Query Task : id=%d", id);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005828 break;
5829 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005830 snprintf(evStr, EVENT_DESCR_STR_SZ,
5831 "SAS Device Status Change: Unknown: id=%d", id);
5832 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005833 }
5834 break;
5835 }
5836 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5837 ds = "Bus Timer Expired";
5838 break;
5839 case MPI_EVENT_QUEUE_FULL:
5840 ds = "Queue Full";
5841 break;
5842 case MPI_EVENT_SAS_SES:
5843 ds = "SAS SES Event";
5844 break;
5845 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5846 ds = "Persistent Table Full";
5847 break;
5848 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005849 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005850 u8 LinkRates = (u8)(evData0 >> 8);
5851 u8 PhyNumber = (u8)(evData0);
5852 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5853 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5854 switch (LinkRates) {
5855 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005856 snprintf(evStr, EVENT_DESCR_STR_SZ,
5857 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005858 " Rate Unknown",PhyNumber);
5859 break;
5860 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005861 snprintf(evStr, EVENT_DESCR_STR_SZ,
5862 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005863 " Phy Disabled",PhyNumber);
5864 break;
5865 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005866 snprintf(evStr, EVENT_DESCR_STR_SZ,
5867 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005868 " Failed Speed Nego",PhyNumber);
5869 break;
5870 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005871 snprintf(evStr, EVENT_DESCR_STR_SZ,
5872 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005873 " Sata OOB Completed",PhyNumber);
5874 break;
5875 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005876 snprintf(evStr, EVENT_DESCR_STR_SZ,
5877 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005878 " Rate 1.5 Gbps",PhyNumber);
5879 break;
5880 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005881 snprintf(evStr, EVENT_DESCR_STR_SZ,
5882 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005883 " Rate 3.0 Gpbs",PhyNumber);
5884 break;
5885 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005886 snprintf(evStr, EVENT_DESCR_STR_SZ,
5887 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005888 break;
5889 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005890 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005891 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005892 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5893 ds = "SAS Discovery Error";
5894 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005895 case MPI_EVENT_IR_RESYNC_UPDATE:
5896 {
5897 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005898 snprintf(evStr, EVENT_DESCR_STR_SZ,
5899 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005900 break;
5901 }
5902 case MPI_EVENT_IR2:
5903 {
5904 u8 ReasonCode = (u8)(evData0 >> 16);
5905 switch (ReasonCode) {
5906 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5907 ds = "IR2: LD State Changed";
5908 break;
5909 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5910 ds = "IR2: PD State Changed";
5911 break;
5912 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5913 ds = "IR2: Bad Block Table Full";
5914 break;
5915 case MPI_EVENT_IR2_RC_PD_INSERTED:
5916 ds = "IR2: PD Inserted";
5917 break;
5918 case MPI_EVENT_IR2_RC_PD_REMOVED:
5919 ds = "IR2: PD Removed";
5920 break;
5921 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5922 ds = "IR2: Foreign CFG Detected";
5923 break;
5924 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5925 ds = "IR2: Rebuild Medium Error";
5926 break;
5927 default:
5928 ds = "IR2";
5929 break;
5930 }
5931 break;
5932 }
5933 case MPI_EVENT_SAS_DISCOVERY:
5934 {
5935 if (evData0)
5936 ds = "SAS Discovery: Start";
5937 else
5938 ds = "SAS Discovery: Stop";
5939 break;
5940 }
5941 case MPI_EVENT_LOG_ENTRY_ADDED:
5942 ds = "SAS Log Entry Added";
5943 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005944
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 /*
5946 * MPT base "custom" events may be added here...
5947 */
5948 default:
5949 ds = "Unknown";
5950 break;
5951 }
Eric Moore509e5e52006-04-26 13:22:37 -06005952 if (ds)
5953 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954}
5955
5956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005957/**
5958 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 * @ioc: Pointer to MPT_ADAPTER structure
5960 * @pEventReply: Pointer to EventNotification reply frame
5961 * @evHandlers: Pointer to integer, number of event handlers
5962 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005963 * Routes a received EventNotificationReply to all currently registered
5964 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 * Returns sum of event handlers return values.
5966 */
5967static int
5968ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5969{
5970 u16 evDataLen;
5971 u32 evData0 = 0;
5972// u32 evCtx;
5973 int ii;
5974 int r = 0;
5975 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06005976 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 u8 event;
5978
5979 /*
5980 * Do platform normalization of values
5981 */
5982 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5983// evCtx = le32_to_cpu(pEventReply->EventContext);
5984 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5985 if (evDataLen) {
5986 evData0 = le32_to_cpu(pEventReply->Data[0]);
5987 }
5988
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005989 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07005990 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07005992 event,
5993 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Moore, Eric3a892be2006-03-14 09:14:03 -07005995#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5997 for (ii = 0; ii < evDataLen; ii++)
5998 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
5999 printk("\n");
6000#endif
6001
6002 /*
6003 * Do general / base driver event processing
6004 */
6005 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6007 if (evDataLen) {
6008 u8 evState = evData0 & 0xFF;
6009
6010 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6011
6012 /* Update EventState field in cached IocFacts */
6013 if (ioc->facts.Function) {
6014 ioc->facts.EventState = evState;
6015 }
6016 }
6017 break;
Moore, Ericece50912006-01-16 18:53:19 -07006018 case MPI_EVENT_INTEGRATED_RAID:
6019 mptbase_raid_process_event_data(ioc,
6020 (MpiEventDataRaid_t *)pEventReply->Data);
6021 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006022 default:
6023 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 }
6025
6026 /*
6027 * Should this event be logged? Events are written sequentially.
6028 * When buffer is full, start again at the top.
6029 */
6030 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6031 int idx;
6032
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006033 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034
6035 ioc->events[idx].event = event;
6036 ioc->events[idx].eventContext = ioc->eventContext;
6037
6038 for (ii = 0; ii < 2; ii++) {
6039 if (ii < evDataLen)
6040 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6041 else
6042 ioc->events[idx].data[ii] = 0;
6043 }
6044
6045 ioc->eventContext++;
6046 }
6047
6048
6049 /*
6050 * Call each currently registered protocol event handler.
6051 */
6052 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6053 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006054 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 ioc->name, ii));
6056 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6057 handlers++;
6058 }
6059 }
6060 /* FIXME? Examine results here? */
6061
6062 /*
6063 * If needed, send (a single) EventAck.
6064 */
6065 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006066 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006067 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006069 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 ioc->name, ii));
6071 }
6072 }
6073
6074 *evHandlers = handlers;
6075 return r;
6076}
6077
6078/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006079/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6081 * @ioc: Pointer to MPT_ADAPTER structure
6082 * @log_info: U32 LogInfo reply word from the IOC
6083 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006084 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 */
6086static void
6087mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6088{
6089 static char *subcl_str[8] = {
6090 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6091 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6092 };
6093 u8 subcl = (log_info >> 24) & 0x7;
6094
6095 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6096 ioc->name, log_info, subcl_str[subcl]);
6097}
6098
6099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006100/**
Moore, Eric335a9412006-01-17 17:06:23 -07006101 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 * @ioc: Pointer to MPT_ADAPTER structure
6103 * @mr: Pointer to MPT reply frame
6104 * @log_info: U32 LogInfo word from the IOC
6105 *
6106 * Refer to lsi/sp_log.h.
6107 */
6108static void
Moore, Eric335a9412006-01-17 17:06:23 -07006109mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110{
6111 u32 info = log_info & 0x00FF0000;
6112 char *desc = "unknown";
6113
6114 switch (info) {
6115 case 0x00010000:
6116 desc = "bug! MID not found";
6117 if (ioc->reload_fw == 0)
6118 ioc->reload_fw++;
6119 break;
6120
6121 case 0x00020000:
6122 desc = "Parity Error";
6123 break;
6124
6125 case 0x00030000:
6126 desc = "ASYNC Outbound Overrun";
6127 break;
6128
6129 case 0x00040000:
6130 desc = "SYNC Offset Error";
6131 break;
6132
6133 case 0x00050000:
6134 desc = "BM Change";
6135 break;
6136
6137 case 0x00060000:
6138 desc = "Msg In Overflow";
6139 break;
6140
6141 case 0x00070000:
6142 desc = "DMA Error";
6143 break;
6144
6145 case 0x00080000:
6146 desc = "Outbound DMA Overrun";
6147 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006148
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 case 0x00090000:
6150 desc = "Task Management";
6151 break;
6152
6153 case 0x000A0000:
6154 desc = "Device Problem";
6155 break;
6156
6157 case 0x000B0000:
6158 desc = "Invalid Phase Change";
6159 break;
6160
6161 case 0x000C0000:
6162 desc = "Untagged Table Size";
6163 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006164
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 }
6166
6167 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6168}
6169
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006170/* strings for sas loginfo */
6171 static char *originator_str[] = {
6172 "IOP", /* 00h */
6173 "PL", /* 01h */
6174 "IR" /* 02h */
6175 };
6176 static char *iop_code_str[] = {
6177 NULL, /* 00h */
6178 "Invalid SAS Address", /* 01h */
6179 NULL, /* 02h */
6180 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006181 "Diag Message Error", /* 04h */
6182 "Task Terminated", /* 05h */
6183 "Enclosure Management", /* 06h */
6184 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006185 };
6186 static char *pl_code_str[] = {
6187 NULL, /* 00h */
6188 "Open Failure", /* 01h */
6189 "Invalid Scatter Gather List", /* 02h */
6190 "Wrong Relative Offset or Frame Length", /* 03h */
6191 "Frame Transfer Error", /* 04h */
6192 "Transmit Frame Connected Low", /* 05h */
6193 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6194 "SATA Read Log Receive Data Error", /* 07h */
6195 "SATA NCQ Fail All Commands After Error", /* 08h */
6196 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6197 "Receive Frame Invalid Message", /* 0Ah */
6198 "Receive Context Message Valid Error", /* 0Bh */
6199 "Receive Frame Current Frame Error", /* 0Ch */
6200 "SATA Link Down", /* 0Dh */
6201 "Discovery SATA Init W IOS", /* 0Eh */
6202 "Config Invalid Page", /* 0Fh */
6203 "Discovery SATA Init Timeout", /* 10h */
6204 "Reset", /* 11h */
6205 "Abort", /* 12h */
6206 "IO Not Yet Executed", /* 13h */
6207 "IO Executed", /* 14h */
Jan Engelhardt03a67a42006-11-30 05:32:19 +01006208 "Persistent Reservation Out Not Affiliation Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006209 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006210 "IO Device Missing Delay Retry", /* 17h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006211 NULL, /* 18h */
6212 NULL, /* 19h */
6213 NULL, /* 1Ah */
6214 NULL, /* 1Bh */
6215 NULL, /* 1Ch */
6216 NULL, /* 1Dh */
6217 NULL, /* 1Eh */
6218 NULL, /* 1Fh */
6219 "Enclosure Management" /* 20h */
6220 };
6221
6222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006223/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006224 * mpt_sas_log_info - Log information returned from SAS IOC.
6225 * @ioc: Pointer to MPT_ADAPTER structure
6226 * @log_info: U32 LogInfo reply word from the IOC
6227 *
6228 * Refer to lsi/mpi_log_sas.h.
6229 */
6230static void
6231mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6232{
6233union loginfo_type {
6234 u32 loginfo;
6235 struct {
6236 u32 subcode:16;
6237 u32 code:8;
6238 u32 originator:4;
6239 u32 bus_type:4;
6240 }dw;
6241};
6242 union loginfo_type sas_loginfo;
6243 char *code_desc = NULL;
6244
6245 sas_loginfo.loginfo = log_info;
6246 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6247 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6248 return;
6249 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6250 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6251 code_desc = iop_code_str[sas_loginfo.dw.code];
6252 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6253 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6254 code_desc = pl_code_str[sas_loginfo.dw.code];
6255 }
6256
6257 if (code_desc != NULL)
6258 printk(MYIOC_s_INFO_FMT
6259 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6260 " SubCode(0x%04x)\n",
6261 ioc->name,
6262 log_info,
6263 originator_str[sas_loginfo.dw.originator],
6264 code_desc,
6265 sas_loginfo.dw.subcode);
6266 else
6267 printk(MYIOC_s_INFO_FMT
6268 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6269 " SubCode(0x%04x)\n",
6270 ioc->name,
6271 log_info,
6272 originator_str[sas_loginfo.dw.originator],
6273 sas_loginfo.dw.code,
6274 sas_loginfo.dw.subcode);
6275}
6276
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006278/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6280 * @ioc: Pointer to MPT_ADAPTER structure
6281 * @ioc_status: U32 IOCStatus word from IOC
6282 * @mf: Pointer to MPT request frame
6283 *
6284 * Refer to lsi/mpi.h.
6285 */
6286static void
6287mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6288{
6289 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06006290 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291
6292 switch (status) {
6293 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6294 desc = "Invalid Function";
6295 break;
6296
6297 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6298 desc = "Busy";
6299 break;
6300
6301 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6302 desc = "Invalid SGL";
6303 break;
6304
6305 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6306 desc = "Internal Error";
6307 break;
6308
6309 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6310 desc = "Reserved";
6311 break;
6312
6313 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6314 desc = "Insufficient Resources";
6315 break;
6316
6317 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6318 desc = "Invalid Field";
6319 break;
6320
6321 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6322 desc = "Invalid State";
6323 break;
6324
6325 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6326 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6327 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6328 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6329 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6330 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6331 /* No message for Config IOCStatus values */
6332 break;
6333
6334 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6335 /* No message for recovered error
6336 desc = "SCSI Recovered Error";
6337 */
6338 break;
6339
6340 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6341 desc = "SCSI Invalid Bus";
6342 break;
6343
6344 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6345 desc = "SCSI Invalid TargetID";
6346 break;
6347
6348 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6349 {
6350 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6351 U8 cdb = pScsiReq->CDB[0];
6352 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6353 desc = "SCSI Device Not There";
6354 }
6355 break;
6356 }
6357
6358 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6359 desc = "SCSI Data Overrun";
6360 break;
6361
6362 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006363 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 desc = "SCSI Data Underrun";
6365 */
6366 break;
6367
6368 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6369 desc = "SCSI I/O Data Error";
6370 break;
6371
6372 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6373 desc = "SCSI Protocol Error";
6374 break;
6375
6376 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6377 desc = "SCSI Task Terminated";
6378 break;
6379
6380 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6381 desc = "SCSI Residual Mismatch";
6382 break;
6383
6384 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6385 desc = "SCSI Task Management Failed";
6386 break;
6387
6388 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6389 desc = "SCSI IOC Terminated";
6390 break;
6391
6392 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6393 desc = "SCSI Ext Terminated";
6394 break;
6395
6396 default:
6397 desc = "Others";
6398 break;
6399 }
Eric Moore4f766dc2006-07-11 17:24:07 -06006400 if (desc != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6402}
6403
6404/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006405EXPORT_SYMBOL(mpt_attach);
6406EXPORT_SYMBOL(mpt_detach);
6407#ifdef CONFIG_PM
6408EXPORT_SYMBOL(mpt_resume);
6409EXPORT_SYMBOL(mpt_suspend);
6410#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006412EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413EXPORT_SYMBOL(mpt_register);
6414EXPORT_SYMBOL(mpt_deregister);
6415EXPORT_SYMBOL(mpt_event_register);
6416EXPORT_SYMBOL(mpt_event_deregister);
6417EXPORT_SYMBOL(mpt_reset_register);
6418EXPORT_SYMBOL(mpt_reset_deregister);
6419EXPORT_SYMBOL(mpt_device_driver_register);
6420EXPORT_SYMBOL(mpt_device_driver_deregister);
6421EXPORT_SYMBOL(mpt_get_msg_frame);
6422EXPORT_SYMBOL(mpt_put_msg_frame);
6423EXPORT_SYMBOL(mpt_free_msg_frame);
6424EXPORT_SYMBOL(mpt_add_sge);
6425EXPORT_SYMBOL(mpt_send_handshake_request);
6426EXPORT_SYMBOL(mpt_verify_adapter);
6427EXPORT_SYMBOL(mpt_GetIocState);
6428EXPORT_SYMBOL(mpt_print_ioc_summary);
6429EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006430EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431EXPORT_SYMBOL(mpt_HardResetHandler);
6432EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434EXPORT_SYMBOL(mpt_alloc_fw_memory);
6435EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006436EXPORT_SYMBOL(mptbase_sas_persist_operation);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006439/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 * fusion_init - Fusion MPT base driver initialization routine.
6441 *
6442 * Returns 0 for success, non-zero for failure.
6443 */
6444static int __init
6445fusion_init(void)
6446{
6447 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448
6449 show_mptmod_ver(my_NAME, my_VERSION);
6450 printk(KERN_INFO COPYRIGHT "\n");
6451
6452 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6453 MptCallbacks[i] = NULL;
6454 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6455 MptEvHandlers[i] = NULL;
6456 MptResetHandlers[i] = NULL;
6457 }
6458
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006459 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460 * EventNotification handling.
6461 */
6462 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6463
6464 /* Register for hard reset handling callbacks.
6465 */
6466 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6467 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6468 } else {
6469 /* FIXME! */
6470 }
6471
6472#ifdef CONFIG_PROC_FS
6473 (void) procmpt_create();
6474#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006475 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476}
6477
6478/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006479/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480 * fusion_exit - Perform driver unload cleanup.
6481 *
6482 * This routine frees all resources associated with each MPT adapter
6483 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6484 */
6485static void __exit
6486fusion_exit(void)
6487{
6488
6489 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6490
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 mpt_reset_deregister(mpt_base_index);
6492
6493#ifdef CONFIG_PROC_FS
6494 procmpt_destroy();
6495#endif
6496}
6497
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498module_init(fusion_init);
6499module_exit(fusion_exit);