blob: 642a61b6d0a4ebd3a89732c002a071dc633156ce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008 * Copyright (c) 1999-2005 LSI Logic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * (mailto:mpt_linux_developer@lsil.com)
10 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
49#include <linux/config.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/errno.h>
53#include <linux/init.h>
54#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66#ifdef __sparc__
67#include <asm/irq.h> /* needed for __irq_itoa() proto */
68#endif
69
70#include "mptbase.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
80
81/*
82 * cmd line parameters
83 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000084static int mpt_msi_enable;
85module_param(mpt_msi_enable, int, 0);
86MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#ifdef MFCNT
89static int mfcounter = 0;
90#define PRINT_MF_COUNT 20000
91#endif
92
93/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
94/*
95 * Public data...
96 */
97int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080098int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Linus Torvaldsf7473072005-11-29 14:21:57 -0800100struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102#define WHOINIT_UNKNOWN 0xAA
103
104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
105/*
106 * Private data...
107 */
108 /* Adapter link list */
109LIST_HEAD(ioc_list);
110 /* Callback lookup table */
111static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
112 /* Protocol driver class lookup table */
113static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
114 /* Event handler lookup table */
115static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116 /* Reset handler lookup table */
117static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
118static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
119
120static int mpt_base_index = -1;
121static int last_drv_idx = -1;
122
123static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Forward protos...
128 */
129static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
130static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
131static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
132 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
133 int sleepFlag);
134static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
135static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
136static void mpt_adapter_disable(MPT_ADAPTER *ioc);
137static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
138
139static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
140static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
142static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
143static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
144static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
145static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200146static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
148static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
149static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
150static int PrimeIocFifos(MPT_ADAPTER *ioc);
151static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
152static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
153static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
154static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200156int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
158static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
159static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
160static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
161static void mpt_timer_expired(unsigned long data);
162static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
163static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200164static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
165static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167#ifdef CONFIG_PROC_FS
168static int procmpt_summary_read(char *buf, char **start, off_t offset,
169 int request, int *eof, void *data);
170static int procmpt_version_read(char *buf, char **start, off_t offset,
171 int request, int *eof, void *data);
172static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
173 int request, int *eof, void *data);
174#endif
175static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
176
177//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
178static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
179static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
180static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700181static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600182static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int __init fusion_init (void);
186static void __exit fusion_exit (void);
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#define CHIPREG_READ32(addr) readl_relaxed(addr)
189#define CHIPREG_READ32_dmasync(addr) readl(addr)
190#define CHIPREG_WRITE32(addr,val) writel(val, addr)
191#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
192#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
193
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600194static void
195pci_disable_io_access(struct pci_dev *pdev)
196{
197 u16 command_reg;
198
199 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
200 command_reg &= ~1;
201 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
202}
203
204static void
205pci_enable_io_access(struct pci_dev *pdev)
206{
207 u16 command_reg;
208
209 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
210 command_reg |= 1;
211 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
212}
213
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600214/*
215 * Process turbo (context) reply...
216 */
217static void
218mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
219{
220 MPT_FRAME_HDR *mf = NULL;
221 MPT_FRAME_HDR *mr = NULL;
222 int req_idx = 0;
223 int cb_idx;
224
225 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
226 ioc->name, pa));
227
228 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
229 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
230 req_idx = pa & 0x0000FFFF;
231 cb_idx = (pa & 0x00FF0000) >> 16;
232 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
233 break;
234 case MPI_CONTEXT_REPLY_TYPE_LAN:
235 cb_idx = mpt_lan_index;
236 /*
237 * Blind set of mf to NULL here was fatal
238 * after lan_reply says "freeme"
239 * Fix sort of combined with an optimization here;
240 * added explicit check for case where lan_reply
241 * was just returning 1 and doing nothing else.
242 * For this case skip the callback, but set up
243 * proper mf value first here:-)
244 */
245 if ((pa & 0x58000000) == 0x58000000) {
246 req_idx = pa & 0x0000FFFF;
247 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
248 mpt_free_msg_frame(ioc, mf);
249 mb();
250 return;
251 break;
252 }
253 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
254 break;
255 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
256 cb_idx = mpt_stm_index;
257 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
258 break;
259 default:
260 cb_idx = 0;
261 BUG();
262 }
263
264 /* Check for (valid) IO callback! */
265 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
266 MptCallbacks[cb_idx] == NULL) {
267 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
268 __FUNCTION__, ioc->name, cb_idx);
269 goto out;
270 }
271
272 if (MptCallbacks[cb_idx](ioc, mf, mr))
273 mpt_free_msg_frame(ioc, mf);
274 out:
275 mb();
276}
277
278static void
279mpt_reply(MPT_ADAPTER *ioc, u32 pa)
280{
281 MPT_FRAME_HDR *mf;
282 MPT_FRAME_HDR *mr;
283 int req_idx;
284 int cb_idx;
285 int freeme;
286
287 u32 reply_dma_low;
288 u16 ioc_stat;
289
290 /* non-TURBO reply! Hmmm, something may be up...
291 * Newest turbo reply mechanism; get address
292 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
293 */
294
295 /* Map DMA address of reply header to cpu address.
296 * pa is 32 bits - but the dma address may be 32 or 64 bits
297 * get offset based only only the low addresses
298 */
299
300 reply_dma_low = (pa <<= 1);
301 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
302 (reply_dma_low - ioc->reply_frames_low_dma));
303
304 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
305 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
306 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
307
308 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
309 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
310 DBG_DUMP_REPLY_FRAME(mr)
311
312 /* Check/log IOC log info
313 */
314 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
315 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
316 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
317 if (ioc->bus_type == FC)
318 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700319 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700320 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600321 else if (ioc->bus_type == SAS)
322 mpt_sas_log_info(ioc, log_info);
323 }
324 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700325 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600326 cb_idx != mpt_stm_index &&
327 cb_idx != mpt_lan_index)
328 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
329 }
330
331
332 /* Check for (valid) IO callback! */
333 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
334 MptCallbacks[cb_idx] == NULL) {
335 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
336 __FUNCTION__, ioc->name, cb_idx);
337 freeme = 0;
338 goto out;
339 }
340
341 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
342
343 out:
344 /* Flush (non-TURBO) reply with a WRITE! */
345 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
346
347 if (freeme)
348 mpt_free_msg_frame(ioc, mf);
349 mb();
350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
353/*
354 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
355 * @irq: irq number (not used)
356 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
357 * @r: pt_regs pointer (not used)
358 *
359 * This routine is registered via the request_irq() kernel API call,
360 * and handles all interrupts generated from a specific MPT adapter
361 * (also referred to as a IO Controller or IOC).
362 * This routine must clear the interrupt from the adapter and does
363 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200364 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 *
366 * This routine handles register-level access of the adapter but
367 * dispatches (calls) a protocol-specific callback routine to handle
368 * the protocol-specific details of the MPT request completion.
369 */
370static irqreturn_t
371mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
372{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 MPT_ADAPTER *ioc = bus_id;
374 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /*
377 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 */
379 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600380 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
381 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600383 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
384 mpt_reply(ioc, pa);
385 else
386 mpt_turbo_reply(ioc, pa);
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 return IRQ_HANDLED;
390}
391
392/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
393/*
394 * mpt_base_reply - MPT base driver's callback routine; all base driver
395 * "internal" request/reply processing is routed here.
396 * Currently used for EventNotification and EventAck handling.
397 * @ioc: Pointer to MPT_ADAPTER structure
398 * @mf: Pointer to original MPT request frame
399 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
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? */
431 devtprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
432 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 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
442 ioc->name, pEvReply));
443 } else {
444 devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
445 ioc->name, pEvReply));
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
448#ifdef CONFIG_PROC_FS
449// LogEvent(ioc, pEvReply);
450#endif
451
452 } else if (func == MPI_FUNCTION_EVENT_ACK) {
453 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
454 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700455 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 CONFIGPARMS *pCfg;
457 unsigned long flags;
458
459 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
460 ioc->name, mf, reply));
461
462 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
463
464 if (pCfg) {
465 /* disable timer and remove from linked list */
466 del_timer(&pCfg->timer);
467
468 spin_lock_irqsave(&ioc->FreeQlock, flags);
469 list_del(&pCfg->linkage);
470 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
471
472 /*
473 * If IOC Status is SUCCESS, save the header
474 * and set the status code to GOOD.
475 */
476 pCfg->status = MPT_CONFIG_ERROR;
477 if (reply) {
478 ConfigReply_t *pReply = (ConfigReply_t *)reply;
479 u16 status;
480
481 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
482 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
483 status, le32_to_cpu(pReply->IOCLogInfo)));
484
485 pCfg->status = status;
486 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200487 if ((pReply->Header.PageType &
488 MPI_CONFIG_PAGETYPE_MASK) ==
489 MPI_CONFIG_PAGETYPE_EXTENDED) {
490 pCfg->cfghdr.ehdr->ExtPageLength =
491 le16_to_cpu(pReply->ExtPageLength);
492 pCfg->cfghdr.ehdr->ExtPageType =
493 pReply->ExtPageType;
494 }
495 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
496
497 /* If this is a regular header, save PageLength. */
498 /* LMP Do this better so not using a reserved field! */
499 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
500 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
501 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
503 }
504
505 /*
506 * Wake up the original calling thread
507 */
508 pCfg->wait_done = 1;
509 wake_up(&mpt_waitq);
510 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200511 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
512 /* we should be always getting a reply frame */
513 memcpy(ioc->persist_reply_frame, reply,
514 min(MPT_DEFAULT_FRAME_SIZE,
515 4*reply->u.reply.MsgLength));
516 del_timer(&ioc->persist_timer);
517 ioc->persist_wait_done = 1;
518 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 } else {
520 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
521 ioc->name, func);
522 }
523
524 /*
525 * Conditionally tell caller to free the original
526 * EventNotification/EventAck/unexpected request frame!
527 */
528 return freereq;
529}
530
531/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
532/**
533 * mpt_register - Register protocol-specific main callback handler.
534 * @cbfunc: callback function pointer
535 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
536 *
537 * This routine is called by a protocol-specific driver (SCSI host,
538 * LAN, SCSI target) to register it's reply callback routine. Each
539 * protocol-specific driver must do this before it will be able to
540 * use any IOC resources, such as obtaining request frames.
541 *
542 * NOTES: The SCSI protocol driver currently calls this routine thrice
543 * in order to register separate callbacks; one for "normal" SCSI IO;
544 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
545 *
546 * Returns a positive integer valued "handle" in the
547 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
548 * Any non-positive return value (including zero!) should be considered
549 * an error by the caller.
550 */
551int
552mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
553{
554 int i;
555
556 last_drv_idx = -1;
557
558 /*
559 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
560 * (slot/handle 0 is reserved!)
561 */
562 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
563 if (MptCallbacks[i] == NULL) {
564 MptCallbacks[i] = cbfunc;
565 MptDriverClass[i] = dclass;
566 MptEvHandlers[i] = NULL;
567 last_drv_idx = i;
568 break;
569 }
570 }
571
572 return last_drv_idx;
573}
574
575/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
576/**
577 * mpt_deregister - Deregister a protocol drivers resources.
578 * @cb_idx: previously registered callback handle
579 *
580 * Each protocol-specific driver should call this routine when it's
581 * module is unloaded.
582 */
583void
584mpt_deregister(int cb_idx)
585{
586 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
587 MptCallbacks[cb_idx] = NULL;
588 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
589 MptEvHandlers[cb_idx] = NULL;
590
591 last_drv_idx++;
592 }
593}
594
595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
596/**
597 * mpt_event_register - Register protocol-specific event callback
598 * handler.
599 * @cb_idx: previously registered (via mpt_register) callback handle
600 * @ev_cbfunc: callback function
601 *
602 * This routine can be called by one or more protocol-specific drivers
603 * if/when they choose to be notified of MPT events.
604 *
605 * Returns 0 for success.
606 */
607int
608mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
609{
610 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
611 return -1;
612
613 MptEvHandlers[cb_idx] = ev_cbfunc;
614 return 0;
615}
616
617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
618/**
619 * mpt_event_deregister - Deregister protocol-specific event callback
620 * handler.
621 * @cb_idx: previously registered callback handle
622 *
623 * Each protocol-specific driver should call this routine
624 * when it does not (or can no longer) handle events,
625 * or when it's module is unloaded.
626 */
627void
628mpt_event_deregister(int cb_idx)
629{
630 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
631 return;
632
633 MptEvHandlers[cb_idx] = NULL;
634}
635
636/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
637/**
638 * mpt_reset_register - Register protocol-specific IOC reset handler.
639 * @cb_idx: previously registered (via mpt_register) callback handle
640 * @reset_func: reset function
641 *
642 * This routine can be called by one or more protocol-specific drivers
643 * if/when they choose to be notified of IOC resets.
644 *
645 * Returns 0 for success.
646 */
647int
648mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
649{
650 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
651 return -1;
652
653 MptResetHandlers[cb_idx] = reset_func;
654 return 0;
655}
656
657/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
658/**
659 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
660 * @cb_idx: previously registered callback handle
661 *
662 * Each protocol-specific driver should call this routine
663 * when it does not (or can no longer) handle IOC reset handling,
664 * or when it's module is unloaded.
665 */
666void
667mpt_reset_deregister(int cb_idx)
668{
669 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
670 return;
671
672 MptResetHandlers[cb_idx] = NULL;
673}
674
675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
676/**
677 * mpt_device_driver_register - Register device driver hooks
678 */
679int
680mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
681{
682 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400685 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
687
688 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
689
690 /* call per pci device probe entry point */
691 list_for_each_entry(ioc, &ioc_list, list) {
692 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400693 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
696 }
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
704 */
705void
706mpt_device_driver_deregister(int cb_idx)
707{
708 struct mpt_pci_driver *dd_cbfunc;
709 MPT_ADAPTER *ioc;
710
711 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
712 return;
713
714 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
715
716 list_for_each_entry(ioc, &ioc_list, list) {
717 if (dd_cbfunc->remove)
718 dd_cbfunc->remove(ioc->pcidev);
719 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 MptDeviceDriverHandlers[cb_idx] = NULL;
722}
723
724
725/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
726/**
727 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
728 * allocated per MPT adapter.
729 * @handle: Handle of registered MPT protocol driver
730 * @ioc: Pointer to MPT adapter structure
731 *
732 * Returns pointer to a MPT request frame or %NULL if none are available
733 * or IOC is not active.
734 */
735MPT_FRAME_HDR*
736mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
737{
738 MPT_FRAME_HDR *mf;
739 unsigned long flags;
740 u16 req_idx; /* Request index */
741
742 /* validate handle and ioc identifier */
743
744#ifdef MFCNT
745 if (!ioc->active)
746 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
747#endif
748
749 /* If interrupts are not attached, do not return a request frame */
750 if (!ioc->active)
751 return NULL;
752
753 spin_lock_irqsave(&ioc->FreeQlock, flags);
754 if (!list_empty(&ioc->FreeQ)) {
755 int req_offset;
756
757 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
758 u.frame.linkage.list);
759 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200760 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
762 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
763 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500764 req_idx = req_offset / ioc->req_sz;
765 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
767 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
768#ifdef MFCNT
769 ioc->mfcnt++;
770#endif
771 }
772 else
773 mf = NULL;
774 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
775
776#ifdef MFCNT
777 if (mf == NULL)
778 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
779 mfcounter++;
780 if (mfcounter == PRINT_MF_COUNT)
781 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
782#endif
783
784 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
785 ioc->name, handle, ioc->id, mf));
786 return mf;
787}
788
789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
790/**
791 * mpt_put_msg_frame - Send a protocol specific MPT request frame
792 * to a IOC.
793 * @handle: Handle of registered MPT protocol driver
794 * @ioc: Pointer to MPT adapter structure
795 * @mf: Pointer to MPT request frame
796 *
797 * This routine posts a MPT request frame to the request post FIFO of a
798 * specific MPT adapter.
799 */
800void
801mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
802{
803 u32 mf_dma_addr;
804 int req_offset;
805 u16 req_idx; /* Request index */
806
807 /* ensure values are reset properly! */
808 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
809 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
810 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500811 req_idx = req_offset / ioc->req_sz;
812 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
814
815#ifdef MPT_DEBUG_MSG_FRAME
816 {
817 u32 *m = mf->u.frame.hwhdr.__hdr;
818 int ii, n;
819
820 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
821 ioc->name, m);
822 n = ioc->req_sz/4 - 1;
823 while (m[n] == 0)
824 n--;
825 for (ii=0; ii<=n; ii++) {
826 if (ii && ((ii%8)==0))
827 printk("\n" KERN_INFO " ");
828 printk(" %08x", le32_to_cpu(m[ii]));
829 }
830 printk("\n");
831 }
832#endif
833
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200834 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 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]));
836 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
837}
838
839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
840/**
841 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
842 * @handle: Handle of registered MPT protocol driver
843 * @ioc: Pointer to MPT adapter structure
844 * @mf: Pointer to MPT request frame
845 *
846 * This routine places a MPT request frame back on the MPT adapter's
847 * FreeQ.
848 */
849void
850mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
851{
852 unsigned long flags;
853
854 /* Put Request back on FreeQ! */
855 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200856 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
858#ifdef MFCNT
859 ioc->mfcnt--;
860#endif
861 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
862}
863
864/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
865/**
866 * mpt_add_sge - Place a simple SGE at address pAddr.
867 * @pAddr: virtual address for SGE
868 * @flagslength: SGE flags and data transfer length
869 * @dma_addr: Physical address
870 *
871 * This routine places a MPT request frame back on the MPT adapter's
872 * FreeQ.
873 */
874void
875mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
876{
877 if (sizeof(dma_addr_t) == sizeof(u64)) {
878 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
879 u32 tmp = dma_addr & 0xFFFFFFFF;
880
881 pSge->FlagsLength = cpu_to_le32(flagslength);
882 pSge->Address.Low = cpu_to_le32(tmp);
883 tmp = (u32) ((u64)dma_addr >> 32);
884 pSge->Address.High = cpu_to_le32(tmp);
885
886 } else {
887 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
888 pSge->FlagsLength = cpu_to_le32(flagslength);
889 pSge->Address = cpu_to_le32(dma_addr);
890 }
891}
892
893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
894/**
895 * mpt_send_handshake_request - Send MPT request via doorbell
896 * handshake method.
897 * @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 Hellwig82ffb6712005-09-09 16:25:54 +0200983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return r;
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
988/**
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200989 * mpt_host_page_access_control - provides mechanism for the host
990 * driver to control the IOC's Host Page Buffer access.
991 * @ioc: Pointer to MPT adapter structure
992 * @access_control_value: define bits below
993 *
994 * Access Control Value - bits[15:12]
995 * 0h Reserved
996 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
997 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
998 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
999 *
1000 * Returns 0 for success, non-zero for failure.
1001 */
1002
1003static int
1004mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1005{
1006 int r = 0;
1007
1008 /* return if in use */
1009 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1010 & MPI_DOORBELL_ACTIVE)
1011 return -1;
1012
1013 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1014
1015 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1016 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1017 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1018 (access_control_value<<12)));
1019
1020 /* Wait for IOC to clear Doorbell Status bit */
1021 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1022 return -2;
1023 }else
1024 return 0;
1025}
1026
1027/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1028/**
1029 * mpt_host_page_alloc - allocate system memory for the fw
1030 * If we already allocated memory in past, then resend the same pointer.
1031 * ioc@: Pointer to pointer to IOC adapter
1032 * ioc_init@: Pointer to ioc init config page
1033 *
1034 * Returns 0 for success, non-zero for failure.
1035 */
1036static int
1037mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1038{
1039 char *psge;
1040 int flags_length;
1041 u32 host_page_buffer_sz=0;
1042
1043 if(!ioc->HostPageBuffer) {
1044
1045 host_page_buffer_sz =
1046 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1047
1048 if(!host_page_buffer_sz)
1049 return 0; /* fw doesn't need any host buffers */
1050
1051 /* spin till we get enough memory */
1052 while(host_page_buffer_sz > 0) {
1053
1054 if((ioc->HostPageBuffer = pci_alloc_consistent(
1055 ioc->pcidev,
1056 host_page_buffer_sz,
1057 &ioc->HostPageBuffer_dma)) != NULL) {
1058
1059 dinitprintk((MYIOC_s_INFO_FMT
1060 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1061 ioc->name,
1062 ioc->HostPageBuffer,
1063 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001064 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001065 ioc->alloc_total += host_page_buffer_sz;
1066 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1067 break;
1068 }
1069
1070 host_page_buffer_sz -= (4*1024);
1071 }
1072 }
1073
1074 if(!ioc->HostPageBuffer) {
1075 printk(MYIOC_s_ERR_FMT
1076 "Failed to alloc memory for host_page_buffer!\n",
1077 ioc->name);
1078 return -999;
1079 }
1080
1081 psge = (char *)&ioc_init->HostPageBufferSGE;
1082 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1083 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1084 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1085 MPI_SGE_FLAGS_HOST_TO_IOC |
1086 MPI_SGE_FLAGS_END_OF_BUFFER;
1087 if (sizeof(dma_addr_t) == sizeof(u64)) {
1088 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1089 }
1090 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1091 flags_length |= ioc->HostPageBuffer_sz;
1092 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1093 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1094
1095return 0;
1096}
1097
1098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1099/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1101 * the associated MPT adapter structure.
1102 * @iocid: IOC unique identifier (integer)
1103 * @iocpp: Pointer to pointer to IOC adapter
1104 *
1105 * Returns iocid and sets iocpp.
1106 */
1107int
1108mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1109{
1110 MPT_ADAPTER *ioc;
1111
1112 list_for_each_entry(ioc,&ioc_list,list) {
1113 if (ioc->id == iocid) {
1114 *iocpp =ioc;
1115 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 *iocpp = NULL;
1120 return -1;
1121}
1122
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001123int
1124mpt_alt_ioc_wait(MPT_ADAPTER *ioc)
1125{
1126 int loop_count = 30 * 4; /* Wait 30 seconds */
1127 int status = -1; /* -1 means failed to get board READY */
1128
1129 do {
1130 spin_lock(&ioc->initializing_hba_lock);
1131 if (ioc->initializing_hba_lock_flag == 0) {
1132 ioc->initializing_hba_lock_flag=1;
1133 spin_unlock(&ioc->initializing_hba_lock);
1134 status = 0;
1135 break;
1136 }
1137 spin_unlock(&ioc->initializing_hba_lock);
1138 set_current_state(TASK_INTERRUPTIBLE);
1139 schedule_timeout(HZ/4);
1140 } while (--loop_count);
1141
1142 return status;
1143}
1144
1145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1146/*
1147 * mpt_bringup_adapter - This is a wrapper function for mpt_do_ioc_recovery
1148 * @ioc: Pointer to MPT adapter structure
1149 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1150 *
1151 * This routine performs all the steps necessary to bring the IOC
1152 * to a OPERATIONAL state.
1153 *
1154 * Special Note: This function was added with spin lock's so as to allow
1155 * the dv(domain validation) work thread to succeed on the other channel
1156 * that maybe occuring at the same time when this function is called.
1157 * Without this lock, the dv would fail when message frames were
1158 * requested during hba bringup on the alternate ioc.
1159 */
1160static int
1161mpt_bringup_adapter(MPT_ADAPTER *ioc, int sleepFlag)
1162{
1163 int r;
1164
1165 if(ioc->alt_ioc) {
1166 if((r=mpt_alt_ioc_wait(ioc->alt_ioc)!=0))
1167 return r;
1168 }
1169
1170 r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1171 CAN_SLEEP);
1172
1173 if(ioc->alt_ioc) {
1174 spin_lock(&ioc->alt_ioc->initializing_hba_lock);
1175 ioc->alt_ioc->initializing_hba_lock_flag=0;
1176 spin_unlock(&ioc->alt_ioc->initializing_hba_lock);
1177 }
1178
1179return r;
1180}
1181
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1183/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001184 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 * @pdev: Pointer to pci_dev structure
1186 *
1187 * This routine performs all the steps necessary to bring the IOC of
1188 * a MPT adapter to a OPERATIONAL state. This includes registering
1189 * memory regions, registering the interrupt, and allocating request
1190 * and reply memory pools.
1191 *
1192 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1193 * MPT adapter.
1194 *
1195 * Returns 0 for success, non-zero for failure.
1196 *
1197 * TODO: Add support for polled controllers
1198 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001199int
1200mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 MPT_ADAPTER *ioc;
1203 u8 __iomem *mem;
1204 unsigned long mem_phys;
1205 unsigned long port;
1206 u32 msize;
1207 u32 psize;
1208 int ii;
1209 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 u8 revision;
1211 u8 pcixcmd;
1212 static int mpt_ids = 0;
1213#ifdef CONFIG_PROC_FS
1214 struct proc_dir_entry *dent, *ent;
1215#endif
1216
1217 if (pci_enable_device(pdev))
1218 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001221
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001222 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 dprintk((KERN_INFO MYNAM
1224 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001225 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1227 return r;
1228 }
1229
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001230 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 dprintk((KERN_INFO MYNAM
1232 ": Using 64 bit consistent mask\n"));
1233 else
1234 dprintk((KERN_INFO MYNAM
1235 ": Not using 64 bit consistent mask\n"));
1236
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001237 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 if (ioc == NULL) {
1239 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1240 return -ENOMEM;
1241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 ioc->alloc_total = sizeof(MPT_ADAPTER);
1243 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1244 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 ioc->pcidev = pdev;
1247 ioc->diagPending = 0;
1248 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001249 spin_lock_init(&ioc->fc_rescan_work_lock);
1250 spin_lock_init(&ioc->fc_rport_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001251 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253 /* Initialize the event logging.
1254 */
1255 ioc->eventTypes = 0; /* None */
1256 ioc->eventContext = 0;
1257 ioc->eventLogSize = 0;
1258 ioc->events = NULL;
1259
1260#ifdef MFCNT
1261 ioc->mfcnt = 0;
1262#endif
1263
1264 ioc->cached_fw = NULL;
1265
1266 /* Initilize SCSI Config Data structure
1267 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001268 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 /* Initialize the running configQ head.
1271 */
1272 INIT_LIST_HEAD(&ioc->configQ);
1273
Michael Reed05e8ec12006-01-13 14:31:54 -06001274 /* Initialize the fc rport list head.
1275 */
1276 INIT_LIST_HEAD(&ioc->fc_rports);
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 /* Find lookup slot. */
1279 INIT_LIST_HEAD(&ioc->list);
1280 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 mem_phys = msize = 0;
1283 port = psize = 0;
1284 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1285 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1286 /* Get I/O space! */
1287 port = pci_resource_start(pdev, ii);
1288 psize = pci_resource_len(pdev,ii);
1289 } else {
1290 /* Get memmap */
1291 mem_phys = pci_resource_start(pdev, ii);
1292 msize = pci_resource_len(pdev,ii);
1293 break;
1294 }
1295 }
1296 ioc->mem_size = msize;
1297
1298 if (ii == DEVICE_COUNT_RESOURCE) {
1299 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1300 kfree(ioc);
1301 return -EINVAL;
1302 }
1303
1304 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1305 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1306
1307 mem = NULL;
1308 /* Get logical ptr for PciMem0 space */
1309 /*mem = ioremap(mem_phys, msize);*/
1310 mem = ioremap(mem_phys, 0x100);
1311 if (mem == NULL) {
1312 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1313 kfree(ioc);
1314 return -EINVAL;
1315 }
1316 ioc->memmap = mem;
1317 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1318
1319 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1320 &ioc->facts, &ioc->pfacts[0]));
1321
1322 ioc->mem_phys = mem_phys;
1323 ioc->chip = (SYSIF_REGS __iomem *)mem;
1324
1325 /* Save Port IO values in case we need to do downloadboot */
1326 {
1327 u8 *pmem = (u8*)port;
1328 ioc->pio_mem_phys = port;
1329 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1330 }
1331
1332 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1333 ioc->prod_name = "LSIFC909";
1334 ioc->bus_type = FC;
1335 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001336 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 ioc->prod_name = "LSIFC929";
1338 ioc->bus_type = FC;
1339 }
1340 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1341 ioc->prod_name = "LSIFC919";
1342 ioc->bus_type = FC;
1343 }
1344 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1345 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1346 ioc->bus_type = FC;
1347 if (revision < XL_929) {
1348 ioc->prod_name = "LSIFC929X";
1349 /* 929X Chip Fix. Set Split transactions level
1350 * for PCIX. Set MOST bits to zero.
1351 */
1352 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1353 pcixcmd &= 0x8F;
1354 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1355 } else {
1356 ioc->prod_name = "LSIFC929XL";
1357 /* 929XL Chip Fix. Set MMRBC to 0x08.
1358 */
1359 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1360 pcixcmd |= 0x08;
1361 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1362 }
1363 }
1364 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1365 ioc->prod_name = "LSIFC919X";
1366 ioc->bus_type = FC;
1367 /* 919X Chip Fix. Set Split transactions level
1368 * for PCIX. Set MOST bits to zero.
1369 */
1370 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1371 pcixcmd &= 0x8F;
1372 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1373 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001374 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1375 ioc->prod_name = "LSIFC939X";
1376 ioc->bus_type = FC;
1377 ioc->errata_flag_1064 = 1;
1378 }
1379 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1380 ioc->prod_name = "LSIFC949X";
1381 ioc->bus_type = FC;
1382 ioc->errata_flag_1064 = 1;
1383 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001384 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1385 ioc->prod_name = "LSIFC949E";
1386 ioc->bus_type = FC;
1387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1389 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001390 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 /* 1030 Chip Fix. Disable Split transactions
1392 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1393 */
1394 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1395 if (revision < C0_1030) {
1396 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1397 pcixcmd &= 0x8F;
1398 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1399 }
1400 }
1401 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1402 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001403 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001405 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1406 ioc->prod_name = "LSISAS1064";
1407 ioc->bus_type = SAS;
1408 ioc->errata_flag_1064 = 1;
1409 }
1410 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1411 ioc->prod_name = "LSISAS1066";
1412 ioc->bus_type = SAS;
1413 ioc->errata_flag_1064 = 1;
1414 }
1415 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1416 ioc->prod_name = "LSISAS1068";
1417 ioc->bus_type = SAS;
1418 ioc->errata_flag_1064 = 1;
1419 }
1420 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1421 ioc->prod_name = "LSISAS1064E";
1422 ioc->bus_type = SAS;
1423 }
1424 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1425 ioc->prod_name = "LSISAS1066E";
1426 ioc->bus_type = SAS;
1427 }
1428 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1429 ioc->prod_name = "LSISAS1068E";
1430 ioc->bus_type = SAS;
1431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001433 if (ioc->errata_flag_1064)
1434 pci_disable_io_access(pdev);
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 sprintf(ioc->name, "ioc%d", ioc->id);
1437
1438 spin_lock_init(&ioc->FreeQlock);
1439
1440 /* Disable all! */
1441 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1442 ioc->active = 0;
1443 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1444
1445 /* Set lookup ptr. */
1446 list_add_tail(&ioc->list, &ioc_list);
1447
1448 ioc->pci_irq = -1;
1449 if (pdev->irq) {
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001450 if (mpt_msi_enable && !pci_enable_msi(pdev))
1451 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1454
1455 if (r < 0) {
1456#ifndef __sparc__
1457 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1458 ioc->name, pdev->irq);
1459#else
1460 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n",
1461 ioc->name, __irq_itoa(pdev->irq));
1462#endif
1463 list_del(&ioc->list);
1464 iounmap(mem);
1465 kfree(ioc);
1466 return -EBUSY;
1467 }
1468
1469 ioc->pci_irq = pdev->irq;
1470
1471 pci_set_master(pdev); /* ?? */
1472 pci_set_drvdata(pdev, ioc);
1473
1474#ifndef __sparc__
1475 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
1476#else
1477 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq)));
1478#endif
1479 }
1480
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001481 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 */
1483 mpt_detect_bound_ports(ioc, pdev);
1484
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001485 if ((r = mpt_bringup_adapter(ioc, CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 printk(KERN_WARNING MYNAM
1487 ": WARNING - %s did not initialize properly! (%d)\n",
1488 ioc->name, r);
1489
1490 list_del(&ioc->list);
1491 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001492 if (mpt_msi_enable)
1493 pci_disable_msi(pdev);
Moore, Eric335a9412006-01-17 17:06:23 -07001494 if (ioc->alt_ioc)
1495 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 iounmap(mem);
1497 kfree(ioc);
1498 pci_set_drvdata(pdev, NULL);
1499 return r;
1500 }
1501
1502 /* call per device driver probe entry point */
1503 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1504 if(MptDeviceDriverHandlers[ii] &&
1505 MptDeviceDriverHandlers[ii]->probe) {
1506 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1507 }
1508 }
1509
1510#ifdef CONFIG_PROC_FS
1511 /*
1512 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1513 */
1514 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1515 if (dent) {
1516 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1517 if (ent) {
1518 ent->read_proc = procmpt_iocinfo_read;
1519 ent->data = ioc;
1520 }
1521 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1522 if (ent) {
1523 ent->read_proc = procmpt_summary_read;
1524 ent->data = ioc;
1525 }
1526 }
1527#endif
1528
1529 return 0;
1530}
1531
1532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1533/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001534 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 * @pdev: Pointer to pci_dev structure
1536 *
1537 */
1538
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001539void
1540mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
1542 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1543 char pname[32];
1544 int ii;
1545
1546 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1547 remove_proc_entry(pname, NULL);
1548 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1549 remove_proc_entry(pname, NULL);
1550 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1551 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* call per device driver remove entry point */
1554 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1555 if(MptDeviceDriverHandlers[ii] &&
1556 MptDeviceDriverHandlers[ii]->remove) {
1557 MptDeviceDriverHandlers[ii]->remove(pdev);
1558 }
1559 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 /* Disable interrupts! */
1562 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1563
1564 ioc->active = 0;
1565 synchronize_irq(pdev->irq);
1566
1567 /* Clear any lingering interrupt */
1568 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1569
1570 CHIPREG_READ32(&ioc->chip->IntStatus);
1571
1572 mpt_adapter_dispose(ioc);
1573
1574 pci_set_drvdata(pdev, NULL);
1575}
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577/**************************************************************************
1578 * Power Management
1579 */
1580#ifdef CONFIG_PM
1581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1582/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001583 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 *
1585 *
1586 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001587int
1588mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
1590 u32 device_state;
1591 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Pavel Machek2a569572005-07-07 17:56:40 -07001593 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 printk(MYIOC_s_INFO_FMT
1596 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1597 ioc->name, pdev, pci_name(pdev), device_state);
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 pci_save_state(pdev);
1600
1601 /* put ioc into READY_STATE */
1602 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1603 printk(MYIOC_s_ERR_FMT
1604 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1605 }
1606
1607 /* disable interrupts */
1608 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1609 ioc->active = 0;
1610
1611 /* Clear any lingering interrupt */
1612 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1613
1614 pci_disable_device(pdev);
1615 pci_set_power_state(pdev, device_state);
1616
1617 return 0;
1618}
1619
1620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1621/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001622 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 *
1624 *
1625 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001626int
1627mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
1629 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1630 u32 device_state = pdev->current_state;
1631 int recovery_state;
1632 int ii;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 printk(MYIOC_s_INFO_FMT
1635 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1636 ioc->name, pdev, pci_name(pdev), device_state);
1637
1638 pci_set_power_state(pdev, 0);
1639 pci_restore_state(pdev);
1640 pci_enable_device(pdev);
1641
1642 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001643 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 ioc->active = 1;
1645
1646 /* F/W not running */
1647 if(!CHIPREG_READ32(&ioc->chip->Doorbell)) {
1648 /* enable domain validation flags */
1649 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
1650 ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV;
1651 }
1652 }
1653
1654 printk(MYIOC_s_INFO_FMT
1655 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1656 ioc->name,
1657 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1658 CHIPREG_READ32(&ioc->chip->Doorbell));
1659
1660 /* bring ioc to operational state */
1661 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1662 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1663 printk(MYIOC_s_INFO_FMT
1664 "pci-resume: Cannot recover, error:[%x]\n",
1665 ioc->name, recovery_state);
1666 } else {
1667 printk(MYIOC_s_INFO_FMT
1668 "pci-resume: success\n", ioc->name);
1669 }
1670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 return 0;
1672}
1673#endif
1674
1675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1676/*
1677 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1678 * @ioc: Pointer to MPT adapter structure
1679 * @reason: Event word / reason
1680 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1681 *
1682 * This routine performs all the steps necessary to bring the IOC
1683 * to a OPERATIONAL state.
1684 *
1685 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1686 * MPT adapter.
1687 *
1688 * Returns:
1689 * 0 for success
1690 * -1 if failed to get board READY
1691 * -2 if READY but IOCFacts Failed
1692 * -3 if READY but PrimeIOCFifos Failed
1693 * -4 if READY but IOCInit Failed
1694 */
1695static int
1696mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1697{
1698 int hard_reset_done = 0;
1699 int alt_ioc_ready = 0;
1700 int hard;
1701 int rc=0;
1702 int ii;
1703 int handlers;
1704 int ret = 0;
1705 int reset_alt_ioc_active = 0;
1706
1707 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1708 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1709
1710 /* Disable reply interrupts (also blocks FreeQ) */
1711 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1712 ioc->active = 0;
1713
1714 if (ioc->alt_ioc) {
1715 if (ioc->alt_ioc->active)
1716 reset_alt_ioc_active = 1;
1717
1718 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1719 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1720 ioc->alt_ioc->active = 0;
1721 }
1722
1723 hard = 1;
1724 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1725 hard = 0;
1726
1727 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1728 if (hard_reset_done == -4) {
1729 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1730 ioc->name);
1731
1732 if (reset_alt_ioc_active && ioc->alt_ioc) {
1733 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1734 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1735 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001736 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 ioc->alt_ioc->active = 1;
1738 }
1739
1740 } else {
1741 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1742 ioc->name);
1743 }
1744 return -1;
1745 }
1746
1747 /* hard_reset_done = 0 if a soft reset was performed
1748 * and 1 if a hard reset was performed.
1749 */
1750 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1751 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1752 alt_ioc_ready = 1;
1753 else
1754 printk(KERN_WARNING MYNAM
1755 ": alt-%s: Not ready WARNING!\n",
1756 ioc->alt_ioc->name);
1757 }
1758
1759 for (ii=0; ii<5; ii++) {
1760 /* Get IOC facts! Allow 5 retries */
1761 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1762 break;
1763 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
1766 if (ii == 5) {
1767 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1768 ret = -2;
1769 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1770 MptDisplayIocCapabilities(ioc);
1771 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 if (alt_ioc_ready) {
1774 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1775 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1776 /* Retry - alt IOC was initialized once
1777 */
1778 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1779 }
1780 if (rc) {
1781 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1782 alt_ioc_ready = 0;
1783 reset_alt_ioc_active = 0;
1784 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1785 MptDisplayIocCapabilities(ioc->alt_ioc);
1786 }
1787 }
1788
1789 /* Prime reply & request queues!
1790 * (mucho alloc's) Must be done prior to
1791 * init as upper addresses are needed for init.
1792 * If fails, continue with alt-ioc processing
1793 */
1794 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1795 ret = -3;
1796
1797 /* May need to check/upload firmware & data here!
1798 * If fails, continue with alt-ioc processing
1799 */
1800 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1801 ret = -4;
1802// NEW!
1803 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1804 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1805 ioc->alt_ioc->name, rc);
1806 alt_ioc_ready = 0;
1807 reset_alt_ioc_active = 0;
1808 }
1809
1810 if (alt_ioc_ready) {
1811 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1812 alt_ioc_ready = 0;
1813 reset_alt_ioc_active = 0;
1814 printk(KERN_WARNING MYNAM
1815 ": alt-%s: (%d) init failure WARNING!\n",
1816 ioc->alt_ioc->name, rc);
1817 }
1818 }
1819
1820 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1821 if (ioc->upload_fw) {
1822 ddlprintk((MYIOC_s_INFO_FMT
1823 "firmware upload required!\n", ioc->name));
1824
1825 /* Controller is not operational, cannot do upload
1826 */
1827 if (ret == 0) {
1828 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001829 if (rc == 0) {
1830 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1831 /*
1832 * Maintain only one pointer to FW memory
1833 * so there will not be two attempt to
1834 * downloadboot onboard dual function
1835 * chips (mpt_adapter_disable,
1836 * mpt_diag_reset)
1837 */
1838 ioc->cached_fw = NULL;
1839 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1840 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1841 }
1842 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001844 ret = -5;
1845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 }
1847 }
1848 }
1849
1850 if (ret == 0) {
1851 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001852 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 ioc->active = 1;
1854 }
1855
1856 if (reset_alt_ioc_active && ioc->alt_ioc) {
1857 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001858 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001860 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 ioc->alt_ioc->active = 1;
1862 }
1863
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001864 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 * and EventAck handling.
1866 */
1867 if ((ret == 0) && (!ioc->facts.EventState))
1868 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1869
1870 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1871 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1872
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001873 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1875 * recursive scenario; GetLanConfigPages times out, timer expired
1876 * routine calls HardResetHandler, which calls into here again,
1877 * and we try GetLanConfigPages again...
1878 */
1879 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001880 if (ioc->bus_type == SAS) {
1881
1882 /* clear persistency table */
1883 if(ioc->facts.IOCExceptions &
1884 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1885 ret = mptbase_sas_persist_operation(ioc,
1886 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1887 if(ret != 0)
1888 return -1;
1889 }
1890
1891 /* Find IM volumes
1892 */
1893 mpt_findImVolumes(ioc);
1894
1895 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 /*
1897 * Pre-fetch FC port WWN and stuff...
1898 * (FCPortPage0_t stuff)
1899 */
1900 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001901 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 }
1903
1904 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1905 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1906 /*
1907 * Pre-fetch the ports LAN MAC address!
1908 * (LANPage1_t stuff)
1909 */
1910 (void) GetLanConfigPages(ioc);
1911#ifdef MPT_DEBUG
1912 {
1913 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1914 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1915 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1916 }
1917#endif
1918 }
1919 } else {
1920 /* Get NVRAM and adapter maximums from SPP 0 and 2
1921 */
1922 mpt_GetScsiPortSettings(ioc, 0);
1923
1924 /* Get version and length of SDP 1
1925 */
1926 mpt_readScsiDevicePageHeaders(ioc, 0);
1927
1928 /* Find IM volumes
1929 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001930 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 mpt_findImVolumes(ioc);
1932
1933 /* Check, and possibly reset, the coalescing value
1934 */
1935 mpt_read_ioc_pg_1(ioc);
1936
1937 mpt_read_ioc_pg_4(ioc);
1938 }
1939
1940 GetIoUnitPage2(ioc);
1941 }
1942
1943 /*
1944 * Call each currently registered protocol IOC reset handler
1945 * with post-reset indication.
1946 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1947 * MptResetHandlers[] registered yet.
1948 */
1949 if (hard_reset_done) {
1950 rc = handlers = 0;
1951 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1952 if ((ret == 0) && MptResetHandlers[ii]) {
1953 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1954 ioc->name, ii));
1955 rc += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
1956 handlers++;
1957 }
1958
1959 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001960 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 ioc->name, ioc->alt_ioc->name, ii));
1962 rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
1963 handlers++;
1964 }
1965 }
1966 /* FIXME? Examine results here? */
1967 }
1968
1969 return ret;
1970}
1971
1972/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1973/*
1974 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1975 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1976 * 929X, 1030 or 1035.
1977 * @ioc: Pointer to MPT adapter structure
1978 * @pdev: Pointer to (struct pci_dev) structure
1979 *
1980 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1981 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1982 */
1983static void
1984mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1985{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001986 struct pci_dev *peer=NULL;
1987 unsigned int slot = PCI_SLOT(pdev->devfn);
1988 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 MPT_ADAPTER *ioc_srch;
1990
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001991 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1992 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001993 ioc->name, pci_name(pdev), pdev->bus->number,
1994 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001995
1996 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1997 if (!peer) {
1998 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1999 if (!peer)
2000 return;
2001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
2003 list_for_each_entry(ioc_srch, &ioc_list, list) {
2004 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002005 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 /* Paranoia checks */
2007 if (ioc->alt_ioc != NULL) {
2008 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002009 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 break;
2011 } else if (ioc_srch->alt_ioc != NULL) {
2012 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002013 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 break;
2015 }
2016 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002017 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 ioc_srch->alt_ioc = ioc;
2019 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
2021 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002022 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023}
2024
2025/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2026/*
2027 * mpt_adapter_disable - Disable misbehaving MPT adapter.
2028 * @this: Pointer to MPT adapter structure
2029 */
2030static void
2031mpt_adapter_disable(MPT_ADAPTER *ioc)
2032{
2033 int sz;
2034 int ret;
2035
2036 if (ioc->cached_fw != NULL) {
2037 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002038 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 printk(KERN_WARNING MYNAM
2040 ": firmware downloadboot failure (%d)!\n", ret);
2041 }
2042 }
2043
2044 /* Disable adapter interrupts! */
2045 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2046 ioc->active = 0;
2047 /* Clear any lingering interrupt */
2048 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2049
2050 if (ioc->alloc != NULL) {
2051 sz = ioc->alloc_sz;
2052 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
2053 ioc->name, ioc->alloc, ioc->alloc_sz));
2054 pci_free_consistent(ioc->pcidev, sz,
2055 ioc->alloc, ioc->alloc_dma);
2056 ioc->reply_frames = NULL;
2057 ioc->req_frames = NULL;
2058 ioc->alloc = NULL;
2059 ioc->alloc_total -= sz;
2060 }
2061
2062 if (ioc->sense_buf_pool != NULL) {
2063 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2064 pci_free_consistent(ioc->pcidev, sz,
2065 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2066 ioc->sense_buf_pool = NULL;
2067 ioc->alloc_total -= sz;
2068 }
2069
2070 if (ioc->events != NULL){
2071 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2072 kfree(ioc->events);
2073 ioc->events = NULL;
2074 ioc->alloc_total -= sz;
2075 }
2076
2077 if (ioc->cached_fw != NULL) {
2078 sz = ioc->facts.FWImageSize;
2079 pci_free_consistent(ioc->pcidev, sz,
2080 ioc->cached_fw, ioc->cached_fw_dma);
2081 ioc->cached_fw = NULL;
2082 ioc->alloc_total -= sz;
2083 }
2084
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002085 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002086 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002087 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002088 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
2090 if (ioc->spi_data.pIocPg4 != NULL) {
2091 sz = ioc->spi_data.IocPg4Sz;
2092 pci_free_consistent(ioc->pcidev, sz,
2093 ioc->spi_data.pIocPg4,
2094 ioc->spi_data.IocPg4_dma);
2095 ioc->spi_data.pIocPg4 = NULL;
2096 ioc->alloc_total -= sz;
2097 }
2098
2099 if (ioc->ReqToChain != NULL) {
2100 kfree(ioc->ReqToChain);
2101 kfree(ioc->RequestNB);
2102 ioc->ReqToChain = NULL;
2103 }
2104
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002105 kfree(ioc->ChainToChain);
2106 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002107
2108 if (ioc->HostPageBuffer != NULL) {
2109 if((ret = mpt_host_page_access_control(ioc,
2110 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2111 printk(KERN_ERR MYNAM
2112 ": %s: host page buffers free failed (%d)!\n",
2113 __FUNCTION__, ret);
2114 }
2115 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2116 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2117 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2118 ioc->HostPageBuffer,
2119 ioc->HostPageBuffer_dma);
2120 ioc->HostPageBuffer = NULL;
2121 ioc->HostPageBuffer_sz = 0;
2122 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124}
2125
2126/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2127/*
2128 * mpt_adapter_dispose - Free all resources associated with a MPT
2129 * adapter.
2130 * @ioc: Pointer to MPT adapter structure
2131 *
2132 * This routine unregisters h/w resources and frees all alloc'd memory
2133 * associated with a MPT adapter structure.
2134 */
2135static void
2136mpt_adapter_dispose(MPT_ADAPTER *ioc)
2137{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002138 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002140 if (ioc == NULL)
2141 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002143 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002145 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002147 if (ioc->pci_irq != -1) {
2148 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002149 if (mpt_msi_enable)
2150 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002151 ioc->pci_irq = -1;
2152 }
2153
2154 if (ioc->memmap != NULL) {
2155 iounmap(ioc->memmap);
2156 ioc->memmap = NULL;
2157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
2159#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002160 if (ioc->mtrr_reg > 0) {
2161 mtrr_del(ioc->mtrr_reg, 0, 0);
2162 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164#endif
2165
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002166 /* Zap the adapter lookup ptr! */
2167 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002169 sz_last = ioc->alloc_total;
2170 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2171 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002172
2173 if (ioc->alt_ioc)
2174 ioc->alt_ioc->alt_ioc = NULL;
2175
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002176 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177}
2178
2179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2180/*
2181 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2182 * @ioc: Pointer to MPT adapter structure
2183 */
2184static void
2185MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2186{
2187 int i = 0;
2188
2189 printk(KERN_INFO "%s: ", ioc->name);
2190 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2191 printk("%s: ", ioc->prod_name+3);
2192 printk("Capabilities={");
2193
2194 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2195 printk("Initiator");
2196 i++;
2197 }
2198
2199 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2200 printk("%sTarget", i ? "," : "");
2201 i++;
2202 }
2203
2204 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2205 printk("%sLAN", i ? "," : "");
2206 i++;
2207 }
2208
2209#if 0
2210 /*
2211 * This would probably evoke more questions than it's worth
2212 */
2213 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2214 printk("%sLogBusAddr", i ? "," : "");
2215 i++;
2216 }
2217#endif
2218
2219 printk("}\n");
2220}
2221
2222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2223/*
2224 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2225 * @ioc: Pointer to MPT_ADAPTER structure
2226 * @force: Force hard KickStart of IOC
2227 * @sleepFlag: Specifies whether the process can sleep
2228 *
2229 * Returns:
2230 * 1 - DIAG reset and READY
2231 * 0 - READY initially OR soft reset and READY
2232 * -1 - Any failure on KickStart
2233 * -2 - Msg Unit Reset Failed
2234 * -3 - IO Unit Reset Failed
2235 * -4 - IOC owned by a PEER
2236 */
2237static int
2238MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2239{
2240 u32 ioc_state;
2241 int statefault = 0;
2242 int cntdn;
2243 int hard_reset_done = 0;
2244 int r;
2245 int ii;
2246 int whoinit;
2247
2248 /* Get current [raw] IOC state */
2249 ioc_state = mpt_GetIocState(ioc, 0);
2250 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2251
2252 /*
2253 * Check to see if IOC got left/stuck in doorbell handshake
2254 * grip of death. If so, hard reset the IOC.
2255 */
2256 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2257 statefault = 1;
2258 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2259 ioc->name);
2260 }
2261
2262 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002263 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 return 0;
2265
2266 /*
2267 * Check to see if IOC is in FAULT state.
2268 */
2269 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2270 statefault = 2;
2271 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2272 ioc->name);
2273 printk(KERN_WARNING " FAULT code = %04xh\n",
2274 ioc_state & MPI_DOORBELL_DATA_MASK);
2275 }
2276
2277 /*
2278 * Hmmm... Did it get left operational?
2279 */
2280 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002281 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 ioc->name));
2283
2284 /* Check WhoInit.
2285 * If PCI Peer, exit.
2286 * Else, if no fault conditions are present, issue a MessageUnitReset
2287 * Else, fall through to KickStart case
2288 */
2289 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002290 dinitprintk((KERN_INFO MYNAM
2291 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 whoinit, statefault, force));
2293 if (whoinit == MPI_WHOINIT_PCI_PEER)
2294 return -4;
2295 else {
2296 if ((statefault == 0 ) && (force == 0)) {
2297 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2298 return 0;
2299 }
2300 statefault = 3;
2301 }
2302 }
2303
2304 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2305 if (hard_reset_done < 0)
2306 return -1;
2307
2308 /*
2309 * Loop here waiting for IOC to come READY.
2310 */
2311 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002312 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2315 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2316 /*
2317 * BIOS or previous driver load left IOC in OP state.
2318 * Reset messaging FIFOs.
2319 */
2320 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2321 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2322 return -2;
2323 }
2324 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2325 /*
2326 * Something is wrong. Try to get IOC back
2327 * to a known state.
2328 */
2329 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2330 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2331 return -3;
2332 }
2333 }
2334
2335 ii++; cntdn--;
2336 if (!cntdn) {
2337 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2338 ioc->name, (int)((ii+5)/HZ));
2339 return -ETIME;
2340 }
2341
2342 if (sleepFlag == CAN_SLEEP) {
2343 msleep_interruptible(1);
2344 } else {
2345 mdelay (1); /* 1 msec delay */
2346 }
2347
2348 }
2349
2350 if (statefault < 3) {
2351 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2352 ioc->name,
2353 statefault==1 ? "stuck handshake" : "IOC FAULT");
2354 }
2355
2356 return hard_reset_done;
2357}
2358
2359/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2360/*
2361 * mpt_GetIocState - Get the current state of a MPT adapter.
2362 * @ioc: Pointer to MPT_ADAPTER structure
2363 * @cooked: Request raw or cooked IOC state
2364 *
2365 * Returns all IOC Doorbell register bits if cooked==0, else just the
2366 * Doorbell bits in MPI_IOC_STATE_MASK.
2367 */
2368u32
2369mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2370{
2371 u32 s, sc;
2372
2373 /* Get! */
2374 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2375// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2376 sc = s & MPI_IOC_STATE_MASK;
2377
2378 /* Save! */
2379 ioc->last_state = sc;
2380
2381 return cooked ? sc : s;
2382}
2383
2384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2385/*
2386 * GetIocFacts - Send IOCFacts request to MPT adapter.
2387 * @ioc: Pointer to MPT_ADAPTER structure
2388 * @sleepFlag: Specifies whether the process can sleep
2389 * @reason: If recovery, only update facts.
2390 *
2391 * Returns 0 for success, non-zero for failure.
2392 */
2393static int
2394GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2395{
2396 IOCFacts_t get_facts;
2397 IOCFactsReply_t *facts;
2398 int r;
2399 int req_sz;
2400 int reply_sz;
2401 int sz;
2402 u32 status, vv;
2403 u8 shiftFactor=1;
2404
2405 /* IOC *must* NOT be in RESET state! */
2406 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2407 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2408 ioc->name,
2409 ioc->last_state );
2410 return -44;
2411 }
2412
2413 facts = &ioc->facts;
2414
2415 /* Destination (reply area)... */
2416 reply_sz = sizeof(*facts);
2417 memset(facts, 0, reply_sz);
2418
2419 /* Request area (get_facts on the stack right now!) */
2420 req_sz = sizeof(get_facts);
2421 memset(&get_facts, 0, req_sz);
2422
2423 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2424 /* Assert: All other get_facts fields are zero! */
2425
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002426 dinitprintk((MYIOC_s_INFO_FMT
2427 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 ioc->name, req_sz, reply_sz));
2429
2430 /* No non-zero fields in the get_facts request are greater than
2431 * 1 byte in size, so we can just fire it off as is.
2432 */
2433 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2434 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2435 if (r != 0)
2436 return r;
2437
2438 /*
2439 * Now byte swap (GRRR) the necessary fields before any further
2440 * inspection of reply contents.
2441 *
2442 * But need to do some sanity checks on MsgLength (byte) field
2443 * to make sure we don't zero IOC's req_sz!
2444 */
2445 /* Did we get a valid reply? */
2446 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2447 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2448 /*
2449 * If not been here, done that, save off first WhoInit value
2450 */
2451 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2452 ioc->FirstWhoInit = facts->WhoInit;
2453 }
2454
2455 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2456 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2457 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2458 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2459 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002460 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 /* CHECKME! IOCStatus, IOCLogInfo */
2462
2463 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2464 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2465
2466 /*
2467 * FC f/w version changed between 1.1 and 1.2
2468 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2469 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2470 */
2471 if (facts->MsgVersion < 0x0102) {
2472 /*
2473 * Handle old FC f/w style, convert to new...
2474 */
2475 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2476 facts->FWVersion.Word =
2477 ((oldv<<12) & 0xFF000000) |
2478 ((oldv<<8) & 0x000FFF00);
2479 } else
2480 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2481
2482 facts->ProductID = le16_to_cpu(facts->ProductID);
2483 facts->CurrentHostMfaHighAddr =
2484 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2485 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2486 facts->CurrentSenseBufferHighAddr =
2487 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2488 facts->CurReplyFrameSize =
2489 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002490 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 /*
2493 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2494 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2495 * to 14 in MPI-1.01.0x.
2496 */
2497 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2498 facts->MsgVersion > 0x0100) {
2499 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2500 }
2501
2502 sz = facts->FWImageSize;
2503 if ( sz & 0x01 )
2504 sz += 1;
2505 if ( sz & 0x02 )
2506 sz += 2;
2507 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if (!facts->RequestFrameSize) {
2510 /* Something is wrong! */
2511 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2512 ioc->name);
2513 return -55;
2514 }
2515
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002516 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 vv = ((63 / (sz * 4)) + 1) & 0x03;
2518 ioc->NB_for_64_byte_frame = vv;
2519 while ( sz )
2520 {
2521 shiftFactor++;
2522 sz = sz >> 1;
2523 }
2524 ioc->NBShiftFactor = shiftFactor;
2525 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2526 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002527
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2529 /*
2530 * Set values for this IOC's request & reply frame sizes,
2531 * and request & reply queue depths...
2532 */
2533 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2534 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2535 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2536 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2537
2538 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2539 ioc->name, ioc->reply_sz, ioc->reply_depth));
2540 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2541 ioc->name, ioc->req_sz, ioc->req_depth));
2542
2543 /* Get port facts! */
2544 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2545 return r;
2546 }
2547 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002548 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2550 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2551 RequestFrameSize)/sizeof(u32)));
2552 return -66;
2553 }
2554
2555 return 0;
2556}
2557
2558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2559/*
2560 * GetPortFacts - Send PortFacts request to MPT adapter.
2561 * @ioc: Pointer to MPT_ADAPTER structure
2562 * @portnum: Port number
2563 * @sleepFlag: Specifies whether the process can sleep
2564 *
2565 * Returns 0 for success, non-zero for failure.
2566 */
2567static int
2568GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2569{
2570 PortFacts_t get_pfacts;
2571 PortFactsReply_t *pfacts;
2572 int ii;
2573 int req_sz;
2574 int reply_sz;
2575
2576 /* IOC *must* NOT be in RESET state! */
2577 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2578 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2579 ioc->name,
2580 ioc->last_state );
2581 return -4;
2582 }
2583
2584 pfacts = &ioc->pfacts[portnum];
2585
2586 /* Destination (reply area)... */
2587 reply_sz = sizeof(*pfacts);
2588 memset(pfacts, 0, reply_sz);
2589
2590 /* Request area (get_pfacts on the stack right now!) */
2591 req_sz = sizeof(get_pfacts);
2592 memset(&get_pfacts, 0, req_sz);
2593
2594 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2595 get_pfacts.PortNumber = portnum;
2596 /* Assert: All other get_pfacts fields are zero! */
2597
2598 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2599 ioc->name, portnum));
2600
2601 /* No non-zero fields in the get_pfacts request are greater than
2602 * 1 byte in size, so we can just fire it off as is.
2603 */
2604 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2605 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2606 if (ii != 0)
2607 return ii;
2608
2609 /* Did we get a valid reply? */
2610
2611 /* Now byte swap the necessary fields in the response. */
2612 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2613 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2614 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2615 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2616 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2617 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2618 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2619 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2620 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2621
2622 return 0;
2623}
2624
2625/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2626/*
2627 * SendIocInit - Send IOCInit request to MPT adapter.
2628 * @ioc: Pointer to MPT_ADAPTER structure
2629 * @sleepFlag: Specifies whether the process can sleep
2630 *
2631 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2632 *
2633 * Returns 0 for success, non-zero for failure.
2634 */
2635static int
2636SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2637{
2638 IOCInit_t ioc_init;
2639 MPIDefaultReply_t init_reply;
2640 u32 state;
2641 int r;
2642 int count;
2643 int cntdn;
2644
2645 memset(&ioc_init, 0, sizeof(ioc_init));
2646 memset(&init_reply, 0, sizeof(init_reply));
2647
2648 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2649 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2650
2651 /* If we are in a recovery mode and we uploaded the FW image,
2652 * then this pointer is not NULL. Skip the upload a second time.
2653 * Set this flag if cached_fw set for either IOC.
2654 */
2655 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2656 ioc->upload_fw = 1;
2657 else
2658 ioc->upload_fw = 0;
2659 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2660 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2661
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002662 if(ioc->bus_type == SAS)
2663 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2664 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2666 else
2667 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002669 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2670 ioc->name, ioc->facts.MsgVersion));
2671 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2672 // set MsgVersion and HeaderVersion host driver was built with
2673 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2674 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002676 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2677 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2678 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2679 return -99;
2680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2682
2683 if (sizeof(dma_addr_t) == sizeof(u64)) {
2684 /* Save the upper 32-bits of the request
2685 * (reply) and sense buffers.
2686 */
2687 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2688 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2689 } else {
2690 /* Force 32-bit addressing */
2691 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2692 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2693 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002694
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2696 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002697 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2698 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2701 ioc->name, &ioc_init));
2702
2703 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2704 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002705 if (r != 0) {
2706 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
2710 /* No need to byte swap the multibyte fields in the reply
2711 * since we don't even look at it's contents.
2712 */
2713
2714 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2715 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002716
2717 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2718 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
2722 /* YIKES! SUPER IMPORTANT!!!
2723 * Poll IocState until _OPERATIONAL while IOC is doing
2724 * LoopInit and TargetDiscovery!
2725 */
2726 count = 0;
2727 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2728 state = mpt_GetIocState(ioc, 1);
2729 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2730 if (sleepFlag == CAN_SLEEP) {
2731 msleep_interruptible(1);
2732 } else {
2733 mdelay(1);
2734 }
2735
2736 if (!cntdn) {
2737 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2738 ioc->name, (int)((count+5)/HZ));
2739 return -9;
2740 }
2741
2742 state = mpt_GetIocState(ioc, 1);
2743 count++;
2744 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002745 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 ioc->name, count));
2747
2748 return r;
2749}
2750
2751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2752/*
2753 * SendPortEnable - Send PortEnable request to MPT adapter port.
2754 * @ioc: Pointer to MPT_ADAPTER structure
2755 * @portnum: Port number to enable
2756 * @sleepFlag: Specifies whether the process can sleep
2757 *
2758 * Send PortEnable to bring IOC to OPERATIONAL state.
2759 *
2760 * Returns 0 for success, non-zero for failure.
2761 */
2762static int
2763SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2764{
2765 PortEnable_t port_enable;
2766 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002767 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 int req_sz;
2769 int reply_sz;
2770
2771 /* Destination... */
2772 reply_sz = sizeof(MPIDefaultReply_t);
2773 memset(&reply_buf, 0, reply_sz);
2774
2775 req_sz = sizeof(PortEnable_t);
2776 memset(&port_enable, 0, req_sz);
2777
2778 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2779 port_enable.PortNumber = portnum;
2780/* port_enable.ChainOffset = 0; */
2781/* port_enable.MsgFlags = 0; */
2782/* port_enable.MsgContext = 0; */
2783
2784 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2785 ioc->name, portnum, &port_enable));
2786
2787 /* RAID FW may take a long time to enable
2788 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002789 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2790 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2791 (ioc->bus_type == SAS)) {
2792 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2793 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2794 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002795 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002796 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2797 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2798 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002800 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801}
2802
2803/*
2804 * ioc: Pointer to MPT_ADAPTER structure
2805 * size - total FW bytes
2806 */
2807void
2808mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2809{
2810 if (ioc->cached_fw)
2811 return; /* use already allocated memory */
2812 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2813 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2814 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2815 } else {
2816 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2817 ioc->alloc_total += size;
2818 }
2819}
2820/*
2821 * If alt_img is NULL, delete from ioc structure.
2822 * Else, delete a secondary image in same format.
2823 */
2824void
2825mpt_free_fw_memory(MPT_ADAPTER *ioc)
2826{
2827 int sz;
2828
2829 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002830 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2832 pci_free_consistent(ioc->pcidev, sz,
2833 ioc->cached_fw, ioc->cached_fw_dma);
2834 ioc->cached_fw = NULL;
2835
2836 return;
2837}
2838
2839
2840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2841/*
2842 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2843 * @ioc: Pointer to MPT_ADAPTER structure
2844 * @sleepFlag: Specifies whether the process can sleep
2845 *
2846 * Returns 0 for success, >0 for handshake failure
2847 * <0 for fw upload failure.
2848 *
2849 * Remark: If bound IOC and a successful FWUpload was performed
2850 * on the bound IOC, the second image is discarded
2851 * and memory is free'd. Both channels must upload to prevent
2852 * IOC from running in degraded mode.
2853 */
2854static int
2855mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2856{
2857 u8 request[ioc->req_sz];
2858 u8 reply[sizeof(FWUploadReply_t)];
2859 FWUpload_t *prequest;
2860 FWUploadReply_t *preply;
2861 FWUploadTCSGE_t *ptcsge;
2862 int sgeoffset;
2863 u32 flagsLength;
2864 int ii, sz, reply_sz;
2865 int cmdStatus;
2866
2867 /* If the image size is 0, we are done.
2868 */
2869 if ((sz = ioc->facts.FWImageSize) == 0)
2870 return 0;
2871
2872 mpt_alloc_fw_memory(ioc, sz);
2873
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002874 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002876
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 if (ioc->cached_fw == NULL) {
2878 /* Major Failure.
2879 */
2880 return -ENOMEM;
2881 }
2882
2883 prequest = (FWUpload_t *)&request;
2884 preply = (FWUploadReply_t *)&reply;
2885
2886 /* Destination... */
2887 memset(prequest, 0, ioc->req_sz);
2888
2889 reply_sz = sizeof(reply);
2890 memset(preply, 0, reply_sz);
2891
2892 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2893 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2894
2895 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2896 ptcsge->DetailsLength = 12;
2897 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2898 ptcsge->ImageSize = cpu_to_le32(sz);
2899
2900 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2901
2902 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2903 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2904
2905 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002906 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 prequest, sgeoffset));
2908 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2909
2910 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2911 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2912
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002913 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 cmdStatus = -EFAULT;
2916 if (ii == 0) {
2917 /* Handshake transfer was complete and successful.
2918 * Check the Reply Frame.
2919 */
2920 int status, transfer_sz;
2921 status = le16_to_cpu(preply->IOCStatus);
2922 if (status == MPI_IOCSTATUS_SUCCESS) {
2923 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2924 if (transfer_sz == sz)
2925 cmdStatus = 0;
2926 }
2927 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002928 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 ioc->name, cmdStatus));
2930
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 if (cmdStatus) {
2933
2934 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2935 ioc->name));
2936 mpt_free_fw_memory(ioc);
2937 }
2938
2939 return cmdStatus;
2940}
2941
2942/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2943/*
2944 * mpt_downloadboot - DownloadBoot code
2945 * @ioc: Pointer to MPT_ADAPTER structure
2946 * @flag: Specify which part of IOC memory is to be uploaded.
2947 * @sleepFlag: Specifies whether the process can sleep
2948 *
2949 * FwDownloadBoot requires Programmed IO access.
2950 *
2951 * Returns 0 for success
2952 * -1 FW Image size is 0
2953 * -2 No valid cached_fw Pointer
2954 * <0 for fw upload failure.
2955 */
2956static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002957mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 MpiExtImageHeader_t *pExtImage;
2960 u32 fwSize;
2961 u32 diag0val;
2962 int count;
2963 u32 *ptrFw;
2964 u32 diagRwData;
2965 u32 nextImage;
2966 u32 load_addr;
2967 u32 ioc_state=0;
2968
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002969 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2970 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2973 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2978
2979 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2980
2981 /* wait 1 msec */
2982 if (sleepFlag == CAN_SLEEP) {
2983 msleep_interruptible(1);
2984 } else {
2985 mdelay (1);
2986 }
2987
2988 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2989 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2990
2991 for (count = 0; count < 30; count ++) {
2992 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2993 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2994 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2995 ioc->name, count));
2996 break;
2997 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002998 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003000 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003002 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 }
3004 }
3005
3006 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003007 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
3008 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 ioc->name, diag0val));
3010 return -3;
3011 }
3012
3013 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3014 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3015 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3016 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3017 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3018 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3019
3020 /* Set the DiagRwEn and Disable ARM bits */
3021 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3022
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 fwSize = (pFwHeader->ImageSize + 3)/4;
3024 ptrFw = (u32 *) pFwHeader;
3025
3026 /* Write the LoadStartAddress to the DiagRw Address Register
3027 * using Programmed IO
3028 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003029 if (ioc->errata_flag_1064)
3030 pci_enable_io_access(ioc->pcidev);
3031
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
3033 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
3034 ioc->name, pFwHeader->LoadStartAddress));
3035
3036 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
3037 ioc->name, fwSize*4, ptrFw));
3038 while (fwSize--) {
3039 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3040 }
3041
3042 nextImage = pFwHeader->NextImageHeaderOffset;
3043 while (nextImage) {
3044 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3045
3046 load_addr = pExtImage->LoadStartAddress;
3047
3048 fwSize = (pExtImage->ImageSize + 3) >> 2;
3049 ptrFw = (u32 *)pExtImage;
3050
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003051 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
3052 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3054
3055 while (fwSize--) {
3056 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3057 }
3058 nextImage = pExtImage->NextImageHeaderOffset;
3059 }
3060
3061 /* Write the IopResetVectorRegAddr */
3062 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
3063 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3064
3065 /* Write the IopResetVectorValue */
3066 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3067 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3068
3069 /* Clear the internal flash bad bit - autoincrementing register,
3070 * so must do two writes.
3071 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003072 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003073 /*
3074 * 1030 and 1035 H/W errata, workaround to access
3075 * the ClearFlashBadSignatureBit
3076 */
3077 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3078 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3079 diagRwData |= 0x40000000;
3080 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3081 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3082
3083 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3084 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3085 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3086 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3087
3088 /* wait 1 msec */
3089 if (sleepFlag == CAN_SLEEP) {
3090 msleep_interruptible (1);
3091 } else {
3092 mdelay (1);
3093 }
3094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003096 if (ioc->errata_flag_1064)
3097 pci_disable_io_access(ioc->pcidev);
3098
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003100 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3101 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003103 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3105 ioc->name, diag0val));
3106 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3107
3108 /* Write 0xFF to reset the sequencer */
3109 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3110
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003111 if (ioc->bus_type == SAS) {
3112 ioc_state = mpt_GetIocState(ioc, 0);
3113 if ( (GetIocFacts(ioc, sleepFlag,
3114 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3115 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3116 ioc->name, ioc_state));
3117 return -EFAULT;
3118 }
3119 }
3120
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 for (count=0; count<HZ*20; count++) {
3122 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3123 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3124 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003125 if (ioc->bus_type == SAS) {
3126 return 0;
3127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3129 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3130 ioc->name));
3131 return -EFAULT;
3132 }
3133 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3134 ioc->name));
3135 return 0;
3136 }
3137 if (sleepFlag == CAN_SLEEP) {
3138 msleep_interruptible (10);
3139 } else {
3140 mdelay (10);
3141 }
3142 }
3143 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3144 ioc->name, ioc_state));
3145 return -EFAULT;
3146}
3147
3148/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3149/*
3150 * KickStart - Perform hard reset of MPT adapter.
3151 * @ioc: Pointer to MPT_ADAPTER structure
3152 * @force: Force hard reset
3153 * @sleepFlag: Specifies whether the process can sleep
3154 *
3155 * This routine places MPT adapter in diagnostic mode via the
3156 * WriteSequence register, and then performs a hard reset of adapter
3157 * via the Diagnostic register.
3158 *
3159 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3160 * or NO_SLEEP (interrupt thread, use mdelay)
3161 * force - 1 if doorbell active, board fault state
3162 * board operational, IOC_RECOVERY or
3163 * IOC_BRINGUP and there is an alt_ioc.
3164 * 0 else
3165 *
3166 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003167 * 1 - hard reset, READY
3168 * 0 - no reset due to History bit, READY
3169 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 * OR reset but failed to come READY
3171 * -2 - no reset, could not enter DIAG mode
3172 * -3 - reset but bad FW bit
3173 */
3174static int
3175KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3176{
3177 int hard_reset_done = 0;
3178 u32 ioc_state=0;
3179 int cnt,cntdn;
3180
3181 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003182 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 /* Always issue a Msg Unit Reset first. This will clear some
3184 * SCSI bus hang conditions.
3185 */
3186 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3187
3188 if (sleepFlag == CAN_SLEEP) {
3189 msleep_interruptible (1000);
3190 } else {
3191 mdelay (1000);
3192 }
3193 }
3194
3195 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3196 if (hard_reset_done < 0)
3197 return hard_reset_done;
3198
3199 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3200 ioc->name));
3201
3202 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3203 for (cnt=0; cnt<cntdn; cnt++) {
3204 ioc_state = mpt_GetIocState(ioc, 1);
3205 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3206 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3207 ioc->name, cnt));
3208 return hard_reset_done;
3209 }
3210 if (sleepFlag == CAN_SLEEP) {
3211 msleep_interruptible (10);
3212 } else {
3213 mdelay (10);
3214 }
3215 }
3216
3217 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3218 ioc->name, ioc_state);
3219 return -1;
3220}
3221
3222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3223/*
3224 * mpt_diag_reset - Perform hard reset of the adapter.
3225 * @ioc: Pointer to MPT_ADAPTER structure
3226 * @ignore: Set if to honor and clear to ignore
3227 * the reset history bit
3228 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3229 * else set to NO_SLEEP (use mdelay instead)
3230 *
3231 * This routine places the adapter in diagnostic mode via the
3232 * WriteSequence register and then performs a hard reset of adapter
3233 * via the Diagnostic register. Adapter should be in ready state
3234 * upon successful completion.
3235 *
3236 * Returns: 1 hard reset successful
3237 * 0 no reset performed because reset history bit set
3238 * -2 enabling diagnostic mode failed
3239 * -3 diagnostic reset failed
3240 */
3241static int
3242mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3243{
3244 u32 diag0val;
3245 u32 doorbell;
3246 int hard_reset_done = 0;
3247 int count = 0;
3248#ifdef MPT_DEBUG
3249 u32 diag1val = 0;
3250#endif
3251
3252 /* Clear any existing interrupts */
3253 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3254
3255 /* Use "Diagnostic reset" method! (only thing available!) */
3256 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3257
3258#ifdef MPT_DEBUG
3259 if (ioc->alt_ioc)
3260 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3261 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3262 ioc->name, diag0val, diag1val));
3263#endif
3264
3265 /* Do the reset if we are told to ignore the reset history
3266 * or if the reset history is 0
3267 */
3268 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3269 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3270 /* Write magic sequence to WriteSequence register
3271 * Loop until in diagnostic mode
3272 */
3273 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3274 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3275 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3276 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3277 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3279
3280 /* wait 100 msec */
3281 if (sleepFlag == CAN_SLEEP) {
3282 msleep_interruptible (100);
3283 } else {
3284 mdelay (100);
3285 }
3286
3287 count++;
3288 if (count > 20) {
3289 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3290 ioc->name, diag0val);
3291 return -2;
3292
3293 }
3294
3295 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3296
3297 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3298 ioc->name, diag0val));
3299 }
3300
3301#ifdef MPT_DEBUG
3302 if (ioc->alt_ioc)
3303 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3304 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3305 ioc->name, diag0val, diag1val));
3306#endif
3307 /*
3308 * Disable the ARM (Bug fix)
3309 *
3310 */
3311 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003312 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313
3314 /*
3315 * Now hit the reset bit in the Diagnostic register
3316 * (THE BIG HAMMER!) (Clears DRWE bit).
3317 */
3318 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3319 hard_reset_done = 1;
3320 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3321 ioc->name));
3322
3323 /*
3324 * Call each currently registered protocol IOC reset handler
3325 * with pre-reset indication.
3326 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3327 * MptResetHandlers[] registered yet.
3328 */
3329 {
3330 int ii;
3331 int r = 0;
3332
3333 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3334 if (MptResetHandlers[ii]) {
3335 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3336 ioc->name, ii));
3337 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET);
3338 if (ioc->alt_ioc) {
3339 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3340 ioc->name, ioc->alt_ioc->name, ii));
3341 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
3342 }
3343 }
3344 }
3345 /* FIXME? Examine results here? */
3346 }
3347
3348 if (ioc->cached_fw) {
3349 /* If the DownloadBoot operation fails, the
3350 * IOC will be left unusable. This is a fatal error
3351 * case. _diag_reset will return < 0
3352 */
3353 for (count = 0; count < 30; count ++) {
3354 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3355 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3356 break;
3357 }
3358
3359 /* wait 1 sec */
3360 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003361 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 } else {
3363 mdelay (1000);
3364 }
3365 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003366 if ((count = mpt_downloadboot(ioc,
3367 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 printk(KERN_WARNING MYNAM
3369 ": firmware downloadboot failure (%d)!\n", count);
3370 }
3371
3372 } else {
3373 /* Wait for FW to reload and for board
3374 * to go to the READY state.
3375 * Maximum wait is 60 seconds.
3376 * If fail, no error will check again
3377 * with calling program.
3378 */
3379 for (count = 0; count < 60; count ++) {
3380 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3381 doorbell &= MPI_IOC_STATE_MASK;
3382
3383 if (doorbell == MPI_IOC_STATE_READY) {
3384 break;
3385 }
3386
3387 /* wait 1 sec */
3388 if (sleepFlag == CAN_SLEEP) {
3389 msleep_interruptible (1000);
3390 } else {
3391 mdelay (1000);
3392 }
3393 }
3394 }
3395 }
3396
3397 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3398#ifdef MPT_DEBUG
3399 if (ioc->alt_ioc)
3400 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3401 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3402 ioc->name, diag0val, diag1val));
3403#endif
3404
3405 /* Clear RESET_HISTORY bit! Place board in the
3406 * diagnostic mode to update the diag register.
3407 */
3408 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3409 count = 0;
3410 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3411 /* Write magic sequence to WriteSequence register
3412 * Loop until in diagnostic mode
3413 */
3414 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3415 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3416 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3417 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3418 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3419 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3420
3421 /* wait 100 msec */
3422 if (sleepFlag == CAN_SLEEP) {
3423 msleep_interruptible (100);
3424 } else {
3425 mdelay (100);
3426 }
3427
3428 count++;
3429 if (count > 20) {
3430 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3431 ioc->name, diag0val);
3432 break;
3433 }
3434 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3435 }
3436 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3437 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3438 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3439 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3440 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3441 ioc->name);
3442 }
3443
3444 /* Disable Diagnostic Mode
3445 */
3446 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3447
3448 /* Check FW reload status flags.
3449 */
3450 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3451 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3452 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3453 ioc->name, diag0val);
3454 return -3;
3455 }
3456
3457#ifdef MPT_DEBUG
3458 if (ioc->alt_ioc)
3459 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3460 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3461 ioc->name, diag0val, diag1val));
3462#endif
3463
3464 /*
3465 * Reset flag that says we've enabled event notification
3466 */
3467 ioc->facts.EventState = 0;
3468
3469 if (ioc->alt_ioc)
3470 ioc->alt_ioc->facts.EventState = 0;
3471
3472 return hard_reset_done;
3473}
3474
3475/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3476/*
3477 * SendIocReset - Send IOCReset request to MPT adapter.
3478 * @ioc: Pointer to MPT_ADAPTER structure
3479 * @reset_type: reset type, expected values are
3480 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3481 *
3482 * Send IOCReset request to the MPT adapter.
3483 *
3484 * Returns 0 for success, non-zero for failure.
3485 */
3486static int
3487SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3488{
3489 int r;
3490 u32 state;
3491 int cntdn, count;
3492
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003493 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 ioc->name, reset_type));
3495 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3496 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3497 return r;
3498
3499 /* FW ACK'd request, wait for READY state
3500 */
3501 count = 0;
3502 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3503
3504 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3505 cntdn--;
3506 count++;
3507 if (!cntdn) {
3508 if (sleepFlag != CAN_SLEEP)
3509 count *= 10;
3510
3511 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3512 ioc->name, (int)((count+5)/HZ));
3513 return -ETIME;
3514 }
3515
3516 if (sleepFlag == CAN_SLEEP) {
3517 msleep_interruptible(1);
3518 } else {
3519 mdelay (1); /* 1 msec delay */
3520 }
3521 }
3522
3523 /* TODO!
3524 * Cleanup all event stuff for this IOC; re-issue EventNotification
3525 * request if needed.
3526 */
3527 if (ioc->facts.Function)
3528 ioc->facts.EventState = 0;
3529
3530 return 0;
3531}
3532
3533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3534/*
3535 * initChainBuffers - Allocate memory for and initialize
3536 * chain buffers, chain buffer control arrays and spinlock.
3537 * @hd: Pointer to MPT_SCSI_HOST structure
3538 * @init: If set, initialize the spin lock.
3539 */
3540static int
3541initChainBuffers(MPT_ADAPTER *ioc)
3542{
3543 u8 *mem;
3544 int sz, ii, num_chain;
3545 int scale, num_sge, numSGE;
3546
3547 /* ReqToChain size must equal the req_depth
3548 * index = req_idx
3549 */
3550 if (ioc->ReqToChain == NULL) {
3551 sz = ioc->req_depth * sizeof(int);
3552 mem = kmalloc(sz, GFP_ATOMIC);
3553 if (mem == NULL)
3554 return -1;
3555
3556 ioc->ReqToChain = (int *) mem;
3557 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3558 ioc->name, mem, sz));
3559 mem = kmalloc(sz, GFP_ATOMIC);
3560 if (mem == NULL)
3561 return -1;
3562
3563 ioc->RequestNB = (int *) mem;
3564 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3565 ioc->name, mem, sz));
3566 }
3567 for (ii = 0; ii < ioc->req_depth; ii++) {
3568 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3569 }
3570
3571 /* ChainToChain size must equal the total number
3572 * of chain buffers to be allocated.
3573 * index = chain_idx
3574 *
3575 * Calculate the number of chain buffers needed(plus 1) per I/O
3576 * then multiply the the maximum number of simultaneous cmds
3577 *
3578 * num_sge = num sge in request frame + last chain buffer
3579 * scale = num sge per chain buffer if no chain element
3580 */
3581 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3582 if (sizeof(dma_addr_t) == sizeof(u64))
3583 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3584 else
3585 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3586
3587 if (sizeof(dma_addr_t) == sizeof(u64)) {
3588 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3589 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3590 } else {
3591 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3592 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3593 }
3594 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3595 ioc->name, num_sge, numSGE));
3596
3597 if ( numSGE > MPT_SCSI_SG_DEPTH )
3598 numSGE = MPT_SCSI_SG_DEPTH;
3599
3600 num_chain = 1;
3601 while (numSGE - num_sge > 0) {
3602 num_chain++;
3603 num_sge += (scale - 1);
3604 }
3605 num_chain++;
3606
3607 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3608 ioc->name, numSGE, num_sge, num_chain));
3609
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003610 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 num_chain *= MPT_SCSI_CAN_QUEUE;
3612 else
3613 num_chain *= MPT_FC_CAN_QUEUE;
3614
3615 ioc->num_chain = num_chain;
3616
3617 sz = num_chain * sizeof(int);
3618 if (ioc->ChainToChain == NULL) {
3619 mem = kmalloc(sz, GFP_ATOMIC);
3620 if (mem == NULL)
3621 return -1;
3622
3623 ioc->ChainToChain = (int *) mem;
3624 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3625 ioc->name, mem, sz));
3626 } else {
3627 mem = (u8 *) ioc->ChainToChain;
3628 }
3629 memset(mem, 0xFF, sz);
3630 return num_chain;
3631}
3632
3633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3634/*
3635 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3636 * @ioc: Pointer to MPT_ADAPTER structure
3637 *
3638 * This routine allocates memory for the MPT reply and request frame
3639 * pools (if necessary), and primes the IOC reply FIFO with
3640 * reply frames.
3641 *
3642 * Returns 0 for success, non-zero for failure.
3643 */
3644static int
3645PrimeIocFifos(MPT_ADAPTER *ioc)
3646{
3647 MPT_FRAME_HDR *mf;
3648 unsigned long flags;
3649 dma_addr_t alloc_dma;
3650 u8 *mem;
3651 int i, reply_sz, sz, total_size, num_chain;
3652
3653 /* Prime reply FIFO... */
3654
3655 if (ioc->reply_frames == NULL) {
3656 if ( (num_chain = initChainBuffers(ioc)) < 0)
3657 return -1;
3658
3659 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3660 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3661 ioc->name, ioc->reply_sz, ioc->reply_depth));
3662 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3663 ioc->name, reply_sz, reply_sz));
3664
3665 sz = (ioc->req_sz * ioc->req_depth);
3666 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3667 ioc->name, ioc->req_sz, ioc->req_depth));
3668 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3669 ioc->name, sz, sz));
3670 total_size += sz;
3671
3672 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3673 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3674 ioc->name, ioc->req_sz, num_chain));
3675 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3676 ioc->name, sz, sz, num_chain));
3677
3678 total_size += sz;
3679 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3680 if (mem == NULL) {
3681 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3682 ioc->name);
3683 goto out_fail;
3684 }
3685
3686 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3687 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3688
3689 memset(mem, 0, total_size);
3690 ioc->alloc_total += total_size;
3691 ioc->alloc = mem;
3692 ioc->alloc_dma = alloc_dma;
3693 ioc->alloc_sz = total_size;
3694 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3695 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3696
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003697 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3698 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 alloc_dma += reply_sz;
3701 mem += reply_sz;
3702
3703 /* Request FIFO - WE manage this! */
3704
3705 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3706 ioc->req_frames_dma = alloc_dma;
3707
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003708 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 ioc->name, mem, (void *)(ulong)alloc_dma));
3710
3711 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3712
3713#if defined(CONFIG_MTRR) && 0
3714 /*
3715 * Enable Write Combining MTRR for IOC's memory region.
3716 * (at least as much as we can; "size and base must be
3717 * multiples of 4 kiB"
3718 */
3719 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3720 sz,
3721 MTRR_TYPE_WRCOMB, 1);
3722 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3723 ioc->name, ioc->req_frames_dma, sz));
3724#endif
3725
3726 for (i = 0; i < ioc->req_depth; i++) {
3727 alloc_dma += ioc->req_sz;
3728 mem += ioc->req_sz;
3729 }
3730
3731 ioc->ChainBuffer = mem;
3732 ioc->ChainBufferDMA = alloc_dma;
3733
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003734 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3736
3737 /* Initialize the free chain Q.
3738 */
3739
3740 INIT_LIST_HEAD(&ioc->FreeChainQ);
3741
3742 /* Post the chain buffers to the FreeChainQ.
3743 */
3744 mem = (u8 *)ioc->ChainBuffer;
3745 for (i=0; i < num_chain; i++) {
3746 mf = (MPT_FRAME_HDR *) mem;
3747 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3748 mem += ioc->req_sz;
3749 }
3750
3751 /* Initialize Request frames linked list
3752 */
3753 alloc_dma = ioc->req_frames_dma;
3754 mem = (u8 *) ioc->req_frames;
3755
3756 spin_lock_irqsave(&ioc->FreeQlock, flags);
3757 INIT_LIST_HEAD(&ioc->FreeQ);
3758 for (i = 0; i < ioc->req_depth; i++) {
3759 mf = (MPT_FRAME_HDR *) mem;
3760
3761 /* Queue REQUESTs *internally*! */
3762 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3763
3764 mem += ioc->req_sz;
3765 }
3766 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3767
3768 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3769 ioc->sense_buf_pool =
3770 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3771 if (ioc->sense_buf_pool == NULL) {
3772 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3773 ioc->name);
3774 goto out_fail;
3775 }
3776
3777 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3778 ioc->alloc_total += sz;
3779 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3780 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3781
3782 }
3783
3784 /* Post Reply frames to FIFO
3785 */
3786 alloc_dma = ioc->alloc_dma;
3787 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3788 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3789
3790 for (i = 0; i < ioc->reply_depth; i++) {
3791 /* Write each address to the IOC! */
3792 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3793 alloc_dma += ioc->reply_sz;
3794 }
3795
3796 return 0;
3797
3798out_fail:
3799 if (ioc->alloc != NULL) {
3800 sz = ioc->alloc_sz;
3801 pci_free_consistent(ioc->pcidev,
3802 sz,
3803 ioc->alloc, ioc->alloc_dma);
3804 ioc->reply_frames = NULL;
3805 ioc->req_frames = NULL;
3806 ioc->alloc_total -= sz;
3807 }
3808 if (ioc->sense_buf_pool != NULL) {
3809 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3810 pci_free_consistent(ioc->pcidev,
3811 sz,
3812 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3813 ioc->sense_buf_pool = NULL;
3814 }
3815 return -1;
3816}
3817
3818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3819/**
3820 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3821 * from IOC via doorbell handshake method.
3822 * @ioc: Pointer to MPT_ADAPTER structure
3823 * @reqBytes: Size of the request in bytes
3824 * @req: Pointer to MPT request frame
3825 * @replyBytes: Expected size of the reply in bytes
3826 * @u16reply: Pointer to area where reply should be written
3827 * @maxwait: Max wait time for a reply (in seconds)
3828 * @sleepFlag: Specifies whether the process can sleep
3829 *
3830 * NOTES: It is the callers responsibility to byte-swap fields in the
3831 * request which are greater than 1 byte in size. It is also the
3832 * callers responsibility to byte-swap response fields which are
3833 * greater than 1 byte in size.
3834 *
3835 * Returns 0 for success, non-zero for failure.
3836 */
3837static int
3838mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003839 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840{
3841 MPIDefaultReply_t *mptReply;
3842 int failcnt = 0;
3843 int t;
3844
3845 /*
3846 * Get ready to cache a handshake reply
3847 */
3848 ioc->hs_reply_idx = 0;
3849 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3850 mptReply->MsgLength = 0;
3851
3852 /*
3853 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3854 * then tell IOC that we want to handshake a request of N words.
3855 * (WRITE u32val to Doorbell reg).
3856 */
3857 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3858 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3859 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3860 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3861
3862 /*
3863 * Wait for IOC's doorbell handshake int
3864 */
3865 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3866 failcnt++;
3867
3868 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3869 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3870
3871 /* Read doorbell and check for active bit */
3872 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3873 return -1;
3874
3875 /*
3876 * Clear doorbell int (WRITE 0 to IntStatus reg),
3877 * then wait for IOC to ACKnowledge that it's ready for
3878 * our handshake request.
3879 */
3880 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3881 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3882 failcnt++;
3883
3884 if (!failcnt) {
3885 int ii;
3886 u8 *req_as_bytes = (u8 *) req;
3887
3888 /*
3889 * Stuff request words via doorbell handshake,
3890 * with ACK from IOC for each.
3891 */
3892 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3893 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3894 (req_as_bytes[(ii*4) + 1] << 8) |
3895 (req_as_bytes[(ii*4) + 2] << 16) |
3896 (req_as_bytes[(ii*4) + 3] << 24));
3897
3898 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3899 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3900 failcnt++;
3901 }
3902
3903 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3904 DBG_DUMP_REQUEST_FRAME_HDR(req)
3905
3906 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3907 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3908
3909 /*
3910 * Wait for completion of doorbell handshake reply from the IOC
3911 */
3912 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3913 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003914
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3916 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3917
3918 /*
3919 * Copy out the cached reply...
3920 */
3921 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3922 u16reply[ii] = ioc->hs_reply[ii];
3923 } else {
3924 return -99;
3925 }
3926
3927 return -failcnt;
3928}
3929
3930/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3931/*
3932 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3933 * in it's IntStatus register.
3934 * @ioc: Pointer to MPT_ADAPTER structure
3935 * @howlong: How long to wait (in seconds)
3936 * @sleepFlag: Specifies whether the process can sleep
3937 *
3938 * This routine waits (up to ~2 seconds max) for IOC doorbell
3939 * handshake ACKnowledge.
3940 *
3941 * Returns a negative value on failure, else wait loop count.
3942 */
3943static int
3944WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3945{
3946 int cntdn;
3947 int count = 0;
3948 u32 intstat=0;
3949
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003950 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951
3952 if (sleepFlag == CAN_SLEEP) {
3953 while (--cntdn) {
3954 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3955 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3956 break;
3957 msleep_interruptible (1);
3958 count++;
3959 }
3960 } else {
3961 while (--cntdn) {
3962 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3963 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3964 break;
3965 mdelay (1);
3966 count++;
3967 }
3968 }
3969
3970 if (cntdn) {
3971 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3972 ioc->name, count));
3973 return count;
3974 }
3975
3976 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3977 ioc->name, count, intstat);
3978 return -1;
3979}
3980
3981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3982/*
3983 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3984 * in it's IntStatus register.
3985 * @ioc: Pointer to MPT_ADAPTER structure
3986 * @howlong: How long to wait (in seconds)
3987 * @sleepFlag: Specifies whether the process can sleep
3988 *
3989 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3990 *
3991 * Returns a negative value on failure, else wait loop count.
3992 */
3993static int
3994WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3995{
3996 int cntdn;
3997 int count = 0;
3998 u32 intstat=0;
3999
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004000 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 if (sleepFlag == CAN_SLEEP) {
4002 while (--cntdn) {
4003 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4004 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4005 break;
4006 msleep_interruptible(1);
4007 count++;
4008 }
4009 } else {
4010 while (--cntdn) {
4011 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4012 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4013 break;
4014 mdelay(1);
4015 count++;
4016 }
4017 }
4018
4019 if (cntdn) {
4020 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
4021 ioc->name, count, howlong));
4022 return count;
4023 }
4024
4025 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4026 ioc->name, count, intstat);
4027 return -1;
4028}
4029
4030/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4031/*
4032 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
4033 * @ioc: Pointer to MPT_ADAPTER structure
4034 * @howlong: How long to wait (in seconds)
4035 * @sleepFlag: Specifies whether the process can sleep
4036 *
4037 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4038 * Reply is cached to IOC private area large enough to hold a maximum
4039 * of 128 bytes of reply data.
4040 *
4041 * Returns a negative value on failure, else size of reply in WORDS.
4042 */
4043static int
4044WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4045{
4046 int u16cnt = 0;
4047 int failcnt = 0;
4048 int t;
4049 u16 *hs_reply = ioc->hs_reply;
4050 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4051 u16 hword;
4052
4053 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4054
4055 /*
4056 * Get first two u16's so we can look at IOC's intended reply MsgLength
4057 */
4058 u16cnt=0;
4059 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4060 failcnt++;
4061 } else {
4062 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4063 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4064 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4065 failcnt++;
4066 else {
4067 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4068 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4069 }
4070 }
4071
4072 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004073 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4075
4076 /*
4077 * If no error (and IOC said MsgLength is > 0), piece together
4078 * reply 16 bits at a time.
4079 */
4080 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4081 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4082 failcnt++;
4083 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4084 /* don't overflow our IOC hs_reply[] buffer! */
4085 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4086 hs_reply[u16cnt] = hword;
4087 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4088 }
4089
4090 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4091 failcnt++;
4092 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4093
4094 if (failcnt) {
4095 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4096 ioc->name);
4097 return -failcnt;
4098 }
4099#if 0
4100 else if (u16cnt != (2 * mptReply->MsgLength)) {
4101 return -101;
4102 }
4103 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4104 return -102;
4105 }
4106#endif
4107
4108 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4109 DBG_DUMP_REPLY_FRAME(mptReply)
4110
4111 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4112 ioc->name, t, u16cnt/2));
4113 return u16cnt/2;
4114}
4115
4116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4117/*
4118 * GetLanConfigPages - Fetch LANConfig pages.
4119 * @ioc: Pointer to MPT_ADAPTER structure
4120 *
4121 * Return: 0 for success
4122 * -ENOMEM if no memory available
4123 * -EPERM if not allowed due to ISR context
4124 * -EAGAIN if no msg frames currently available
4125 * -EFAULT for non-successful reply or no reply (timeout)
4126 */
4127static int
4128GetLanConfigPages(MPT_ADAPTER *ioc)
4129{
4130 ConfigPageHeader_t hdr;
4131 CONFIGPARMS cfg;
4132 LANPage0_t *ppage0_alloc;
4133 dma_addr_t page0_dma;
4134 LANPage1_t *ppage1_alloc;
4135 dma_addr_t page1_dma;
4136 int rc = 0;
4137 int data_sz;
4138 int copy_sz;
4139
4140 /* Get LAN Page 0 header */
4141 hdr.PageVersion = 0;
4142 hdr.PageLength = 0;
4143 hdr.PageNumber = 0;
4144 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004145 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 cfg.physAddr = -1;
4147 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4148 cfg.dir = 0;
4149 cfg.pageAddr = 0;
4150 cfg.timeout = 0;
4151
4152 if ((rc = mpt_config(ioc, &cfg)) != 0)
4153 return rc;
4154
4155 if (hdr.PageLength > 0) {
4156 data_sz = hdr.PageLength * 4;
4157 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4158 rc = -ENOMEM;
4159 if (ppage0_alloc) {
4160 memset((u8 *)ppage0_alloc, 0, data_sz);
4161 cfg.physAddr = page0_dma;
4162 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4163
4164 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4165 /* save the data */
4166 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4167 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4168
4169 }
4170
4171 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4172
4173 /* FIXME!
4174 * Normalize endianness of structure data,
4175 * by byte-swapping all > 1 byte fields!
4176 */
4177
4178 }
4179
4180 if (rc)
4181 return rc;
4182 }
4183
4184 /* Get LAN Page 1 header */
4185 hdr.PageVersion = 0;
4186 hdr.PageLength = 0;
4187 hdr.PageNumber = 1;
4188 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004189 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 cfg.physAddr = -1;
4191 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4192 cfg.dir = 0;
4193 cfg.pageAddr = 0;
4194
4195 if ((rc = mpt_config(ioc, &cfg)) != 0)
4196 return rc;
4197
4198 if (hdr.PageLength == 0)
4199 return 0;
4200
4201 data_sz = hdr.PageLength * 4;
4202 rc = -ENOMEM;
4203 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4204 if (ppage1_alloc) {
4205 memset((u8 *)ppage1_alloc, 0, data_sz);
4206 cfg.physAddr = page1_dma;
4207 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4208
4209 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4210 /* save the data */
4211 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4212 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4213 }
4214
4215 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4216
4217 /* FIXME!
4218 * Normalize endianness of structure data,
4219 * by byte-swapping all > 1 byte fields!
4220 */
4221
4222 }
4223
4224 return rc;
4225}
4226
4227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4228/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004229 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 * @ioc: Pointer to MPT_ADAPTER structure
4231 * @portnum: IOC Port number
4232 *
4233 * Return: 0 for success
4234 * -ENOMEM if no memory available
4235 * -EPERM if not allowed due to ISR context
4236 * -EAGAIN if no msg frames currently available
4237 * -EFAULT for non-successful reply or no reply (timeout)
4238 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004239int
4240mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241{
4242 ConfigPageHeader_t hdr;
4243 CONFIGPARMS cfg;
4244 FCPortPage0_t *ppage0_alloc;
4245 FCPortPage0_t *pp0dest;
4246 dma_addr_t page0_dma;
4247 int data_sz;
4248 int copy_sz;
4249 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004250 int count = 400;
4251
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252
4253 /* Get FCPort Page 0 header */
4254 hdr.PageVersion = 0;
4255 hdr.PageLength = 0;
4256 hdr.PageNumber = 0;
4257 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004258 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 cfg.physAddr = -1;
4260 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4261 cfg.dir = 0;
4262 cfg.pageAddr = portnum;
4263 cfg.timeout = 0;
4264
4265 if ((rc = mpt_config(ioc, &cfg)) != 0)
4266 return rc;
4267
4268 if (hdr.PageLength == 0)
4269 return 0;
4270
4271 data_sz = hdr.PageLength * 4;
4272 rc = -ENOMEM;
4273 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4274 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004275
4276 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 memset((u8 *)ppage0_alloc, 0, data_sz);
4278 cfg.physAddr = page0_dma;
4279 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4280
4281 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4282 /* save the data */
4283 pp0dest = &ioc->fc_port_page0[portnum];
4284 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4285 memcpy(pp0dest, ppage0_alloc, copy_sz);
4286
4287 /*
4288 * Normalize endianness of structure data,
4289 * by byte-swapping all > 1 byte fields!
4290 */
4291 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4292 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4293 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4294 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4295 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4296 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4297 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4298 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4299 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4300 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4301 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4302 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4303 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4304 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4305 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4306 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4307
Michael Reed05e8ec12006-01-13 14:31:54 -06004308 /*
4309 * if still doing discovery,
4310 * hang loose a while until finished
4311 */
4312 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4313 if (count-- > 0) {
4314 msleep_interruptible(100);
4315 goto try_again;
4316 }
4317 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4318 " complete.\n",
4319 ioc->name);
4320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 }
4322
4323 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4324 }
4325
4326 return rc;
4327}
4328
4329/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4330/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004331 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4332 * @ioc: Pointer to MPT_ADAPTER structure
4333 * @sas_address: 64bit SAS Address for operation.
4334 * @target_id: specified target for operation
4335 * @bus: specified bus for operation
4336 * @persist_opcode: see below
4337 *
4338 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4339 * devices not currently present.
4340 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4341 *
4342 * NOTE: Don't use not this function during interrupt time.
4343 *
4344 * Returns: 0 for success, non-zero error
4345 */
4346
4347/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4348int
4349mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4350{
4351 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4352 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4353 MPT_FRAME_HDR *mf = NULL;
4354 MPIHeader_t *mpi_hdr;
4355
4356
4357 /* insure garbage is not sent to fw */
4358 switch(persist_opcode) {
4359
4360 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4361 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4362 break;
4363
4364 default:
4365 return -1;
4366 break;
4367 }
4368
4369 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4370
4371 /* Get a MF for this command.
4372 */
4373 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4374 printk("%s: no msg frames!\n",__FUNCTION__);
4375 return -1;
4376 }
4377
4378 mpi_hdr = (MPIHeader_t *) mf;
4379 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4380 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4381 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4382 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4383 sasIoUnitCntrReq->Operation = persist_opcode;
4384
4385 init_timer(&ioc->persist_timer);
4386 ioc->persist_timer.data = (unsigned long) ioc;
4387 ioc->persist_timer.function = mpt_timer_expired;
4388 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4389 ioc->persist_wait_done=0;
4390 add_timer(&ioc->persist_timer);
4391 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4392 wait_event(mpt_waitq, ioc->persist_wait_done);
4393
4394 sasIoUnitCntrReply =
4395 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4396 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4397 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4398 __FUNCTION__,
4399 sasIoUnitCntrReply->IOCStatus,
4400 sasIoUnitCntrReply->IOCLogInfo);
4401 return -1;
4402 }
4403
4404 printk("%s: success\n",__FUNCTION__);
4405 return 0;
4406}
4407
4408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004409
4410static void
4411mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4412 MpiEventDataRaid_t * pRaidEventData)
4413{
4414 int volume;
4415 int reason;
4416 int disk;
4417 int status;
4418 int flags;
4419 int state;
4420
4421 volume = pRaidEventData->VolumeID;
4422 reason = pRaidEventData->ReasonCode;
4423 disk = pRaidEventData->PhysDiskNum;
4424 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4425 flags = (status >> 0) & 0xff;
4426 state = (status >> 8) & 0xff;
4427
4428 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4429 return;
4430 }
4431
4432 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4433 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4434 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4435 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4436 ioc->name, disk);
4437 } else {
4438 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4439 ioc->name, volume);
4440 }
4441
4442 switch(reason) {
4443 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4444 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4445 ioc->name);
4446 break;
4447
4448 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4449
4450 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4451 ioc->name);
4452 break;
4453
4454 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4455 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4456 ioc->name);
4457 break;
4458
4459 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4460 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4461 ioc->name,
4462 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4463 ? "optimal"
4464 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4465 ? "degraded"
4466 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4467 ? "failed"
4468 : "state unknown",
4469 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4470 ? ", enabled" : "",
4471 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4472 ? ", quiesced" : "",
4473 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4474 ? ", resync in progress" : "" );
4475 break;
4476
4477 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4478 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4479 ioc->name, disk);
4480 break;
4481
4482 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4483 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4484 ioc->name);
4485 break;
4486
4487 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4488 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4489 ioc->name);
4490 break;
4491
4492 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4493 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4494 ioc->name);
4495 break;
4496
4497 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4498 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4499 ioc->name,
4500 state == MPI_PHYSDISK0_STATUS_ONLINE
4501 ? "online"
4502 : state == MPI_PHYSDISK0_STATUS_MISSING
4503 ? "missing"
4504 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4505 ? "not compatible"
4506 : state == MPI_PHYSDISK0_STATUS_FAILED
4507 ? "failed"
4508 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4509 ? "initializing"
4510 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4511 ? "offline requested"
4512 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4513 ? "failed requested"
4514 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4515 ? "offline"
4516 : "state unknown",
4517 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4518 ? ", out of sync" : "",
4519 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4520 ? ", quiesced" : "" );
4521 break;
4522
4523 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4524 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4525 ioc->name, disk);
4526 break;
4527
4528 case MPI_EVENT_RAID_RC_SMART_DATA:
4529 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4530 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4531 break;
4532
4533 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4534 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4535 ioc->name, disk);
4536 break;
4537 }
4538}
4539
4540/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004541/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4543 * @ioc: Pointer to MPT_ADAPTER structure
4544 *
4545 * Returns: 0 for success
4546 * -ENOMEM if no memory available
4547 * -EPERM if not allowed due to ISR context
4548 * -EAGAIN if no msg frames currently available
4549 * -EFAULT for non-successful reply or no reply (timeout)
4550 */
4551static int
4552GetIoUnitPage2(MPT_ADAPTER *ioc)
4553{
4554 ConfigPageHeader_t hdr;
4555 CONFIGPARMS cfg;
4556 IOUnitPage2_t *ppage_alloc;
4557 dma_addr_t page_dma;
4558 int data_sz;
4559 int rc;
4560
4561 /* Get the page header */
4562 hdr.PageVersion = 0;
4563 hdr.PageLength = 0;
4564 hdr.PageNumber = 2;
4565 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004566 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 cfg.physAddr = -1;
4568 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4569 cfg.dir = 0;
4570 cfg.pageAddr = 0;
4571 cfg.timeout = 0;
4572
4573 if ((rc = mpt_config(ioc, &cfg)) != 0)
4574 return rc;
4575
4576 if (hdr.PageLength == 0)
4577 return 0;
4578
4579 /* Read the config page */
4580 data_sz = hdr.PageLength * 4;
4581 rc = -ENOMEM;
4582 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4583 if (ppage_alloc) {
4584 memset((u8 *)ppage_alloc, 0, data_sz);
4585 cfg.physAddr = page_dma;
4586 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4587
4588 /* If Good, save data */
4589 if ((rc = mpt_config(ioc, &cfg)) == 0)
4590 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4591
4592 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4593 }
4594
4595 return rc;
4596}
4597
4598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4599/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4600 * @ioc: Pointer to a Adapter Strucutre
4601 * @portnum: IOC port number
4602 *
4603 * Return: -EFAULT if read of config page header fails
4604 * or if no nvram
4605 * If read of SCSI Port Page 0 fails,
4606 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4607 * Adapter settings: async, narrow
4608 * Return 1
4609 * If read of SCSI Port Page 2 fails,
4610 * Adapter settings valid
4611 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4612 * Return 1
4613 * Else
4614 * Both valid
4615 * Return 0
4616 * CHECK - what type of locking mechanisms should be used????
4617 */
4618static int
4619mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4620{
4621 u8 *pbuf;
4622 dma_addr_t buf_dma;
4623 CONFIGPARMS cfg;
4624 ConfigPageHeader_t header;
4625 int ii;
4626 int data, rc = 0;
4627
4628 /* Allocate memory
4629 */
4630 if (!ioc->spi_data.nvram) {
4631 int sz;
4632 u8 *mem;
4633 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4634 mem = kmalloc(sz, GFP_ATOMIC);
4635 if (mem == NULL)
4636 return -EFAULT;
4637
4638 ioc->spi_data.nvram = (int *) mem;
4639
4640 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4641 ioc->name, ioc->spi_data.nvram, sz));
4642 }
4643
4644 /* Invalidate NVRAM information
4645 */
4646 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4647 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4648 }
4649
4650 /* Read SPP0 header, allocate memory, then read page.
4651 */
4652 header.PageVersion = 0;
4653 header.PageLength = 0;
4654 header.PageNumber = 0;
4655 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004656 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 cfg.physAddr = -1;
4658 cfg.pageAddr = portnum;
4659 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4660 cfg.dir = 0;
4661 cfg.timeout = 0; /* use default */
4662 if (mpt_config(ioc, &cfg) != 0)
4663 return -EFAULT;
4664
4665 if (header.PageLength > 0) {
4666 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4667 if (pbuf) {
4668 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4669 cfg.physAddr = buf_dma;
4670 if (mpt_config(ioc, &cfg) != 0) {
4671 ioc->spi_data.maxBusWidth = MPT_NARROW;
4672 ioc->spi_data.maxSyncOffset = 0;
4673 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4674 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4675 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004676 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4677 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 } else {
4679 /* Save the Port Page 0 data
4680 */
4681 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4682 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4683 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4684
4685 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4686 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004687 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 ioc->name, pPP0->Capabilities));
4689 }
4690 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4691 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4692 if (data) {
4693 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4694 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4695 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004696 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4697 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 } else {
4699 ioc->spi_data.maxSyncOffset = 0;
4700 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4701 }
4702
4703 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4704
4705 /* Update the minSyncFactor based on bus type.
4706 */
4707 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4708 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4709
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004710 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004712 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4713 ioc->name, ioc->spi_data.minSyncFactor));
4714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 }
4716 }
4717 if (pbuf) {
4718 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4719 }
4720 }
4721 }
4722
4723 /* SCSI Port Page 2 - Read the header then the page.
4724 */
4725 header.PageVersion = 0;
4726 header.PageLength = 0;
4727 header.PageNumber = 2;
4728 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004729 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 cfg.physAddr = -1;
4731 cfg.pageAddr = portnum;
4732 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4733 cfg.dir = 0;
4734 if (mpt_config(ioc, &cfg) != 0)
4735 return -EFAULT;
4736
4737 if (header.PageLength > 0) {
4738 /* Allocate memory and read SCSI Port Page 2
4739 */
4740 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4741 if (pbuf) {
4742 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4743 cfg.physAddr = buf_dma;
4744 if (mpt_config(ioc, &cfg) != 0) {
4745 /* Nvram data is left with INVALID mark
4746 */
4747 rc = 1;
4748 } else {
4749 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4750 MpiDeviceInfo_t *pdevice = NULL;
4751
Moore, Ericd8e925d2006-01-16 18:53:06 -07004752 /*
4753 * Save "Set to Avoid SCSI Bus Resets" flag
4754 */
4755 ioc->spi_data.bus_reset =
4756 (le32_to_cpu(pPP2->PortFlags) &
4757 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4758 0 : 1 ;
4759
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 /* Save the Port Page 2 data
4761 * (reformat into a 32bit quantity)
4762 */
4763 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4764 ioc->spi_data.PortFlags = data;
4765 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4766 pdevice = &pPP2->DeviceSettings[ii];
4767 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4768 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4769 ioc->spi_data.nvram[ii] = data;
4770 }
4771 }
4772
4773 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4774 }
4775 }
4776
4777 /* Update Adapter limits with those from NVRAM
4778 * Comment: Don't need to do this. Target performance
4779 * parameters will never exceed the adapters limits.
4780 */
4781
4782 return rc;
4783}
4784
4785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4786/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4787 * @ioc: Pointer to a Adapter Strucutre
4788 * @portnum: IOC port number
4789 *
4790 * Return: -EFAULT if read of config page header fails
4791 * or 0 if success.
4792 */
4793static int
4794mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4795{
4796 CONFIGPARMS cfg;
4797 ConfigPageHeader_t header;
4798
4799 /* Read the SCSI Device Page 1 header
4800 */
4801 header.PageVersion = 0;
4802 header.PageLength = 0;
4803 header.PageNumber = 1;
4804 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004805 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 cfg.physAddr = -1;
4807 cfg.pageAddr = portnum;
4808 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4809 cfg.dir = 0;
4810 cfg.timeout = 0;
4811 if (mpt_config(ioc, &cfg) != 0)
4812 return -EFAULT;
4813
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004814 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4815 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816
4817 header.PageVersion = 0;
4818 header.PageLength = 0;
4819 header.PageNumber = 0;
4820 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4821 if (mpt_config(ioc, &cfg) != 0)
4822 return -EFAULT;
4823
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004824 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4825 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826
4827 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4828 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4829
4830 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4831 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4832 return 0;
4833}
4834
4835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4836/**
4837 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4838 * @ioc: Pointer to a Adapter Strucutre
4839 * @portnum: IOC port number
4840 *
4841 * Return:
4842 * 0 on success
4843 * -EFAULT if read of config page header fails or data pointer not NULL
4844 * -ENOMEM if pci_alloc failed
4845 */
4846int
4847mpt_findImVolumes(MPT_ADAPTER *ioc)
4848{
4849 IOCPage2_t *pIoc2;
4850 u8 *mem;
4851 ConfigPageIoc2RaidVol_t *pIocRv;
4852 dma_addr_t ioc2_dma;
4853 CONFIGPARMS cfg;
4854 ConfigPageHeader_t header;
4855 int jj;
4856 int rc = 0;
4857 int iocpage2sz;
4858 u8 nVols, nPhys;
4859 u8 vid, vbus, vioc;
4860
4861 /* Read IOCP2 header then the page.
4862 */
4863 header.PageVersion = 0;
4864 header.PageLength = 0;
4865 header.PageNumber = 2;
4866 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004867 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 cfg.physAddr = -1;
4869 cfg.pageAddr = 0;
4870 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4871 cfg.dir = 0;
4872 cfg.timeout = 0;
4873 if (mpt_config(ioc, &cfg) != 0)
4874 return -EFAULT;
4875
4876 if (header.PageLength == 0)
4877 return -EFAULT;
4878
4879 iocpage2sz = header.PageLength * 4;
4880 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4881 if (!pIoc2)
4882 return -ENOMEM;
4883
4884 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4885 cfg.physAddr = ioc2_dma;
4886 if (mpt_config(ioc, &cfg) != 0)
4887 goto done_and_free;
4888
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004889 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4891 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004892 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 } else {
4894 goto done_and_free;
4895 }
4896 }
4897 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4898
4899 /* Identify RAID Volume Id's */
4900 nVols = pIoc2->NumActiveVolumes;
4901 if ( nVols == 0) {
4902 /* No RAID Volume.
4903 */
4904 goto done_and_free;
4905 } else {
4906 /* At least 1 RAID Volume
4907 */
4908 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004909 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4911 vid = pIocRv->VolumeID;
4912 vbus = pIocRv->VolumeBus;
4913 vioc = pIocRv->VolumeIOC;
4914
4915 /* find the match
4916 */
4917 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004918 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 } else {
4920 /* Error! Always bus 0
4921 */
4922 }
4923 }
4924 }
4925
4926 /* Identify Hidden Physical Disk Id's */
4927 nPhys = pIoc2->NumActivePhysDisks;
4928 if (nPhys == 0) {
4929 /* No physical disks.
4930 */
4931 } else {
4932 mpt_read_ioc_pg_3(ioc);
4933 }
4934
4935done_and_free:
4936 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4937
4938 return rc;
4939}
4940
4941int
4942mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4943{
4944 IOCPage3_t *pIoc3;
4945 u8 *mem;
4946 CONFIGPARMS cfg;
4947 ConfigPageHeader_t header;
4948 dma_addr_t ioc3_dma;
4949 int iocpage3sz = 0;
4950
4951 /* Free the old page
4952 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004953 kfree(ioc->raid_data.pIocPg3);
4954 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955
4956 /* There is at least one physical disk.
4957 * Read and save IOC Page 3
4958 */
4959 header.PageVersion = 0;
4960 header.PageLength = 0;
4961 header.PageNumber = 3;
4962 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004963 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 cfg.physAddr = -1;
4965 cfg.pageAddr = 0;
4966 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4967 cfg.dir = 0;
4968 cfg.timeout = 0;
4969 if (mpt_config(ioc, &cfg) != 0)
4970 return 0;
4971
4972 if (header.PageLength == 0)
4973 return 0;
4974
4975 /* Read Header good, alloc memory
4976 */
4977 iocpage3sz = header.PageLength * 4;
4978 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4979 if (!pIoc3)
4980 return 0;
4981
4982 /* Read the Page and save the data
4983 * into malloc'd memory.
4984 */
4985 cfg.physAddr = ioc3_dma;
4986 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4987 if (mpt_config(ioc, &cfg) == 0) {
4988 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4989 if (mem) {
4990 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004991 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 }
4993 }
4994
4995 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4996
4997 return 0;
4998}
4999
5000static void
5001mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5002{
5003 IOCPage4_t *pIoc4;
5004 CONFIGPARMS cfg;
5005 ConfigPageHeader_t header;
5006 dma_addr_t ioc4_dma;
5007 int iocpage4sz;
5008
5009 /* Read and save IOC Page 4
5010 */
5011 header.PageVersion = 0;
5012 header.PageLength = 0;
5013 header.PageNumber = 4;
5014 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005015 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 cfg.physAddr = -1;
5017 cfg.pageAddr = 0;
5018 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5019 cfg.dir = 0;
5020 cfg.timeout = 0;
5021 if (mpt_config(ioc, &cfg) != 0)
5022 return;
5023
5024 if (header.PageLength == 0)
5025 return;
5026
5027 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5028 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5029 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5030 if (!pIoc4)
5031 return;
5032 } else {
5033 ioc4_dma = ioc->spi_data.IocPg4_dma;
5034 iocpage4sz = ioc->spi_data.IocPg4Sz;
5035 }
5036
5037 /* Read the Page into dma memory.
5038 */
5039 cfg.physAddr = ioc4_dma;
5040 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5041 if (mpt_config(ioc, &cfg) == 0) {
5042 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5043 ioc->spi_data.IocPg4_dma = ioc4_dma;
5044 ioc->spi_data.IocPg4Sz = iocpage4sz;
5045 } else {
5046 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5047 ioc->spi_data.pIocPg4 = NULL;
5048 }
5049}
5050
5051static void
5052mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5053{
5054 IOCPage1_t *pIoc1;
5055 CONFIGPARMS cfg;
5056 ConfigPageHeader_t header;
5057 dma_addr_t ioc1_dma;
5058 int iocpage1sz = 0;
5059 u32 tmp;
5060
5061 /* Check the Coalescing Timeout in IOC Page 1
5062 */
5063 header.PageVersion = 0;
5064 header.PageLength = 0;
5065 header.PageNumber = 1;
5066 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005067 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 cfg.physAddr = -1;
5069 cfg.pageAddr = 0;
5070 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5071 cfg.dir = 0;
5072 cfg.timeout = 0;
5073 if (mpt_config(ioc, &cfg) != 0)
5074 return;
5075
5076 if (header.PageLength == 0)
5077 return;
5078
5079 /* Read Header good, alloc memory
5080 */
5081 iocpage1sz = header.PageLength * 4;
5082 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5083 if (!pIoc1)
5084 return;
5085
5086 /* Read the Page and check coalescing timeout
5087 */
5088 cfg.physAddr = ioc1_dma;
5089 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5090 if (mpt_config(ioc, &cfg) == 0) {
5091
5092 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5093 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5094 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5095
5096 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5097 ioc->name, tmp));
5098
5099 if (tmp > MPT_COALESCING_TIMEOUT) {
5100 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5101
5102 /* Write NVRAM and current
5103 */
5104 cfg.dir = 1;
5105 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5106 if (mpt_config(ioc, &cfg) == 0) {
5107 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5108 ioc->name, MPT_COALESCING_TIMEOUT));
5109
5110 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5111 if (mpt_config(ioc, &cfg) == 0) {
5112 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5113 ioc->name, MPT_COALESCING_TIMEOUT));
5114 } else {
5115 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5116 ioc->name));
5117 }
5118
5119 } else {
5120 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5121 ioc->name));
5122 }
5123 }
5124
5125 } else {
5126 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5127 }
5128 }
5129
5130 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5131
5132 return;
5133}
5134
5135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5136/*
5137 * SendEventNotification - Send EventNotification (on or off) request
5138 * to MPT adapter.
5139 * @ioc: Pointer to MPT_ADAPTER structure
5140 * @EvSwitch: Event switch flags
5141 */
5142static int
5143SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5144{
5145 EventNotification_t *evnp;
5146
5147 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5148 if (evnp == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005149 devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 ioc->name));
5151 return 0;
5152 }
5153 memset(evnp, 0, sizeof(*evnp));
5154
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005155 devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156
5157 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5158 evnp->ChainOffset = 0;
5159 evnp->MsgFlags = 0;
5160 evnp->Switch = EvSwitch;
5161
5162 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5163
5164 return 0;
5165}
5166
5167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5168/**
5169 * SendEventAck - Send EventAck request to MPT adapter.
5170 * @ioc: Pointer to MPT_ADAPTER structure
5171 * @evnp: Pointer to original EventNotification request
5172 */
5173static int
5174SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5175{
5176 EventAck_t *pAck;
5177
5178 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005179 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5180 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5181 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5182 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 return -1;
5184 }
5185 memset(pAck, 0, sizeof(*pAck));
5186
5187 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5188
5189 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5190 pAck->ChainOffset = 0;
5191 pAck->MsgFlags = 0;
5192 pAck->Event = evnp->Event;
5193 pAck->EventContext = evnp->EventContext;
5194
5195 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5196
5197 return 0;
5198}
5199
5200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5201/**
5202 * mpt_config - Generic function to issue config message
5203 * @ioc - Pointer to an adapter structure
5204 * @cfg - Pointer to a configuration structure. Struct contains
5205 * action, page address, direction, physical address
5206 * and pointer to a configuration page header
5207 * Page header is updated.
5208 *
5209 * Returns 0 for success
5210 * -EPERM if not allowed due to ISR context
5211 * -EAGAIN if no msg frames currently available
5212 * -EFAULT for non-successful reply or no reply (timeout)
5213 */
5214int
5215mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5216{
5217 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005218 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 MPT_FRAME_HDR *mf;
5220 unsigned long flags;
5221 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005222 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 int in_isr;
5224
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005225 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 * to be in ISR context, because that is fatal!
5227 */
5228 in_isr = in_interrupt();
5229 if (in_isr) {
5230 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5231 ioc->name));
5232 return -EPERM;
5233 }
5234
5235 /* Get and Populate a free Frame
5236 */
5237 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5238 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5239 ioc->name));
5240 return -EAGAIN;
5241 }
5242 pReq = (Config_t *)mf;
5243 pReq->Action = pCfg->action;
5244 pReq->Reserved = 0;
5245 pReq->ChainOffset = 0;
5246 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005247
5248 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 pReq->ExtPageLength = 0;
5250 pReq->ExtPageType = 0;
5251 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005252
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 for (ii=0; ii < 8; ii++)
5254 pReq->Reserved2[ii] = 0;
5255
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005256 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5257 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5258 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5259 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5260
5261 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5262 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5263 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5264 pReq->ExtPageType = pExtHdr->ExtPageType;
5265 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5266
5267 /* Page Length must be treated as a reserved field for the extended header. */
5268 pReq->Header.PageLength = 0;
5269 }
5270
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5272
5273 /* Add a SGE to the config request.
5274 */
5275 if (pCfg->dir)
5276 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5277 else
5278 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5279
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005280 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5281 flagsLength |= pExtHdr->ExtPageLength * 4;
5282
5283 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5284 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5285 }
5286 else {
5287 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5288
5289 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5290 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
5293 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5294
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 /* Append pCfg pointer to end of mf
5296 */
5297 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5298
5299 /* Initalize the timer
5300 */
5301 init_timer(&pCfg->timer);
5302 pCfg->timer.data = (unsigned long) ioc;
5303 pCfg->timer.function = mpt_timer_expired;
5304 pCfg->wait_done = 0;
5305
5306 /* Set the timer; ensure 10 second minimum */
5307 if (pCfg->timeout < 10)
5308 pCfg->timer.expires = jiffies + HZ*10;
5309 else
5310 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5311
5312 /* Add to end of Q, set timer and then issue this command */
5313 spin_lock_irqsave(&ioc->FreeQlock, flags);
5314 list_add_tail(&pCfg->linkage, &ioc->configQ);
5315 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5316
5317 add_timer(&pCfg->timer);
5318 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5319 wait_event(mpt_waitq, pCfg->wait_done);
5320
5321 /* mf has been freed - do not access */
5322
5323 rc = pCfg->status;
5324
5325 return rc;
5326}
5327
5328/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329/*
5330 * mpt_timer_expired - Call back for timer process.
5331 * Used only internal config functionality.
5332 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5333 */
5334static void
5335mpt_timer_expired(unsigned long data)
5336{
5337 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5338
5339 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5340
5341 /* Perform a FW reload */
5342 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5343 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5344
5345 /* No more processing.
5346 * Hard reset clean-up will wake up
5347 * process and free all resources.
5348 */
5349 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5350
5351 return;
5352}
5353
5354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5355/*
5356 * mpt_ioc_reset - Base cleanup for hard reset
5357 * @ioc: Pointer to the adapter structure
5358 * @reset_phase: Indicates pre- or post-reset functionality
5359 *
5360 * Remark: Free's resources with internally generated commands.
5361 */
5362static int
5363mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5364{
5365 CONFIGPARMS *pCfg;
5366 unsigned long flags;
5367
5368 dprintk((KERN_WARNING MYNAM
5369 ": IOC %s_reset routed to MPT base driver!\n",
5370 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5371 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5372
5373 if (reset_phase == MPT_IOC_SETUP_RESET) {
5374 ;
5375 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5376 /* If the internal config Q is not empty -
5377 * delete timer. MF resources will be freed when
5378 * the FIFO's are primed.
5379 */
5380 spin_lock_irqsave(&ioc->FreeQlock, flags);
5381 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5382 del_timer(&pCfg->timer);
5383 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5384
5385 } else {
5386 CONFIGPARMS *pNext;
5387
5388 /* Search the configQ for internal commands.
5389 * Flush the Q, and wake up all suspended threads.
5390 */
5391 spin_lock_irqsave(&ioc->FreeQlock, flags);
5392 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5393 list_del(&pCfg->linkage);
5394
5395 pCfg->status = MPT_CONFIG_ERROR;
5396 pCfg->wait_done = 1;
5397 wake_up(&mpt_waitq);
5398 }
5399 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5400 }
5401
5402 return 1; /* currently means nothing really */
5403}
5404
5405
5406#ifdef CONFIG_PROC_FS /* { */
5407/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5408/*
5409 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5410 */
5411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5412/*
5413 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5414 *
5415 * Returns 0 for success, non-zero for failure.
5416 */
5417static int
5418procmpt_create(void)
5419{
5420 struct proc_dir_entry *ent;
5421
5422 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5423 if (mpt_proc_root_dir == NULL)
5424 return -ENOTDIR;
5425
5426 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5427 if (ent)
5428 ent->read_proc = procmpt_summary_read;
5429
5430 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5431 if (ent)
5432 ent->read_proc = procmpt_version_read;
5433
5434 return 0;
5435}
5436
5437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5438/*
5439 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5440 *
5441 * Returns 0 for success, non-zero for failure.
5442 */
5443static void
5444procmpt_destroy(void)
5445{
5446 remove_proc_entry("version", mpt_proc_root_dir);
5447 remove_proc_entry("summary", mpt_proc_root_dir);
5448 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5449}
5450
5451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5452/*
5453 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5454 * or from /proc/mpt/iocN/summary.
5455 * @buf: Pointer to area to write information
5456 * @start: Pointer to start pointer
5457 * @offset: Offset to start writing
5458 * @request:
5459 * @eof: Pointer to EOF integer
5460 * @data: Pointer
5461 *
5462 * Returns number of characters written to process performing the read.
5463 */
5464static int
5465procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5466{
5467 MPT_ADAPTER *ioc;
5468 char *out = buf;
5469 int len;
5470
5471 if (data) {
5472 int more = 0;
5473
5474 ioc = data;
5475 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5476
5477 out += more;
5478 } else {
5479 list_for_each_entry(ioc, &ioc_list, list) {
5480 int more = 0;
5481
5482 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5483
5484 out += more;
5485 if ((out-buf) >= request)
5486 break;
5487 }
5488 }
5489
5490 len = out - buf;
5491
5492 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5493}
5494
5495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5496/*
5497 * procmpt_version_read - Handle read request from /proc/mpt/version.
5498 * @buf: Pointer to area to write information
5499 * @start: Pointer to start pointer
5500 * @offset: Offset to start writing
5501 * @request:
5502 * @eof: Pointer to EOF integer
5503 * @data: Pointer
5504 *
5505 * Returns number of characters written to process performing the read.
5506 */
5507static int
5508procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5509{
5510 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005511 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 char *drvname;
5513 int len;
5514
5515 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5516 len += sprintf(buf+len, " Fusion MPT base driver\n");
5517
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005518 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5520 drvname = NULL;
5521 if (MptCallbacks[ii]) {
5522 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005523 case MPTSPI_DRIVER:
5524 if (!scsi++) drvname = "SPI host";
5525 break;
5526 case MPTFC_DRIVER:
5527 if (!fc++) drvname = "FC host";
5528 break;
5529 case MPTSAS_DRIVER:
5530 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 break;
5532 case MPTLAN_DRIVER:
5533 if (!lan++) drvname = "LAN";
5534 break;
5535 case MPTSTM_DRIVER:
5536 if (!targ++) drvname = "SCSI target";
5537 break;
5538 case MPTCTL_DRIVER:
5539 if (!ctl++) drvname = "ioctl";
5540 break;
5541 }
5542
5543 if (drvname)
5544 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5545 }
5546 }
5547
5548 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5549}
5550
5551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5552/*
5553 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5554 * @buf: Pointer to area to write information
5555 * @start: Pointer to start pointer
5556 * @offset: Offset to start writing
5557 * @request:
5558 * @eof: Pointer to EOF integer
5559 * @data: Pointer
5560 *
5561 * Returns number of characters written to process performing the read.
5562 */
5563static int
5564procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5565{
5566 MPT_ADAPTER *ioc = data;
5567 int len;
5568 char expVer[32];
5569 int sz;
5570 int p;
5571
5572 mpt_get_fw_exp_ver(expVer, ioc);
5573
5574 len = sprintf(buf, "%s:", ioc->name);
5575 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5576 len += sprintf(buf+len, " (f/w download boot flag set)");
5577// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5578// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5579
5580 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5581 ioc->facts.ProductID,
5582 ioc->prod_name);
5583 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5584 if (ioc->facts.FWImageSize)
5585 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5586 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5587 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5588 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5589
5590 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5591 ioc->facts.CurrentHostMfaHighAddr);
5592 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5593 ioc->facts.CurrentSenseBufferHighAddr);
5594
5595 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5596 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5597
5598 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5599 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5600 /*
5601 * Rounding UP to nearest 4-kB boundary here...
5602 */
5603 sz = (ioc->req_sz * ioc->req_depth) + 128;
5604 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5605 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5606 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5607 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5608 4*ioc->facts.RequestFrameSize,
5609 ioc->facts.GlobalCredits);
5610
5611 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5612 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5613 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5614 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5615 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5616 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5617 ioc->facts.CurReplyFrameSize,
5618 ioc->facts.ReplyQueueDepth);
5619
5620 len += sprintf(buf+len, " MaxDevices = %d\n",
5621 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5622 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5623
5624 /* per-port info */
5625 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5626 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5627 p+1,
5628 ioc->facts.NumberOfPorts);
5629 if (ioc->bus_type == FC) {
5630 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5631 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5632 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5633 a[5], a[4], a[3], a[2], a[1], a[0]);
5634 }
5635 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5636 ioc->fc_port_page0[p].WWNN.High,
5637 ioc->fc_port_page0[p].WWNN.Low,
5638 ioc->fc_port_page0[p].WWPN.High,
5639 ioc->fc_port_page0[p].WWPN.Low);
5640 }
5641 }
5642
5643 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5644}
5645
5646#endif /* CONFIG_PROC_FS } */
5647
5648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5649static void
5650mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5651{
5652 buf[0] ='\0';
5653 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5654 sprintf(buf, " (Exp %02d%02d)",
5655 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5656 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5657
5658 /* insider hack! */
5659 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5660 strcat(buf, " [MDBG]");
5661 }
5662}
5663
5664/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5665/**
5666 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5667 * @ioc: Pointer to MPT_ADAPTER structure
5668 * @buffer: Pointer to buffer where IOC summary info should be written
5669 * @size: Pointer to number of bytes we wrote (set by this routine)
5670 * @len: Offset at which to start writing in buffer
5671 * @showlan: Display LAN stuff?
5672 *
5673 * This routine writes (english readable) ASCII text, which represents
5674 * a summary of IOC information, to a buffer.
5675 */
5676void
5677mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5678{
5679 char expVer[32];
5680 int y;
5681
5682 mpt_get_fw_exp_ver(expVer, ioc);
5683
5684 /*
5685 * Shorter summary of attached ioc's...
5686 */
5687 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5688 ioc->name,
5689 ioc->prod_name,
5690 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5691 ioc->facts.FWVersion.Word,
5692 expVer,
5693 ioc->facts.NumberOfPorts,
5694 ioc->req_depth);
5695
5696 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5697 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5698 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5699 a[5], a[4], a[3], a[2], a[1], a[0]);
5700 }
5701
5702#ifndef __sparc__
5703 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
5704#else
5705 y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq));
5706#endif
5707
5708 if (!ioc->active)
5709 y += sprintf(buffer+len+y, " (disabled)");
5710
5711 y += sprintf(buffer+len+y, "\n");
5712
5713 *size = y;
5714}
5715
5716/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5717/*
5718 * Reset Handling
5719 */
5720/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5721/**
5722 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5723 * Management call based on input arg values. If TaskMgmt fails,
5724 * return associated SCSI request.
5725 * @ioc: Pointer to MPT_ADAPTER structure
5726 * @sleepFlag: Indicates if sleep or schedule must be called.
5727 *
5728 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5729 * or a non-interrupt thread. In the former, must not call schedule().
5730 *
5731 * Remark: A return of -1 is a FATAL error case, as it means a
5732 * FW reload/initialization failed.
5733 *
5734 * Returns 0 for SUCCESS or -1 if FAILED.
5735 */
5736int
5737mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5738{
5739 int rc;
5740 unsigned long flags;
5741
5742 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5743#ifdef MFCNT
5744 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5745 printk("MF count 0x%x !\n", ioc->mfcnt);
5746#endif
5747
5748 /* Reset the adapter. Prevent more than 1 call to
5749 * mpt_do_ioc_recovery at any instant in time.
5750 */
5751 spin_lock_irqsave(&ioc->diagLock, flags);
5752 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5753 spin_unlock_irqrestore(&ioc->diagLock, flags);
5754 return 0;
5755 } else {
5756 ioc->diagPending = 1;
5757 }
5758 spin_unlock_irqrestore(&ioc->diagLock, flags);
5759
5760 /* FIXME: If do_ioc_recovery fails, repeat....
5761 */
5762
5763 /* The SCSI driver needs to adjust timeouts on all current
5764 * commands prior to the diagnostic reset being issued.
5765 * Prevents timeouts occuring during a diagnostic reset...very bad.
5766 * For all other protocol drivers, this is a no-op.
5767 */
5768 {
5769 int ii;
5770 int r = 0;
5771
5772 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5773 if (MptResetHandlers[ii]) {
5774 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5775 ioc->name, ii));
5776 r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
5777 if (ioc->alt_ioc) {
5778 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5779 ioc->name, ioc->alt_ioc->name, ii));
5780 r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
5781 }
5782 }
5783 }
5784 }
5785
5786 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5787 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5788 rc, ioc->name);
5789 }
5790 ioc->reload_fw = 0;
5791 if (ioc->alt_ioc)
5792 ioc->alt_ioc->reload_fw = 0;
5793
5794 spin_lock_irqsave(&ioc->diagLock, flags);
5795 ioc->diagPending = 0;
5796 if (ioc->alt_ioc)
5797 ioc->alt_ioc->diagPending = 0;
5798 spin_unlock_irqrestore(&ioc->diagLock, flags);
5799
5800 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5801
5802 return rc;
5803}
5804
5805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005806static void
5807EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808{
5809 char *ds;
5810
5811 switch(event) {
5812 case MPI_EVENT_NONE:
5813 ds = "None";
5814 break;
5815 case MPI_EVENT_LOG_DATA:
5816 ds = "Log Data";
5817 break;
5818 case MPI_EVENT_STATE_CHANGE:
5819 ds = "State Change";
5820 break;
5821 case MPI_EVENT_UNIT_ATTENTION:
5822 ds = "Unit Attention";
5823 break;
5824 case MPI_EVENT_IOC_BUS_RESET:
5825 ds = "IOC Bus Reset";
5826 break;
5827 case MPI_EVENT_EXT_BUS_RESET:
5828 ds = "External Bus Reset";
5829 break;
5830 case MPI_EVENT_RESCAN:
5831 ds = "Bus Rescan Event";
5832 /* Ok, do we need to do anything here? As far as
5833 I can tell, this is when a new device gets added
5834 to the loop. */
5835 break;
5836 case MPI_EVENT_LINK_STATUS_CHANGE:
5837 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5838 ds = "Link Status(FAILURE) Change";
5839 else
5840 ds = "Link Status(ACTIVE) Change";
5841 break;
5842 case MPI_EVENT_LOOP_STATE_CHANGE:
5843 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5844 ds = "Loop State(LIP) Change";
5845 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
5846 ds = "Loop State(LPE) Change"; /* ??? */
5847 else
5848 ds = "Loop State(LPB) Change"; /* ??? */
5849 break;
5850 case MPI_EVENT_LOGOUT:
5851 ds = "Logout";
5852 break;
5853 case MPI_EVENT_EVENT_CHANGE:
5854 if (evData0)
5855 ds = "Events(ON) Change";
5856 else
5857 ds = "Events(OFF) Change";
5858 break;
5859 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005860 {
5861 u8 ReasonCode = (u8)(evData0 >> 16);
5862 switch (ReasonCode) {
5863 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5864 ds = "Integrated Raid: Volume Created";
5865 break;
5866 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5867 ds = "Integrated Raid: Volume Deleted";
5868 break;
5869 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5870 ds = "Integrated Raid: Volume Settings Changed";
5871 break;
5872 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5873 ds = "Integrated Raid: Volume Status Changed";
5874 break;
5875 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5876 ds = "Integrated Raid: Volume Physdisk Changed";
5877 break;
5878 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5879 ds = "Integrated Raid: Physdisk Created";
5880 break;
5881 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5882 ds = "Integrated Raid: Physdisk Deleted";
5883 break;
5884 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5885 ds = "Integrated Raid: Physdisk Settings Changed";
5886 break;
5887 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5888 ds = "Integrated Raid: Physdisk Status Changed";
5889 break;
5890 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5891 ds = "Integrated Raid: Domain Validation Needed";
5892 break;
5893 case MPI_EVENT_RAID_RC_SMART_DATA :
5894 ds = "Integrated Raid; Smart Data";
5895 break;
5896 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5897 ds = "Integrated Raid: Replace Action Started";
5898 break;
5899 default:
5900 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005902 }
5903 break;
5904 }
5905 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5906 ds = "SCSI Device Status Change";
5907 break;
5908 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5909 {
5910 u8 ReasonCode = (u8)(evData0 >> 16);
5911 switch (ReasonCode) {
5912 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
5913 ds = "SAS Device Status Change: Added";
5914 break;
5915 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
5916 ds = "SAS Device Status Change: Deleted";
5917 break;
5918 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
5919 ds = "SAS Device Status Change: SMART Data";
5920 break;
5921 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
5922 ds = "SAS Device Status Change: No Persistancy Added";
5923 break;
5924 default:
5925 ds = "SAS Device Status Change: Unknown";
5926 break;
5927 }
5928 break;
5929 }
5930 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5931 ds = "Bus Timer Expired";
5932 break;
5933 case MPI_EVENT_QUEUE_FULL:
5934 ds = "Queue Full";
5935 break;
5936 case MPI_EVENT_SAS_SES:
5937 ds = "SAS SES Event";
5938 break;
5939 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5940 ds = "Persistent Table Full";
5941 break;
5942 case MPI_EVENT_SAS_PHY_LINK_STATUS:
5943 ds = "SAS PHY Link Status";
5944 break;
5945 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5946 ds = "SAS Discovery Error";
5947 break;
5948
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 /*
5950 * MPT base "custom" events may be added here...
5951 */
5952 default:
5953 ds = "Unknown";
5954 break;
5955 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005956 strcpy(evStr,ds);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957}
5958
5959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5960/*
5961 * ProcessEventNotification - Route a received EventNotificationReply to
5962 * all currently regeistered event handlers.
5963 * @ioc: Pointer to MPT_ADAPTER structure
5964 * @pEventReply: Pointer to EventNotification reply frame
5965 * @evHandlers: Pointer to integer, number of event handlers
5966 *
5967 * Returns sum of event handlers return values.
5968 */
5969static int
5970ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
5971{
5972 u16 evDataLen;
5973 u32 evData0 = 0;
5974// u32 evCtx;
5975 int ii;
5976 int r = 0;
5977 int handlers = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005978 char evStr[100];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 u8 event;
5980
5981 /*
5982 * Do platform normalization of values
5983 */
5984 event = le32_to_cpu(pEventReply->Event) & 0xFF;
5985// evCtx = le32_to_cpu(pEventReply->EventContext);
5986 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
5987 if (evDataLen) {
5988 evData0 = le32_to_cpu(pEventReply->Data[0]);
5989 }
5990
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005991 EventDescriptionStr(event, evData0, evStr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n",
5993 ioc->name,
5994 evStr,
5995 event));
5996
5997#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS)
5998 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
5999 for (ii = 0; ii < evDataLen; ii++)
6000 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6001 printk("\n");
6002#endif
6003
6004 /*
6005 * Do general / base driver event processing
6006 */
6007 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6009 if (evDataLen) {
6010 u8 evState = evData0 & 0xFF;
6011
6012 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6013
6014 /* Update EventState field in cached IocFacts */
6015 if (ioc->facts.Function) {
6016 ioc->facts.EventState = evState;
6017 }
6018 }
6019 break;
Moore, Ericece50912006-01-16 18:53:19 -07006020 case MPI_EVENT_INTEGRATED_RAID:
6021 mptbase_raid_process_event_data(ioc,
6022 (MpiEventDataRaid_t *)pEventReply->Data);
6023 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006024 default:
6025 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026 }
6027
6028 /*
6029 * Should this event be logged? Events are written sequentially.
6030 * When buffer is full, start again at the top.
6031 */
6032 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6033 int idx;
6034
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006035 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
6037 ioc->events[idx].event = event;
6038 ioc->events[idx].eventContext = ioc->eventContext;
6039
6040 for (ii = 0; ii < 2; ii++) {
6041 if (ii < evDataLen)
6042 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6043 else
6044 ioc->events[idx].data[ii] = 0;
6045 }
6046
6047 ioc->eventContext++;
6048 }
6049
6050
6051 /*
6052 * Call each currently registered protocol event handler.
6053 */
6054 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6055 if (MptEvHandlers[ii]) {
6056 devtprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
6057 ioc->name, ii));
6058 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6059 handlers++;
6060 }
6061 }
6062 /* FIXME? Examine results here? */
6063
6064 /*
6065 * If needed, send (a single) EventAck.
6066 */
6067 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006068 devtprintk((MYIOC_s_WARN_FMT
6069 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
6071 devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
6072 ioc->name, ii));
6073 }
6074 }
6075
6076 *evHandlers = handlers;
6077 return r;
6078}
6079
6080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6081/*
6082 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6083 * @ioc: Pointer to MPT_ADAPTER structure
6084 * @log_info: U32 LogInfo reply word from the IOC
6085 *
6086 * Refer to lsi/fc_log.h.
6087 */
6088static void
6089mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6090{
6091 static char *subcl_str[8] = {
6092 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6093 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6094 };
6095 u8 subcl = (log_info >> 24) & 0x7;
6096
6097 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6098 ioc->name, log_info, subcl_str[subcl]);
6099}
6100
6101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6102/*
Moore, Eric335a9412006-01-17 17:06:23 -07006103 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 * @ioc: Pointer to MPT_ADAPTER structure
6105 * @mr: Pointer to MPT reply frame
6106 * @log_info: U32 LogInfo word from the IOC
6107 *
6108 * Refer to lsi/sp_log.h.
6109 */
6110static void
Moore, Eric335a9412006-01-17 17:06:23 -07006111mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112{
6113 u32 info = log_info & 0x00FF0000;
6114 char *desc = "unknown";
6115
6116 switch (info) {
6117 case 0x00010000:
6118 desc = "bug! MID not found";
6119 if (ioc->reload_fw == 0)
6120 ioc->reload_fw++;
6121 break;
6122
6123 case 0x00020000:
6124 desc = "Parity Error";
6125 break;
6126
6127 case 0x00030000:
6128 desc = "ASYNC Outbound Overrun";
6129 break;
6130
6131 case 0x00040000:
6132 desc = "SYNC Offset Error";
6133 break;
6134
6135 case 0x00050000:
6136 desc = "BM Change";
6137 break;
6138
6139 case 0x00060000:
6140 desc = "Msg In Overflow";
6141 break;
6142
6143 case 0x00070000:
6144 desc = "DMA Error";
6145 break;
6146
6147 case 0x00080000:
6148 desc = "Outbound DMA Overrun";
6149 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006150
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 case 0x00090000:
6152 desc = "Task Management";
6153 break;
6154
6155 case 0x000A0000:
6156 desc = "Device Problem";
6157 break;
6158
6159 case 0x000B0000:
6160 desc = "Invalid Phase Change";
6161 break;
6162
6163 case 0x000C0000:
6164 desc = "Untagged Table Size";
6165 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006166
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 }
6168
6169 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6170}
6171
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006172/* strings for sas loginfo */
6173 static char *originator_str[] = {
6174 "IOP", /* 00h */
6175 "PL", /* 01h */
6176 "IR" /* 02h */
6177 };
6178 static char *iop_code_str[] = {
6179 NULL, /* 00h */
6180 "Invalid SAS Address", /* 01h */
6181 NULL, /* 02h */
6182 "Invalid Page", /* 03h */
6183 NULL, /* 04h */
6184 "Task Terminated" /* 05h */
6185 };
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 */
6208 NULL, /* 15h */
6209 NULL, /* 16h */
6210 NULL, /* 17h */
6211 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/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6223/*
6224 * 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/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6278/*
6279 * 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;
6290 char *desc = "";
6291
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 }
6400 if (desc != "")
6401 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);
6434EXPORT_SYMBOL(mpt_read_ioc_pg_3);
6435EXPORT_SYMBOL(mpt_alloc_fw_memory);
6436EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006437EXPORT_SYMBOL(mptbase_sas_persist_operation);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07006438EXPORT_SYMBOL(mpt_alt_ioc_wait);
Michael Reed05e8ec12006-01-13 14:31:54 -06006439EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441
6442/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6443/*
6444 * fusion_init - Fusion MPT base driver initialization routine.
6445 *
6446 * Returns 0 for success, non-zero for failure.
6447 */
6448static int __init
6449fusion_init(void)
6450{
6451 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
6453 show_mptmod_ver(my_NAME, my_VERSION);
6454 printk(KERN_INFO COPYRIGHT "\n");
6455
6456 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6457 MptCallbacks[i] = NULL;
6458 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6459 MptEvHandlers[i] = NULL;
6460 MptResetHandlers[i] = NULL;
6461 }
6462
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006463 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464 * EventNotification handling.
6465 */
6466 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6467
6468 /* Register for hard reset handling callbacks.
6469 */
6470 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6471 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6472 } else {
6473 /* FIXME! */
6474 }
6475
6476#ifdef CONFIG_PROC_FS
6477 (void) procmpt_create();
6478#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006479 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480}
6481
6482/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6483/*
6484 * fusion_exit - Perform driver unload cleanup.
6485 *
6486 * This routine frees all resources associated with each MPT adapter
6487 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6488 */
6489static void __exit
6490fusion_exit(void)
6491{
6492
6493 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6494
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 mpt_reset_deregister(mpt_base_index);
6496
6497#ifdef CONFIG_PROC_FS
6498 procmpt_destroy();
6499#endif
6500}
6501
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502module_init(fusion_init);
6503module_exit(fusion_exit);