blob: 59690cbabfcaf8da4a271bb32ff76ec9b5c99bcb [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
68
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
77
78/*
79 * cmd line parameters
80 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000081static int mpt_msi_enable;
82module_param(mpt_msi_enable, int, 0);
83MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#ifdef MFCNT
86static int mfcounter = 0;
87#define PRINT_MF_COUNT 20000
88#endif
89
90/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
91/*
92 * Public data...
93 */
94int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -080095int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvaldsf7473072005-11-29 14:21:57 -080097struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99#define WHOINIT_UNKNOWN 0xAA
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Private data...
104 */
105 /* Adapter link list */
106LIST_HEAD(ioc_list);
107 /* Callback lookup table */
108static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
109 /* Protocol driver class lookup table */
110static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
111 /* Event handler lookup table */
112static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
113 /* Reset handler lookup table */
114static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
115static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
116
117static int mpt_base_index = -1;
118static int last_drv_idx = -1;
119
120static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Forward protos...
125 */
126static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
127static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
128static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
129 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
130 int sleepFlag);
131static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
132static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
133static void mpt_adapter_disable(MPT_ADAPTER *ioc);
134static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
135
136static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
137static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
139static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
140static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
141static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
142static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200143static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
145static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
146static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
147static int PrimeIocFifos(MPT_ADAPTER *ioc);
148static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
149static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
150static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
151static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200153int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
155static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
156static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
157static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
158static void mpt_timer_expired(unsigned long data);
159static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
160static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200161static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
162static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164#ifdef CONFIG_PROC_FS
165static int procmpt_summary_read(char *buf, char **start, off_t offset,
166 int request, int *eof, void *data);
167static int procmpt_version_read(char *buf, char **start, off_t offset,
168 int request, int *eof, void *data);
169static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
170 int request, int *eof, void *data);
171#endif
172static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
173
174//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
175static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
176static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
177static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700178static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600179static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700180static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static int __init fusion_init (void);
184static void __exit fusion_exit (void);
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#define CHIPREG_READ32(addr) readl_relaxed(addr)
187#define CHIPREG_READ32_dmasync(addr) readl(addr)
188#define CHIPREG_WRITE32(addr,val) writel(val, addr)
189#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
190#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
191
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600192static void
193pci_disable_io_access(struct pci_dev *pdev)
194{
195 u16 command_reg;
196
197 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
198 command_reg &= ~1;
199 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
200}
201
202static void
203pci_enable_io_access(struct pci_dev *pdev)
204{
205 u16 command_reg;
206
207 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
208 command_reg |= 1;
209 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
210}
211
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600212/*
213 * Process turbo (context) reply...
214 */
215static void
216mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
217{
218 MPT_FRAME_HDR *mf = NULL;
219 MPT_FRAME_HDR *mr = NULL;
220 int req_idx = 0;
221 int cb_idx;
222
223 dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
224 ioc->name, pa));
225
226 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
227 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
228 req_idx = pa & 0x0000FFFF;
229 cb_idx = (pa & 0x00FF0000) >> 16;
230 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
231 break;
232 case MPI_CONTEXT_REPLY_TYPE_LAN:
233 cb_idx = mpt_lan_index;
234 /*
235 * Blind set of mf to NULL here was fatal
236 * after lan_reply says "freeme"
237 * Fix sort of combined with an optimization here;
238 * added explicit check for case where lan_reply
239 * was just returning 1 and doing nothing else.
240 * For this case skip the callback, but set up
241 * proper mf value first here:-)
242 */
243 if ((pa & 0x58000000) == 0x58000000) {
244 req_idx = pa & 0x0000FFFF;
245 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
246 mpt_free_msg_frame(ioc, mf);
247 mb();
248 return;
249 break;
250 }
251 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
252 break;
253 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
254 cb_idx = mpt_stm_index;
255 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
256 break;
257 default:
258 cb_idx = 0;
259 BUG();
260 }
261
262 /* Check for (valid) IO callback! */
263 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
264 MptCallbacks[cb_idx] == NULL) {
265 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
266 __FUNCTION__, ioc->name, cb_idx);
267 goto out;
268 }
269
270 if (MptCallbacks[cb_idx](ioc, mf, mr))
271 mpt_free_msg_frame(ioc, mf);
272 out:
273 mb();
274}
275
276static void
277mpt_reply(MPT_ADAPTER *ioc, u32 pa)
278{
279 MPT_FRAME_HDR *mf;
280 MPT_FRAME_HDR *mr;
281 int req_idx;
282 int cb_idx;
283 int freeme;
284
285 u32 reply_dma_low;
286 u16 ioc_stat;
287
288 /* non-TURBO reply! Hmmm, something may be up...
289 * Newest turbo reply mechanism; get address
290 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
291 */
292
293 /* Map DMA address of reply header to cpu address.
294 * pa is 32 bits - but the dma address may be 32 or 64 bits
295 * get offset based only only the low addresses
296 */
297
298 reply_dma_low = (pa <<= 1);
299 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
300 (reply_dma_low - ioc->reply_frames_low_dma));
301
302 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
303 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
304 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
305
306 dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
307 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
308 DBG_DUMP_REPLY_FRAME(mr)
309
310 /* Check/log IOC log info
311 */
312 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
313 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
314 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
315 if (ioc->bus_type == FC)
316 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700317 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700318 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600319 else if (ioc->bus_type == SAS)
320 mpt_sas_log_info(ioc, log_info);
321 }
322 if (ioc_stat & MPI_IOCSTATUS_MASK) {
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700323 if (ioc->bus_type == SPI &&
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600324 cb_idx != mpt_stm_index &&
325 cb_idx != mpt_lan_index)
326 mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
327 }
328
329
330 /* Check for (valid) IO callback! */
331 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
332 MptCallbacks[cb_idx] == NULL) {
333 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
334 __FUNCTION__, ioc->name, cb_idx);
335 freeme = 0;
336 goto out;
337 }
338
339 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
340
341 out:
342 /* Flush (non-TURBO) reply with a WRITE! */
343 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
344
345 if (freeme)
346 mpt_free_msg_frame(ioc, mf);
347 mb();
348}
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
351/*
352 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
353 * @irq: irq number (not used)
354 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
355 * @r: pt_regs pointer (not used)
356 *
357 * This routine is registered via the request_irq() kernel API call,
358 * and handles all interrupts generated from a specific MPT adapter
359 * (also referred to as a IO Controller or IOC).
360 * This routine must clear the interrupt from the adapter and does
361 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200362 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 *
364 * This routine handles register-level access of the adapter but
365 * dispatches (calls) a protocol-specific callback routine to handle
366 * the protocol-specific details of the MPT request completion.
367 */
368static irqreturn_t
369mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
370{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600371 MPT_ADAPTER *ioc = bus_id;
372 u32 pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 /*
375 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 */
377 while (1) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600378 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
379 if (pa == 0xFFFFFFFF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 return IRQ_HANDLED;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 else if (pa & MPI_ADDRESS_REPLY_A_BIT)
382 mpt_reply(ioc, pa);
383 else
384 mpt_turbo_reply(ioc, pa);
385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 return IRQ_HANDLED;
388}
389
390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
391/*
392 * mpt_base_reply - MPT base driver's callback routine; all base driver
393 * "internal" request/reply processing is routed here.
394 * Currently used for EventNotification and EventAck handling.
395 * @ioc: Pointer to MPT_ADAPTER structure
396 * @mf: Pointer to original MPT request frame
397 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
398 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200399 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 * should be freed, or 0 if it shouldn't.
401 */
402static int
403mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
404{
405 int freereq = 1;
406 u8 func;
407
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200408 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200410#if defined(MPT_DEBUG_MSG_FRAME)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
412 dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
413 DBG_DUMP_REQUEST_FRAME_HDR(mf)
414 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200415#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417 func = reply->u.hdr.Function;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200418 dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 ioc->name, func));
420
421 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
422 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
423 int evHandlers = 0;
424 int results;
425
426 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
427 if (results != evHandlers) {
428 /* CHECKME! Any special handling needed here? */
Moore, Eric3a892be2006-03-14 09:14:03 -0700429 devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 ioc->name, evHandlers, results));
431 }
432
433 /*
434 * Hmmm... It seems that EventNotificationReply is an exception
435 * to the rule of one reply per request.
436 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200437 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 freereq = 0;
Moore, Eric3a892be2006-03-14 09:14:03 -0700439 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200440 ioc->name, pEvReply));
441 } else {
Moore, Eric3a892be2006-03-14 09:14:03 -0700442 devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200443 ioc->name, pEvReply));
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446#ifdef CONFIG_PROC_FS
447// LogEvent(ioc, pEvReply);
448#endif
449
450 } else if (func == MPI_FUNCTION_EVENT_ACK) {
451 dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
452 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700453 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 CONFIGPARMS *pCfg;
455 unsigned long flags;
456
457 dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
458 ioc->name, mf, reply));
459
460 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
461
462 if (pCfg) {
463 /* disable timer and remove from linked list */
464 del_timer(&pCfg->timer);
465
466 spin_lock_irqsave(&ioc->FreeQlock, flags);
467 list_del(&pCfg->linkage);
468 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
469
470 /*
471 * If IOC Status is SUCCESS, save the header
472 * and set the status code to GOOD.
473 */
474 pCfg->status = MPT_CONFIG_ERROR;
475 if (reply) {
476 ConfigReply_t *pReply = (ConfigReply_t *)reply;
477 u16 status;
478
479 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
480 dcprintk((KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
481 status, le32_to_cpu(pReply->IOCLogInfo)));
482
483 pCfg->status = status;
484 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200485 if ((pReply->Header.PageType &
486 MPI_CONFIG_PAGETYPE_MASK) ==
487 MPI_CONFIG_PAGETYPE_EXTENDED) {
488 pCfg->cfghdr.ehdr->ExtPageLength =
489 le16_to_cpu(pReply->ExtPageLength);
490 pCfg->cfghdr.ehdr->ExtPageType =
491 pReply->ExtPageType;
492 }
493 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
494
495 /* If this is a regular header, save PageLength. */
496 /* LMP Do this better so not using a reserved field! */
497 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
498 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
499 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
501 }
502
503 /*
504 * Wake up the original calling thread
505 */
506 pCfg->wait_done = 1;
507 wake_up(&mpt_waitq);
508 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200509 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
510 /* we should be always getting a reply frame */
511 memcpy(ioc->persist_reply_frame, reply,
512 min(MPT_DEFAULT_FRAME_SIZE,
513 4*reply->u.reply.MsgLength));
514 del_timer(&ioc->persist_timer);
515 ioc->persist_wait_done = 1;
516 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 } else {
518 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
519 ioc->name, func);
520 }
521
522 /*
523 * Conditionally tell caller to free the original
524 * EventNotification/EventAck/unexpected request frame!
525 */
526 return freereq;
527}
528
529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
530/**
531 * mpt_register - Register protocol-specific main callback handler.
532 * @cbfunc: callback function pointer
533 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
534 *
535 * This routine is called by a protocol-specific driver (SCSI host,
536 * LAN, SCSI target) to register it's reply callback routine. Each
537 * protocol-specific driver must do this before it will be able to
538 * use any IOC resources, such as obtaining request frames.
539 *
540 * NOTES: The SCSI protocol driver currently calls this routine thrice
541 * in order to register separate callbacks; one for "normal" SCSI IO;
542 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
543 *
544 * Returns a positive integer valued "handle" in the
545 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
546 * Any non-positive return value (including zero!) should be considered
547 * an error by the caller.
548 */
549int
550mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
551{
552 int i;
553
554 last_drv_idx = -1;
555
556 /*
557 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
558 * (slot/handle 0 is reserved!)
559 */
560 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
561 if (MptCallbacks[i] == NULL) {
562 MptCallbacks[i] = cbfunc;
563 MptDriverClass[i] = dclass;
564 MptEvHandlers[i] = NULL;
565 last_drv_idx = i;
566 break;
567 }
568 }
569
570 return last_drv_idx;
571}
572
573/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
574/**
575 * mpt_deregister - Deregister a protocol drivers resources.
576 * @cb_idx: previously registered callback handle
577 *
578 * Each protocol-specific driver should call this routine when it's
579 * module is unloaded.
580 */
581void
582mpt_deregister(int cb_idx)
583{
584 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
585 MptCallbacks[cb_idx] = NULL;
586 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
587 MptEvHandlers[cb_idx] = NULL;
588
589 last_drv_idx++;
590 }
591}
592
593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
594/**
595 * mpt_event_register - Register protocol-specific event callback
596 * handler.
597 * @cb_idx: previously registered (via mpt_register) callback handle
598 * @ev_cbfunc: callback function
599 *
600 * This routine can be called by one or more protocol-specific drivers
601 * if/when they choose to be notified of MPT events.
602 *
603 * Returns 0 for success.
604 */
605int
606mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
607{
608 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
609 return -1;
610
611 MptEvHandlers[cb_idx] = ev_cbfunc;
612 return 0;
613}
614
615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
616/**
617 * mpt_event_deregister - Deregister protocol-specific event callback
618 * handler.
619 * @cb_idx: previously registered callback handle
620 *
621 * Each protocol-specific driver should call this routine
622 * when it does not (or can no longer) handle events,
623 * or when it's module is unloaded.
624 */
625void
626mpt_event_deregister(int cb_idx)
627{
628 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
629 return;
630
631 MptEvHandlers[cb_idx] = NULL;
632}
633
634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
635/**
636 * mpt_reset_register - Register protocol-specific IOC reset handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @reset_func: reset function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of IOC resets.
642 *
643 * Returns 0 for success.
644 */
645int
646mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
647{
648 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
649 return -1;
650
651 MptResetHandlers[cb_idx] = reset_func;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
658 * @cb_idx: previously registered callback handle
659 *
660 * Each protocol-specific driver should call this routine
661 * when it does not (or can no longer) handle IOC reset handling,
662 * or when it's module is unloaded.
663 */
664void
665mpt_reset_deregister(int cb_idx)
666{
667 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
668 return;
669
670 MptResetHandlers[cb_idx] = NULL;
671}
672
673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
674/**
675 * mpt_device_driver_register - Register device driver hooks
676 */
677int
678mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
679{
680 MPT_ADAPTER *ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400683 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685
686 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
687
688 /* call per pci device probe entry point */
689 list_for_each_entry(ioc, &ioc_list, list) {
690 if(dd_cbfunc->probe) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400691 dd_cbfunc->probe(ioc->pcidev,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 ioc->pcidev->driver->id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
694 }
695
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400696 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
700/**
701 * mpt_device_driver_deregister - DeRegister device driver hooks
702 */
703void
704mpt_device_driver_deregister(int cb_idx)
705{
706 struct mpt_pci_driver *dd_cbfunc;
707 MPT_ADAPTER *ioc;
708
709 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
710 return;
711
712 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
713
714 list_for_each_entry(ioc, &ioc_list, list) {
715 if (dd_cbfunc->remove)
716 dd_cbfunc->remove(ioc->pcidev);
717 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 MptDeviceDriverHandlers[cb_idx] = NULL;
720}
721
722
723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
724/**
725 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
726 * allocated per MPT adapter.
727 * @handle: Handle of registered MPT protocol driver
728 * @ioc: Pointer to MPT adapter structure
729 *
730 * Returns pointer to a MPT request frame or %NULL if none are available
731 * or IOC is not active.
732 */
733MPT_FRAME_HDR*
734mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
735{
736 MPT_FRAME_HDR *mf;
737 unsigned long flags;
738 u16 req_idx; /* Request index */
739
740 /* validate handle and ioc identifier */
741
742#ifdef MFCNT
743 if (!ioc->active)
744 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
745#endif
746
747 /* If interrupts are not attached, do not return a request frame */
748 if (!ioc->active)
749 return NULL;
750
751 spin_lock_irqsave(&ioc->FreeQlock, flags);
752 if (!list_empty(&ioc->FreeQ)) {
753 int req_offset;
754
755 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
756 u.frame.linkage.list);
757 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200758 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
760 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
761 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500762 req_idx = req_offset / ioc->req_sz;
763 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
765 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
766#ifdef MFCNT
767 ioc->mfcnt++;
768#endif
769 }
770 else
771 mf = NULL;
772 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
773
774#ifdef MFCNT
775 if (mf == NULL)
776 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
777 mfcounter++;
778 if (mfcounter == PRINT_MF_COUNT)
779 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
780#endif
781
782 dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
783 ioc->name, handle, ioc->id, mf));
784 return mf;
785}
786
787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
788/**
789 * mpt_put_msg_frame - Send a protocol specific MPT request frame
790 * to a IOC.
791 * @handle: Handle of registered MPT protocol driver
792 * @ioc: Pointer to MPT adapter structure
793 * @mf: Pointer to MPT request frame
794 *
795 * This routine posts a MPT request frame to the request post FIFO of a
796 * specific MPT adapter.
797 */
798void
799mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
800{
801 u32 mf_dma_addr;
802 int req_offset;
803 u16 req_idx; /* Request index */
804
805 /* ensure values are reset properly! */
806 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
807 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
808 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500809 req_idx = req_offset / ioc->req_sz;
810 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
812
813#ifdef MPT_DEBUG_MSG_FRAME
814 {
815 u32 *m = mf->u.frame.hwhdr.__hdr;
816 int ii, n;
817
818 printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
819 ioc->name, m);
820 n = ioc->req_sz/4 - 1;
821 while (m[n] == 0)
822 n--;
823 for (ii=0; ii<=n; ii++) {
824 if (ii && ((ii%8)==0))
825 printk("\n" KERN_INFO " ");
826 printk(" %08x", le32_to_cpu(m[ii]));
827 }
828 printk("\n");
829 }
830#endif
831
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200832 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
834 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
835}
836
837/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
838/**
839 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
840 * @handle: Handle of registered MPT protocol driver
841 * @ioc: Pointer to MPT adapter structure
842 * @mf: Pointer to MPT request frame
843 *
844 * This routine places a MPT request frame back on the MPT adapter's
845 * FreeQ.
846 */
847void
848mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
849{
850 unsigned long flags;
851
852 /* Put Request back on FreeQ! */
853 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200854 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
856#ifdef MFCNT
857 ioc->mfcnt--;
858#endif
859 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
860}
861
862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
863/**
864 * mpt_add_sge - Place a simple SGE at address pAddr.
865 * @pAddr: virtual address for SGE
866 * @flagslength: SGE flags and data transfer length
867 * @dma_addr: Physical address
868 *
869 * This routine places a MPT request frame back on the MPT adapter's
870 * FreeQ.
871 */
872void
873mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
874{
875 if (sizeof(dma_addr_t) == sizeof(u64)) {
876 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
877 u32 tmp = dma_addr & 0xFFFFFFFF;
878
879 pSge->FlagsLength = cpu_to_le32(flagslength);
880 pSge->Address.Low = cpu_to_le32(tmp);
881 tmp = (u32) ((u64)dma_addr >> 32);
882 pSge->Address.High = cpu_to_le32(tmp);
883
884 } else {
885 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
886 pSge->FlagsLength = cpu_to_le32(flagslength);
887 pSge->Address = cpu_to_le32(dma_addr);
888 }
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
893 * mpt_send_handshake_request - Send MPT request via doorbell
894 * handshake method.
895 * @handle: Handle of registered MPT protocol driver
896 * @ioc: Pointer to MPT adapter structure
897 * @reqBytes: Size of the request in bytes
898 * @req: Pointer to MPT request frame
899 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
900 *
901 * This routine is used exclusively to send MptScsiTaskMgmt
902 * requests since they are required to be sent via doorbell handshake.
903 *
904 * NOTE: It is the callers responsibility to byte-swap fields in the
905 * request which are greater than 1 byte in size.
906 *
907 * Returns 0 for success, non-zero for failure.
908 */
909int
910mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
911{
912 int r = 0;
913 u8 *req_as_bytes;
914 int ii;
915
916 /* State is known to be good upon entering
917 * this function so issue the bus reset
918 * request.
919 */
920
921 /*
922 * Emulate what mpt_put_msg_frame() does /wrt to sanity
923 * setting cb_idx/req_idx. But ONLY if this request
924 * is in proper (pre-alloc'd) request buffer range...
925 */
926 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
927 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
928 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
929 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
930 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
931 }
932
933 /* Make sure there are no doorbells */
934 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 CHIPREG_WRITE32(&ioc->chip->Doorbell,
937 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
938 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
939
940 /* Wait for IOC doorbell int */
941 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
942 return ii;
943 }
944
945 /* Read doorbell and check for active bit */
946 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
947 return -5;
948
949 dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200950 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
953
954 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
955 return -2;
956 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 /* Send request via doorbell handshake */
959 req_as_bytes = (u8 *) req;
960 for (ii = 0; ii < reqBytes/4; ii++) {
961 u32 word;
962
963 word = ((req_as_bytes[(ii*4) + 0] << 0) |
964 (req_as_bytes[(ii*4) + 1] << 8) |
965 (req_as_bytes[(ii*4) + 2] << 16) |
966 (req_as_bytes[(ii*4) + 3] << 24));
967 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
968 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
969 r = -3;
970 break;
971 }
972 }
973
974 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
975 r = 0;
976 else
977 r = -4;
978
979 /* Make sure there are no doorbells */
980 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return r;
983}
984
985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
986/**
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200987 * mpt_host_page_access_control - provides mechanism for the host
988 * driver to control the IOC's Host Page Buffer access.
989 * @ioc: Pointer to MPT adapter structure
990 * @access_control_value: define bits below
991 *
992 * Access Control Value - bits[15:12]
993 * 0h Reserved
994 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
995 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
996 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
997 *
998 * Returns 0 for success, non-zero for failure.
999 */
1000
1001static int
1002mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1003{
1004 int r = 0;
1005
1006 /* return if in use */
1007 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1008 & MPI_DOORBELL_ACTIVE)
1009 return -1;
1010
1011 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1012
1013 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1014 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1015 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1016 (access_control_value<<12)));
1017
1018 /* Wait for IOC to clear Doorbell Status bit */
1019 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1020 return -2;
1021 }else
1022 return 0;
1023}
1024
1025/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1026/**
1027 * mpt_host_page_alloc - allocate system memory for the fw
1028 * If we already allocated memory in past, then resend the same pointer.
1029 * ioc@: Pointer to pointer to IOC adapter
1030 * ioc_init@: Pointer to ioc init config page
1031 *
1032 * Returns 0 for success, non-zero for failure.
1033 */
1034static int
1035mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1036{
1037 char *psge;
1038 int flags_length;
1039 u32 host_page_buffer_sz=0;
1040
1041 if(!ioc->HostPageBuffer) {
1042
1043 host_page_buffer_sz =
1044 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1045
1046 if(!host_page_buffer_sz)
1047 return 0; /* fw doesn't need any host buffers */
1048
1049 /* spin till we get enough memory */
1050 while(host_page_buffer_sz > 0) {
1051
1052 if((ioc->HostPageBuffer = pci_alloc_consistent(
1053 ioc->pcidev,
1054 host_page_buffer_sz,
1055 &ioc->HostPageBuffer_dma)) != NULL) {
1056
1057 dinitprintk((MYIOC_s_INFO_FMT
1058 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
1059 ioc->name,
1060 ioc->HostPageBuffer,
1061 ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001062 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001063 ioc->alloc_total += host_page_buffer_sz;
1064 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1065 break;
1066 }
1067
1068 host_page_buffer_sz -= (4*1024);
1069 }
1070 }
1071
1072 if(!ioc->HostPageBuffer) {
1073 printk(MYIOC_s_ERR_FMT
1074 "Failed to alloc memory for host_page_buffer!\n",
1075 ioc->name);
1076 return -999;
1077 }
1078
1079 psge = (char *)&ioc_init->HostPageBufferSGE;
1080 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1081 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1082 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1083 MPI_SGE_FLAGS_HOST_TO_IOC |
1084 MPI_SGE_FLAGS_END_OF_BUFFER;
1085 if (sizeof(dma_addr_t) == sizeof(u64)) {
1086 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1087 }
1088 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1089 flags_length |= ioc->HostPageBuffer_sz;
1090 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1091 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1092
1093return 0;
1094}
1095
1096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1097/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 * mpt_verify_adapter - Given a unique IOC identifier, set pointer to
1099 * the associated MPT adapter structure.
1100 * @iocid: IOC unique identifier (integer)
1101 * @iocpp: Pointer to pointer to IOC adapter
1102 *
1103 * Returns iocid and sets iocpp.
1104 */
1105int
1106mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1107{
1108 MPT_ADAPTER *ioc;
1109
1110 list_for_each_entry(ioc,&ioc_list,list) {
1111 if (ioc->id == iocid) {
1112 *iocpp =ioc;
1113 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 *iocpp = NULL;
1118 return -1;
1119}
1120
1121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1122/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001123 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 * @pdev: Pointer to pci_dev structure
1125 *
1126 * This routine performs all the steps necessary to bring the IOC of
1127 * a MPT adapter to a OPERATIONAL state. This includes registering
1128 * memory regions, registering the interrupt, and allocating request
1129 * and reply memory pools.
1130 *
1131 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1132 * MPT adapter.
1133 *
1134 * Returns 0 for success, non-zero for failure.
1135 *
1136 * TODO: Add support for polled controllers
1137 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001138int
1139mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
1141 MPT_ADAPTER *ioc;
1142 u8 __iomem *mem;
1143 unsigned long mem_phys;
1144 unsigned long port;
1145 u32 msize;
1146 u32 psize;
1147 int ii;
1148 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 u8 revision;
1150 u8 pcixcmd;
1151 static int mpt_ids = 0;
1152#ifdef CONFIG_PROC_FS
1153 struct proc_dir_entry *dent, *ent;
1154#endif
1155
1156 if (pci_enable_device(pdev))
1157 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001160
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001161 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 dprintk((KERN_INFO MYNAM
1163 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001164 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1166 return r;
1167 }
1168
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001169 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 dprintk((KERN_INFO MYNAM
1171 ": Using 64 bit consistent mask\n"));
1172 else
1173 dprintk((KERN_INFO MYNAM
1174 ": Not using 64 bit consistent mask\n"));
1175
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001176 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (ioc == NULL) {
1178 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1179 return -ENOMEM;
1180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 ioc->alloc_total = sizeof(MPT_ADAPTER);
1182 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1183 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 ioc->pcidev = pdev;
1186 ioc->diagPending = 0;
1187 spin_lock_init(&ioc->diagLock);
Michael Reed05e8ec12006-01-13 14:31:54 -06001188 spin_lock_init(&ioc->fc_rescan_work_lock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001189 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191 /* Initialize the event logging.
1192 */
1193 ioc->eventTypes = 0; /* None */
1194 ioc->eventContext = 0;
1195 ioc->eventLogSize = 0;
1196 ioc->events = NULL;
1197
1198#ifdef MFCNT
1199 ioc->mfcnt = 0;
1200#endif
1201
1202 ioc->cached_fw = NULL;
1203
1204 /* Initilize SCSI Config Data structure
1205 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001206 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 /* Initialize the running configQ head.
1209 */
1210 INIT_LIST_HEAD(&ioc->configQ);
1211
Michael Reed05e8ec12006-01-13 14:31:54 -06001212 /* Initialize the fc rport list head.
1213 */
1214 INIT_LIST_HEAD(&ioc->fc_rports);
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 /* Find lookup slot. */
1217 INIT_LIST_HEAD(&ioc->list);
1218 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 mem_phys = msize = 0;
1221 port = psize = 0;
1222 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1223 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1224 /* Get I/O space! */
1225 port = pci_resource_start(pdev, ii);
1226 psize = pci_resource_len(pdev,ii);
1227 } else {
1228 /* Get memmap */
1229 mem_phys = pci_resource_start(pdev, ii);
1230 msize = pci_resource_len(pdev,ii);
1231 break;
1232 }
1233 }
1234 ioc->mem_size = msize;
1235
1236 if (ii == DEVICE_COUNT_RESOURCE) {
1237 printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
1238 kfree(ioc);
1239 return -EINVAL;
1240 }
1241
1242 dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
1243 dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
1244
1245 mem = NULL;
1246 /* Get logical ptr for PciMem0 space */
1247 /*mem = ioremap(mem_phys, msize);*/
1248 mem = ioremap(mem_phys, 0x100);
1249 if (mem == NULL) {
1250 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1251 kfree(ioc);
1252 return -EINVAL;
1253 }
1254 ioc->memmap = mem;
1255 dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
1256
1257 dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
1258 &ioc->facts, &ioc->pfacts[0]));
1259
1260 ioc->mem_phys = mem_phys;
1261 ioc->chip = (SYSIF_REGS __iomem *)mem;
1262
1263 /* Save Port IO values in case we need to do downloadboot */
1264 {
1265 u8 *pmem = (u8*)port;
1266 ioc->pio_mem_phys = port;
1267 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1268 }
1269
1270 if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
1271 ioc->prod_name = "LSIFC909";
1272 ioc->bus_type = FC;
1273 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001274 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 ioc->prod_name = "LSIFC929";
1276 ioc->bus_type = FC;
1277 }
1278 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
1279 ioc->prod_name = "LSIFC919";
1280 ioc->bus_type = FC;
1281 }
1282 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
1283 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1284 ioc->bus_type = FC;
1285 if (revision < XL_929) {
1286 ioc->prod_name = "LSIFC929X";
1287 /* 929X Chip Fix. Set Split transactions level
1288 * for PCIX. Set MOST bits to zero.
1289 */
1290 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1291 pcixcmd &= 0x8F;
1292 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1293 } else {
1294 ioc->prod_name = "LSIFC929XL";
1295 /* 929XL Chip Fix. Set MMRBC to 0x08.
1296 */
1297 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1298 pcixcmd |= 0x08;
1299 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1300 }
1301 }
1302 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
1303 ioc->prod_name = "LSIFC919X";
1304 ioc->bus_type = FC;
1305 /* 919X Chip Fix. Set Split transactions level
1306 * for PCIX. Set MOST bits to zero.
1307 */
1308 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1309 pcixcmd &= 0x8F;
1310 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1311 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001312 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
1313 ioc->prod_name = "LSIFC939X";
1314 ioc->bus_type = FC;
1315 ioc->errata_flag_1064 = 1;
1316 }
1317 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
1318 ioc->prod_name = "LSIFC949X";
1319 ioc->bus_type = FC;
1320 ioc->errata_flag_1064 = 1;
1321 }
Moore, Eric6d5b0c32006-01-13 16:25:26 -07001322 else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
1323 ioc->prod_name = "LSIFC949E";
1324 ioc->bus_type = FC;
1325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
1327 ioc->prod_name = "LSI53C1030";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001328 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 /* 1030 Chip Fix. Disable Split transactions
1330 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1331 */
1332 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1333 if (revision < C0_1030) {
1334 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1335 pcixcmd &= 0x8F;
1336 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1337 }
1338 }
1339 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
1340 ioc->prod_name = "LSI53C1035";
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001341 ioc->bus_type = SPI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001343 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
1344 ioc->prod_name = "LSISAS1064";
1345 ioc->bus_type = SAS;
1346 ioc->errata_flag_1064 = 1;
1347 }
1348 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
1349 ioc->prod_name = "LSISAS1066";
1350 ioc->bus_type = SAS;
1351 ioc->errata_flag_1064 = 1;
1352 }
1353 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
1354 ioc->prod_name = "LSISAS1068";
1355 ioc->bus_type = SAS;
1356 ioc->errata_flag_1064 = 1;
1357 }
1358 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
1359 ioc->prod_name = "LSISAS1064E";
1360 ioc->bus_type = SAS;
1361 }
1362 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
1363 ioc->prod_name = "LSISAS1066E";
1364 ioc->bus_type = SAS;
1365 }
1366 else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
1367 ioc->prod_name = "LSISAS1068E";
1368 ioc->bus_type = SAS;
1369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001371 if (ioc->errata_flag_1064)
1372 pci_disable_io_access(pdev);
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 sprintf(ioc->name, "ioc%d", ioc->id);
1375
1376 spin_lock_init(&ioc->FreeQlock);
1377
1378 /* Disable all! */
1379 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1380 ioc->active = 0;
1381 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1382
1383 /* Set lookup ptr. */
1384 list_add_tail(&ioc->list, &ioc_list);
1385
1386 ioc->pci_irq = -1;
1387 if (pdev->irq) {
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001388 if (mpt_msi_enable && !pci_enable_msi(pdev))
1389 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
1392
1393 if (r < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n",
1395 ioc->name, pdev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 list_del(&ioc->list);
1397 iounmap(mem);
1398 kfree(ioc);
1399 return -EBUSY;
1400 }
1401
1402 ioc->pci_irq = pdev->irq;
1403
1404 pci_set_master(pdev); /* ?? */
1405 pci_set_drvdata(pdev, ioc);
1406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
1409
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001410 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 */
1412 mpt_detect_bound_ports(ioc, pdev);
1413
James Bottomleyc92f2222006-03-01 09:02:49 -06001414 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1415 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 printk(KERN_WARNING MYNAM
1417 ": WARNING - %s did not initialize properly! (%d)\n",
1418 ioc->name, r);
1419
1420 list_del(&ioc->list);
1421 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00001422 if (mpt_msi_enable)
1423 pci_disable_msi(pdev);
Moore, Eric335a9412006-01-17 17:06:23 -07001424 if (ioc->alt_ioc)
1425 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 iounmap(mem);
1427 kfree(ioc);
1428 pci_set_drvdata(pdev, NULL);
1429 return r;
1430 }
1431
1432 /* call per device driver probe entry point */
1433 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1434 if(MptDeviceDriverHandlers[ii] &&
1435 MptDeviceDriverHandlers[ii]->probe) {
1436 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1437 }
1438 }
1439
1440#ifdef CONFIG_PROC_FS
1441 /*
1442 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1443 */
1444 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1445 if (dent) {
1446 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1447 if (ent) {
1448 ent->read_proc = procmpt_iocinfo_read;
1449 ent->data = ioc;
1450 }
1451 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1452 if (ent) {
1453 ent->read_proc = procmpt_summary_read;
1454 ent->data = ioc;
1455 }
1456 }
1457#endif
1458
1459 return 0;
1460}
1461
1462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1463/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001464 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 * @pdev: Pointer to pci_dev structure
1466 *
1467 */
1468
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001469void
1470mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
1472 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1473 char pname[32];
1474 int ii;
1475
1476 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1477 remove_proc_entry(pname, NULL);
1478 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1479 remove_proc_entry(pname, NULL);
1480 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1481 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 /* call per device driver remove entry point */
1484 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1485 if(MptDeviceDriverHandlers[ii] &&
1486 MptDeviceDriverHandlers[ii]->remove) {
1487 MptDeviceDriverHandlers[ii]->remove(pdev);
1488 }
1489 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 /* Disable interrupts! */
1492 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1493
1494 ioc->active = 0;
1495 synchronize_irq(pdev->irq);
1496
1497 /* Clear any lingering interrupt */
1498 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1499
1500 CHIPREG_READ32(&ioc->chip->IntStatus);
1501
1502 mpt_adapter_dispose(ioc);
1503
1504 pci_set_drvdata(pdev, NULL);
1505}
1506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507/**************************************************************************
1508 * Power Management
1509 */
1510#ifdef CONFIG_PM
1511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1512/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001513 * mpt_suspend - Fusion MPT base driver suspend routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 *
1515 *
1516 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001517int
1518mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
1520 u32 device_state;
1521 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
Pavel Machek2a569572005-07-07 17:56:40 -07001523 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 printk(MYIOC_s_INFO_FMT
1526 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1527 ioc->name, pdev, pci_name(pdev), device_state);
1528
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 pci_save_state(pdev);
1530
1531 /* put ioc into READY_STATE */
1532 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1533 printk(MYIOC_s_ERR_FMT
1534 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1535 }
1536
1537 /* disable interrupts */
1538 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1539 ioc->active = 0;
1540
1541 /* Clear any lingering interrupt */
1542 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1543
1544 pci_disable_device(pdev);
1545 pci_set_power_state(pdev, device_state);
1546
1547 return 0;
1548}
1549
1550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1551/*
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001552 * mpt_resume - Fusion MPT base driver resume routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 *
1554 *
1555 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001556int
1557mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558{
1559 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1560 u32 device_state = pdev->current_state;
1561 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 printk(MYIOC_s_INFO_FMT
1564 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1565 ioc->name, pdev, pci_name(pdev), device_state);
1566
1567 pci_set_power_state(pdev, 0);
1568 pci_restore_state(pdev);
1569 pci_enable_device(pdev);
1570
1571 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001572 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 ioc->active = 1;
1574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 printk(MYIOC_s_INFO_FMT
1576 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1577 ioc->name,
1578 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1579 CHIPREG_READ32(&ioc->chip->Doorbell));
1580
1581 /* bring ioc to operational state */
1582 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1583 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1584 printk(MYIOC_s_INFO_FMT
1585 "pci-resume: Cannot recover, error:[%x]\n",
1586 ioc->name, recovery_state);
1587 } else {
1588 printk(MYIOC_s_INFO_FMT
1589 "pci-resume: success\n", ioc->name);
1590 }
1591
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 return 0;
1593}
1594#endif
1595
James Bottomley4ff42a62006-05-17 18:06:52 -05001596static int
1597mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1598{
1599 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1600 ioc->bus_type != SPI) ||
1601 (MptDriverClass[index] == MPTFC_DRIVER &&
1602 ioc->bus_type != FC) ||
1603 (MptDriverClass[index] == MPTSAS_DRIVER &&
1604 ioc->bus_type != SAS))
1605 /* make sure we only call the relevant reset handler
1606 * for the bus */
1607 return 0;
1608 return (MptResetHandlers[index])(ioc, reset_phase);
1609}
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1612/*
1613 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1614 * @ioc: Pointer to MPT adapter structure
1615 * @reason: Event word / reason
1616 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1617 *
1618 * This routine performs all the steps necessary to bring the IOC
1619 * to a OPERATIONAL state.
1620 *
1621 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1622 * MPT adapter.
1623 *
1624 * Returns:
1625 * 0 for success
1626 * -1 if failed to get board READY
1627 * -2 if READY but IOCFacts Failed
1628 * -3 if READY but PrimeIOCFifos Failed
1629 * -4 if READY but IOCInit Failed
1630 */
1631static int
1632mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1633{
1634 int hard_reset_done = 0;
1635 int alt_ioc_ready = 0;
1636 int hard;
1637 int rc=0;
1638 int ii;
1639 int handlers;
1640 int ret = 0;
1641 int reset_alt_ioc_active = 0;
1642
1643 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1644 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1645
1646 /* Disable reply interrupts (also blocks FreeQ) */
1647 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1648 ioc->active = 0;
1649
1650 if (ioc->alt_ioc) {
1651 if (ioc->alt_ioc->active)
1652 reset_alt_ioc_active = 1;
1653
1654 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1655 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1656 ioc->alt_ioc->active = 0;
1657 }
1658
1659 hard = 1;
1660 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1661 hard = 0;
1662
1663 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1664 if (hard_reset_done == -4) {
1665 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1666 ioc->name);
1667
1668 if (reset_alt_ioc_active && ioc->alt_ioc) {
1669 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
1670 dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
1671 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001672 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 ioc->alt_ioc->active = 1;
1674 }
1675
1676 } else {
1677 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1678 ioc->name);
1679 }
1680 return -1;
1681 }
1682
1683 /* hard_reset_done = 0 if a soft reset was performed
1684 * and 1 if a hard reset was performed.
1685 */
1686 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1687 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1688 alt_ioc_ready = 1;
1689 else
1690 printk(KERN_WARNING MYNAM
1691 ": alt-%s: Not ready WARNING!\n",
1692 ioc->alt_ioc->name);
1693 }
1694
1695 for (ii=0; ii<5; ii++) {
1696 /* Get IOC facts! Allow 5 retries */
1697 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1698 break;
1699 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702 if (ii == 5) {
1703 dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
1704 ret = -2;
1705 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1706 MptDisplayIocCapabilities(ioc);
1707 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 if (alt_ioc_ready) {
1710 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
1711 dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
1712 /* Retry - alt IOC was initialized once
1713 */
1714 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1715 }
1716 if (rc) {
1717 dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
1718 alt_ioc_ready = 0;
1719 reset_alt_ioc_active = 0;
1720 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1721 MptDisplayIocCapabilities(ioc->alt_ioc);
1722 }
1723 }
1724
1725 /* Prime reply & request queues!
1726 * (mucho alloc's) Must be done prior to
1727 * init as upper addresses are needed for init.
1728 * If fails, continue with alt-ioc processing
1729 */
1730 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1731 ret = -3;
1732
1733 /* May need to check/upload firmware & data here!
1734 * If fails, continue with alt-ioc processing
1735 */
1736 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1737 ret = -4;
1738// NEW!
1739 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1740 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1741 ioc->alt_ioc->name, rc);
1742 alt_ioc_ready = 0;
1743 reset_alt_ioc_active = 0;
1744 }
1745
1746 if (alt_ioc_ready) {
1747 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1748 alt_ioc_ready = 0;
1749 reset_alt_ioc_active = 0;
1750 printk(KERN_WARNING MYNAM
1751 ": alt-%s: (%d) init failure WARNING!\n",
1752 ioc->alt_ioc->name, rc);
1753 }
1754 }
1755
1756 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1757 if (ioc->upload_fw) {
1758 ddlprintk((MYIOC_s_INFO_FMT
1759 "firmware upload required!\n", ioc->name));
1760
1761 /* Controller is not operational, cannot do upload
1762 */
1763 if (ret == 0) {
1764 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001765 if (rc == 0) {
1766 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1767 /*
1768 * Maintain only one pointer to FW memory
1769 * so there will not be two attempt to
1770 * downloadboot onboard dual function
1771 * chips (mpt_adapter_disable,
1772 * mpt_diag_reset)
1773 */
1774 ioc->cached_fw = NULL;
1775 ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
1776 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
1777 }
1778 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001780 ret = -5;
1781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 }
1783 }
1784 }
1785
1786 if (ret == 0) {
1787 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07001788 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 ioc->active = 1;
1790 }
1791
1792 if (reset_alt_ioc_active && ioc->alt_ioc) {
1793 /* (re)Enable alt-IOC! (reply interrupt) */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001794 dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001796 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 ioc->alt_ioc->active = 1;
1798 }
1799
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001800 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 * and EventAck handling.
1802 */
1803 if ((ret == 0) && (!ioc->facts.EventState))
1804 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
1805
1806 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
1807 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
1808
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001809 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 * (combined with GetIoUnitPage2 call). This prevents a somewhat
1811 * recursive scenario; GetLanConfigPages times out, timer expired
1812 * routine calls HardResetHandler, which calls into here again,
1813 * and we try GetLanConfigPages again...
1814 */
1815 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001816 if (ioc->bus_type == SAS) {
1817
1818 /* clear persistency table */
1819 if(ioc->facts.IOCExceptions &
1820 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
1821 ret = mptbase_sas_persist_operation(ioc,
1822 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1823 if(ret != 0)
1824 return -1;
1825 }
1826
1827 /* Find IM volumes
1828 */
1829 mpt_findImVolumes(ioc);
1830
1831 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 /*
1833 * Pre-fetch FC port WWN and stuff...
1834 * (FCPortPage0_t stuff)
1835 */
1836 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
Michael Reed05e8ec12006-01-13 14:31:54 -06001837 (void) mptbase_GetFcPortPage0(ioc, ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
1839
1840 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
1841 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
1842 /*
1843 * Pre-fetch the ports LAN MAC address!
1844 * (LANPage1_t stuff)
1845 */
1846 (void) GetLanConfigPages(ioc);
1847#ifdef MPT_DEBUG
1848 {
1849 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
1850 dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
1851 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
1852 }
1853#endif
1854 }
1855 } else {
1856 /* Get NVRAM and adapter maximums from SPP 0 and 2
1857 */
1858 mpt_GetScsiPortSettings(ioc, 0);
1859
1860 /* Get version and length of SDP 1
1861 */
1862 mpt_readScsiDevicePageHeaders(ioc, 0);
1863
1864 /* Find IM volumes
1865 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001866 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 mpt_findImVolumes(ioc);
1868
1869 /* Check, and possibly reset, the coalescing value
1870 */
1871 mpt_read_ioc_pg_1(ioc);
1872
1873 mpt_read_ioc_pg_4(ioc);
1874 }
1875
1876 GetIoUnitPage2(ioc);
1877 }
1878
1879 /*
1880 * Call each currently registered protocol IOC reset handler
1881 * with post-reset indication.
1882 * NOTE: If we're doing _IOC_BRINGUP, there can be no
1883 * MptResetHandlers[] registered yet.
1884 */
1885 if (hard_reset_done) {
1886 rc = handlers = 0;
1887 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
1888 if ((ret == 0) && MptResetHandlers[ii]) {
1889 dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
1890 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001891 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 handlers++;
1893 }
1894
1895 if (alt_ioc_ready && MptResetHandlers[ii]) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001896 drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05001898 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 handlers++;
1900 }
1901 }
1902 /* FIXME? Examine results here? */
1903 }
1904
1905 return ret;
1906}
1907
1908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1909/*
1910 * mpt_detect_bound_ports - Search for PCI bus/dev_function
1911 * which matches PCI bus/dev_function (+/-1) for newly discovered 929,
1912 * 929X, 1030 or 1035.
1913 * @ioc: Pointer to MPT adapter structure
1914 * @pdev: Pointer to (struct pci_dev) structure
1915 *
1916 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
1917 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
1918 */
1919static void
1920mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
1921{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001922 struct pci_dev *peer=NULL;
1923 unsigned int slot = PCI_SLOT(pdev->devfn);
1924 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 MPT_ADAPTER *ioc_srch;
1926
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001927 dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
1928 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001929 ioc->name, pci_name(pdev), pdev->bus->number,
1930 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001931
1932 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
1933 if (!peer) {
1934 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
1935 if (!peer)
1936 return;
1937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938
1939 list_for_each_entry(ioc_srch, &ioc_list, list) {
1940 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001941 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 /* Paranoia checks */
1943 if (ioc->alt_ioc != NULL) {
1944 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001945 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 break;
1947 } else if (ioc_srch->alt_ioc != NULL) {
1948 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001949 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 break;
1951 }
1952 dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001953 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 ioc_srch->alt_ioc = ioc;
1955 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001958 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959}
1960
1961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1962/*
1963 * mpt_adapter_disable - Disable misbehaving MPT adapter.
1964 * @this: Pointer to MPT adapter structure
1965 */
1966static void
1967mpt_adapter_disable(MPT_ADAPTER *ioc)
1968{
1969 int sz;
1970 int ret;
1971
1972 if (ioc->cached_fw != NULL) {
1973 ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001974 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 printk(KERN_WARNING MYNAM
1976 ": firmware downloadboot failure (%d)!\n", ret);
1977 }
1978 }
1979
1980 /* Disable adapter interrupts! */
1981 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1982 ioc->active = 0;
1983 /* Clear any lingering interrupt */
1984 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1985
1986 if (ioc->alloc != NULL) {
1987 sz = ioc->alloc_sz;
1988 dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
1989 ioc->name, ioc->alloc, ioc->alloc_sz));
1990 pci_free_consistent(ioc->pcidev, sz,
1991 ioc->alloc, ioc->alloc_dma);
1992 ioc->reply_frames = NULL;
1993 ioc->req_frames = NULL;
1994 ioc->alloc = NULL;
1995 ioc->alloc_total -= sz;
1996 }
1997
1998 if (ioc->sense_buf_pool != NULL) {
1999 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2000 pci_free_consistent(ioc->pcidev, sz,
2001 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2002 ioc->sense_buf_pool = NULL;
2003 ioc->alloc_total -= sz;
2004 }
2005
2006 if (ioc->events != NULL){
2007 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2008 kfree(ioc->events);
2009 ioc->events = NULL;
2010 ioc->alloc_total -= sz;
2011 }
2012
2013 if (ioc->cached_fw != NULL) {
2014 sz = ioc->facts.FWImageSize;
2015 pci_free_consistent(ioc->pcidev, sz,
2016 ioc->cached_fw, ioc->cached_fw_dma);
2017 ioc->cached_fw = NULL;
2018 ioc->alloc_total -= sz;
2019 }
2020
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002021 kfree(ioc->spi_data.nvram);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002022 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002023 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002024 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 if (ioc->spi_data.pIocPg4 != NULL) {
2027 sz = ioc->spi_data.IocPg4Sz;
2028 pci_free_consistent(ioc->pcidev, sz,
2029 ioc->spi_data.pIocPg4,
2030 ioc->spi_data.IocPg4_dma);
2031 ioc->spi_data.pIocPg4 = NULL;
2032 ioc->alloc_total -= sz;
2033 }
2034
2035 if (ioc->ReqToChain != NULL) {
2036 kfree(ioc->ReqToChain);
2037 kfree(ioc->RequestNB);
2038 ioc->ReqToChain = NULL;
2039 }
2040
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002041 kfree(ioc->ChainToChain);
2042 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002043
2044 if (ioc->HostPageBuffer != NULL) {
2045 if((ret = mpt_host_page_access_control(ioc,
2046 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2047 printk(KERN_ERR MYNAM
2048 ": %s: host page buffers free failed (%d)!\n",
2049 __FUNCTION__, ret);
2050 }
2051 dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
2052 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2053 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2054 ioc->HostPageBuffer,
2055 ioc->HostPageBuffer_dma);
2056 ioc->HostPageBuffer = NULL;
2057 ioc->HostPageBuffer_sz = 0;
2058 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060}
2061
2062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2063/*
2064 * mpt_adapter_dispose - Free all resources associated with a MPT
2065 * adapter.
2066 * @ioc: Pointer to MPT adapter structure
2067 *
2068 * This routine unregisters h/w resources and frees all alloc'd memory
2069 * associated with a MPT adapter structure.
2070 */
2071static void
2072mpt_adapter_dispose(MPT_ADAPTER *ioc)
2073{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002074 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002076 if (ioc == NULL)
2077 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002079 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002081 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002083 if (ioc->pci_irq != -1) {
2084 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002085 if (mpt_msi_enable)
2086 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002087 ioc->pci_irq = -1;
2088 }
2089
2090 if (ioc->memmap != NULL) {
2091 iounmap(ioc->memmap);
2092 ioc->memmap = NULL;
2093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
2095#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002096 if (ioc->mtrr_reg > 0) {
2097 mtrr_del(ioc->mtrr_reg, 0, 0);
2098 dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
2099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100#endif
2101
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102 /* Zap the adapter lookup ptr! */
2103 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002105 sz_last = ioc->alloc_total;
2106 dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
2107 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002108
2109 if (ioc->alt_ioc)
2110 ioc->alt_ioc->alt_ioc = NULL;
2111
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002112 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113}
2114
2115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2116/*
2117 * MptDisplayIocCapabilities - Disply IOC's capacilities.
2118 * @ioc: Pointer to MPT adapter structure
2119 */
2120static void
2121MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2122{
2123 int i = 0;
2124
2125 printk(KERN_INFO "%s: ", ioc->name);
2126 if (ioc->prod_name && strlen(ioc->prod_name) > 3)
2127 printk("%s: ", ioc->prod_name+3);
2128 printk("Capabilities={");
2129
2130 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2131 printk("Initiator");
2132 i++;
2133 }
2134
2135 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2136 printk("%sTarget", i ? "," : "");
2137 i++;
2138 }
2139
2140 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2141 printk("%sLAN", i ? "," : "");
2142 i++;
2143 }
2144
2145#if 0
2146 /*
2147 * This would probably evoke more questions than it's worth
2148 */
2149 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2150 printk("%sLogBusAddr", i ? "," : "");
2151 i++;
2152 }
2153#endif
2154
2155 printk("}\n");
2156}
2157
2158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2159/*
2160 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2161 * @ioc: Pointer to MPT_ADAPTER structure
2162 * @force: Force hard KickStart of IOC
2163 * @sleepFlag: Specifies whether the process can sleep
2164 *
2165 * Returns:
2166 * 1 - DIAG reset and READY
2167 * 0 - READY initially OR soft reset and READY
2168 * -1 - Any failure on KickStart
2169 * -2 - Msg Unit Reset Failed
2170 * -3 - IO Unit Reset Failed
2171 * -4 - IOC owned by a PEER
2172 */
2173static int
2174MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2175{
2176 u32 ioc_state;
2177 int statefault = 0;
2178 int cntdn;
2179 int hard_reset_done = 0;
2180 int r;
2181 int ii;
2182 int whoinit;
2183
2184 /* Get current [raw] IOC state */
2185 ioc_state = mpt_GetIocState(ioc, 0);
2186 dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
2187
2188 /*
2189 * Check to see if IOC got left/stuck in doorbell handshake
2190 * grip of death. If so, hard reset the IOC.
2191 */
2192 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2193 statefault = 1;
2194 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2195 ioc->name);
2196 }
2197
2198 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002199 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 return 0;
2201
2202 /*
2203 * Check to see if IOC is in FAULT state.
2204 */
2205 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2206 statefault = 2;
2207 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2208 ioc->name);
2209 printk(KERN_WARNING " FAULT code = %04xh\n",
2210 ioc_state & MPI_DOORBELL_DATA_MASK);
2211 }
2212
2213 /*
2214 * Hmmm... Did it get left operational?
2215 */
2216 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002217 dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 ioc->name));
2219
2220 /* Check WhoInit.
2221 * If PCI Peer, exit.
2222 * Else, if no fault conditions are present, issue a MessageUnitReset
2223 * Else, fall through to KickStart case
2224 */
2225 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002226 dinitprintk((KERN_INFO MYNAM
2227 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 whoinit, statefault, force));
2229 if (whoinit == MPI_WHOINIT_PCI_PEER)
2230 return -4;
2231 else {
2232 if ((statefault == 0 ) && (force == 0)) {
2233 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2234 return 0;
2235 }
2236 statefault = 3;
2237 }
2238 }
2239
2240 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2241 if (hard_reset_done < 0)
2242 return -1;
2243
2244 /*
2245 * Loop here waiting for IOC to come READY.
2246 */
2247 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002248 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2251 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2252 /*
2253 * BIOS or previous driver load left IOC in OP state.
2254 * Reset messaging FIFOs.
2255 */
2256 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2257 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2258 return -2;
2259 }
2260 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2261 /*
2262 * Something is wrong. Try to get IOC back
2263 * to a known state.
2264 */
2265 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2266 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2267 return -3;
2268 }
2269 }
2270
2271 ii++; cntdn--;
2272 if (!cntdn) {
2273 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2274 ioc->name, (int)((ii+5)/HZ));
2275 return -ETIME;
2276 }
2277
2278 if (sleepFlag == CAN_SLEEP) {
2279 msleep_interruptible(1);
2280 } else {
2281 mdelay (1); /* 1 msec delay */
2282 }
2283
2284 }
2285
2286 if (statefault < 3) {
2287 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2288 ioc->name,
2289 statefault==1 ? "stuck handshake" : "IOC FAULT");
2290 }
2291
2292 return hard_reset_done;
2293}
2294
2295/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2296/*
2297 * mpt_GetIocState - Get the current state of a MPT adapter.
2298 * @ioc: Pointer to MPT_ADAPTER structure
2299 * @cooked: Request raw or cooked IOC state
2300 *
2301 * Returns all IOC Doorbell register bits if cooked==0, else just the
2302 * Doorbell bits in MPI_IOC_STATE_MASK.
2303 */
2304u32
2305mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2306{
2307 u32 s, sc;
2308
2309 /* Get! */
2310 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2311// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2312 sc = s & MPI_IOC_STATE_MASK;
2313
2314 /* Save! */
2315 ioc->last_state = sc;
2316
2317 return cooked ? sc : s;
2318}
2319
2320/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2321/*
2322 * GetIocFacts - Send IOCFacts request to MPT adapter.
2323 * @ioc: Pointer to MPT_ADAPTER structure
2324 * @sleepFlag: Specifies whether the process can sleep
2325 * @reason: If recovery, only update facts.
2326 *
2327 * Returns 0 for success, non-zero for failure.
2328 */
2329static int
2330GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2331{
2332 IOCFacts_t get_facts;
2333 IOCFactsReply_t *facts;
2334 int r;
2335 int req_sz;
2336 int reply_sz;
2337 int sz;
2338 u32 status, vv;
2339 u8 shiftFactor=1;
2340
2341 /* IOC *must* NOT be in RESET state! */
2342 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2343 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2344 ioc->name,
2345 ioc->last_state );
2346 return -44;
2347 }
2348
2349 facts = &ioc->facts;
2350
2351 /* Destination (reply area)... */
2352 reply_sz = sizeof(*facts);
2353 memset(facts, 0, reply_sz);
2354
2355 /* Request area (get_facts on the stack right now!) */
2356 req_sz = sizeof(get_facts);
2357 memset(&get_facts, 0, req_sz);
2358
2359 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2360 /* Assert: All other get_facts fields are zero! */
2361
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002362 dinitprintk((MYIOC_s_INFO_FMT
2363 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 ioc->name, req_sz, reply_sz));
2365
2366 /* No non-zero fields in the get_facts request are greater than
2367 * 1 byte in size, so we can just fire it off as is.
2368 */
2369 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2370 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2371 if (r != 0)
2372 return r;
2373
2374 /*
2375 * Now byte swap (GRRR) the necessary fields before any further
2376 * inspection of reply contents.
2377 *
2378 * But need to do some sanity checks on MsgLength (byte) field
2379 * to make sure we don't zero IOC's req_sz!
2380 */
2381 /* Did we get a valid reply? */
2382 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2383 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2384 /*
2385 * If not been here, done that, save off first WhoInit value
2386 */
2387 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2388 ioc->FirstWhoInit = facts->WhoInit;
2389 }
2390
2391 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2392 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2393 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2394 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2395 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002396 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 /* CHECKME! IOCStatus, IOCLogInfo */
2398
2399 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2400 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2401
2402 /*
2403 * FC f/w version changed between 1.1 and 1.2
2404 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2405 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2406 */
2407 if (facts->MsgVersion < 0x0102) {
2408 /*
2409 * Handle old FC f/w style, convert to new...
2410 */
2411 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2412 facts->FWVersion.Word =
2413 ((oldv<<12) & 0xFF000000) |
2414 ((oldv<<8) & 0x000FFF00);
2415 } else
2416 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2417
2418 facts->ProductID = le16_to_cpu(facts->ProductID);
2419 facts->CurrentHostMfaHighAddr =
2420 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2421 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2422 facts->CurrentSenseBufferHighAddr =
2423 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2424 facts->CurReplyFrameSize =
2425 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002426 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
2428 /*
2429 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2430 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2431 * to 14 in MPI-1.01.0x.
2432 */
2433 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2434 facts->MsgVersion > 0x0100) {
2435 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2436 }
2437
2438 sz = facts->FWImageSize;
2439 if ( sz & 0x01 )
2440 sz += 1;
2441 if ( sz & 0x02 )
2442 sz += 2;
2443 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 if (!facts->RequestFrameSize) {
2446 /* Something is wrong! */
2447 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2448 ioc->name);
2449 return -55;
2450 }
2451
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002452 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 vv = ((63 / (sz * 4)) + 1) & 0x03;
2454 ioc->NB_for_64_byte_frame = vv;
2455 while ( sz )
2456 {
2457 shiftFactor++;
2458 sz = sz >> 1;
2459 }
2460 ioc->NBShiftFactor = shiftFactor;
2461 dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2462 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2465 /*
2466 * Set values for this IOC's request & reply frame sizes,
2467 * and request & reply queue depths...
2468 */
2469 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2470 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2471 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2472 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2473
2474 dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
2475 ioc->name, ioc->reply_sz, ioc->reply_depth));
2476 dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n",
2477 ioc->name, ioc->req_sz, ioc->req_depth));
2478
2479 /* Get port facts! */
2480 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2481 return r;
2482 }
2483 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002484 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2486 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2487 RequestFrameSize)/sizeof(u32)));
2488 return -66;
2489 }
2490
2491 return 0;
2492}
2493
2494/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2495/*
2496 * GetPortFacts - Send PortFacts request to MPT adapter.
2497 * @ioc: Pointer to MPT_ADAPTER structure
2498 * @portnum: Port number
2499 * @sleepFlag: Specifies whether the process can sleep
2500 *
2501 * Returns 0 for success, non-zero for failure.
2502 */
2503static int
2504GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2505{
2506 PortFacts_t get_pfacts;
2507 PortFactsReply_t *pfacts;
2508 int ii;
2509 int req_sz;
2510 int reply_sz;
2511
2512 /* IOC *must* NOT be in RESET state! */
2513 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2514 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2515 ioc->name,
2516 ioc->last_state );
2517 return -4;
2518 }
2519
2520 pfacts = &ioc->pfacts[portnum];
2521
2522 /* Destination (reply area)... */
2523 reply_sz = sizeof(*pfacts);
2524 memset(pfacts, 0, reply_sz);
2525
2526 /* Request area (get_pfacts on the stack right now!) */
2527 req_sz = sizeof(get_pfacts);
2528 memset(&get_pfacts, 0, req_sz);
2529
2530 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2531 get_pfacts.PortNumber = portnum;
2532 /* Assert: All other get_pfacts fields are zero! */
2533
2534 dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
2535 ioc->name, portnum));
2536
2537 /* No non-zero fields in the get_pfacts request are greater than
2538 * 1 byte in size, so we can just fire it off as is.
2539 */
2540 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2541 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2542 if (ii != 0)
2543 return ii;
2544
2545 /* Did we get a valid reply? */
2546
2547 /* Now byte swap the necessary fields in the response. */
2548 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2549 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2550 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2551 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2552 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2553 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2554 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2555 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2556 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2557
2558 return 0;
2559}
2560
2561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2562/*
2563 * SendIocInit - Send IOCInit request to MPT adapter.
2564 * @ioc: Pointer to MPT_ADAPTER structure
2565 * @sleepFlag: Specifies whether the process can sleep
2566 *
2567 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2568 *
2569 * Returns 0 for success, non-zero for failure.
2570 */
2571static int
2572SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2573{
2574 IOCInit_t ioc_init;
2575 MPIDefaultReply_t init_reply;
2576 u32 state;
2577 int r;
2578 int count;
2579 int cntdn;
2580
2581 memset(&ioc_init, 0, sizeof(ioc_init));
2582 memset(&init_reply, 0, sizeof(init_reply));
2583
2584 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2585 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2586
2587 /* If we are in a recovery mode and we uploaded the FW image,
2588 * then this pointer is not NULL. Skip the upload a second time.
2589 * Set this flag if cached_fw set for either IOC.
2590 */
2591 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2592 ioc->upload_fw = 1;
2593 else
2594 ioc->upload_fw = 0;
2595 ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
2596 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2597
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002598 if(ioc->bus_type == SAS)
2599 ioc_init.MaxDevices = ioc->facts.MaxDevices;
2600 else if(ioc->bus_type == FC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
2602 else
2603 ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 ioc_init.MaxBuses = MPT_MAX_BUS;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002605 dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
2606 ioc->name, ioc->facts.MsgVersion));
2607 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2608 // set MsgVersion and HeaderVersion host driver was built with
2609 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2610 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002612 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2613 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2614 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2615 return -99;
2616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2618
2619 if (sizeof(dma_addr_t) == sizeof(u64)) {
2620 /* Save the upper 32-bits of the request
2621 * (reply) and sense buffers.
2622 */
2623 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2624 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2625 } else {
2626 /* Force 32-bit addressing */
2627 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2628 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2629 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2632 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002633 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2634 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
2637 ioc->name, &ioc_init));
2638
2639 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2640 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002641 if (r != 0) {
2642 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 /* No need to byte swap the multibyte fields in the reply
2647 * since we don't even look at it's contents.
2648 */
2649
2650 dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
2651 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002652
2653 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2654 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
2658 /* YIKES! SUPER IMPORTANT!!!
2659 * Poll IocState until _OPERATIONAL while IOC is doing
2660 * LoopInit and TargetDiscovery!
2661 */
2662 count = 0;
2663 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2664 state = mpt_GetIocState(ioc, 1);
2665 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2666 if (sleepFlag == CAN_SLEEP) {
2667 msleep_interruptible(1);
2668 } else {
2669 mdelay(1);
2670 }
2671
2672 if (!cntdn) {
2673 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2674 ioc->name, (int)((count+5)/HZ));
2675 return -9;
2676 }
2677
2678 state = mpt_GetIocState(ioc, 1);
2679 count++;
2680 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002681 dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 ioc->name, count));
2683
2684 return r;
2685}
2686
2687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2688/*
2689 * SendPortEnable - Send PortEnable request to MPT adapter port.
2690 * @ioc: Pointer to MPT_ADAPTER structure
2691 * @portnum: Port number to enable
2692 * @sleepFlag: Specifies whether the process can sleep
2693 *
2694 * Send PortEnable to bring IOC to OPERATIONAL state.
2695 *
2696 * Returns 0 for success, non-zero for failure.
2697 */
2698static int
2699SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2700{
2701 PortEnable_t port_enable;
2702 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002703 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 int req_sz;
2705 int reply_sz;
2706
2707 /* Destination... */
2708 reply_sz = sizeof(MPIDefaultReply_t);
2709 memset(&reply_buf, 0, reply_sz);
2710
2711 req_sz = sizeof(PortEnable_t);
2712 memset(&port_enable, 0, req_sz);
2713
2714 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2715 port_enable.PortNumber = portnum;
2716/* port_enable.ChainOffset = 0; */
2717/* port_enable.MsgFlags = 0; */
2718/* port_enable.MsgContext = 0; */
2719
2720 dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
2721 ioc->name, portnum, &port_enable));
2722
2723 /* RAID FW may take a long time to enable
2724 */
Moore, Eric432b4c82006-01-16 18:53:11 -07002725 if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2726 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
2727 (ioc->bus_type == SAS)) {
2728 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2729 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2730 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002731 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002732 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2733 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2734 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002736 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737}
2738
2739/*
2740 * ioc: Pointer to MPT_ADAPTER structure
2741 * size - total FW bytes
2742 */
2743void
2744mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
2745{
2746 if (ioc->cached_fw)
2747 return; /* use already allocated memory */
2748 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2749 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
2750 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
2751 } else {
2752 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
2753 ioc->alloc_total += size;
2754 }
2755}
2756/*
2757 * If alt_img is NULL, delete from ioc structure.
2758 * Else, delete a secondary image in same format.
2759 */
2760void
2761mpt_free_fw_memory(MPT_ADAPTER *ioc)
2762{
2763 int sz;
2764
2765 sz = ioc->facts.FWImageSize;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002766 dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
2768 pci_free_consistent(ioc->pcidev, sz,
2769 ioc->cached_fw, ioc->cached_fw_dma);
2770 ioc->cached_fw = NULL;
2771
2772 return;
2773}
2774
2775
2776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2777/*
2778 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
2779 * @ioc: Pointer to MPT_ADAPTER structure
2780 * @sleepFlag: Specifies whether the process can sleep
2781 *
2782 * Returns 0 for success, >0 for handshake failure
2783 * <0 for fw upload failure.
2784 *
2785 * Remark: If bound IOC and a successful FWUpload was performed
2786 * on the bound IOC, the second image is discarded
2787 * and memory is free'd. Both channels must upload to prevent
2788 * IOC from running in degraded mode.
2789 */
2790static int
2791mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
2792{
2793 u8 request[ioc->req_sz];
2794 u8 reply[sizeof(FWUploadReply_t)];
2795 FWUpload_t *prequest;
2796 FWUploadReply_t *preply;
2797 FWUploadTCSGE_t *ptcsge;
2798 int sgeoffset;
2799 u32 flagsLength;
2800 int ii, sz, reply_sz;
2801 int cmdStatus;
2802
2803 /* If the image size is 0, we are done.
2804 */
2805 if ((sz = ioc->facts.FWImageSize) == 0)
2806 return 0;
2807
2808 mpt_alloc_fw_memory(ioc, sz);
2809
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002810 dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002812
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 if (ioc->cached_fw == NULL) {
2814 /* Major Failure.
2815 */
2816 return -ENOMEM;
2817 }
2818
2819 prequest = (FWUpload_t *)&request;
2820 preply = (FWUploadReply_t *)&reply;
2821
2822 /* Destination... */
2823 memset(prequest, 0, ioc->req_sz);
2824
2825 reply_sz = sizeof(reply);
2826 memset(preply, 0, reply_sz);
2827
2828 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
2829 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
2830
2831 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
2832 ptcsge->DetailsLength = 12;
2833 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
2834 ptcsge->ImageSize = cpu_to_le32(sz);
2835
2836 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
2837
2838 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
2839 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
2840
2841 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002842 dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 prequest, sgeoffset));
2844 DBG_DUMP_FW_REQUEST_FRAME(prequest)
2845
2846 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
2847 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
2848
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002849 dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851 cmdStatus = -EFAULT;
2852 if (ii == 0) {
2853 /* Handshake transfer was complete and successful.
2854 * Check the Reply Frame.
2855 */
2856 int status, transfer_sz;
2857 status = le16_to_cpu(preply->IOCStatus);
2858 if (status == MPI_IOCSTATUS_SUCCESS) {
2859 transfer_sz = le32_to_cpu(preply->ActualImageSize);
2860 if (transfer_sz == sz)
2861 cmdStatus = 0;
2862 }
2863 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002864 dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 ioc->name, cmdStatus));
2866
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002867
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 if (cmdStatus) {
2869
2870 ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
2871 ioc->name));
2872 mpt_free_fw_memory(ioc);
2873 }
2874
2875 return cmdStatus;
2876}
2877
2878/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
2879/*
2880 * mpt_downloadboot - DownloadBoot code
2881 * @ioc: Pointer to MPT_ADAPTER structure
2882 * @flag: Specify which part of IOC memory is to be uploaded.
2883 * @sleepFlag: Specifies whether the process can sleep
2884 *
2885 * FwDownloadBoot requires Programmed IO access.
2886 *
2887 * Returns 0 for success
2888 * -1 FW Image size is 0
2889 * -2 No valid cached_fw Pointer
2890 * <0 for fw upload failure.
2891 */
2892static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002893mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 MpiExtImageHeader_t *pExtImage;
2896 u32 fwSize;
2897 u32 diag0val;
2898 int count;
2899 u32 *ptrFw;
2900 u32 diagRwData;
2901 u32 nextImage;
2902 u32 load_addr;
2903 u32 ioc_state=0;
2904
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002905 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
2906 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002907
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2909 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2910 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2911 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2912 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2913 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2914
2915 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
2916
2917 /* wait 1 msec */
2918 if (sleepFlag == CAN_SLEEP) {
2919 msleep_interruptible(1);
2920 } else {
2921 mdelay (1);
2922 }
2923
2924 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2925 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
2926
2927 for (count = 0; count < 30; count ++) {
2928 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
2929 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
2930 ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
2931 ioc->name, count));
2932 break;
2933 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002934 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002936 msleep_interruptible (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002938 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 }
2940 }
2941
2942 if ( count == 30 ) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002943 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
2944 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 ioc->name, diag0val));
2946 return -3;
2947 }
2948
2949 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
2950 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
2951 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
2952 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
2953 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
2954 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
2955
2956 /* Set the DiagRwEn and Disable ARM bits */
2957 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
2958
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 fwSize = (pFwHeader->ImageSize + 3)/4;
2960 ptrFw = (u32 *) pFwHeader;
2961
2962 /* Write the LoadStartAddress to the DiagRw Address Register
2963 * using Programmed IO
2964 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06002965 if (ioc->errata_flag_1064)
2966 pci_enable_io_access(ioc->pcidev);
2967
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
2969 ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
2970 ioc->name, pFwHeader->LoadStartAddress));
2971
2972 ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
2973 ioc->name, fwSize*4, ptrFw));
2974 while (fwSize--) {
2975 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2976 }
2977
2978 nextImage = pFwHeader->NextImageHeaderOffset;
2979 while (nextImage) {
2980 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
2981
2982 load_addr = pExtImage->LoadStartAddress;
2983
2984 fwSize = (pExtImage->ImageSize + 3) >> 2;
2985 ptrFw = (u32 *)pExtImage;
2986
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002987 ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
2988 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
2990
2991 while (fwSize--) {
2992 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
2993 }
2994 nextImage = pExtImage->NextImageHeaderOffset;
2995 }
2996
2997 /* Write the IopResetVectorRegAddr */
2998 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
2999 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3000
3001 /* Write the IopResetVectorValue */
3002 ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
3003 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3004
3005 /* Clear the internal flash bad bit - autoincrementing register,
3006 * so must do two writes.
3007 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003008 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003009 /*
3010 * 1030 and 1035 H/W errata, workaround to access
3011 * the ClearFlashBadSignatureBit
3012 */
3013 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3014 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3015 diagRwData |= 0x40000000;
3016 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3017 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3018
3019 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3020 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3021 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3022 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3023
3024 /* wait 1 msec */
3025 if (sleepFlag == CAN_SLEEP) {
3026 msleep_interruptible (1);
3027 } else {
3028 mdelay (1);
3029 }
3030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003032 if (ioc->errata_flag_1064)
3033 pci_disable_io_access(ioc->pcidev);
3034
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003036 ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
3037 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003039 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
3041 ioc->name, diag0val));
3042 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3043
3044 /* Write 0xFF to reset the sequencer */
3045 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3046
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003047 if (ioc->bus_type == SAS) {
3048 ioc_state = mpt_GetIocState(ioc, 0);
3049 if ( (GetIocFacts(ioc, sleepFlag,
3050 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
3051 ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
3052 ioc->name, ioc_state));
3053 return -EFAULT;
3054 }
3055 }
3056
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 for (count=0; count<HZ*20; count++) {
3058 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
3059 ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
3060 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003061 if (ioc->bus_type == SAS) {
3062 return 0;
3063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 if ((SendIocInit(ioc, sleepFlag)) != 0) {
3065 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
3066 ioc->name));
3067 return -EFAULT;
3068 }
3069 ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
3070 ioc->name));
3071 return 0;
3072 }
3073 if (sleepFlag == CAN_SLEEP) {
3074 msleep_interruptible (10);
3075 } else {
3076 mdelay (10);
3077 }
3078 }
3079 ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
3080 ioc->name, ioc_state));
3081 return -EFAULT;
3082}
3083
3084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3085/*
3086 * KickStart - Perform hard reset of MPT adapter.
3087 * @ioc: Pointer to MPT_ADAPTER structure
3088 * @force: Force hard reset
3089 * @sleepFlag: Specifies whether the process can sleep
3090 *
3091 * This routine places MPT adapter in diagnostic mode via the
3092 * WriteSequence register, and then performs a hard reset of adapter
3093 * via the Diagnostic register.
3094 *
3095 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3096 * or NO_SLEEP (interrupt thread, use mdelay)
3097 * force - 1 if doorbell active, board fault state
3098 * board operational, IOC_RECOVERY or
3099 * IOC_BRINGUP and there is an alt_ioc.
3100 * 0 else
3101 *
3102 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003103 * 1 - hard reset, READY
3104 * 0 - no reset due to History bit, READY
3105 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 * OR reset but failed to come READY
3107 * -2 - no reset, could not enter DIAG mode
3108 * -3 - reset but bad FW bit
3109 */
3110static int
3111KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3112{
3113 int hard_reset_done = 0;
3114 u32 ioc_state=0;
3115 int cnt,cntdn;
3116
3117 dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003118 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 /* Always issue a Msg Unit Reset first. This will clear some
3120 * SCSI bus hang conditions.
3121 */
3122 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3123
3124 if (sleepFlag == CAN_SLEEP) {
3125 msleep_interruptible (1000);
3126 } else {
3127 mdelay (1000);
3128 }
3129 }
3130
3131 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3132 if (hard_reset_done < 0)
3133 return hard_reset_done;
3134
3135 dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
3136 ioc->name));
3137
3138 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3139 for (cnt=0; cnt<cntdn; cnt++) {
3140 ioc_state = mpt_GetIocState(ioc, 1);
3141 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
3142 dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
3143 ioc->name, cnt));
3144 return hard_reset_done;
3145 }
3146 if (sleepFlag == CAN_SLEEP) {
3147 msleep_interruptible (10);
3148 } else {
3149 mdelay (10);
3150 }
3151 }
3152
3153 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3154 ioc->name, ioc_state);
3155 return -1;
3156}
3157
3158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3159/*
3160 * mpt_diag_reset - Perform hard reset of the adapter.
3161 * @ioc: Pointer to MPT_ADAPTER structure
3162 * @ignore: Set if to honor and clear to ignore
3163 * the reset history bit
3164 * @sleepflag: CAN_SLEEP if called in a non-interrupt thread,
3165 * else set to NO_SLEEP (use mdelay instead)
3166 *
3167 * This routine places the adapter in diagnostic mode via the
3168 * WriteSequence register and then performs a hard reset of adapter
3169 * via the Diagnostic register. Adapter should be in ready state
3170 * upon successful completion.
3171 *
3172 * Returns: 1 hard reset successful
3173 * 0 no reset performed because reset history bit set
3174 * -2 enabling diagnostic mode failed
3175 * -3 diagnostic reset failed
3176 */
3177static int
3178mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3179{
3180 u32 diag0val;
3181 u32 doorbell;
3182 int hard_reset_done = 0;
3183 int count = 0;
3184#ifdef MPT_DEBUG
3185 u32 diag1val = 0;
3186#endif
3187
3188 /* Clear any existing interrupts */
3189 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3190
3191 /* Use "Diagnostic reset" method! (only thing available!) */
3192 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3193
3194#ifdef MPT_DEBUG
3195 if (ioc->alt_ioc)
3196 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3197 dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
3198 ioc->name, diag0val, diag1val));
3199#endif
3200
3201 /* Do the reset if we are told to ignore the reset history
3202 * or if the reset history is 0
3203 */
3204 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3205 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3206 /* Write magic sequence to WriteSequence register
3207 * Loop until in diagnostic mode
3208 */
3209 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3210 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3211 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3212 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3213 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3214 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3215
3216 /* wait 100 msec */
3217 if (sleepFlag == CAN_SLEEP) {
3218 msleep_interruptible (100);
3219 } else {
3220 mdelay (100);
3221 }
3222
3223 count++;
3224 if (count > 20) {
3225 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3226 ioc->name, diag0val);
3227 return -2;
3228
3229 }
3230
3231 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3232
3233 dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
3234 ioc->name, diag0val));
3235 }
3236
3237#ifdef MPT_DEBUG
3238 if (ioc->alt_ioc)
3239 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3240 dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
3241 ioc->name, diag0val, diag1val));
3242#endif
3243 /*
3244 * Disable the ARM (Bug fix)
3245 *
3246 */
3247 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003248 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250 /*
3251 * Now hit the reset bit in the Diagnostic register
3252 * (THE BIG HAMMER!) (Clears DRWE bit).
3253 */
3254 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3255 hard_reset_done = 1;
3256 dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
3257 ioc->name));
3258
3259 /*
3260 * Call each currently registered protocol IOC reset handler
3261 * with pre-reset indication.
3262 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3263 * MptResetHandlers[] registered yet.
3264 */
3265 {
3266 int ii;
3267 int r = 0;
3268
3269 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3270 if (MptResetHandlers[ii]) {
3271 dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
3272 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003273 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 if (ioc->alt_ioc) {
3275 dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
3276 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003277 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 }
3279 }
3280 }
3281 /* FIXME? Examine results here? */
3282 }
3283
3284 if (ioc->cached_fw) {
3285 /* If the DownloadBoot operation fails, the
3286 * IOC will be left unusable. This is a fatal error
3287 * case. _diag_reset will return < 0
3288 */
3289 for (count = 0; count < 30; count ++) {
3290 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3291 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3292 break;
3293 }
3294
3295 /* wait 1 sec */
3296 if (sleepFlag == CAN_SLEEP) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003297 msleep_interruptible (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 } else {
3299 mdelay (1000);
3300 }
3301 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003302 if ((count = mpt_downloadboot(ioc,
3303 (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 printk(KERN_WARNING MYNAM
3305 ": firmware downloadboot failure (%d)!\n", count);
3306 }
3307
3308 } else {
3309 /* Wait for FW to reload and for board
3310 * to go to the READY state.
3311 * Maximum wait is 60 seconds.
3312 * If fail, no error will check again
3313 * with calling program.
3314 */
3315 for (count = 0; count < 60; count ++) {
3316 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3317 doorbell &= MPI_IOC_STATE_MASK;
3318
3319 if (doorbell == MPI_IOC_STATE_READY) {
3320 break;
3321 }
3322
3323 /* wait 1 sec */
3324 if (sleepFlag == CAN_SLEEP) {
3325 msleep_interruptible (1000);
3326 } else {
3327 mdelay (1000);
3328 }
3329 }
3330 }
3331 }
3332
3333 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3334#ifdef MPT_DEBUG
3335 if (ioc->alt_ioc)
3336 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3337 dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3338 ioc->name, diag0val, diag1val));
3339#endif
3340
3341 /* Clear RESET_HISTORY bit! Place board in the
3342 * diagnostic mode to update the diag register.
3343 */
3344 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3345 count = 0;
3346 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3347 /* Write magic sequence to WriteSequence register
3348 * Loop until in diagnostic mode
3349 */
3350 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3351 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3352 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3353 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3354 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3355 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3356
3357 /* wait 100 msec */
3358 if (sleepFlag == CAN_SLEEP) {
3359 msleep_interruptible (100);
3360 } else {
3361 mdelay (100);
3362 }
3363
3364 count++;
3365 if (count > 20) {
3366 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3367 ioc->name, diag0val);
3368 break;
3369 }
3370 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3371 }
3372 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3373 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3374 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3375 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3376 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3377 ioc->name);
3378 }
3379
3380 /* Disable Diagnostic Mode
3381 */
3382 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3383
3384 /* Check FW reload status flags.
3385 */
3386 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3387 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3388 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3389 ioc->name, diag0val);
3390 return -3;
3391 }
3392
3393#ifdef MPT_DEBUG
3394 if (ioc->alt_ioc)
3395 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3396 dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
3397 ioc->name, diag0val, diag1val));
3398#endif
3399
3400 /*
3401 * Reset flag that says we've enabled event notification
3402 */
3403 ioc->facts.EventState = 0;
3404
3405 if (ioc->alt_ioc)
3406 ioc->alt_ioc->facts.EventState = 0;
3407
3408 return hard_reset_done;
3409}
3410
3411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3412/*
3413 * SendIocReset - Send IOCReset request to MPT adapter.
3414 * @ioc: Pointer to MPT_ADAPTER structure
3415 * @reset_type: reset type, expected values are
3416 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
3417 *
3418 * Send IOCReset request to the MPT adapter.
3419 *
3420 * Returns 0 for success, non-zero for failure.
3421 */
3422static int
3423SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3424{
3425 int r;
3426 u32 state;
3427 int cntdn, count;
3428
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003429 drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 ioc->name, reset_type));
3431 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3432 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3433 return r;
3434
3435 /* FW ACK'd request, wait for READY state
3436 */
3437 count = 0;
3438 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3439
3440 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3441 cntdn--;
3442 count++;
3443 if (!cntdn) {
3444 if (sleepFlag != CAN_SLEEP)
3445 count *= 10;
3446
3447 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3448 ioc->name, (int)((count+5)/HZ));
3449 return -ETIME;
3450 }
3451
3452 if (sleepFlag == CAN_SLEEP) {
3453 msleep_interruptible(1);
3454 } else {
3455 mdelay (1); /* 1 msec delay */
3456 }
3457 }
3458
3459 /* TODO!
3460 * Cleanup all event stuff for this IOC; re-issue EventNotification
3461 * request if needed.
3462 */
3463 if (ioc->facts.Function)
3464 ioc->facts.EventState = 0;
3465
3466 return 0;
3467}
3468
3469/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3470/*
3471 * initChainBuffers - Allocate memory for and initialize
3472 * chain buffers, chain buffer control arrays and spinlock.
3473 * @hd: Pointer to MPT_SCSI_HOST structure
3474 * @init: If set, initialize the spin lock.
3475 */
3476static int
3477initChainBuffers(MPT_ADAPTER *ioc)
3478{
3479 u8 *mem;
3480 int sz, ii, num_chain;
3481 int scale, num_sge, numSGE;
3482
3483 /* ReqToChain size must equal the req_depth
3484 * index = req_idx
3485 */
3486 if (ioc->ReqToChain == NULL) {
3487 sz = ioc->req_depth * sizeof(int);
3488 mem = kmalloc(sz, GFP_ATOMIC);
3489 if (mem == NULL)
3490 return -1;
3491
3492 ioc->ReqToChain = (int *) mem;
3493 dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n",
3494 ioc->name, mem, sz));
3495 mem = kmalloc(sz, GFP_ATOMIC);
3496 if (mem == NULL)
3497 return -1;
3498
3499 ioc->RequestNB = (int *) mem;
3500 dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n",
3501 ioc->name, mem, sz));
3502 }
3503 for (ii = 0; ii < ioc->req_depth; ii++) {
3504 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3505 }
3506
3507 /* ChainToChain size must equal the total number
3508 * of chain buffers to be allocated.
3509 * index = chain_idx
3510 *
3511 * Calculate the number of chain buffers needed(plus 1) per I/O
3512 * then multiply the the maximum number of simultaneous cmds
3513 *
3514 * num_sge = num sge in request frame + last chain buffer
3515 * scale = num sge per chain buffer if no chain element
3516 */
3517 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3518 if (sizeof(dma_addr_t) == sizeof(u64))
3519 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3520 else
3521 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3522
3523 if (sizeof(dma_addr_t) == sizeof(u64)) {
3524 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3525 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3526 } else {
3527 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3528 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3529 }
3530 dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
3531 ioc->name, num_sge, numSGE));
3532
3533 if ( numSGE > MPT_SCSI_SG_DEPTH )
3534 numSGE = MPT_SCSI_SG_DEPTH;
3535
3536 num_chain = 1;
3537 while (numSGE - num_sge > 0) {
3538 num_chain++;
3539 num_sge += (scale - 1);
3540 }
3541 num_chain++;
3542
3543 dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
3544 ioc->name, numSGE, num_sge, num_chain));
3545
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003546 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 num_chain *= MPT_SCSI_CAN_QUEUE;
3548 else
3549 num_chain *= MPT_FC_CAN_QUEUE;
3550
3551 ioc->num_chain = num_chain;
3552
3553 sz = num_chain * sizeof(int);
3554 if (ioc->ChainToChain == NULL) {
3555 mem = kmalloc(sz, GFP_ATOMIC);
3556 if (mem == NULL)
3557 return -1;
3558
3559 ioc->ChainToChain = (int *) mem;
3560 dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
3561 ioc->name, mem, sz));
3562 } else {
3563 mem = (u8 *) ioc->ChainToChain;
3564 }
3565 memset(mem, 0xFF, sz);
3566 return num_chain;
3567}
3568
3569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3570/*
3571 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3572 * @ioc: Pointer to MPT_ADAPTER structure
3573 *
3574 * This routine allocates memory for the MPT reply and request frame
3575 * pools (if necessary), and primes the IOC reply FIFO with
3576 * reply frames.
3577 *
3578 * Returns 0 for success, non-zero for failure.
3579 */
3580static int
3581PrimeIocFifos(MPT_ADAPTER *ioc)
3582{
3583 MPT_FRAME_HDR *mf;
3584 unsigned long flags;
3585 dma_addr_t alloc_dma;
3586 u8 *mem;
3587 int i, reply_sz, sz, total_size, num_chain;
3588
3589 /* Prime reply FIFO... */
3590
3591 if (ioc->reply_frames == NULL) {
3592 if ( (num_chain = initChainBuffers(ioc)) < 0)
3593 return -1;
3594
3595 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
3596 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
3597 ioc->name, ioc->reply_sz, ioc->reply_depth));
3598 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
3599 ioc->name, reply_sz, reply_sz));
3600
3601 sz = (ioc->req_sz * ioc->req_depth);
3602 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
3603 ioc->name, ioc->req_sz, ioc->req_depth));
3604 dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
3605 ioc->name, sz, sz));
3606 total_size += sz;
3607
3608 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
3609 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
3610 ioc->name, ioc->req_sz, num_chain));
3611 dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
3612 ioc->name, sz, sz, num_chain));
3613
3614 total_size += sz;
3615 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3616 if (mem == NULL) {
3617 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3618 ioc->name);
3619 goto out_fail;
3620 }
3621
3622 dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
3623 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3624
3625 memset(mem, 0, total_size);
3626 ioc->alloc_total += total_size;
3627 ioc->alloc = mem;
3628 ioc->alloc_dma = alloc_dma;
3629 ioc->alloc_sz = total_size;
3630 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3631 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3632
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003633 dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
3634 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 alloc_dma += reply_sz;
3637 mem += reply_sz;
3638
3639 /* Request FIFO - WE manage this! */
3640
3641 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3642 ioc->req_frames_dma = alloc_dma;
3643
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003644 dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 ioc->name, mem, (void *)(ulong)alloc_dma));
3646
3647 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3648
3649#if defined(CONFIG_MTRR) && 0
3650 /*
3651 * Enable Write Combining MTRR for IOC's memory region.
3652 * (at least as much as we can; "size and base must be
3653 * multiples of 4 kiB"
3654 */
3655 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3656 sz,
3657 MTRR_TYPE_WRCOMB, 1);
3658 dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
3659 ioc->name, ioc->req_frames_dma, sz));
3660#endif
3661
3662 for (i = 0; i < ioc->req_depth; i++) {
3663 alloc_dma += ioc->req_sz;
3664 mem += ioc->req_sz;
3665 }
3666
3667 ioc->ChainBuffer = mem;
3668 ioc->ChainBufferDMA = alloc_dma;
3669
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003670 dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3672
3673 /* Initialize the free chain Q.
3674 */
3675
3676 INIT_LIST_HEAD(&ioc->FreeChainQ);
3677
3678 /* Post the chain buffers to the FreeChainQ.
3679 */
3680 mem = (u8 *)ioc->ChainBuffer;
3681 for (i=0; i < num_chain; i++) {
3682 mf = (MPT_FRAME_HDR *) mem;
3683 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3684 mem += ioc->req_sz;
3685 }
3686
3687 /* Initialize Request frames linked list
3688 */
3689 alloc_dma = ioc->req_frames_dma;
3690 mem = (u8 *) ioc->req_frames;
3691
3692 spin_lock_irqsave(&ioc->FreeQlock, flags);
3693 INIT_LIST_HEAD(&ioc->FreeQ);
3694 for (i = 0; i < ioc->req_depth; i++) {
3695 mf = (MPT_FRAME_HDR *) mem;
3696
3697 /* Queue REQUESTs *internally*! */
3698 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
3699
3700 mem += ioc->req_sz;
3701 }
3702 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3703
3704 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3705 ioc->sense_buf_pool =
3706 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
3707 if (ioc->sense_buf_pool == NULL) {
3708 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
3709 ioc->name);
3710 goto out_fail;
3711 }
3712
3713 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
3714 ioc->alloc_total += sz;
3715 dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
3716 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
3717
3718 }
3719
3720 /* Post Reply frames to FIFO
3721 */
3722 alloc_dma = ioc->alloc_dma;
3723 dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
3724 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3725
3726 for (i = 0; i < ioc->reply_depth; i++) {
3727 /* Write each address to the IOC! */
3728 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
3729 alloc_dma += ioc->reply_sz;
3730 }
3731
3732 return 0;
3733
3734out_fail:
3735 if (ioc->alloc != NULL) {
3736 sz = ioc->alloc_sz;
3737 pci_free_consistent(ioc->pcidev,
3738 sz,
3739 ioc->alloc, ioc->alloc_dma);
3740 ioc->reply_frames = NULL;
3741 ioc->req_frames = NULL;
3742 ioc->alloc_total -= sz;
3743 }
3744 if (ioc->sense_buf_pool != NULL) {
3745 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
3746 pci_free_consistent(ioc->pcidev,
3747 sz,
3748 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
3749 ioc->sense_buf_pool = NULL;
3750 }
3751 return -1;
3752}
3753
3754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3755/**
3756 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
3757 * from IOC via doorbell handshake method.
3758 * @ioc: Pointer to MPT_ADAPTER structure
3759 * @reqBytes: Size of the request in bytes
3760 * @req: Pointer to MPT request frame
3761 * @replyBytes: Expected size of the reply in bytes
3762 * @u16reply: Pointer to area where reply should be written
3763 * @maxwait: Max wait time for a reply (in seconds)
3764 * @sleepFlag: Specifies whether the process can sleep
3765 *
3766 * NOTES: It is the callers responsibility to byte-swap fields in the
3767 * request which are greater than 1 byte in size. It is also the
3768 * callers responsibility to byte-swap response fields which are
3769 * greater than 1 byte in size.
3770 *
3771 * Returns 0 for success, non-zero for failure.
3772 */
3773static int
3774mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003775 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776{
3777 MPIDefaultReply_t *mptReply;
3778 int failcnt = 0;
3779 int t;
3780
3781 /*
3782 * Get ready to cache a handshake reply
3783 */
3784 ioc->hs_reply_idx = 0;
3785 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3786 mptReply->MsgLength = 0;
3787
3788 /*
3789 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
3790 * then tell IOC that we want to handshake a request of N words.
3791 * (WRITE u32val to Doorbell reg).
3792 */
3793 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3794 CHIPREG_WRITE32(&ioc->chip->Doorbell,
3795 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
3796 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
3797
3798 /*
3799 * Wait for IOC's doorbell handshake int
3800 */
3801 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
3802 failcnt++;
3803
3804 dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
3805 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
3806
3807 /* Read doorbell and check for active bit */
3808 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
3809 return -1;
3810
3811 /*
3812 * Clear doorbell int (WRITE 0 to IntStatus reg),
3813 * then wait for IOC to ACKnowledge that it's ready for
3814 * our handshake request.
3815 */
3816 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3817 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3818 failcnt++;
3819
3820 if (!failcnt) {
3821 int ii;
3822 u8 *req_as_bytes = (u8 *) req;
3823
3824 /*
3825 * Stuff request words via doorbell handshake,
3826 * with ACK from IOC for each.
3827 */
3828 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
3829 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
3830 (req_as_bytes[(ii*4) + 1] << 8) |
3831 (req_as_bytes[(ii*4) + 2] << 16) |
3832 (req_as_bytes[(ii*4) + 3] << 24));
3833
3834 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
3835 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3836 failcnt++;
3837 }
3838
3839 dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
3840 DBG_DUMP_REQUEST_FRAME_HDR(req)
3841
3842 dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
3843 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
3844
3845 /*
3846 * Wait for completion of doorbell handshake reply from the IOC
3847 */
3848 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
3849 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003850
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
3852 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
3853
3854 /*
3855 * Copy out the cached reply...
3856 */
3857 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
3858 u16reply[ii] = ioc->hs_reply[ii];
3859 } else {
3860 return -99;
3861 }
3862
3863 return -failcnt;
3864}
3865
3866/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3867/*
3868 * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
3869 * in it's IntStatus register.
3870 * @ioc: Pointer to MPT_ADAPTER structure
3871 * @howlong: How long to wait (in seconds)
3872 * @sleepFlag: Specifies whether the process can sleep
3873 *
3874 * This routine waits (up to ~2 seconds max) for IOC doorbell
3875 * handshake ACKnowledge.
3876 *
3877 * Returns a negative value on failure, else wait loop count.
3878 */
3879static int
3880WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3881{
3882 int cntdn;
3883 int count = 0;
3884 u32 intstat=0;
3885
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003886 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
3888 if (sleepFlag == CAN_SLEEP) {
3889 while (--cntdn) {
3890 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3891 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3892 break;
3893 msleep_interruptible (1);
3894 count++;
3895 }
3896 } else {
3897 while (--cntdn) {
3898 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3899 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
3900 break;
3901 mdelay (1);
3902 count++;
3903 }
3904 }
3905
3906 if (cntdn) {
3907 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
3908 ioc->name, count));
3909 return count;
3910 }
3911
3912 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
3913 ioc->name, count, intstat);
3914 return -1;
3915}
3916
3917/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3918/*
3919 * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
3920 * in it's IntStatus register.
3921 * @ioc: Pointer to MPT_ADAPTER structure
3922 * @howlong: How long to wait (in seconds)
3923 * @sleepFlag: Specifies whether the process can sleep
3924 *
3925 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
3926 *
3927 * Returns a negative value on failure, else wait loop count.
3928 */
3929static int
3930WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3931{
3932 int cntdn;
3933 int count = 0;
3934 u32 intstat=0;
3935
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003936 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 if (sleepFlag == CAN_SLEEP) {
3938 while (--cntdn) {
3939 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3940 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3941 break;
3942 msleep_interruptible(1);
3943 count++;
3944 }
3945 } else {
3946 while (--cntdn) {
3947 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
3948 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
3949 break;
3950 mdelay(1);
3951 count++;
3952 }
3953 }
3954
3955 if (cntdn) {
3956 dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
3957 ioc->name, count, howlong));
3958 return count;
3959 }
3960
3961 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
3962 ioc->name, count, intstat);
3963 return -1;
3964}
3965
3966/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
3967/*
3968 * WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
3969 * @ioc: Pointer to MPT_ADAPTER structure
3970 * @howlong: How long to wait (in seconds)
3971 * @sleepFlag: Specifies whether the process can sleep
3972 *
3973 * This routine polls the IOC for a handshake reply, 16 bits at a time.
3974 * Reply is cached to IOC private area large enough to hold a maximum
3975 * of 128 bytes of reply data.
3976 *
3977 * Returns a negative value on failure, else size of reply in WORDS.
3978 */
3979static int
3980WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
3981{
3982 int u16cnt = 0;
3983 int failcnt = 0;
3984 int t;
3985 u16 *hs_reply = ioc->hs_reply;
3986 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
3987 u16 hword;
3988
3989 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
3990
3991 /*
3992 * Get first two u16's so we can look at IOC's intended reply MsgLength
3993 */
3994 u16cnt=0;
3995 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
3996 failcnt++;
3997 } else {
3998 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
3999 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4000 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4001 failcnt++;
4002 else {
4003 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4004 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4005 }
4006 }
4007
4008 dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004009 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4011
4012 /*
4013 * If no error (and IOC said MsgLength is > 0), piece together
4014 * reply 16 bits at a time.
4015 */
4016 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4017 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4018 failcnt++;
4019 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4020 /* don't overflow our IOC hs_reply[] buffer! */
4021 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4022 hs_reply[u16cnt] = hword;
4023 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4024 }
4025
4026 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4027 failcnt++;
4028 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4029
4030 if (failcnt) {
4031 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4032 ioc->name);
4033 return -failcnt;
4034 }
4035#if 0
4036 else if (u16cnt != (2 * mptReply->MsgLength)) {
4037 return -101;
4038 }
4039 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4040 return -102;
4041 }
4042#endif
4043
4044 dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
4045 DBG_DUMP_REPLY_FRAME(mptReply)
4046
4047 dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
4048 ioc->name, t, u16cnt/2));
4049 return u16cnt/2;
4050}
4051
4052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4053/*
4054 * GetLanConfigPages - Fetch LANConfig pages.
4055 * @ioc: Pointer to MPT_ADAPTER structure
4056 *
4057 * Return: 0 for success
4058 * -ENOMEM if no memory available
4059 * -EPERM if not allowed due to ISR context
4060 * -EAGAIN if no msg frames currently available
4061 * -EFAULT for non-successful reply or no reply (timeout)
4062 */
4063static int
4064GetLanConfigPages(MPT_ADAPTER *ioc)
4065{
4066 ConfigPageHeader_t hdr;
4067 CONFIGPARMS cfg;
4068 LANPage0_t *ppage0_alloc;
4069 dma_addr_t page0_dma;
4070 LANPage1_t *ppage1_alloc;
4071 dma_addr_t page1_dma;
4072 int rc = 0;
4073 int data_sz;
4074 int copy_sz;
4075
4076 /* Get LAN Page 0 header */
4077 hdr.PageVersion = 0;
4078 hdr.PageLength = 0;
4079 hdr.PageNumber = 0;
4080 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004081 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 cfg.physAddr = -1;
4083 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4084 cfg.dir = 0;
4085 cfg.pageAddr = 0;
4086 cfg.timeout = 0;
4087
4088 if ((rc = mpt_config(ioc, &cfg)) != 0)
4089 return rc;
4090
4091 if (hdr.PageLength > 0) {
4092 data_sz = hdr.PageLength * 4;
4093 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4094 rc = -ENOMEM;
4095 if (ppage0_alloc) {
4096 memset((u8 *)ppage0_alloc, 0, data_sz);
4097 cfg.physAddr = page0_dma;
4098 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4099
4100 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4101 /* save the data */
4102 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4103 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4104
4105 }
4106
4107 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4108
4109 /* FIXME!
4110 * Normalize endianness of structure data,
4111 * by byte-swapping all > 1 byte fields!
4112 */
4113
4114 }
4115
4116 if (rc)
4117 return rc;
4118 }
4119
4120 /* Get LAN Page 1 header */
4121 hdr.PageVersion = 0;
4122 hdr.PageLength = 0;
4123 hdr.PageNumber = 1;
4124 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004125 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 cfg.physAddr = -1;
4127 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4128 cfg.dir = 0;
4129 cfg.pageAddr = 0;
4130
4131 if ((rc = mpt_config(ioc, &cfg)) != 0)
4132 return rc;
4133
4134 if (hdr.PageLength == 0)
4135 return 0;
4136
4137 data_sz = hdr.PageLength * 4;
4138 rc = -ENOMEM;
4139 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4140 if (ppage1_alloc) {
4141 memset((u8 *)ppage1_alloc, 0, data_sz);
4142 cfg.physAddr = page1_dma;
4143 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4144
4145 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4146 /* save the data */
4147 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4148 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4149 }
4150
4151 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4152
4153 /* FIXME!
4154 * Normalize endianness of structure data,
4155 * by byte-swapping all > 1 byte fields!
4156 */
4157
4158 }
4159
4160 return rc;
4161}
4162
4163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4164/*
Michael Reed05e8ec12006-01-13 14:31:54 -06004165 * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 * @ioc: Pointer to MPT_ADAPTER structure
4167 * @portnum: IOC Port number
4168 *
4169 * Return: 0 for success
4170 * -ENOMEM if no memory available
4171 * -EPERM if not allowed due to ISR context
4172 * -EAGAIN if no msg frames currently available
4173 * -EFAULT for non-successful reply or no reply (timeout)
4174 */
Michael Reed05e8ec12006-01-13 14:31:54 -06004175int
4176mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177{
4178 ConfigPageHeader_t hdr;
4179 CONFIGPARMS cfg;
4180 FCPortPage0_t *ppage0_alloc;
4181 FCPortPage0_t *pp0dest;
4182 dma_addr_t page0_dma;
4183 int data_sz;
4184 int copy_sz;
4185 int rc;
Michael Reed05e8ec12006-01-13 14:31:54 -06004186 int count = 400;
4187
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
4189 /* Get FCPort Page 0 header */
4190 hdr.PageVersion = 0;
4191 hdr.PageLength = 0;
4192 hdr.PageNumber = 0;
4193 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004194 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 cfg.physAddr = -1;
4196 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4197 cfg.dir = 0;
4198 cfg.pageAddr = portnum;
4199 cfg.timeout = 0;
4200
4201 if ((rc = mpt_config(ioc, &cfg)) != 0)
4202 return rc;
4203
4204 if (hdr.PageLength == 0)
4205 return 0;
4206
4207 data_sz = hdr.PageLength * 4;
4208 rc = -ENOMEM;
4209 ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4210 if (ppage0_alloc) {
Michael Reed05e8ec12006-01-13 14:31:54 -06004211
4212 try_again:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 memset((u8 *)ppage0_alloc, 0, data_sz);
4214 cfg.physAddr = page0_dma;
4215 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4216
4217 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4218 /* save the data */
4219 pp0dest = &ioc->fc_port_page0[portnum];
4220 copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
4221 memcpy(pp0dest, ppage0_alloc, copy_sz);
4222
4223 /*
4224 * Normalize endianness of structure data,
4225 * by byte-swapping all > 1 byte fields!
4226 */
4227 pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
4228 pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
4229 pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
4230 pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
4231 pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
4232 pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
4233 pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
4234 pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
4235 pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
4236 pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
4237 pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
4238 pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
4239 pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
4240 pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
4241 pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
4242 pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
4243
Michael Reed05e8ec12006-01-13 14:31:54 -06004244 /*
4245 * if still doing discovery,
4246 * hang loose a while until finished
4247 */
4248 if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
4249 if (count-- > 0) {
4250 msleep_interruptible(100);
4251 goto try_again;
4252 }
4253 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
4254 " complete.\n",
4255 ioc->name);
4256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 }
4258
4259 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4260 }
4261
4262 return rc;
4263}
4264
4265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4266/*
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004267 * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table
4268 * @ioc: Pointer to MPT_ADAPTER structure
4269 * @sas_address: 64bit SAS Address for operation.
4270 * @target_id: specified target for operation
4271 * @bus: specified bus for operation
4272 * @persist_opcode: see below
4273 *
4274 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4275 * devices not currently present.
4276 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4277 *
4278 * NOTE: Don't use not this function during interrupt time.
4279 *
4280 * Returns: 0 for success, non-zero error
4281 */
4282
4283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4284int
4285mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4286{
4287 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4288 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4289 MPT_FRAME_HDR *mf = NULL;
4290 MPIHeader_t *mpi_hdr;
4291
4292
4293 /* insure garbage is not sent to fw */
4294 switch(persist_opcode) {
4295
4296 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4297 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4298 break;
4299
4300 default:
4301 return -1;
4302 break;
4303 }
4304
4305 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4306
4307 /* Get a MF for this command.
4308 */
4309 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4310 printk("%s: no msg frames!\n",__FUNCTION__);
4311 return -1;
4312 }
4313
4314 mpi_hdr = (MPIHeader_t *) mf;
4315 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4316 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4317 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4318 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4319 sasIoUnitCntrReq->Operation = persist_opcode;
4320
4321 init_timer(&ioc->persist_timer);
4322 ioc->persist_timer.data = (unsigned long) ioc;
4323 ioc->persist_timer.function = mpt_timer_expired;
4324 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4325 ioc->persist_wait_done=0;
4326 add_timer(&ioc->persist_timer);
4327 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4328 wait_event(mpt_waitq, ioc->persist_wait_done);
4329
4330 sasIoUnitCntrReply =
4331 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4332 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4333 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4334 __FUNCTION__,
4335 sasIoUnitCntrReply->IOCStatus,
4336 sasIoUnitCntrReply->IOCLogInfo);
4337 return -1;
4338 }
4339
4340 printk("%s: success\n",__FUNCTION__);
4341 return 0;
4342}
4343
4344/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004345
4346static void
4347mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4348 MpiEventDataRaid_t * pRaidEventData)
4349{
4350 int volume;
4351 int reason;
4352 int disk;
4353 int status;
4354 int flags;
4355 int state;
4356
4357 volume = pRaidEventData->VolumeID;
4358 reason = pRaidEventData->ReasonCode;
4359 disk = pRaidEventData->PhysDiskNum;
4360 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4361 flags = (status >> 0) & 0xff;
4362 state = (status >> 8) & 0xff;
4363
4364 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4365 return;
4366 }
4367
4368 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4369 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4370 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
4371 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
4372 ioc->name, disk);
4373 } else {
4374 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4375 ioc->name, volume);
4376 }
4377
4378 switch(reason) {
4379 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4380 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4381 ioc->name);
4382 break;
4383
4384 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4385
4386 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4387 ioc->name);
4388 break;
4389
4390 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4391 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4392 ioc->name);
4393 break;
4394
4395 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4396 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4397 ioc->name,
4398 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4399 ? "optimal"
4400 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4401 ? "degraded"
4402 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4403 ? "failed"
4404 : "state unknown",
4405 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4406 ? ", enabled" : "",
4407 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4408 ? ", quiesced" : "",
4409 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4410 ? ", resync in progress" : "" );
4411 break;
4412
4413 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4414 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4415 ioc->name, disk);
4416 break;
4417
4418 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4419 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4420 ioc->name);
4421 break;
4422
4423 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4424 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4425 ioc->name);
4426 break;
4427
4428 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4429 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4430 ioc->name);
4431 break;
4432
4433 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4434 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4435 ioc->name,
4436 state == MPI_PHYSDISK0_STATUS_ONLINE
4437 ? "online"
4438 : state == MPI_PHYSDISK0_STATUS_MISSING
4439 ? "missing"
4440 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4441 ? "not compatible"
4442 : state == MPI_PHYSDISK0_STATUS_FAILED
4443 ? "failed"
4444 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4445 ? "initializing"
4446 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4447 ? "offline requested"
4448 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4449 ? "failed requested"
4450 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4451 ? "offline"
4452 : "state unknown",
4453 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4454 ? ", out of sync" : "",
4455 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4456 ? ", quiesced" : "" );
4457 break;
4458
4459 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4460 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4461 ioc->name, disk);
4462 break;
4463
4464 case MPI_EVENT_RAID_RC_SMART_DATA:
4465 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4466 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4467 break;
4468
4469 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4470 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4471 ioc->name, disk);
4472 break;
4473 }
4474}
4475
4476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004477/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4479 * @ioc: Pointer to MPT_ADAPTER structure
4480 *
4481 * Returns: 0 for success
4482 * -ENOMEM if no memory available
4483 * -EPERM if not allowed due to ISR context
4484 * -EAGAIN if no msg frames currently available
4485 * -EFAULT for non-successful reply or no reply (timeout)
4486 */
4487static int
4488GetIoUnitPage2(MPT_ADAPTER *ioc)
4489{
4490 ConfigPageHeader_t hdr;
4491 CONFIGPARMS cfg;
4492 IOUnitPage2_t *ppage_alloc;
4493 dma_addr_t page_dma;
4494 int data_sz;
4495 int rc;
4496
4497 /* Get the page header */
4498 hdr.PageVersion = 0;
4499 hdr.PageLength = 0;
4500 hdr.PageNumber = 2;
4501 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004502 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 cfg.physAddr = -1;
4504 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4505 cfg.dir = 0;
4506 cfg.pageAddr = 0;
4507 cfg.timeout = 0;
4508
4509 if ((rc = mpt_config(ioc, &cfg)) != 0)
4510 return rc;
4511
4512 if (hdr.PageLength == 0)
4513 return 0;
4514
4515 /* Read the config page */
4516 data_sz = hdr.PageLength * 4;
4517 rc = -ENOMEM;
4518 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4519 if (ppage_alloc) {
4520 memset((u8 *)ppage_alloc, 0, data_sz);
4521 cfg.physAddr = page_dma;
4522 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4523
4524 /* If Good, save data */
4525 if ((rc = mpt_config(ioc, &cfg)) == 0)
4526 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4527
4528 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4529 }
4530
4531 return rc;
4532}
4533
4534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4535/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
4536 * @ioc: Pointer to a Adapter Strucutre
4537 * @portnum: IOC port number
4538 *
4539 * Return: -EFAULT if read of config page header fails
4540 * or if no nvram
4541 * If read of SCSI Port Page 0 fails,
4542 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4543 * Adapter settings: async, narrow
4544 * Return 1
4545 * If read of SCSI Port Page 2 fails,
4546 * Adapter settings valid
4547 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4548 * Return 1
4549 * Else
4550 * Both valid
4551 * Return 0
4552 * CHECK - what type of locking mechanisms should be used????
4553 */
4554static int
4555mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4556{
4557 u8 *pbuf;
4558 dma_addr_t buf_dma;
4559 CONFIGPARMS cfg;
4560 ConfigPageHeader_t header;
4561 int ii;
4562 int data, rc = 0;
4563
4564 /* Allocate memory
4565 */
4566 if (!ioc->spi_data.nvram) {
4567 int sz;
4568 u8 *mem;
4569 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4570 mem = kmalloc(sz, GFP_ATOMIC);
4571 if (mem == NULL)
4572 return -EFAULT;
4573
4574 ioc->spi_data.nvram = (int *) mem;
4575
4576 dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
4577 ioc->name, ioc->spi_data.nvram, sz));
4578 }
4579
4580 /* Invalidate NVRAM information
4581 */
4582 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4583 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4584 }
4585
4586 /* Read SPP0 header, allocate memory, then read page.
4587 */
4588 header.PageVersion = 0;
4589 header.PageLength = 0;
4590 header.PageNumber = 0;
4591 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004592 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 cfg.physAddr = -1;
4594 cfg.pageAddr = portnum;
4595 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4596 cfg.dir = 0;
4597 cfg.timeout = 0; /* use default */
4598 if (mpt_config(ioc, &cfg) != 0)
4599 return -EFAULT;
4600
4601 if (header.PageLength > 0) {
4602 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4603 if (pbuf) {
4604 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4605 cfg.physAddr = buf_dma;
4606 if (mpt_config(ioc, &cfg) != 0) {
4607 ioc->spi_data.maxBusWidth = MPT_NARROW;
4608 ioc->spi_data.maxSyncOffset = 0;
4609 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4610 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4611 rc = 1;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004612 ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
4613 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 } else {
4615 /* Save the Port Page 0 data
4616 */
4617 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4618 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4619 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4620
4621 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4622 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004623 ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 ioc->name, pPP0->Capabilities));
4625 }
4626 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4627 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4628 if (data) {
4629 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4630 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4631 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004632 ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
4633 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 } else {
4635 ioc->spi_data.maxSyncOffset = 0;
4636 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4637 }
4638
4639 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4640
4641 /* Update the minSyncFactor based on bus type.
4642 */
4643 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4644 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4645
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004646 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004648 ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
4649 ioc->name, ioc->spi_data.minSyncFactor));
4650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 }
4652 }
4653 if (pbuf) {
4654 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4655 }
4656 }
4657 }
4658
4659 /* SCSI Port Page 2 - Read the header then the page.
4660 */
4661 header.PageVersion = 0;
4662 header.PageLength = 0;
4663 header.PageNumber = 2;
4664 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004665 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 cfg.physAddr = -1;
4667 cfg.pageAddr = portnum;
4668 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4669 cfg.dir = 0;
4670 if (mpt_config(ioc, &cfg) != 0)
4671 return -EFAULT;
4672
4673 if (header.PageLength > 0) {
4674 /* Allocate memory and read SCSI Port Page 2
4675 */
4676 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4677 if (pbuf) {
4678 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4679 cfg.physAddr = buf_dma;
4680 if (mpt_config(ioc, &cfg) != 0) {
4681 /* Nvram data is left with INVALID mark
4682 */
4683 rc = 1;
4684 } else {
4685 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4686 MpiDeviceInfo_t *pdevice = NULL;
4687
Moore, Ericd8e925d2006-01-16 18:53:06 -07004688 /*
4689 * Save "Set to Avoid SCSI Bus Resets" flag
4690 */
4691 ioc->spi_data.bus_reset =
4692 (le32_to_cpu(pPP2->PortFlags) &
4693 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4694 0 : 1 ;
4695
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 /* Save the Port Page 2 data
4697 * (reformat into a 32bit quantity)
4698 */
4699 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4700 ioc->spi_data.PortFlags = data;
4701 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4702 pdevice = &pPP2->DeviceSettings[ii];
4703 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4704 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4705 ioc->spi_data.nvram[ii] = data;
4706 }
4707 }
4708
4709 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4710 }
4711 }
4712
4713 /* Update Adapter limits with those from NVRAM
4714 * Comment: Don't need to do this. Target performance
4715 * parameters will never exceed the adapters limits.
4716 */
4717
4718 return rc;
4719}
4720
4721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4722/* mpt_readScsiDevicePageHeaders - save version and length of SDP1
4723 * @ioc: Pointer to a Adapter Strucutre
4724 * @portnum: IOC port number
4725 *
4726 * Return: -EFAULT if read of config page header fails
4727 * or 0 if success.
4728 */
4729static int
4730mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4731{
4732 CONFIGPARMS cfg;
4733 ConfigPageHeader_t header;
4734
4735 /* Read the SCSI Device Page 1 header
4736 */
4737 header.PageVersion = 0;
4738 header.PageLength = 0;
4739 header.PageNumber = 1;
4740 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004741 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 cfg.physAddr = -1;
4743 cfg.pageAddr = portnum;
4744 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4745 cfg.dir = 0;
4746 cfg.timeout = 0;
4747 if (mpt_config(ioc, &cfg) != 0)
4748 return -EFAULT;
4749
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004750 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4751 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
4753 header.PageVersion = 0;
4754 header.PageLength = 0;
4755 header.PageNumber = 0;
4756 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4757 if (mpt_config(ioc, &cfg) != 0)
4758 return -EFAULT;
4759
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004760 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
4761 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
4763 dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
4764 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
4765
4766 dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
4767 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
4768 return 0;
4769}
4770
4771/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4772/**
4773 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
4774 * @ioc: Pointer to a Adapter Strucutre
4775 * @portnum: IOC port number
4776 *
4777 * Return:
4778 * 0 on success
4779 * -EFAULT if read of config page header fails or data pointer not NULL
4780 * -ENOMEM if pci_alloc failed
4781 */
4782int
4783mpt_findImVolumes(MPT_ADAPTER *ioc)
4784{
4785 IOCPage2_t *pIoc2;
4786 u8 *mem;
4787 ConfigPageIoc2RaidVol_t *pIocRv;
4788 dma_addr_t ioc2_dma;
4789 CONFIGPARMS cfg;
4790 ConfigPageHeader_t header;
4791 int jj;
4792 int rc = 0;
4793 int iocpage2sz;
4794 u8 nVols, nPhys;
4795 u8 vid, vbus, vioc;
4796
4797 /* Read IOCP2 header then the page.
4798 */
4799 header.PageVersion = 0;
4800 header.PageLength = 0;
4801 header.PageNumber = 2;
4802 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004803 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 cfg.physAddr = -1;
4805 cfg.pageAddr = 0;
4806 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4807 cfg.dir = 0;
4808 cfg.timeout = 0;
4809 if (mpt_config(ioc, &cfg) != 0)
4810 return -EFAULT;
4811
4812 if (header.PageLength == 0)
4813 return -EFAULT;
4814
4815 iocpage2sz = header.PageLength * 4;
4816 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
4817 if (!pIoc2)
4818 return -ENOMEM;
4819
4820 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4821 cfg.physAddr = ioc2_dma;
4822 if (mpt_config(ioc, &cfg) != 0)
4823 goto done_and_free;
4824
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004825 if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 mem = kmalloc(iocpage2sz, GFP_ATOMIC);
4827 if (mem) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004828 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 } else {
4830 goto done_and_free;
4831 }
4832 }
4833 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
4834
4835 /* Identify RAID Volume Id's */
4836 nVols = pIoc2->NumActiveVolumes;
4837 if ( nVols == 0) {
4838 /* No RAID Volume.
4839 */
4840 goto done_and_free;
4841 } else {
4842 /* At least 1 RAID Volume
4843 */
4844 pIocRv = pIoc2->RaidVolume;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004845 ioc->raid_data.isRaid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 for (jj = 0; jj < nVols; jj++, pIocRv++) {
4847 vid = pIocRv->VolumeID;
4848 vbus = pIocRv->VolumeBus;
4849 vioc = pIocRv->VolumeIOC;
4850
4851 /* find the match
4852 */
4853 if (vbus == 0) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004854 ioc->raid_data.isRaid |= (1 << vid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 } else {
4856 /* Error! Always bus 0
4857 */
4858 }
4859 }
4860 }
4861
4862 /* Identify Hidden Physical Disk Id's */
4863 nPhys = pIoc2->NumActivePhysDisks;
4864 if (nPhys == 0) {
4865 /* No physical disks.
4866 */
4867 } else {
4868 mpt_read_ioc_pg_3(ioc);
4869 }
4870
4871done_and_free:
4872 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
4873
4874 return rc;
4875}
4876
Moore, Ericc972c702006-03-14 09:14:06 -07004877static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
4879{
4880 IOCPage3_t *pIoc3;
4881 u8 *mem;
4882 CONFIGPARMS cfg;
4883 ConfigPageHeader_t header;
4884 dma_addr_t ioc3_dma;
4885 int iocpage3sz = 0;
4886
4887 /* Free the old page
4888 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004889 kfree(ioc->raid_data.pIocPg3);
4890 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
4892 /* There is at least one physical disk.
4893 * Read and save IOC Page 3
4894 */
4895 header.PageVersion = 0;
4896 header.PageLength = 0;
4897 header.PageNumber = 3;
4898 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004899 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 cfg.physAddr = -1;
4901 cfg.pageAddr = 0;
4902 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4903 cfg.dir = 0;
4904 cfg.timeout = 0;
4905 if (mpt_config(ioc, &cfg) != 0)
4906 return 0;
4907
4908 if (header.PageLength == 0)
4909 return 0;
4910
4911 /* Read Header good, alloc memory
4912 */
4913 iocpage3sz = header.PageLength * 4;
4914 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
4915 if (!pIoc3)
4916 return 0;
4917
4918 /* Read the Page and save the data
4919 * into malloc'd memory.
4920 */
4921 cfg.physAddr = ioc3_dma;
4922 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4923 if (mpt_config(ioc, &cfg) == 0) {
4924 mem = kmalloc(iocpage3sz, GFP_ATOMIC);
4925 if (mem) {
4926 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004927 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928 }
4929 }
4930
4931 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
4932
4933 return 0;
4934}
4935
4936static void
4937mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
4938{
4939 IOCPage4_t *pIoc4;
4940 CONFIGPARMS cfg;
4941 ConfigPageHeader_t header;
4942 dma_addr_t ioc4_dma;
4943 int iocpage4sz;
4944
4945 /* Read and save IOC Page 4
4946 */
4947 header.PageVersion = 0;
4948 header.PageLength = 0;
4949 header.PageNumber = 4;
4950 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004951 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 cfg.physAddr = -1;
4953 cfg.pageAddr = 0;
4954 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4955 cfg.dir = 0;
4956 cfg.timeout = 0;
4957 if (mpt_config(ioc, &cfg) != 0)
4958 return;
4959
4960 if (header.PageLength == 0)
4961 return;
4962
4963 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
4964 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
4965 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
4966 if (!pIoc4)
4967 return;
4968 } else {
4969 ioc4_dma = ioc->spi_data.IocPg4_dma;
4970 iocpage4sz = ioc->spi_data.IocPg4Sz;
4971 }
4972
4973 /* Read the Page into dma memory.
4974 */
4975 cfg.physAddr = ioc4_dma;
4976 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4977 if (mpt_config(ioc, &cfg) == 0) {
4978 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
4979 ioc->spi_data.IocPg4_dma = ioc4_dma;
4980 ioc->spi_data.IocPg4Sz = iocpage4sz;
4981 } else {
4982 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
4983 ioc->spi_data.pIocPg4 = NULL;
4984 }
4985}
4986
4987static void
4988mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
4989{
4990 IOCPage1_t *pIoc1;
4991 CONFIGPARMS cfg;
4992 ConfigPageHeader_t header;
4993 dma_addr_t ioc1_dma;
4994 int iocpage1sz = 0;
4995 u32 tmp;
4996
4997 /* Check the Coalescing Timeout in IOC Page 1
4998 */
4999 header.PageVersion = 0;
5000 header.PageLength = 0;
5001 header.PageNumber = 1;
5002 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005003 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 cfg.physAddr = -1;
5005 cfg.pageAddr = 0;
5006 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5007 cfg.dir = 0;
5008 cfg.timeout = 0;
5009 if (mpt_config(ioc, &cfg) != 0)
5010 return;
5011
5012 if (header.PageLength == 0)
5013 return;
5014
5015 /* Read Header good, alloc memory
5016 */
5017 iocpage1sz = header.PageLength * 4;
5018 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5019 if (!pIoc1)
5020 return;
5021
5022 /* Read the Page and check coalescing timeout
5023 */
5024 cfg.physAddr = ioc1_dma;
5025 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5026 if (mpt_config(ioc, &cfg) == 0) {
5027
5028 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5029 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5030 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5031
5032 dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
5033 ioc->name, tmp));
5034
5035 if (tmp > MPT_COALESCING_TIMEOUT) {
5036 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5037
5038 /* Write NVRAM and current
5039 */
5040 cfg.dir = 1;
5041 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5042 if (mpt_config(ioc, &cfg) == 0) {
5043 dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
5044 ioc->name, MPT_COALESCING_TIMEOUT));
5045
5046 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5047 if (mpt_config(ioc, &cfg) == 0) {
5048 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
5049 ioc->name, MPT_COALESCING_TIMEOUT));
5050 } else {
5051 dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
5052 ioc->name));
5053 }
5054
5055 } else {
5056 dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
5057 ioc->name));
5058 }
5059 }
5060
5061 } else {
5062 dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
5063 }
5064 }
5065
5066 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5067
5068 return;
5069}
5070
5071/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5072/*
5073 * SendEventNotification - Send EventNotification (on or off) request
5074 * to MPT adapter.
5075 * @ioc: Pointer to MPT_ADAPTER structure
5076 * @EvSwitch: Event switch flags
5077 */
5078static int
5079SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5080{
5081 EventNotification_t *evnp;
5082
5083 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5084 if (evnp == NULL) {
Moore, Eric3a892be2006-03-14 09:14:03 -07005085 devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 ioc->name));
5087 return 0;
5088 }
5089 memset(evnp, 0, sizeof(*evnp));
5090
Moore, Eric3a892be2006-03-14 09:14:03 -07005091 devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092
5093 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5094 evnp->ChainOffset = 0;
5095 evnp->MsgFlags = 0;
5096 evnp->Switch = EvSwitch;
5097
5098 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5099
5100 return 0;
5101}
5102
5103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5104/**
5105 * SendEventAck - Send EventAck request to MPT adapter.
5106 * @ioc: Pointer to MPT_ADAPTER structure
5107 * @evnp: Pointer to original EventNotification request
5108 */
5109static int
5110SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5111{
5112 EventAck_t *pAck;
5113
5114 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005115 printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
5116 "request frame for Event=%x EventContext=%x EventData=%x!\n",
5117 ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
5118 le32_to_cpu(evnp->Data[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 return -1;
5120 }
5121 memset(pAck, 0, sizeof(*pAck));
5122
5123 dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
5124
5125 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5126 pAck->ChainOffset = 0;
5127 pAck->MsgFlags = 0;
5128 pAck->Event = evnp->Event;
5129 pAck->EventContext = evnp->EventContext;
5130
5131 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5132
5133 return 0;
5134}
5135
5136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5137/**
5138 * mpt_config - Generic function to issue config message
5139 * @ioc - Pointer to an adapter structure
5140 * @cfg - Pointer to a configuration structure. Struct contains
5141 * action, page address, direction, physical address
5142 * and pointer to a configuration page header
5143 * Page header is updated.
5144 *
5145 * Returns 0 for success
5146 * -EPERM if not allowed due to ISR context
5147 * -EAGAIN if no msg frames currently available
5148 * -EFAULT for non-successful reply or no reply (timeout)
5149 */
5150int
5151mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5152{
5153 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005154 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 MPT_FRAME_HDR *mf;
5156 unsigned long flags;
5157 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005158 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 int in_isr;
5160
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005161 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 * to be in ISR context, because that is fatal!
5163 */
5164 in_isr = in_interrupt();
5165 if (in_isr) {
5166 dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
5167 ioc->name));
5168 return -EPERM;
5169 }
5170
5171 /* Get and Populate a free Frame
5172 */
5173 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
5174 dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
5175 ioc->name));
5176 return -EAGAIN;
5177 }
5178 pReq = (Config_t *)mf;
5179 pReq->Action = pCfg->action;
5180 pReq->Reserved = 0;
5181 pReq->ChainOffset = 0;
5182 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005183
5184 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 pReq->ExtPageLength = 0;
5186 pReq->ExtPageType = 0;
5187 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005188
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 for (ii=0; ii < 8; ii++)
5190 pReq->Reserved2[ii] = 0;
5191
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005192 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5193 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5194 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5195 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5196
5197 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5198 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5199 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5200 pReq->ExtPageType = pExtHdr->ExtPageType;
5201 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5202
5203 /* Page Length must be treated as a reserved field for the extended header. */
5204 pReq->Header.PageLength = 0;
5205 }
5206
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5208
5209 /* Add a SGE to the config request.
5210 */
5211 if (pCfg->dir)
5212 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5213 else
5214 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5215
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005216 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5217 flagsLength |= pExtHdr->ExtPageLength * 4;
5218
5219 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5220 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5221 }
5222 else {
5223 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5224
5225 dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
5226 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228
5229 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5230
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 /* Append pCfg pointer to end of mf
5232 */
5233 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5234
5235 /* Initalize the timer
5236 */
5237 init_timer(&pCfg->timer);
5238 pCfg->timer.data = (unsigned long) ioc;
5239 pCfg->timer.function = mpt_timer_expired;
5240 pCfg->wait_done = 0;
5241
5242 /* Set the timer; ensure 10 second minimum */
5243 if (pCfg->timeout < 10)
5244 pCfg->timer.expires = jiffies + HZ*10;
5245 else
5246 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5247
5248 /* Add to end of Q, set timer and then issue this command */
5249 spin_lock_irqsave(&ioc->FreeQlock, flags);
5250 list_add_tail(&pCfg->linkage, &ioc->configQ);
5251 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5252
5253 add_timer(&pCfg->timer);
5254 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5255 wait_event(mpt_waitq, pCfg->wait_done);
5256
5257 /* mf has been freed - do not access */
5258
5259 rc = pCfg->status;
5260
5261 return rc;
5262}
5263
5264/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265/*
5266 * mpt_timer_expired - Call back for timer process.
5267 * Used only internal config functionality.
5268 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5269 */
5270static void
5271mpt_timer_expired(unsigned long data)
5272{
5273 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5274
5275 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
5276
5277 /* Perform a FW reload */
5278 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5279 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5280
5281 /* No more processing.
5282 * Hard reset clean-up will wake up
5283 * process and free all resources.
5284 */
5285 dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
5286
5287 return;
5288}
5289
5290/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5291/*
5292 * mpt_ioc_reset - Base cleanup for hard reset
5293 * @ioc: Pointer to the adapter structure
5294 * @reset_phase: Indicates pre- or post-reset functionality
5295 *
5296 * Remark: Free's resources with internally generated commands.
5297 */
5298static int
5299mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5300{
5301 CONFIGPARMS *pCfg;
5302 unsigned long flags;
5303
5304 dprintk((KERN_WARNING MYNAM
5305 ": IOC %s_reset routed to MPT base driver!\n",
5306 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5307 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5308
5309 if (reset_phase == MPT_IOC_SETUP_RESET) {
5310 ;
5311 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5312 /* If the internal config Q is not empty -
5313 * delete timer. MF resources will be freed when
5314 * the FIFO's are primed.
5315 */
5316 spin_lock_irqsave(&ioc->FreeQlock, flags);
5317 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5318 del_timer(&pCfg->timer);
5319 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5320
5321 } else {
5322 CONFIGPARMS *pNext;
5323
5324 /* Search the configQ for internal commands.
5325 * Flush the Q, and wake up all suspended threads.
5326 */
5327 spin_lock_irqsave(&ioc->FreeQlock, flags);
5328 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5329 list_del(&pCfg->linkage);
5330
5331 pCfg->status = MPT_CONFIG_ERROR;
5332 pCfg->wait_done = 1;
5333 wake_up(&mpt_waitq);
5334 }
5335 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5336 }
5337
5338 return 1; /* currently means nothing really */
5339}
5340
5341
5342#ifdef CONFIG_PROC_FS /* { */
5343/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5344/*
5345 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5346 */
5347/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5348/*
5349 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5350 *
5351 * Returns 0 for success, non-zero for failure.
5352 */
5353static int
5354procmpt_create(void)
5355{
5356 struct proc_dir_entry *ent;
5357
5358 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5359 if (mpt_proc_root_dir == NULL)
5360 return -ENOTDIR;
5361
5362 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5363 if (ent)
5364 ent->read_proc = procmpt_summary_read;
5365
5366 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5367 if (ent)
5368 ent->read_proc = procmpt_version_read;
5369
5370 return 0;
5371}
5372
5373/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5374/*
5375 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5376 *
5377 * Returns 0 for success, non-zero for failure.
5378 */
5379static void
5380procmpt_destroy(void)
5381{
5382 remove_proc_entry("version", mpt_proc_root_dir);
5383 remove_proc_entry("summary", mpt_proc_root_dir);
5384 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5385}
5386
5387/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5388/*
5389 * procmpt_summary_read - Handle read request from /proc/mpt/summary
5390 * or from /proc/mpt/iocN/summary.
5391 * @buf: Pointer to area to write information
5392 * @start: Pointer to start pointer
5393 * @offset: Offset to start writing
5394 * @request:
5395 * @eof: Pointer to EOF integer
5396 * @data: Pointer
5397 *
5398 * Returns number of characters written to process performing the read.
5399 */
5400static int
5401procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5402{
5403 MPT_ADAPTER *ioc;
5404 char *out = buf;
5405 int len;
5406
5407 if (data) {
5408 int more = 0;
5409
5410 ioc = data;
5411 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5412
5413 out += more;
5414 } else {
5415 list_for_each_entry(ioc, &ioc_list, list) {
5416 int more = 0;
5417
5418 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5419
5420 out += more;
5421 if ((out-buf) >= request)
5422 break;
5423 }
5424 }
5425
5426 len = out - buf;
5427
5428 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5429}
5430
5431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5432/*
5433 * procmpt_version_read - Handle read request from /proc/mpt/version.
5434 * @buf: Pointer to area to write information
5435 * @start: Pointer to start pointer
5436 * @offset: Offset to start writing
5437 * @request:
5438 * @eof: Pointer to EOF integer
5439 * @data: Pointer
5440 *
5441 * Returns number of characters written to process performing the read.
5442 */
5443static int
5444procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5445{
5446 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005447 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 char *drvname;
5449 int len;
5450
5451 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5452 len += sprintf(buf+len, " Fusion MPT base driver\n");
5453
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005454 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5456 drvname = NULL;
5457 if (MptCallbacks[ii]) {
5458 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005459 case MPTSPI_DRIVER:
5460 if (!scsi++) drvname = "SPI host";
5461 break;
5462 case MPTFC_DRIVER:
5463 if (!fc++) drvname = "FC host";
5464 break;
5465 case MPTSAS_DRIVER:
5466 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 break;
5468 case MPTLAN_DRIVER:
5469 if (!lan++) drvname = "LAN";
5470 break;
5471 case MPTSTM_DRIVER:
5472 if (!targ++) drvname = "SCSI target";
5473 break;
5474 case MPTCTL_DRIVER:
5475 if (!ctl++) drvname = "ioctl";
5476 break;
5477 }
5478
5479 if (drvname)
5480 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5481 }
5482 }
5483
5484 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5485}
5486
5487/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5488/*
5489 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5490 * @buf: Pointer to area to write information
5491 * @start: Pointer to start pointer
5492 * @offset: Offset to start writing
5493 * @request:
5494 * @eof: Pointer to EOF integer
5495 * @data: Pointer
5496 *
5497 * Returns number of characters written to process performing the read.
5498 */
5499static int
5500procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5501{
5502 MPT_ADAPTER *ioc = data;
5503 int len;
5504 char expVer[32];
5505 int sz;
5506 int p;
5507
5508 mpt_get_fw_exp_ver(expVer, ioc);
5509
5510 len = sprintf(buf, "%s:", ioc->name);
5511 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5512 len += sprintf(buf+len, " (f/w download boot flag set)");
5513// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5514// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5515
5516 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5517 ioc->facts.ProductID,
5518 ioc->prod_name);
5519 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5520 if (ioc->facts.FWImageSize)
5521 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5522 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5523 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5524 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5525
5526 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5527 ioc->facts.CurrentHostMfaHighAddr);
5528 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5529 ioc->facts.CurrentSenseBufferHighAddr);
5530
5531 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5532 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5533
5534 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5535 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5536 /*
5537 * Rounding UP to nearest 4-kB boundary here...
5538 */
5539 sz = (ioc->req_sz * ioc->req_depth) + 128;
5540 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5541 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5542 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5543 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5544 4*ioc->facts.RequestFrameSize,
5545 ioc->facts.GlobalCredits);
5546
5547 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5548 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5549 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5550 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5551 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5552 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5553 ioc->facts.CurReplyFrameSize,
5554 ioc->facts.ReplyQueueDepth);
5555
5556 len += sprintf(buf+len, " MaxDevices = %d\n",
5557 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5558 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5559
5560 /* per-port info */
5561 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5562 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5563 p+1,
5564 ioc->facts.NumberOfPorts);
5565 if (ioc->bus_type == FC) {
5566 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5567 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5568 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
5569 a[5], a[4], a[3], a[2], a[1], a[0]);
5570 }
5571 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
5572 ioc->fc_port_page0[p].WWNN.High,
5573 ioc->fc_port_page0[p].WWNN.Low,
5574 ioc->fc_port_page0[p].WWPN.High,
5575 ioc->fc_port_page0[p].WWPN.Low);
5576 }
5577 }
5578
5579 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5580}
5581
5582#endif /* CONFIG_PROC_FS } */
5583
5584/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5585static void
5586mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
5587{
5588 buf[0] ='\0';
5589 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
5590 sprintf(buf, " (Exp %02d%02d)",
5591 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
5592 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
5593
5594 /* insider hack! */
5595 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
5596 strcat(buf, " [MDBG]");
5597 }
5598}
5599
5600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5601/**
5602 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
5603 * @ioc: Pointer to MPT_ADAPTER structure
5604 * @buffer: Pointer to buffer where IOC summary info should be written
5605 * @size: Pointer to number of bytes we wrote (set by this routine)
5606 * @len: Offset at which to start writing in buffer
5607 * @showlan: Display LAN stuff?
5608 *
5609 * This routine writes (english readable) ASCII text, which represents
5610 * a summary of IOC information, to a buffer.
5611 */
5612void
5613mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
5614{
5615 char expVer[32];
5616 int y;
5617
5618 mpt_get_fw_exp_ver(expVer, ioc);
5619
5620 /*
5621 * Shorter summary of attached ioc's...
5622 */
5623 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
5624 ioc->name,
5625 ioc->prod_name,
5626 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
5627 ioc->facts.FWVersion.Word,
5628 expVer,
5629 ioc->facts.NumberOfPorts,
5630 ioc->req_depth);
5631
5632 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
5633 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
5634 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
5635 a[5], a[4], a[3], a[2], a[1], a[0]);
5636 }
5637
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639
5640 if (!ioc->active)
5641 y += sprintf(buffer+len+y, " (disabled)");
5642
5643 y += sprintf(buffer+len+y, "\n");
5644
5645 *size = y;
5646}
5647
5648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5649/*
5650 * Reset Handling
5651 */
5652/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5653/**
5654 * mpt_HardResetHandler - Generic reset handler, issue SCSI Task
5655 * Management call based on input arg values. If TaskMgmt fails,
5656 * return associated SCSI request.
5657 * @ioc: Pointer to MPT_ADAPTER structure
5658 * @sleepFlag: Indicates if sleep or schedule must be called.
5659 *
5660 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
5661 * or a non-interrupt thread. In the former, must not call schedule().
5662 *
5663 * Remark: A return of -1 is a FATAL error case, as it means a
5664 * FW reload/initialization failed.
5665 *
5666 * Returns 0 for SUCCESS or -1 if FAILED.
5667 */
5668int
5669mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
5670{
5671 int rc;
5672 unsigned long flags;
5673
5674 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
5675#ifdef MFCNT
5676 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
5677 printk("MF count 0x%x !\n", ioc->mfcnt);
5678#endif
5679
5680 /* Reset the adapter. Prevent more than 1 call to
5681 * mpt_do_ioc_recovery at any instant in time.
5682 */
5683 spin_lock_irqsave(&ioc->diagLock, flags);
5684 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
5685 spin_unlock_irqrestore(&ioc->diagLock, flags);
5686 return 0;
5687 } else {
5688 ioc->diagPending = 1;
5689 }
5690 spin_unlock_irqrestore(&ioc->diagLock, flags);
5691
5692 /* FIXME: If do_ioc_recovery fails, repeat....
5693 */
5694
5695 /* The SCSI driver needs to adjust timeouts on all current
5696 * commands prior to the diagnostic reset being issued.
5697 * Prevents timeouts occuring during a diagnostic reset...very bad.
5698 * For all other protocol drivers, this is a no-op.
5699 */
5700 {
5701 int ii;
5702 int r = 0;
5703
5704 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5705 if (MptResetHandlers[ii]) {
5706 dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
5707 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005708 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 if (ioc->alt_ioc) {
5710 dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
5711 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05005712 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713 }
5714 }
5715 }
5716 }
5717
5718 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
5719 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
5720 rc, ioc->name);
5721 }
5722 ioc->reload_fw = 0;
5723 if (ioc->alt_ioc)
5724 ioc->alt_ioc->reload_fw = 0;
5725
5726 spin_lock_irqsave(&ioc->diagLock, flags);
5727 ioc->diagPending = 0;
5728 if (ioc->alt_ioc)
5729 ioc->alt_ioc->diagPending = 0;
5730 spin_unlock_irqrestore(&ioc->diagLock, flags);
5731
5732 dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
5733
5734 return rc;
5735}
5736
Eric Moore509e5e52006-04-26 13:22:37 -06005737# define EVENT_DESCR_STR_SZ 100
5738
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005740static void
5741EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742{
Eric Moore509e5e52006-04-26 13:22:37 -06005743 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744
5745 switch(event) {
5746 case MPI_EVENT_NONE:
5747 ds = "None";
5748 break;
5749 case MPI_EVENT_LOG_DATA:
5750 ds = "Log Data";
5751 break;
5752 case MPI_EVENT_STATE_CHANGE:
5753 ds = "State Change";
5754 break;
5755 case MPI_EVENT_UNIT_ATTENTION:
5756 ds = "Unit Attention";
5757 break;
5758 case MPI_EVENT_IOC_BUS_RESET:
5759 ds = "IOC Bus Reset";
5760 break;
5761 case MPI_EVENT_EXT_BUS_RESET:
5762 ds = "External Bus Reset";
5763 break;
5764 case MPI_EVENT_RESCAN:
5765 ds = "Bus Rescan Event";
5766 /* Ok, do we need to do anything here? As far as
5767 I can tell, this is when a new device gets added
5768 to the loop. */
5769 break;
5770 case MPI_EVENT_LINK_STATUS_CHANGE:
5771 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
5772 ds = "Link Status(FAILURE) Change";
5773 else
5774 ds = "Link Status(ACTIVE) Change";
5775 break;
5776 case MPI_EVENT_LOOP_STATE_CHANGE:
5777 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
5778 ds = "Loop State(LIP) Change";
5779 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06005780 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 else
Eric Moore509e5e52006-04-26 13:22:37 -06005782 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 break;
5784 case MPI_EVENT_LOGOUT:
5785 ds = "Logout";
5786 break;
5787 case MPI_EVENT_EVENT_CHANGE:
5788 if (evData0)
5789 ds = "Events(ON) Change";
5790 else
5791 ds = "Events(OFF) Change";
5792 break;
5793 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005794 {
5795 u8 ReasonCode = (u8)(evData0 >> 16);
5796 switch (ReasonCode) {
5797 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
5798 ds = "Integrated Raid: Volume Created";
5799 break;
5800 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
5801 ds = "Integrated Raid: Volume Deleted";
5802 break;
5803 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
5804 ds = "Integrated Raid: Volume Settings Changed";
5805 break;
5806 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
5807 ds = "Integrated Raid: Volume Status Changed";
5808 break;
5809 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
5810 ds = "Integrated Raid: Volume Physdisk Changed";
5811 break;
5812 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
5813 ds = "Integrated Raid: Physdisk Created";
5814 break;
5815 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
5816 ds = "Integrated Raid: Physdisk Deleted";
5817 break;
5818 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
5819 ds = "Integrated Raid: Physdisk Settings Changed";
5820 break;
5821 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
5822 ds = "Integrated Raid: Physdisk Status Changed";
5823 break;
5824 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
5825 ds = "Integrated Raid: Domain Validation Needed";
5826 break;
5827 case MPI_EVENT_RAID_RC_SMART_DATA :
5828 ds = "Integrated Raid; Smart Data";
5829 break;
5830 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
5831 ds = "Integrated Raid: Replace Action Started";
5832 break;
5833 default:
5834 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005836 }
5837 break;
5838 }
5839 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
5840 ds = "SCSI Device Status Change";
5841 break;
5842 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5843 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005844 u8 id = (u8)(evData0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005845 u8 ReasonCode = (u8)(evData0 >> 16);
5846 switch (ReasonCode) {
5847 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005848 snprintf(evStr, EVENT_DESCR_STR_SZ,
5849 "SAS Device Status Change: Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005850 break;
5851 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06005852 snprintf(evStr, EVENT_DESCR_STR_SZ,
5853 "SAS Device Status Change: Deleted: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005854 break;
5855 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06005856 snprintf(evStr, EVENT_DESCR_STR_SZ,
5857 "SAS Device Status Change: SMART Data: id=%d",
5858 id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005859 break;
5860 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06005861 snprintf(evStr, EVENT_DESCR_STR_SZ,
5862 "SAS Device Status Change: No Persistancy "
5863 "Added: id=%d", id);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005864 break;
5865 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005866 snprintf(evStr, EVENT_DESCR_STR_SZ,
5867 "SAS Device Status Change: Unknown: id=%d", id);
5868 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005869 }
5870 break;
5871 }
5872 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
5873 ds = "Bus Timer Expired";
5874 break;
5875 case MPI_EVENT_QUEUE_FULL:
5876 ds = "Queue Full";
5877 break;
5878 case MPI_EVENT_SAS_SES:
5879 ds = "SAS SES Event";
5880 break;
5881 case MPI_EVENT_PERSISTENT_TABLE_FULL:
5882 ds = "Persistent Table Full";
5883 break;
5884 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07005885 {
Moore, Eric3a892be2006-03-14 09:14:03 -07005886 u8 LinkRates = (u8)(evData0 >> 8);
5887 u8 PhyNumber = (u8)(evData0);
5888 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
5889 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
5890 switch (LinkRates) {
5891 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06005892 snprintf(evStr, EVENT_DESCR_STR_SZ,
5893 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005894 " Rate Unknown",PhyNumber);
5895 break;
5896 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06005897 snprintf(evStr, EVENT_DESCR_STR_SZ,
5898 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005899 " Phy Disabled",PhyNumber);
5900 break;
5901 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06005902 snprintf(evStr, EVENT_DESCR_STR_SZ,
5903 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005904 " Failed Speed Nego",PhyNumber);
5905 break;
5906 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06005907 snprintf(evStr, EVENT_DESCR_STR_SZ,
5908 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005909 " Sata OOB Completed",PhyNumber);
5910 break;
5911 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06005912 snprintf(evStr, EVENT_DESCR_STR_SZ,
5913 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005914 " Rate 1.5 Gbps",PhyNumber);
5915 break;
5916 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06005917 snprintf(evStr, EVENT_DESCR_STR_SZ,
5918 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07005919 " Rate 3.0 Gpbs",PhyNumber);
5920 break;
5921 default:
Eric Moore509e5e52006-04-26 13:22:37 -06005922 snprintf(evStr, EVENT_DESCR_STR_SZ,
5923 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07005924 break;
5925 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005926 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005927 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005928 case MPI_EVENT_SAS_DISCOVERY_ERROR:
5929 ds = "SAS Discovery Error";
5930 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07005931 case MPI_EVENT_IR_RESYNC_UPDATE:
5932 {
5933 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06005934 snprintf(evStr, EVENT_DESCR_STR_SZ,
5935 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07005936 break;
5937 }
5938 case MPI_EVENT_IR2:
5939 {
5940 u8 ReasonCode = (u8)(evData0 >> 16);
5941 switch (ReasonCode) {
5942 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
5943 ds = "IR2: LD State Changed";
5944 break;
5945 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
5946 ds = "IR2: PD State Changed";
5947 break;
5948 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
5949 ds = "IR2: Bad Block Table Full";
5950 break;
5951 case MPI_EVENT_IR2_RC_PD_INSERTED:
5952 ds = "IR2: PD Inserted";
5953 break;
5954 case MPI_EVENT_IR2_RC_PD_REMOVED:
5955 ds = "IR2: PD Removed";
5956 break;
5957 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
5958 ds = "IR2: Foreign CFG Detected";
5959 break;
5960 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
5961 ds = "IR2: Rebuild Medium Error";
5962 break;
5963 default:
5964 ds = "IR2";
5965 break;
5966 }
5967 break;
5968 }
5969 case MPI_EVENT_SAS_DISCOVERY:
5970 {
5971 if (evData0)
5972 ds = "SAS Discovery: Start";
5973 else
5974 ds = "SAS Discovery: Stop";
5975 break;
5976 }
5977 case MPI_EVENT_LOG_ENTRY_ADDED:
5978 ds = "SAS Log Entry Added";
5979 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005980
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 /*
5982 * MPT base "custom" events may be added here...
5983 */
5984 default:
5985 ds = "Unknown";
5986 break;
5987 }
Eric Moore509e5e52006-04-26 13:22:37 -06005988 if (ds)
5989 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990}
5991
5992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5993/*
5994 * ProcessEventNotification - Route a received EventNotificationReply to
5995 * all currently regeistered event handlers.
5996 * @ioc: Pointer to MPT_ADAPTER structure
5997 * @pEventReply: Pointer to EventNotification reply frame
5998 * @evHandlers: Pointer to integer, number of event handlers
5999 *
6000 * Returns sum of event handlers return values.
6001 */
6002static int
6003ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6004{
6005 u16 evDataLen;
6006 u32 evData0 = 0;
6007// u32 evCtx;
6008 int ii;
6009 int r = 0;
6010 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006011 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 u8 event;
6013
6014 /*
6015 * Do platform normalization of values
6016 */
6017 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6018// evCtx = le32_to_cpu(pEventReply->EventContext);
6019 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6020 if (evDataLen) {
6021 evData0 = le32_to_cpu(pEventReply->Data[0]);
6022 }
6023
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006024 EventDescriptionStr(event, evData0, evStr);
Moore, Eric3a892be2006-03-14 09:14:03 -07006025 devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006027 event,
6028 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029
Moore, Eric3a892be2006-03-14 09:14:03 -07006030#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
6032 for (ii = 0; ii < evDataLen; ii++)
6033 printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
6034 printk("\n");
6035#endif
6036
6037 /*
6038 * Do general / base driver event processing
6039 */
6040 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6042 if (evDataLen) {
6043 u8 evState = evData0 & 0xFF;
6044
6045 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6046
6047 /* Update EventState field in cached IocFacts */
6048 if (ioc->facts.Function) {
6049 ioc->facts.EventState = evState;
6050 }
6051 }
6052 break;
Moore, Ericece50912006-01-16 18:53:19 -07006053 case MPI_EVENT_INTEGRATED_RAID:
6054 mptbase_raid_process_event_data(ioc,
6055 (MpiEventDataRaid_t *)pEventReply->Data);
6056 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006057 default:
6058 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 }
6060
6061 /*
6062 * Should this event be logged? Events are written sequentially.
6063 * When buffer is full, start again at the top.
6064 */
6065 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6066 int idx;
6067
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006068 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069
6070 ioc->events[idx].event = event;
6071 ioc->events[idx].eventContext = ioc->eventContext;
6072
6073 for (ii = 0; ii < 2; ii++) {
6074 if (ii < evDataLen)
6075 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6076 else
6077 ioc->events[idx].data[ii] = 0;
6078 }
6079
6080 ioc->eventContext++;
6081 }
6082
6083
6084 /*
6085 * Call each currently registered protocol event handler.
6086 */
6087 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6088 if (MptEvHandlers[ii]) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006089 devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 ioc->name, ii));
6091 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6092 handlers++;
6093 }
6094 }
6095 /* FIXME? Examine results here? */
6096
6097 /*
6098 * If needed, send (a single) EventAck.
6099 */
6100 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006101 devtverboseprintk((MYIOC_s_WARN_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006102 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07006104 devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 ioc->name, ii));
6106 }
6107 }
6108
6109 *evHandlers = handlers;
6110 return r;
6111}
6112
6113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6114/*
6115 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6116 * @ioc: Pointer to MPT_ADAPTER structure
6117 * @log_info: U32 LogInfo reply word from the IOC
6118 *
6119 * Refer to lsi/fc_log.h.
6120 */
6121static void
6122mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6123{
6124 static char *subcl_str[8] = {
6125 "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
6126 "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
6127 };
6128 u8 subcl = (log_info >> 24) & 0x7;
6129
6130 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
6131 ioc->name, log_info, subcl_str[subcl]);
6132}
6133
6134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6135/*
Moore, Eric335a9412006-01-17 17:06:23 -07006136 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 * @ioc: Pointer to MPT_ADAPTER structure
6138 * @mr: Pointer to MPT reply frame
6139 * @log_info: U32 LogInfo word from the IOC
6140 *
6141 * Refer to lsi/sp_log.h.
6142 */
6143static void
Moore, Eric335a9412006-01-17 17:06:23 -07006144mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145{
6146 u32 info = log_info & 0x00FF0000;
6147 char *desc = "unknown";
6148
6149 switch (info) {
6150 case 0x00010000:
6151 desc = "bug! MID not found";
6152 if (ioc->reload_fw == 0)
6153 ioc->reload_fw++;
6154 break;
6155
6156 case 0x00020000:
6157 desc = "Parity Error";
6158 break;
6159
6160 case 0x00030000:
6161 desc = "ASYNC Outbound Overrun";
6162 break;
6163
6164 case 0x00040000:
6165 desc = "SYNC Offset Error";
6166 break;
6167
6168 case 0x00050000:
6169 desc = "BM Change";
6170 break;
6171
6172 case 0x00060000:
6173 desc = "Msg In Overflow";
6174 break;
6175
6176 case 0x00070000:
6177 desc = "DMA Error";
6178 break;
6179
6180 case 0x00080000:
6181 desc = "Outbound DMA Overrun";
6182 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006183
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 case 0x00090000:
6185 desc = "Task Management";
6186 break;
6187
6188 case 0x000A0000:
6189 desc = "Device Problem";
6190 break;
6191
6192 case 0x000B0000:
6193 desc = "Invalid Phase Change";
6194 break;
6195
6196 case 0x000C0000:
6197 desc = "Untagged Table Size";
6198 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006199
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 }
6201
6202 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6203}
6204
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006205/* strings for sas loginfo */
6206 static char *originator_str[] = {
6207 "IOP", /* 00h */
6208 "PL", /* 01h */
6209 "IR" /* 02h */
6210 };
6211 static char *iop_code_str[] = {
6212 NULL, /* 00h */
6213 "Invalid SAS Address", /* 01h */
6214 NULL, /* 02h */
6215 "Invalid Page", /* 03h */
6216 NULL, /* 04h */
6217 "Task Terminated" /* 05h */
6218 };
6219 static char *pl_code_str[] = {
6220 NULL, /* 00h */
6221 "Open Failure", /* 01h */
6222 "Invalid Scatter Gather List", /* 02h */
6223 "Wrong Relative Offset or Frame Length", /* 03h */
6224 "Frame Transfer Error", /* 04h */
6225 "Transmit Frame Connected Low", /* 05h */
6226 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6227 "SATA Read Log Receive Data Error", /* 07h */
6228 "SATA NCQ Fail All Commands After Error", /* 08h */
6229 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6230 "Receive Frame Invalid Message", /* 0Ah */
6231 "Receive Context Message Valid Error", /* 0Bh */
6232 "Receive Frame Current Frame Error", /* 0Ch */
6233 "SATA Link Down", /* 0Dh */
6234 "Discovery SATA Init W IOS", /* 0Eh */
6235 "Config Invalid Page", /* 0Fh */
6236 "Discovery SATA Init Timeout", /* 10h */
6237 "Reset", /* 11h */
6238 "Abort", /* 12h */
6239 "IO Not Yet Executed", /* 13h */
6240 "IO Executed", /* 14h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006241 "Persistant Reservation Out Not Affiliation Owner", /* 15h */
6242 "Open Transmit DMA Abort", /* 16h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006243 NULL, /* 17h */
6244 NULL, /* 18h */
6245 NULL, /* 19h */
6246 NULL, /* 1Ah */
6247 NULL, /* 1Bh */
6248 NULL, /* 1Ch */
6249 NULL, /* 1Dh */
6250 NULL, /* 1Eh */
6251 NULL, /* 1Fh */
6252 "Enclosure Management" /* 20h */
6253 };
6254
6255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6256/*
6257 * mpt_sas_log_info - Log information returned from SAS IOC.
6258 * @ioc: Pointer to MPT_ADAPTER structure
6259 * @log_info: U32 LogInfo reply word from the IOC
6260 *
6261 * Refer to lsi/mpi_log_sas.h.
6262 */
6263static void
6264mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6265{
6266union loginfo_type {
6267 u32 loginfo;
6268 struct {
6269 u32 subcode:16;
6270 u32 code:8;
6271 u32 originator:4;
6272 u32 bus_type:4;
6273 }dw;
6274};
6275 union loginfo_type sas_loginfo;
6276 char *code_desc = NULL;
6277
6278 sas_loginfo.loginfo = log_info;
6279 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6280 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6281 return;
6282 if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
6283 (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
6284 code_desc = iop_code_str[sas_loginfo.dw.code];
6285 }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
6286 (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
6287 code_desc = pl_code_str[sas_loginfo.dw.code];
6288 }
6289
6290 if (code_desc != NULL)
6291 printk(MYIOC_s_INFO_FMT
6292 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6293 " SubCode(0x%04x)\n",
6294 ioc->name,
6295 log_info,
6296 originator_str[sas_loginfo.dw.originator],
6297 code_desc,
6298 sas_loginfo.dw.subcode);
6299 else
6300 printk(MYIOC_s_INFO_FMT
6301 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6302 " SubCode(0x%04x)\n",
6303 ioc->name,
6304 log_info,
6305 originator_str[sas_loginfo.dw.originator],
6306 sas_loginfo.dw.code,
6307 sas_loginfo.dw.subcode);
6308}
6309
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6311/*
6312 * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
6313 * @ioc: Pointer to MPT_ADAPTER structure
6314 * @ioc_status: U32 IOCStatus word from IOC
6315 * @mf: Pointer to MPT request frame
6316 *
6317 * Refer to lsi/mpi.h.
6318 */
6319static void
6320mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
6321{
6322 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
6323 char *desc = "";
6324
6325 switch (status) {
6326 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
6327 desc = "Invalid Function";
6328 break;
6329
6330 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
6331 desc = "Busy";
6332 break;
6333
6334 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
6335 desc = "Invalid SGL";
6336 break;
6337
6338 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
6339 desc = "Internal Error";
6340 break;
6341
6342 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
6343 desc = "Reserved";
6344 break;
6345
6346 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
6347 desc = "Insufficient Resources";
6348 break;
6349
6350 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
6351 desc = "Invalid Field";
6352 break;
6353
6354 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
6355 desc = "Invalid State";
6356 break;
6357
6358 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
6359 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
6360 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
6361 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
6362 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
6363 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
6364 /* No message for Config IOCStatus values */
6365 break;
6366
6367 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
6368 /* No message for recovered error
6369 desc = "SCSI Recovered Error";
6370 */
6371 break;
6372
6373 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
6374 desc = "SCSI Invalid Bus";
6375 break;
6376
6377 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
6378 desc = "SCSI Invalid TargetID";
6379 break;
6380
6381 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
6382 {
6383 SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
6384 U8 cdb = pScsiReq->CDB[0];
6385 if (cdb != 0x12) { /* Inquiry is issued for device scanning */
6386 desc = "SCSI Device Not There";
6387 }
6388 break;
6389 }
6390
6391 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
6392 desc = "SCSI Data Overrun";
6393 break;
6394
6395 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006396 /* This error is checked in scsi_io_done(). Skip.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 desc = "SCSI Data Underrun";
6398 */
6399 break;
6400
6401 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
6402 desc = "SCSI I/O Data Error";
6403 break;
6404
6405 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
6406 desc = "SCSI Protocol Error";
6407 break;
6408
6409 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
6410 desc = "SCSI Task Terminated";
6411 break;
6412
6413 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
6414 desc = "SCSI Residual Mismatch";
6415 break;
6416
6417 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
6418 desc = "SCSI Task Management Failed";
6419 break;
6420
6421 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
6422 desc = "SCSI IOC Terminated";
6423 break;
6424
6425 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
6426 desc = "SCSI Ext Terminated";
6427 break;
6428
6429 default:
6430 desc = "Others";
6431 break;
6432 }
6433 if (desc != "")
6434 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
6435}
6436
6437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006438EXPORT_SYMBOL(mpt_attach);
6439EXPORT_SYMBOL(mpt_detach);
6440#ifdef CONFIG_PM
6441EXPORT_SYMBOL(mpt_resume);
6442EXPORT_SYMBOL(mpt_suspend);
6443#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006445EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446EXPORT_SYMBOL(mpt_register);
6447EXPORT_SYMBOL(mpt_deregister);
6448EXPORT_SYMBOL(mpt_event_register);
6449EXPORT_SYMBOL(mpt_event_deregister);
6450EXPORT_SYMBOL(mpt_reset_register);
6451EXPORT_SYMBOL(mpt_reset_deregister);
6452EXPORT_SYMBOL(mpt_device_driver_register);
6453EXPORT_SYMBOL(mpt_device_driver_deregister);
6454EXPORT_SYMBOL(mpt_get_msg_frame);
6455EXPORT_SYMBOL(mpt_put_msg_frame);
6456EXPORT_SYMBOL(mpt_free_msg_frame);
6457EXPORT_SYMBOL(mpt_add_sge);
6458EXPORT_SYMBOL(mpt_send_handshake_request);
6459EXPORT_SYMBOL(mpt_verify_adapter);
6460EXPORT_SYMBOL(mpt_GetIocState);
6461EXPORT_SYMBOL(mpt_print_ioc_summary);
6462EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08006463EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464EXPORT_SYMBOL(mpt_HardResetHandler);
6465EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006467EXPORT_SYMBOL(mpt_alloc_fw_memory);
6468EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006469EXPORT_SYMBOL(mptbase_sas_persist_operation);
Michael Reed05e8ec12006-01-13 14:31:54 -06006470EXPORT_SYMBOL(mptbase_GetFcPortPage0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472
6473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6474/*
6475 * fusion_init - Fusion MPT base driver initialization routine.
6476 *
6477 * Returns 0 for success, non-zero for failure.
6478 */
6479static int __init
6480fusion_init(void)
6481{
6482 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483
6484 show_mptmod_ver(my_NAME, my_VERSION);
6485 printk(KERN_INFO COPYRIGHT "\n");
6486
6487 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
6488 MptCallbacks[i] = NULL;
6489 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
6490 MptEvHandlers[i] = NULL;
6491 MptResetHandlers[i] = NULL;
6492 }
6493
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006494 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 * EventNotification handling.
6496 */
6497 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
6498
6499 /* Register for hard reset handling callbacks.
6500 */
6501 if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
6502 dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
6503 } else {
6504 /* FIXME! */
6505 }
6506
6507#ifdef CONFIG_PROC_FS
6508 (void) procmpt_create();
6509#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006510 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511}
6512
6513/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6514/*
6515 * fusion_exit - Perform driver unload cleanup.
6516 *
6517 * This routine frees all resources associated with each MPT adapter
6518 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
6519 */
6520static void __exit
6521fusion_exit(void)
6522{
6523
6524 dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
6525
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 mpt_reset_deregister(mpt_base_index);
6527
6528#ifdef CONFIG_PROC_FS
6529 procmpt_destroy();
6530#endif
6531}
6532
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533module_init(fusion_init);
6534module_exit(fusion_exit);