blob: 828f0ca7c1b3209a7278f1765a26ce862e3ee2e3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005 * For use with LSI Logic PCI chip/adapter(s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
7 *
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
105int mpt_lan_index = -1;
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106int mpt_stm_index = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Linus Torvaldsf7473072005-11-29 14:21:57 -0800108struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110#define WHOINIT_UNKNOWN 0xAA
111
112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
113/*
114 * Private data...
115 */
116 /* Adapter link list */
117LIST_HEAD(ioc_list);
118 /* Callback lookup table */
119static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Protocol driver class lookup table */
121static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Event handler lookup table */
123static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124 /* Reset handler lookup table */
125static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
126static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
127
128static int mpt_base_index = -1;
129static int last_drv_idx = -1;
130
131static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Forward protos...
136 */
David Howells7d12e782006-10-05 14:55:46 +0100137static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
139static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
140 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
141 int sleepFlag);
142static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
143static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
144static void mpt_adapter_disable(MPT_ADAPTER *ioc);
145static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
146
147static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
148static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
150static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
151static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
152static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
153static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200154static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
156static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
158static int PrimeIocFifos(MPT_ADAPTER *ioc);
159static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
160static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200164int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
166static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
167static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
168static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
169static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530170static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
172static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200173static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
174static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176#ifdef CONFIG_PROC_FS
177static int procmpt_summary_read(char *buf, char **start, off_t offset,
178 int request, int *eof, void *data);
179static int procmpt_version_read(char *buf, char **start, off_t offset,
180 int request, int *eof, void *data);
181static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
182 int request, int *eof, void *data);
183#endif
184static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
185
186//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
187static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700188static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700190static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600191static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700192static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700193static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int __init fusion_init (void);
197static void __exit fusion_exit (void);
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#define CHIPREG_READ32(addr) readl_relaxed(addr)
200#define CHIPREG_READ32_dmasync(addr) readl(addr)
201#define CHIPREG_WRITE32(addr,val) writel(val, addr)
202#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
203#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
204
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600205static void
206pci_disable_io_access(struct pci_dev *pdev)
207{
208 u16 command_reg;
209
210 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
211 command_reg &= ~1;
212 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
213}
214
215static void
216pci_enable_io_access(struct pci_dev *pdev)
217{
218 u16 command_reg;
219
220 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
221 command_reg |= 1;
222 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
223}
224
James Bottomleydb47c2d2007-07-28 13:40:21 -0400225static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
226{
227 int ret = param_set_int(val, kp);
228 MPT_ADAPTER *ioc;
229
230 if (ret)
231 return ret;
232
233 list_for_each_entry(ioc, &ioc_list, list)
234 ioc->debug_level = mpt_debug_level;
235 return 0;
236}
237
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600238/*
239 * Process turbo (context) reply...
240 */
241static void
242mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
243{
244 MPT_FRAME_HDR *mf = NULL;
245 MPT_FRAME_HDR *mr = NULL;
246 int req_idx = 0;
247 int cb_idx;
248
Prakash, Sathya436ace72007-07-24 15:42:08 +0530249 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600250 ioc->name, pa));
251
252 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
253 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
254 req_idx = pa & 0x0000FFFF;
255 cb_idx = (pa & 0x00FF0000) >> 16;
256 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
257 break;
258 case MPI_CONTEXT_REPLY_TYPE_LAN:
259 cb_idx = mpt_lan_index;
260 /*
261 * Blind set of mf to NULL here was fatal
262 * after lan_reply says "freeme"
263 * Fix sort of combined with an optimization here;
264 * added explicit check for case where lan_reply
265 * was just returning 1 and doing nothing else.
266 * For this case skip the callback, but set up
267 * proper mf value first here:-)
268 */
269 if ((pa & 0x58000000) == 0x58000000) {
270 req_idx = pa & 0x0000FFFF;
271 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
272 mpt_free_msg_frame(ioc, mf);
273 mb();
274 return;
275 break;
276 }
277 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
278 break;
279 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
280 cb_idx = mpt_stm_index;
281 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
282 break;
283 default:
284 cb_idx = 0;
285 BUG();
286 }
287
288 /* Check for (valid) IO callback! */
289 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
290 MptCallbacks[cb_idx] == NULL) {
291 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
292 __FUNCTION__, ioc->name, cb_idx);
293 goto out;
294 }
295
296 if (MptCallbacks[cb_idx](ioc, mf, mr))
297 mpt_free_msg_frame(ioc, mf);
298 out:
299 mb();
300}
301
302static void
303mpt_reply(MPT_ADAPTER *ioc, u32 pa)
304{
305 MPT_FRAME_HDR *mf;
306 MPT_FRAME_HDR *mr;
307 int req_idx;
308 int cb_idx;
309 int freeme;
310
311 u32 reply_dma_low;
312 u16 ioc_stat;
313
314 /* non-TURBO reply! Hmmm, something may be up...
315 * Newest turbo reply mechanism; get address
316 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
317 */
318
319 /* Map DMA address of reply header to cpu address.
320 * pa is 32 bits - but the dma address may be 32 or 64 bits
321 * get offset based only only the low addresses
322 */
323
324 reply_dma_low = (pa <<= 1);
325 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
326 (reply_dma_low - ioc->reply_frames_low_dma));
327
328 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
329 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
330 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
331
Prakash, Sathya436ace72007-07-24 15:42:08 +0530332 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600333 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Prakash, Sathya436ace72007-07-24 15:42:08 +0530334 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600335
336 /* Check/log IOC log info
337 */
338 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
339 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
340 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
341 if (ioc->bus_type == FC)
342 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700343 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700344 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600345 else if (ioc->bus_type == SAS)
346 mpt_sas_log_info(ioc, log_info);
347 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600348
Eric Moorec6c727a2007-01-29 09:44:54 -0700349 if (ioc_stat & MPI_IOCSTATUS_MASK)
350 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600351
352 /* Check for (valid) IO callback! */
353 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
354 MptCallbacks[cb_idx] == NULL) {
355 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
356 __FUNCTION__, ioc->name, cb_idx);
357 freeme = 0;
358 goto out;
359 }
360
361 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
362
363 out:
364 /* Flush (non-TURBO) reply with a WRITE! */
365 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
366
367 if (freeme)
368 mpt_free_msg_frame(ioc, mf);
369 mb();
370}
371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800373/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
375 * @irq: irq number (not used)
376 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 *
378 * This routine is registered via the request_irq() kernel API call,
379 * and handles all interrupts generated from a specific MPT adapter
380 * (also referred to as a IO Controller or IOC).
381 * This routine must clear the interrupt from the adapter and does
382 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200383 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 *
385 * This routine handles register-level access of the adapter but
386 * dispatches (calls) a protocol-specific callback routine to handle
387 * the protocol-specific details of the MPT request completion.
388 */
389static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100390mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600392 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600393 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
394
395 if (pa == 0xFFFFFFFF)
396 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 /*
399 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600401 do {
402 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600403 mpt_reply(ioc, pa);
404 else
405 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600406 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
407 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 return IRQ_HANDLED;
410}
411
412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800413/**
414 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 * @ioc: Pointer to MPT_ADAPTER structure
416 * @mf: Pointer to original MPT request frame
417 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
418 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800419 * MPT base driver's callback routine; all base driver
420 * "internal" request/reply processing is routed here.
421 * Currently used for EventNotification and EventAck handling.
422 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200423 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 * should be freed, or 0 if it shouldn't.
425 */
426static int
427mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
428{
429 int freereq = 1;
430 u8 func;
431
Prakash, Sathya436ace72007-07-24 15:42:08 +0530432 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
433#ifdef CONFIG_FUSION_LOGGING
434 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
435 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
436 dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
437 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200439#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530442 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 ioc->name, func));
444
445 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
446 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
447 int evHandlers = 0;
448 int results;
449
450 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
451 if (results != evHandlers) {
452 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530453 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 ioc->name, evHandlers, results));
455 }
456
457 /*
458 * Hmmm... It seems that EventNotificationReply is an exception
459 * to the rule of one reply per request.
460 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200461 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200463 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530464 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200465 ioc->name, pEvReply));
466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468#ifdef CONFIG_PROC_FS
469// LogEvent(ioc, pEvReply);
470#endif
471
472 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530473 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700475 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 CONFIGPARMS *pCfg;
477 unsigned long flags;
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 ioc->name, mf, reply));
481
482 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
483
484 if (pCfg) {
485 /* disable timer and remove from linked list */
486 del_timer(&pCfg->timer);
487
488 spin_lock_irqsave(&ioc->FreeQlock, flags);
489 list_del(&pCfg->linkage);
490 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
491
492 /*
493 * If IOC Status is SUCCESS, save the header
494 * and set the status code to GOOD.
495 */
496 pCfg->status = MPT_CONFIG_ERROR;
497 if (reply) {
498 ConfigReply_t *pReply = (ConfigReply_t *)reply;
499 u16 status;
500
501 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530502 dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 status, le32_to_cpu(pReply->IOCLogInfo)));
504
505 pCfg->status = status;
506 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200507 if ((pReply->Header.PageType &
508 MPI_CONFIG_PAGETYPE_MASK) ==
509 MPI_CONFIG_PAGETYPE_EXTENDED) {
510 pCfg->cfghdr.ehdr->ExtPageLength =
511 le16_to_cpu(pReply->ExtPageLength);
512 pCfg->cfghdr.ehdr->ExtPageType =
513 pReply->ExtPageType;
514 }
515 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
516
517 /* If this is a regular header, save PageLength. */
518 /* LMP Do this better so not using a reserved field! */
519 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
520 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
521 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 }
523 }
524
525 /*
526 * Wake up the original calling thread
527 */
528 pCfg->wait_done = 1;
529 wake_up(&mpt_waitq);
530 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200531 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
532 /* we should be always getting a reply frame */
533 memcpy(ioc->persist_reply_frame, reply,
534 min(MPT_DEFAULT_FRAME_SIZE,
535 4*reply->u.reply.MsgLength));
536 del_timer(&ioc->persist_timer);
537 ioc->persist_wait_done = 1;
538 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 } else {
540 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
541 ioc->name, func);
542 }
543
544 /*
545 * Conditionally tell caller to free the original
546 * EventNotification/EventAck/unexpected request frame!
547 */
548 return freereq;
549}
550
551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
552/**
553 * mpt_register - Register protocol-specific main callback handler.
554 * @cbfunc: callback function pointer
555 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
556 *
557 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800558 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 * protocol-specific driver must do this before it will be able to
560 * use any IOC resources, such as obtaining request frames.
561 *
562 * NOTES: The SCSI protocol driver currently calls this routine thrice
563 * in order to register separate callbacks; one for "normal" SCSI IO;
564 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
565 *
566 * Returns a positive integer valued "handle" in the
567 * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
568 * Any non-positive return value (including zero!) should be considered
569 * an error by the caller.
570 */
571int
572mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
573{
574 int i;
575
576 last_drv_idx = -1;
577
578 /*
579 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
580 * (slot/handle 0 is reserved!)
581 */
582 for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
583 if (MptCallbacks[i] == NULL) {
584 MptCallbacks[i] = cbfunc;
585 MptDriverClass[i] = dclass;
586 MptEvHandlers[i] = NULL;
587 last_drv_idx = i;
588 break;
589 }
590 }
591
592 return last_drv_idx;
593}
594
595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
596/**
597 * mpt_deregister - Deregister a protocol drivers resources.
598 * @cb_idx: previously registered callback handle
599 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800600 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 * module is unloaded.
602 */
603void
604mpt_deregister(int cb_idx)
605{
606 if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
607 MptCallbacks[cb_idx] = NULL;
608 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
609 MptEvHandlers[cb_idx] = NULL;
610
611 last_drv_idx++;
612 }
613}
614
615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
616/**
617 * mpt_event_register - Register protocol-specific event callback
618 * handler.
619 * @cb_idx: previously registered (via mpt_register) callback handle
620 * @ev_cbfunc: callback function
621 *
622 * This routine can be called by one or more protocol-specific drivers
623 * if/when they choose to be notified of MPT events.
624 *
625 * Returns 0 for success.
626 */
627int
628mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
629{
630 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
631 return -1;
632
633 MptEvHandlers[cb_idx] = ev_cbfunc;
634 return 0;
635}
636
637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
638/**
639 * mpt_event_deregister - Deregister protocol-specific event callback
640 * handler.
641 * @cb_idx: previously registered callback handle
642 *
643 * Each protocol-specific driver should call this routine
644 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800645 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 */
647void
648mpt_event_deregister(int cb_idx)
649{
650 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
651 return;
652
653 MptEvHandlers[cb_idx] = NULL;
654}
655
656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
657/**
658 * mpt_reset_register - Register protocol-specific IOC reset handler.
659 * @cb_idx: previously registered (via mpt_register) callback handle
660 * @reset_func: reset function
661 *
662 * This routine can be called by one or more protocol-specific drivers
663 * if/when they choose to be notified of IOC resets.
664 *
665 * Returns 0 for success.
666 */
667int
668mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
669{
670 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
671 return -1;
672
673 MptResetHandlers[cb_idx] = reset_func;
674 return 0;
675}
676
677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
678/**
679 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
680 * @cb_idx: previously registered callback handle
681 *
682 * Each protocol-specific driver should call this routine
683 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800684 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 */
686void
687mpt_reset_deregister(int cb_idx)
688{
689 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
690 return;
691
692 MptResetHandlers[cb_idx] = NULL;
693}
694
695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
696/**
697 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800698 * @dd_cbfunc: driver callbacks struct
699 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 */
701int
702mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
703{
704 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600705 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Eric Moored58b2722006-07-11 17:23:23 -0600707 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400708 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
711
712 /* call per pci device probe entry point */
713 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600714 id = ioc->pcidev->driver ?
715 ioc->pcidev->driver->id_table : NULL;
716 if (dd_cbfunc->probe)
717 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400720 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
724/**
725 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800726 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 */
728void
729mpt_device_driver_deregister(int cb_idx)
730{
731 struct mpt_pci_driver *dd_cbfunc;
732 MPT_ADAPTER *ioc;
733
734 if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
735 return;
736
737 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
738
739 list_for_each_entry(ioc, &ioc_list, list) {
740 if (dd_cbfunc->remove)
741 dd_cbfunc->remove(ioc->pcidev);
742 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 MptDeviceDriverHandlers[cb_idx] = NULL;
745}
746
747
748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
749/**
750 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
751 * allocated per MPT adapter.
752 * @handle: Handle of registered MPT protocol driver
753 * @ioc: Pointer to MPT adapter structure
754 *
755 * Returns pointer to a MPT request frame or %NULL if none are available
756 * or IOC is not active.
757 */
758MPT_FRAME_HDR*
759mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
760{
761 MPT_FRAME_HDR *mf;
762 unsigned long flags;
763 u16 req_idx; /* Request index */
764
765 /* validate handle and ioc identifier */
766
767#ifdef MFCNT
768 if (!ioc->active)
769 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
770#endif
771
772 /* If interrupts are not attached, do not return a request frame */
773 if (!ioc->active)
774 return NULL;
775
776 spin_lock_irqsave(&ioc->FreeQlock, flags);
777 if (!list_empty(&ioc->FreeQ)) {
778 int req_offset;
779
780 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
781 u.frame.linkage.list);
782 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200783 mf->u.frame.linkage.arg1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
785 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
786 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500787 req_idx = req_offset / ioc->req_sz;
788 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
790 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
791#ifdef MFCNT
792 ioc->mfcnt++;
793#endif
794 }
795 else
796 mf = NULL;
797 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
798
799#ifdef MFCNT
800 if (mf == NULL)
801 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
802 mfcounter++;
803 if (mfcounter == PRINT_MF_COUNT)
804 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
805#endif
806
Prakash, Sathya436ace72007-07-24 15:42:08 +0530807 dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 ioc->name, handle, ioc->id, mf));
809 return mf;
810}
811
812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
813/**
814 * mpt_put_msg_frame - Send a protocol specific MPT request frame
815 * to a IOC.
816 * @handle: Handle of registered MPT protocol driver
817 * @ioc: Pointer to MPT adapter structure
818 * @mf: Pointer to MPT request frame
819 *
820 * This routine posts a MPT request frame to the request post FIFO of a
821 * specific MPT adapter.
822 */
823void
824mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
825{
826 u32 mf_dma_addr;
827 int req_offset;
828 u16 req_idx; /* Request index */
829
830 /* ensure values are reset properly! */
831 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
832 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
833 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500834 req_idx = req_offset / ioc->req_sz;
835 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
837
Prakash, Sathya436ace72007-07-24 15:42:08 +0530838 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200840 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530841 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
843}
844
845/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
846/**
847 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
848 * @handle: Handle of registered MPT protocol driver
849 * @ioc: Pointer to MPT adapter structure
850 * @mf: Pointer to MPT request frame
851 *
852 * This routine places a MPT request frame back on the MPT adapter's
853 * FreeQ.
854 */
855void
856mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
857{
858 unsigned long flags;
859
860 /* Put Request back on FreeQ! */
861 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200862 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
864#ifdef MFCNT
865 ioc->mfcnt--;
866#endif
867 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
868}
869
870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
871/**
872 * mpt_add_sge - Place a simple SGE at address pAddr.
873 * @pAddr: virtual address for SGE
874 * @flagslength: SGE flags and data transfer length
875 * @dma_addr: Physical address
876 *
877 * This routine places a MPT request frame back on the MPT adapter's
878 * FreeQ.
879 */
880void
881mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
882{
883 if (sizeof(dma_addr_t) == sizeof(u64)) {
884 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
885 u32 tmp = dma_addr & 0xFFFFFFFF;
886
887 pSge->FlagsLength = cpu_to_le32(flagslength);
888 pSge->Address.Low = cpu_to_le32(tmp);
889 tmp = (u32) ((u64)dma_addr >> 32);
890 pSge->Address.High = cpu_to_le32(tmp);
891
892 } else {
893 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
894 pSge->FlagsLength = cpu_to_le32(flagslength);
895 pSge->Address = cpu_to_le32(dma_addr);
896 }
897}
898
899/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
900/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800901 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 * @handle: Handle of registered MPT protocol driver
903 * @ioc: Pointer to MPT adapter structure
904 * @reqBytes: Size of the request in bytes
905 * @req: Pointer to MPT request frame
906 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
907 *
908 * This routine is used exclusively to send MptScsiTaskMgmt
909 * requests since they are required to be sent via doorbell handshake.
910 *
911 * NOTE: It is the callers responsibility to byte-swap fields in the
912 * request which are greater than 1 byte in size.
913 *
914 * Returns 0 for success, non-zero for failure.
915 */
916int
917mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
918{
Eric Moorecd2c6192007-01-29 09:47:47 -0700919 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 u8 *req_as_bytes;
921 int ii;
922
923 /* State is known to be good upon entering
924 * this function so issue the bus reset
925 * request.
926 */
927
928 /*
929 * Emulate what mpt_put_msg_frame() does /wrt to sanity
930 * setting cb_idx/req_idx. But ONLY if this request
931 * is in proper (pre-alloc'd) request buffer range...
932 */
933 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
934 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
935 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
936 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
937 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
938 }
939
940 /* Make sure there are no doorbells */
941 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 CHIPREG_WRITE32(&ioc->chip->Doorbell,
944 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
945 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
946
947 /* Wait for IOC doorbell int */
948 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
949 return ii;
950 }
951
952 /* Read doorbell and check for active bit */
953 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
954 return -5;
955
Prakash, Sathya436ace72007-07-24 15:42:08 +0530956 dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200957 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
960
961 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
962 return -2;
963 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 /* Send request via doorbell handshake */
966 req_as_bytes = (u8 *) req;
967 for (ii = 0; ii < reqBytes/4; ii++) {
968 u32 word;
969
970 word = ((req_as_bytes[(ii*4) + 0] << 0) |
971 (req_as_bytes[(ii*4) + 1] << 8) |
972 (req_as_bytes[(ii*4) + 2] << 16) |
973 (req_as_bytes[(ii*4) + 3] << 24));
974 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
975 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
976 r = -3;
977 break;
978 }
979 }
980
981 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
982 r = 0;
983 else
984 r = -4;
985
986 /* Make sure there are no doorbells */
987 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return r;
990}
991
992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
993/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800994 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200995 * @ioc: Pointer to MPT adapter structure
996 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800997 * @sleepFlag: Specifies whether the process can sleep
998 *
999 * Provides mechanism for the host driver to control the IOC's
1000 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001001 *
1002 * Access Control Value - bits[15:12]
1003 * 0h Reserved
1004 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1005 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1006 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1007 *
1008 * Returns 0 for success, non-zero for failure.
1009 */
1010
1011static int
1012mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1013{
1014 int r = 0;
1015
1016 /* return if in use */
1017 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1018 & MPI_DOORBELL_ACTIVE)
1019 return -1;
1020
1021 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1022
1023 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1024 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1025 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1026 (access_control_value<<12)));
1027
1028 /* Wait for IOC to clear Doorbell Status bit */
1029 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1030 return -2;
1031 }else
1032 return 0;
1033}
1034
1035/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1036/**
1037 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001038 * @ioc: Pointer to pointer to IOC adapter
1039 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001040 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001041 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001042 * Returns 0 for success, non-zero for failure.
1043 */
1044static int
1045mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1046{
1047 char *psge;
1048 int flags_length;
1049 u32 host_page_buffer_sz=0;
1050
1051 if(!ioc->HostPageBuffer) {
1052
1053 host_page_buffer_sz =
1054 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1055
1056 if(!host_page_buffer_sz)
1057 return 0; /* fw doesn't need any host buffers */
1058
1059 /* spin till we get enough memory */
1060 while(host_page_buffer_sz > 0) {
1061
1062 if((ioc->HostPageBuffer = pci_alloc_consistent(
1063 ioc->pcidev,
1064 host_page_buffer_sz,
1065 &ioc->HostPageBuffer_dma)) != NULL) {
1066
Prakash, Sathya436ace72007-07-24 15:42:08 +05301067 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001068 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001069 ioc->name, ioc->HostPageBuffer,
1070 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001071 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001072 ioc->alloc_total += host_page_buffer_sz;
1073 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1074 break;
1075 }
1076
1077 host_page_buffer_sz -= (4*1024);
1078 }
1079 }
1080
1081 if(!ioc->HostPageBuffer) {
1082 printk(MYIOC_s_ERR_FMT
1083 "Failed to alloc memory for host_page_buffer!\n",
1084 ioc->name);
1085 return -999;
1086 }
1087
1088 psge = (char *)&ioc_init->HostPageBufferSGE;
1089 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1090 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1091 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1092 MPI_SGE_FLAGS_HOST_TO_IOC |
1093 MPI_SGE_FLAGS_END_OF_BUFFER;
1094 if (sizeof(dma_addr_t) == sizeof(u64)) {
1095 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1096 }
1097 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1098 flags_length |= ioc->HostPageBuffer_sz;
1099 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1100 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1101
1102return 0;
1103}
1104
1105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1106/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001107 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 * @iocid: IOC unique identifier (integer)
1109 * @iocpp: Pointer to pointer to IOC adapter
1110 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * Given a unique IOC identifier, set pointer to the associated MPT
1112 * adapter structure.
1113 *
1114 * Returns iocid and sets iocpp if iocid is found.
1115 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 */
1117int
1118mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1119{
1120 MPT_ADAPTER *ioc;
1121
1122 list_for_each_entry(ioc,&ioc_list,list) {
1123 if (ioc->id == iocid) {
1124 *iocpp =ioc;
1125 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 *iocpp = NULL;
1130 return -1;
1131}
1132
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301133/**
1134 * mpt_get_product_name - returns product string
1135 * @vendor: pci vendor id
1136 * @device: pci device id
1137 * @revision: pci revision id
1138 * @prod_name: string returned
1139 *
1140 * Returns product string displayed when driver loads,
1141 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1142 *
1143 **/
1144static void
1145mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1146{
1147 char *product_str = NULL;
1148
1149 if (vendor == PCI_VENDOR_ID_BROCADE) {
1150 switch (device)
1151 {
1152 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1153 switch (revision)
1154 {
1155 case 0x00:
1156 product_str = "BRE040 A0";
1157 break;
1158 case 0x01:
1159 product_str = "BRE040 A1";
1160 break;
1161 default:
1162 product_str = "BRE040";
1163 break;
1164 }
1165 break;
1166 }
1167 goto out;
1168 }
1169
1170 switch (device)
1171 {
1172 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1173 product_str = "LSIFC909 B1";
1174 break;
1175 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1176 product_str = "LSIFC919 B0";
1177 break;
1178 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1179 product_str = "LSIFC929 B0";
1180 break;
1181 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1182 if (revision < 0x80)
1183 product_str = "LSIFC919X A0";
1184 else
1185 product_str = "LSIFC919XL A1";
1186 break;
1187 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1188 if (revision < 0x80)
1189 product_str = "LSIFC929X A0";
1190 else
1191 product_str = "LSIFC929XL A1";
1192 break;
1193 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1194 product_str = "LSIFC939X A1";
1195 break;
1196 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1197 product_str = "LSIFC949X A1";
1198 break;
1199 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1200 switch (revision)
1201 {
1202 case 0x00:
1203 product_str = "LSIFC949E A0";
1204 break;
1205 case 0x01:
1206 product_str = "LSIFC949E A1";
1207 break;
1208 default:
1209 product_str = "LSIFC949E";
1210 break;
1211 }
1212 break;
1213 case MPI_MANUFACTPAGE_DEVID_53C1030:
1214 switch (revision)
1215 {
1216 case 0x00:
1217 product_str = "LSI53C1030 A0";
1218 break;
1219 case 0x01:
1220 product_str = "LSI53C1030 B0";
1221 break;
1222 case 0x03:
1223 product_str = "LSI53C1030 B1";
1224 break;
1225 case 0x07:
1226 product_str = "LSI53C1030 B2";
1227 break;
1228 case 0x08:
1229 product_str = "LSI53C1030 C0";
1230 break;
1231 case 0x80:
1232 product_str = "LSI53C1030T A0";
1233 break;
1234 case 0x83:
1235 product_str = "LSI53C1030T A2";
1236 break;
1237 case 0x87:
1238 product_str = "LSI53C1030T A3";
1239 break;
1240 case 0xc1:
1241 product_str = "LSI53C1020A A1";
1242 break;
1243 default:
1244 product_str = "LSI53C1030";
1245 break;
1246 }
1247 break;
1248 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1249 switch (revision)
1250 {
1251 case 0x03:
1252 product_str = "LSI53C1035 A2";
1253 break;
1254 case 0x04:
1255 product_str = "LSI53C1035 B0";
1256 break;
1257 default:
1258 product_str = "LSI53C1035";
1259 break;
1260 }
1261 break;
1262 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1263 switch (revision)
1264 {
1265 case 0x00:
1266 product_str = "LSISAS1064 A1";
1267 break;
1268 case 0x01:
1269 product_str = "LSISAS1064 A2";
1270 break;
1271 case 0x02:
1272 product_str = "LSISAS1064 A3";
1273 break;
1274 case 0x03:
1275 product_str = "LSISAS1064 A4";
1276 break;
1277 default:
1278 product_str = "LSISAS1064";
1279 break;
1280 }
1281 break;
1282 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1283 switch (revision)
1284 {
1285 case 0x00:
1286 product_str = "LSISAS1064E A0";
1287 break;
1288 case 0x01:
1289 product_str = "LSISAS1064E B0";
1290 break;
1291 case 0x02:
1292 product_str = "LSISAS1064E B1";
1293 break;
1294 case 0x04:
1295 product_str = "LSISAS1064E B2";
1296 break;
1297 case 0x08:
1298 product_str = "LSISAS1064E B3";
1299 break;
1300 default:
1301 product_str = "LSISAS1064E";
1302 break;
1303 }
1304 break;
1305 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1306 switch (revision)
1307 {
1308 case 0x00:
1309 product_str = "LSISAS1068 A0";
1310 break;
1311 case 0x01:
1312 product_str = "LSISAS1068 B0";
1313 break;
1314 case 0x02:
1315 product_str = "LSISAS1068 B1";
1316 break;
1317 default:
1318 product_str = "LSISAS1068";
1319 break;
1320 }
1321 break;
1322 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1323 switch (revision)
1324 {
1325 case 0x00:
1326 product_str = "LSISAS1068E A0";
1327 break;
1328 case 0x01:
1329 product_str = "LSISAS1068E B0";
1330 break;
1331 case 0x02:
1332 product_str = "LSISAS1068E B1";
1333 break;
1334 case 0x04:
1335 product_str = "LSISAS1068E B2";
1336 break;
1337 case 0x08:
1338 product_str = "LSISAS1068E B3";
1339 break;
1340 default:
1341 product_str = "LSISAS1068E";
1342 break;
1343 }
1344 break;
1345 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1346 switch (revision)
1347 {
1348 case 0x00:
1349 product_str = "LSISAS1078 A0";
1350 break;
1351 case 0x01:
1352 product_str = "LSISAS1078 B0";
1353 break;
1354 case 0x02:
1355 product_str = "LSISAS1078 C0";
1356 break;
1357 case 0x03:
1358 product_str = "LSISAS1078 C1";
1359 break;
1360 case 0x04:
1361 product_str = "LSISAS1078 C2";
1362 break;
1363 default:
1364 product_str = "LSISAS1078";
1365 break;
1366 }
1367 break;
1368 }
1369
1370 out:
1371 if (product_str)
1372 sprintf(prod_name, "%s", product_str);
1373}
1374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001376/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001377 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001379 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 *
1381 * This routine performs all the steps necessary to bring the IOC of
1382 * a MPT adapter to a OPERATIONAL state. This includes registering
1383 * memory regions, registering the interrupt, and allocating request
1384 * and reply memory pools.
1385 *
1386 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1387 * MPT adapter.
1388 *
1389 * Returns 0 for success, non-zero for failure.
1390 *
1391 * TODO: Add support for polled controllers
1392 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001393int
1394mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395{
1396 MPT_ADAPTER *ioc;
1397 u8 __iomem *mem;
1398 unsigned long mem_phys;
1399 unsigned long port;
1400 u32 msize;
1401 u32 psize;
1402 int ii;
1403 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 u8 revision;
1405 u8 pcixcmd;
1406 static int mpt_ids = 0;
1407#ifdef CONFIG_PROC_FS
1408 struct proc_dir_entry *dent, *ent;
1409#endif
1410
Prakash, Sathya436ace72007-07-24 15:42:08 +05301411 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1412 if (ioc == NULL) {
1413 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1414 return -ENOMEM;
1415 }
1416
1417 ioc->debug_level = mpt_debug_level;
1418 if (mpt_debug_level)
1419 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (pci_enable_device(pdev))
1422 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001423
Prakash, Sathya436ace72007-07-24 15:42:08 +05301424 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001425
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001426 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301427 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001429 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1431 return r;
1432 }
1433
Prakash, Sathya436ace72007-07-24 15:42:08 +05301434 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1435 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 ": Using 64 bit consistent mask\n"));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301437 } else {
1438 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 ": Not using 64 bit consistent mask\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 ioc->alloc_total = sizeof(MPT_ADAPTER);
1443 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1444 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001445
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 ioc->pcidev = pdev;
1447 ioc->diagPending = 0;
1448 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001449 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451 /* Initialize the event logging.
1452 */
1453 ioc->eventTypes = 0; /* None */
1454 ioc->eventContext = 0;
1455 ioc->eventLogSize = 0;
1456 ioc->events = NULL;
1457
1458#ifdef MFCNT
1459 ioc->mfcnt = 0;
1460#endif
1461
1462 ioc->cached_fw = NULL;
1463
1464 /* Initilize SCSI Config Data structure
1465 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001466 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 /* Initialize the running configQ head.
1469 */
1470 INIT_LIST_HEAD(&ioc->configQ);
1471
Michael Reed05e8ec12006-01-13 14:31:54 -06001472 /* Initialize the fc rport list head.
1473 */
1474 INIT_LIST_HEAD(&ioc->fc_rports);
1475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 /* Find lookup slot. */
1477 INIT_LIST_HEAD(&ioc->list);
1478 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 mem_phys = msize = 0;
1481 port = psize = 0;
1482 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1483 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001484 if (psize)
1485 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 /* Get I/O space! */
1487 port = pci_resource_start(pdev, ii);
1488 psize = pci_resource_len(pdev,ii);
1489 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001490 if (msize)
1491 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 /* Get memmap */
1493 mem_phys = pci_resource_start(pdev, ii);
1494 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 }
1496 }
1497 ioc->mem_size = msize;
1498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 mem = NULL;
1500 /* Get logical ptr for PciMem0 space */
1501 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001502 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (mem == NULL) {
1504 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1505 kfree(ioc);
1506 return -EINVAL;
1507 }
1508 ioc->memmap = mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301509 dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Prakash, Sathya436ace72007-07-24 15:42:08 +05301511 dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 &ioc->facts, &ioc->pfacts[0]));
1513
1514 ioc->mem_phys = mem_phys;
1515 ioc->chip = (SYSIF_REGS __iomem *)mem;
1516
1517 /* Save Port IO values in case we need to do downloadboot */
1518 {
1519 u8 *pmem = (u8*)port;
1520 ioc->pio_mem_phys = port;
1521 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1522 }
1523
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301524 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1525 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1526
1527 switch (pdev->device)
1528 {
1529 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1530 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1531 ioc->errata_flag_1064 = 1;
1532 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1533 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1534 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1535 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301537 break;
1538
1539 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 /* 929X Chip Fix. Set Split transactions level
1542 * for PCIX. Set MOST bits to zero.
1543 */
1544 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1545 pcixcmd &= 0x8F;
1546 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1547 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 /* 929XL Chip Fix. Set MMRBC to 0x08.
1549 */
1550 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1551 pcixcmd |= 0x08;
1552 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301555 break;
1556
1557 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 /* 919X Chip Fix. Set Split transactions level
1559 * for PCIX. Set MOST bits to zero.
1560 */
1561 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1562 pcixcmd &= 0x8F;
1563 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001564 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301565 break;
1566
1567 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 /* 1030 Chip Fix. Disable Split transactions
1569 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1570 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 if (revision < C0_1030) {
1572 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1573 pcixcmd &= 0x8F;
1574 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1575 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301576
1577 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001578 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301579 break;
1580
1581 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1582 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001583 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301584
1585 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1586 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1587 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001588 ioc->bus_type = SAS;
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001591 if (ioc->errata_flag_1064)
1592 pci_disable_io_access(pdev);
1593
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 sprintf(ioc->name, "ioc%d", ioc->id);
1595
1596 spin_lock_init(&ioc->FreeQlock);
1597
1598 /* Disable all! */
1599 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1600 ioc->active = 0;
1601 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1602
1603 /* Set lookup ptr. */
1604 list_add_tail(&ioc->list, &ioc_list);
1605
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001606 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 */
1608 mpt_detect_bound_ports(ioc, pdev);
1609
James Bottomleyc92f2222006-03-01 09:02:49 -06001610 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1611 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 printk(KERN_WARNING MYNAM
1613 ": WARNING - %s did not initialize properly! (%d)\n",
1614 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001617 if (ioc->alt_ioc)
1618 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 iounmap(mem);
1620 kfree(ioc);
1621 pci_set_drvdata(pdev, NULL);
1622 return r;
1623 }
1624
1625 /* call per device driver probe entry point */
1626 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1627 if(MptDeviceDriverHandlers[ii] &&
1628 MptDeviceDriverHandlers[ii]->probe) {
1629 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1630 }
1631 }
1632
1633#ifdef CONFIG_PROC_FS
1634 /*
1635 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1636 */
1637 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1638 if (dent) {
1639 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1640 if (ent) {
1641 ent->read_proc = procmpt_iocinfo_read;
1642 ent->data = ioc;
1643 }
1644 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1645 if (ent) {
1646 ent->read_proc = procmpt_summary_read;
1647 ent->data = ioc;
1648 }
1649 }
1650#endif
1651
1652 return 0;
1653}
1654
1655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001656/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001657 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 */
1660
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001661void
1662mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663{
1664 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1665 char pname[32];
1666 int ii;
1667
1668 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1669 remove_proc_entry(pname, NULL);
1670 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1671 remove_proc_entry(pname, NULL);
1672 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1673 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* call per device driver remove entry point */
1676 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1677 if(MptDeviceDriverHandlers[ii] &&
1678 MptDeviceDriverHandlers[ii]->remove) {
1679 MptDeviceDriverHandlers[ii]->remove(pdev);
1680 }
1681 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 /* Disable interrupts! */
1684 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1685
1686 ioc->active = 0;
1687 synchronize_irq(pdev->irq);
1688
1689 /* Clear any lingering interrupt */
1690 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1691
1692 CHIPREG_READ32(&ioc->chip->IntStatus);
1693
1694 mpt_adapter_dispose(ioc);
1695
1696 pci_set_drvdata(pdev, NULL);
1697}
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699/**************************************************************************
1700 * Power Management
1701 */
1702#ifdef CONFIG_PM
1703/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001704/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001705 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001706 * @pdev: Pointer to pci_dev structure
1707 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001709int
1710mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711{
1712 u32 device_state;
1713 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Pavel Machek2a569572005-07-07 17:56:40 -07001715 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716
1717 printk(MYIOC_s_INFO_FMT
1718 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1719 ioc->name, pdev, pci_name(pdev), device_state);
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 pci_save_state(pdev);
1722
1723 /* put ioc into READY_STATE */
1724 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1725 printk(MYIOC_s_ERR_FMT
1726 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1727 }
1728
1729 /* disable interrupts */
1730 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1731 ioc->active = 0;
1732
1733 /* Clear any lingering interrupt */
1734 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1735
1736 pci_disable_device(pdev);
1737 pci_set_power_state(pdev, device_state);
1738
1739 return 0;
1740}
1741
1742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001743/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001744 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001745 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001747int
1748mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
1750 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1751 u32 device_state = pdev->current_state;
1752 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001753 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 printk(MYIOC_s_INFO_FMT
1756 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1757 ioc->name, pdev, pci_name(pdev), device_state);
1758
1759 pci_set_power_state(pdev, 0);
1760 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001761 err = pci_enable_device(pdev);
1762 if (err)
1763 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001766 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 ioc->active = 1;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 printk(MYIOC_s_INFO_FMT
1770 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1771 ioc->name,
1772 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1773 CHIPREG_READ32(&ioc->chip->Doorbell));
1774
1775 /* bring ioc to operational state */
1776 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1777 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1778 printk(MYIOC_s_INFO_FMT
1779 "pci-resume: Cannot recover, error:[%x]\n",
1780 ioc->name, recovery_state);
1781 } else {
1782 printk(MYIOC_s_INFO_FMT
1783 "pci-resume: success\n", ioc->name);
1784 }
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 return 0;
1787}
1788#endif
1789
James Bottomley4ff42a62006-05-17 18:06:52 -05001790static int
1791mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1792{
1793 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1794 ioc->bus_type != SPI) ||
1795 (MptDriverClass[index] == MPTFC_DRIVER &&
1796 ioc->bus_type != FC) ||
1797 (MptDriverClass[index] == MPTSAS_DRIVER &&
1798 ioc->bus_type != SAS))
1799 /* make sure we only call the relevant reset handler
1800 * for the bus */
1801 return 0;
1802 return (MptResetHandlers[index])(ioc, reset_phase);
1803}
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001806/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1808 * @ioc: Pointer to MPT adapter structure
1809 * @reason: Event word / reason
1810 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1811 *
1812 * This routine performs all the steps necessary to bring the IOC
1813 * to a OPERATIONAL state.
1814 *
1815 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1816 * MPT adapter.
1817 *
1818 * Returns:
1819 * 0 for success
1820 * -1 if failed to get board READY
1821 * -2 if READY but IOCFacts Failed
1822 * -3 if READY but PrimeIOCFifos Failed
1823 * -4 if READY but IOCInit Failed
1824 */
1825static int
1826mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1827{
1828 int hard_reset_done = 0;
1829 int alt_ioc_ready = 0;
1830 int hard;
1831 int rc=0;
1832 int ii;
1833 int handlers;
1834 int ret = 0;
1835 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001836 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301837 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838
1839 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1840 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1841
1842 /* Disable reply interrupts (also blocks FreeQ) */
1843 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1844 ioc->active = 0;
1845
1846 if (ioc->alt_ioc) {
1847 if (ioc->alt_ioc->active)
1848 reset_alt_ioc_active = 1;
1849
1850 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1851 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1852 ioc->alt_ioc->active = 0;
1853 }
1854
1855 hard = 1;
1856 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1857 hard = 0;
1858
1859 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1860 if (hard_reset_done == -4) {
1861 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1862 ioc->name);
1863
1864 if (reset_alt_ioc_active && ioc->alt_ioc) {
1865 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05301866 dprintk(ioc, printk(KERN_INFO MYNAM
1867 ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001869 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 ioc->alt_ioc->active = 1;
1871 }
1872
1873 } else {
1874 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1875 ioc->name);
1876 }
1877 return -1;
1878 }
1879
1880 /* hard_reset_done = 0 if a soft reset was performed
1881 * and 1 if a hard reset was performed.
1882 */
1883 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1884 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1885 alt_ioc_ready = 1;
1886 else
1887 printk(KERN_WARNING MYNAM
1888 ": alt-%s: Not ready WARNING!\n",
1889 ioc->alt_ioc->name);
1890 }
1891
1892 for (ii=0; ii<5; ii++) {
1893 /* Get IOC facts! Allow 5 retries */
1894 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1895 break;
1896 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 if (ii == 5) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301900 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 ret = -2;
1902 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1903 MptDisplayIocCapabilities(ioc);
1904 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (alt_ioc_ready) {
1907 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301908 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1909 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* Retry - alt IOC was initialized once
1911 */
1912 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1913 }
1914 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301915 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1916 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 alt_ioc_ready = 0;
1918 reset_alt_ioc_active = 0;
1919 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1920 MptDisplayIocCapabilities(ioc->alt_ioc);
1921 }
1922 }
1923
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001924 /*
1925 * Device is reset now. It must have de-asserted the interrupt line
1926 * (if it was asserted) and it should be safe to register for the
1927 * interrupt now.
1928 */
1929 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1930 ioc->pci_irq = -1;
1931 if (ioc->pcidev->irq) {
1932 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1933 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1934 ioc->name);
1935 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001936 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001937 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001938 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1939 "interrupt %d!\n", ioc->name,
1940 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001941 if (mpt_msi_enable)
1942 pci_disable_msi(ioc->pcidev);
1943 return -EBUSY;
1944 }
1945 irq_allocated = 1;
1946 ioc->pci_irq = ioc->pcidev->irq;
1947 pci_set_master(ioc->pcidev); /* ?? */
1948 pci_set_drvdata(ioc->pcidev, ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05301949 dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001950 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001951 }
1952 }
1953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 /* Prime reply & request queues!
1955 * (mucho alloc's) Must be done prior to
1956 * init as upper addresses are needed for init.
1957 * If fails, continue with alt-ioc processing
1958 */
1959 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1960 ret = -3;
1961
1962 /* May need to check/upload firmware & data here!
1963 * If fails, continue with alt-ioc processing
1964 */
1965 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1966 ret = -4;
1967// NEW!
1968 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
1969 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
1970 ioc->alt_ioc->name, rc);
1971 alt_ioc_ready = 0;
1972 reset_alt_ioc_active = 0;
1973 }
1974
1975 if (alt_ioc_ready) {
1976 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
1977 alt_ioc_ready = 0;
1978 reset_alt_ioc_active = 0;
1979 printk(KERN_WARNING MYNAM
1980 ": alt-%s: (%d) init failure WARNING!\n",
1981 ioc->alt_ioc->name, rc);
1982 }
1983 }
1984
1985 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
1986 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301987 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 "firmware upload required!\n", ioc->name));
1989
1990 /* Controller is not operational, cannot do upload
1991 */
1992 if (ret == 0) {
1993 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001994 if (rc == 0) {
1995 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
1996 /*
1997 * Maintain only one pointer to FW memory
1998 * so there will not be two attempt to
1999 * downloadboot onboard dual function
2000 * chips (mpt_adapter_disable,
2001 * mpt_diag_reset)
2002 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302003 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2004 ": mpt_upload: alt_%s has cached_fw=%p \n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002005 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002006 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002007 }
2008 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002010 ret = -5;
2011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 }
2013 }
2014 }
2015
2016 if (ret == 0) {
2017 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002018 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 ioc->active = 1;
2020 }
2021
2022 if (reset_alt_ioc_active && ioc->alt_ioc) {
2023 /* (re)Enable alt-IOC! (reply interrupt) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302024 dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002026 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 ioc->alt_ioc->active = 1;
2028 }
2029
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002030 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 * and EventAck handling.
2032 */
2033 if ((ret == 0) && (!ioc->facts.EventState))
2034 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2035
2036 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2037 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2038
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002039 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2041 * recursive scenario; GetLanConfigPages times out, timer expired
2042 * routine calls HardResetHandler, which calls into here again,
2043 * and we try GetLanConfigPages again...
2044 */
2045 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002046
2047 /*
2048 * Initalize link list for inactive raid volumes.
2049 */
2050 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2051 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2052
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002053 if (ioc->bus_type == SAS) {
2054
2055 /* clear persistency table */
2056 if(ioc->facts.IOCExceptions &
2057 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2058 ret = mptbase_sas_persist_operation(ioc,
2059 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2060 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002061 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002062 }
2063
2064 /* Find IM volumes
2065 */
2066 mpt_findImVolumes(ioc);
2067
2068 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2070 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2071 /*
2072 * Pre-fetch the ports LAN MAC address!
2073 * (LANPage1_t stuff)
2074 */
2075 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302076 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2077 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2078 "LanAddr = %02X:%02X:%02X:"
2079 "%02X:%02X:%02X\n",
2080 ioc->name, a[5], a[4],
2081 a[3], a[2], a[1], a[0] ));
2082
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 }
2084 } else {
2085 /* Get NVRAM and adapter maximums from SPP 0 and 2
2086 */
2087 mpt_GetScsiPortSettings(ioc, 0);
2088
2089 /* Get version and length of SDP 1
2090 */
2091 mpt_readScsiDevicePageHeaders(ioc, 0);
2092
2093 /* Find IM volumes
2094 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002095 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 mpt_findImVolumes(ioc);
2097
2098 /* Check, and possibly reset, the coalescing value
2099 */
2100 mpt_read_ioc_pg_1(ioc);
2101
2102 mpt_read_ioc_pg_4(ioc);
2103 }
2104
2105 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302106 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 }
2108
2109 /*
2110 * Call each currently registered protocol IOC reset handler
2111 * with post-reset indication.
2112 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2113 * MptResetHandlers[] registered yet.
2114 */
2115 if (hard_reset_done) {
2116 rc = handlers = 0;
2117 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
2118 if ((ret == 0) && MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302119 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2120 "Calling IOC post_reset handler #%d\n",
2121 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002122 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 handlers++;
2124 }
2125
2126 if (alt_ioc_ready && MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302127 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2128 "Calling alt-%s post_reset handler #%d\n",
2129 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002130 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 handlers++;
2132 }
2133 }
2134 /* FIXME? Examine results here? */
2135 }
2136
Eric Moore0ccdb002006-07-11 17:33:13 -06002137 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002138 if ((ret != 0) && irq_allocated) {
2139 free_irq(ioc->pci_irq, ioc);
2140 if (mpt_msi_enable)
2141 pci_disable_msi(ioc->pcidev);
2142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return ret;
2144}
2145
2146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002147/**
2148 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 * @ioc: Pointer to MPT adapter structure
2150 * @pdev: Pointer to (struct pci_dev) structure
2151 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002152 * Search for PCI bus/dev_function which matches
2153 * PCI bus/dev_function (+/-1) for newly discovered 929,
2154 * 929X, 1030 or 1035.
2155 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2157 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2158 */
2159static void
2160mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2161{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002162 struct pci_dev *peer=NULL;
2163 unsigned int slot = PCI_SLOT(pdev->devfn);
2164 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 MPT_ADAPTER *ioc_srch;
2166
Prakash, Sathya436ace72007-07-24 15:42:08 +05302167 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002168 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002169 ioc->name, pci_name(pdev), pdev->bus->number,
2170 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002171
2172 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2173 if (!peer) {
2174 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2175 if (!peer)
2176 return;
2177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
2179 list_for_each_entry(ioc_srch, &ioc_list, list) {
2180 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002181 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 /* Paranoia checks */
2183 if (ioc->alt_ioc != NULL) {
2184 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002185 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 break;
2187 } else if (ioc_srch->alt_ioc != NULL) {
2188 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002189 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 break;
2191 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302192 dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002193 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 ioc_srch->alt_ioc = ioc;
2195 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002198 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199}
2200
2201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002202/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002204 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 */
2206static void
2207mpt_adapter_disable(MPT_ADAPTER *ioc)
2208{
2209 int sz;
2210 int ret;
2211
2212 if (ioc->cached_fw != NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302213 ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002214 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 printk(KERN_WARNING MYNAM
2216 ": firmware downloadboot failure (%d)!\n", ret);
2217 }
2218 }
2219
2220 /* Disable adapter interrupts! */
2221 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2222 ioc->active = 0;
2223 /* Clear any lingering interrupt */
2224 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2225
2226 if (ioc->alloc != NULL) {
2227 sz = ioc->alloc_sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302228 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 ioc->name, ioc->alloc, ioc->alloc_sz));
2230 pci_free_consistent(ioc->pcidev, sz,
2231 ioc->alloc, ioc->alloc_dma);
2232 ioc->reply_frames = NULL;
2233 ioc->req_frames = NULL;
2234 ioc->alloc = NULL;
2235 ioc->alloc_total -= sz;
2236 }
2237
2238 if (ioc->sense_buf_pool != NULL) {
2239 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2240 pci_free_consistent(ioc->pcidev, sz,
2241 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2242 ioc->sense_buf_pool = NULL;
2243 ioc->alloc_total -= sz;
2244 }
2245
2246 if (ioc->events != NULL){
2247 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2248 kfree(ioc->events);
2249 ioc->events = NULL;
2250 ioc->alloc_total -= sz;
2251 }
2252
2253 if (ioc->cached_fw != NULL) {
2254 sz = ioc->facts.FWImageSize;
2255 pci_free_consistent(ioc->pcidev, sz,
2256 ioc->cached_fw, ioc->cached_fw_dma);
2257 ioc->cached_fw = NULL;
2258 ioc->alloc_total -= sz;
2259 }
2260
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002261 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002262 mpt_inactive_raid_list_free(ioc);
2263 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002264 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002265 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002266 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
2268 if (ioc->spi_data.pIocPg4 != NULL) {
2269 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302270 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 ioc->spi_data.pIocPg4,
2272 ioc->spi_data.IocPg4_dma);
2273 ioc->spi_data.pIocPg4 = NULL;
2274 ioc->alloc_total -= sz;
2275 }
2276
2277 if (ioc->ReqToChain != NULL) {
2278 kfree(ioc->ReqToChain);
2279 kfree(ioc->RequestNB);
2280 ioc->ReqToChain = NULL;
2281 }
2282
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002283 kfree(ioc->ChainToChain);
2284 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002285
2286 if (ioc->HostPageBuffer != NULL) {
2287 if((ret = mpt_host_page_access_control(ioc,
2288 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2289 printk(KERN_ERR MYNAM
2290 ": %s: host page buffers free failed (%d)!\n",
2291 __FUNCTION__, ret);
2292 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302293 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002294 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2295 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2296 ioc->HostPageBuffer,
2297 ioc->HostPageBuffer_dma);
2298 ioc->HostPageBuffer = NULL;
2299 ioc->HostPageBuffer_sz = 0;
2300 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302}
2303
2304/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002305/**
2306 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 * @ioc: Pointer to MPT adapter structure
2308 *
2309 * This routine unregisters h/w resources and frees all alloc'd memory
2310 * associated with a MPT adapter structure.
2311 */
2312static void
2313mpt_adapter_dispose(MPT_ADAPTER *ioc)
2314{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002315 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002317 if (ioc == NULL)
2318 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002320 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002322 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002324 if (ioc->pci_irq != -1) {
2325 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002326 if (mpt_msi_enable)
2327 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002328 ioc->pci_irq = -1;
2329 }
2330
2331 if (ioc->memmap != NULL) {
2332 iounmap(ioc->memmap);
2333 ioc->memmap = NULL;
2334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
2336#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002337 if (ioc->mtrr_reg > 0) {
2338 mtrr_del(ioc->mtrr_reg, 0, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302339 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341#endif
2342
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002343 /* Zap the adapter lookup ptr! */
2344 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002346 sz_last = ioc->alloc_total;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302347 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002348 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002349
2350 if (ioc->alt_ioc)
2351 ioc->alt_ioc->alt_ioc = NULL;
2352
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002353 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354}
2355
2356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002357/**
2358 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 * @ioc: Pointer to MPT adapter structure
2360 */
2361static void
2362MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2363{
2364 int i = 0;
2365
2366 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302367 if (ioc->prod_name)
2368 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 printk("Capabilities={");
2370
2371 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2372 printk("Initiator");
2373 i++;
2374 }
2375
2376 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2377 printk("%sTarget", i ? "," : "");
2378 i++;
2379 }
2380
2381 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2382 printk("%sLAN", i ? "," : "");
2383 i++;
2384 }
2385
2386#if 0
2387 /*
2388 * This would probably evoke more questions than it's worth
2389 */
2390 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2391 printk("%sLogBusAddr", i ? "," : "");
2392 i++;
2393 }
2394#endif
2395
2396 printk("}\n");
2397}
2398
2399/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002400/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2402 * @ioc: Pointer to MPT_ADAPTER structure
2403 * @force: Force hard KickStart of IOC
2404 * @sleepFlag: Specifies whether the process can sleep
2405 *
2406 * Returns:
2407 * 1 - DIAG reset and READY
2408 * 0 - READY initially OR soft reset and READY
2409 * -1 - Any failure on KickStart
2410 * -2 - Msg Unit Reset Failed
2411 * -3 - IO Unit Reset Failed
2412 * -4 - IOC owned by a PEER
2413 */
2414static int
2415MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2416{
2417 u32 ioc_state;
2418 int statefault = 0;
2419 int cntdn;
2420 int hard_reset_done = 0;
2421 int r;
2422 int ii;
2423 int whoinit;
2424
2425 /* Get current [raw] IOC state */
2426 ioc_state = mpt_GetIocState(ioc, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302427 dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
2429 /*
2430 * Check to see if IOC got left/stuck in doorbell handshake
2431 * grip of death. If so, hard reset the IOC.
2432 */
2433 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2434 statefault = 1;
2435 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2436 ioc->name);
2437 }
2438
2439 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002440 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 return 0;
2442
2443 /*
2444 * Check to see if IOC is in FAULT state.
2445 */
2446 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2447 statefault = 2;
2448 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2449 ioc->name);
2450 printk(KERN_WARNING " FAULT code = %04xh\n",
2451 ioc_state & MPI_DOORBELL_DATA_MASK);
2452 }
2453
2454 /*
2455 * Hmmm... Did it get left operational?
2456 */
2457 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 ioc->name));
2460
2461 /* Check WhoInit.
2462 * If PCI Peer, exit.
2463 * Else, if no fault conditions are present, issue a MessageUnitReset
2464 * Else, fall through to KickStart case
2465 */
2466 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302467 dinitprintk(ioc, printk(KERN_INFO MYNAM
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002468 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 whoinit, statefault, force));
2470 if (whoinit == MPI_WHOINIT_PCI_PEER)
2471 return -4;
2472 else {
2473 if ((statefault == 0 ) && (force == 0)) {
2474 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2475 return 0;
2476 }
2477 statefault = 3;
2478 }
2479 }
2480
2481 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2482 if (hard_reset_done < 0)
2483 return -1;
2484
2485 /*
2486 * Loop here waiting for IOC to come READY.
2487 */
2488 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002489 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2492 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2493 /*
2494 * BIOS or previous driver load left IOC in OP state.
2495 * Reset messaging FIFOs.
2496 */
2497 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2498 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2499 return -2;
2500 }
2501 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2502 /*
2503 * Something is wrong. Try to get IOC back
2504 * to a known state.
2505 */
2506 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2507 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2508 return -3;
2509 }
2510 }
2511
2512 ii++; cntdn--;
2513 if (!cntdn) {
2514 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2515 ioc->name, (int)((ii+5)/HZ));
2516 return -ETIME;
2517 }
2518
2519 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002520 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 } else {
2522 mdelay (1); /* 1 msec delay */
2523 }
2524
2525 }
2526
2527 if (statefault < 3) {
2528 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2529 ioc->name,
2530 statefault==1 ? "stuck handshake" : "IOC FAULT");
2531 }
2532
2533 return hard_reset_done;
2534}
2535
2536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002537/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 * mpt_GetIocState - Get the current state of a MPT adapter.
2539 * @ioc: Pointer to MPT_ADAPTER structure
2540 * @cooked: Request raw or cooked IOC state
2541 *
2542 * Returns all IOC Doorbell register bits if cooked==0, else just the
2543 * Doorbell bits in MPI_IOC_STATE_MASK.
2544 */
2545u32
2546mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2547{
2548 u32 s, sc;
2549
2550 /* Get! */
2551 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2552// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2553 sc = s & MPI_IOC_STATE_MASK;
2554
2555 /* Save! */
2556 ioc->last_state = sc;
2557
2558 return cooked ? sc : s;
2559}
2560
2561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002562/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 * GetIocFacts - Send IOCFacts request to MPT adapter.
2564 * @ioc: Pointer to MPT_ADAPTER structure
2565 * @sleepFlag: Specifies whether the process can sleep
2566 * @reason: If recovery, only update facts.
2567 *
2568 * Returns 0 for success, non-zero for failure.
2569 */
2570static int
2571GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2572{
2573 IOCFacts_t get_facts;
2574 IOCFactsReply_t *facts;
2575 int r;
2576 int req_sz;
2577 int reply_sz;
2578 int sz;
2579 u32 status, vv;
2580 u8 shiftFactor=1;
2581
2582 /* IOC *must* NOT be in RESET state! */
2583 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2584 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2585 ioc->name,
2586 ioc->last_state );
2587 return -44;
2588 }
2589
2590 facts = &ioc->facts;
2591
2592 /* Destination (reply area)... */
2593 reply_sz = sizeof(*facts);
2594 memset(facts, 0, reply_sz);
2595
2596 /* Request area (get_facts on the stack right now!) */
2597 req_sz = sizeof(get_facts);
2598 memset(&get_facts, 0, req_sz);
2599
2600 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2601 /* Assert: All other get_facts fields are zero! */
2602
Prakash, Sathya436ace72007-07-24 15:42:08 +05302603 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002604 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 ioc->name, req_sz, reply_sz));
2606
2607 /* No non-zero fields in the get_facts request are greater than
2608 * 1 byte in size, so we can just fire it off as is.
2609 */
2610 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2611 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2612 if (r != 0)
2613 return r;
2614
2615 /*
2616 * Now byte swap (GRRR) the necessary fields before any further
2617 * inspection of reply contents.
2618 *
2619 * But need to do some sanity checks on MsgLength (byte) field
2620 * to make sure we don't zero IOC's req_sz!
2621 */
2622 /* Did we get a valid reply? */
2623 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2624 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2625 /*
2626 * If not been here, done that, save off first WhoInit value
2627 */
2628 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2629 ioc->FirstWhoInit = facts->WhoInit;
2630 }
2631
2632 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2633 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2634 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2635 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2636 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002637 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 /* CHECKME! IOCStatus, IOCLogInfo */
2639
2640 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2641 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2642
2643 /*
2644 * FC f/w version changed between 1.1 and 1.2
2645 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2646 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2647 */
2648 if (facts->MsgVersion < 0x0102) {
2649 /*
2650 * Handle old FC f/w style, convert to new...
2651 */
2652 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2653 facts->FWVersion.Word =
2654 ((oldv<<12) & 0xFF000000) |
2655 ((oldv<<8) & 0x000FFF00);
2656 } else
2657 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2658
2659 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002660 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2661 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2662 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 facts->CurrentHostMfaHighAddr =
2664 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2665 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2666 facts->CurrentSenseBufferHighAddr =
2667 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2668 facts->CurReplyFrameSize =
2669 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002670 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
2672 /*
2673 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2674 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2675 * to 14 in MPI-1.01.0x.
2676 */
2677 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2678 facts->MsgVersion > 0x0100) {
2679 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2680 }
2681
2682 sz = facts->FWImageSize;
2683 if ( sz & 0x01 )
2684 sz += 1;
2685 if ( sz & 0x02 )
2686 sz += 2;
2687 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 if (!facts->RequestFrameSize) {
2690 /* Something is wrong! */
2691 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2692 ioc->name);
2693 return -55;
2694 }
2695
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002696 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 vv = ((63 / (sz * 4)) + 1) & 0x03;
2698 ioc->NB_for_64_byte_frame = vv;
2699 while ( sz )
2700 {
2701 shiftFactor++;
2702 sz = sz >> 1;
2703 }
2704 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302705 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2706 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2707 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2710 /*
2711 * Set values for this IOC's request & reply frame sizes,
2712 * and request & reply queue depths...
2713 */
2714 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2715 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2716 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2717 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2718
Prakash, Sathya436ace72007-07-24 15:42:08 +05302719 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302721 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 ioc->name, ioc->req_sz, ioc->req_depth));
2723
2724 /* Get port facts! */
2725 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2726 return r;
2727 }
2728 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002729 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2731 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2732 RequestFrameSize)/sizeof(u32)));
2733 return -66;
2734 }
2735
2736 return 0;
2737}
2738
2739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002740/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 * GetPortFacts - Send PortFacts request to MPT adapter.
2742 * @ioc: Pointer to MPT_ADAPTER structure
2743 * @portnum: Port number
2744 * @sleepFlag: Specifies whether the process can sleep
2745 *
2746 * Returns 0 for success, non-zero for failure.
2747 */
2748static int
2749GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2750{
2751 PortFacts_t get_pfacts;
2752 PortFactsReply_t *pfacts;
2753 int ii;
2754 int req_sz;
2755 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002756 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
2758 /* IOC *must* NOT be in RESET state! */
2759 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2760 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2761 ioc->name,
2762 ioc->last_state );
2763 return -4;
2764 }
2765
2766 pfacts = &ioc->pfacts[portnum];
2767
2768 /* Destination (reply area)... */
2769 reply_sz = sizeof(*pfacts);
2770 memset(pfacts, 0, reply_sz);
2771
2772 /* Request area (get_pfacts on the stack right now!) */
2773 req_sz = sizeof(get_pfacts);
2774 memset(&get_pfacts, 0, req_sz);
2775
2776 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2777 get_pfacts.PortNumber = portnum;
2778 /* Assert: All other get_pfacts fields are zero! */
2779
Prakash, Sathya436ace72007-07-24 15:42:08 +05302780 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 ioc->name, portnum));
2782
2783 /* No non-zero fields in the get_pfacts request are greater than
2784 * 1 byte in size, so we can just fire it off as is.
2785 */
2786 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2787 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2788 if (ii != 0)
2789 return ii;
2790
2791 /* Did we get a valid reply? */
2792
2793 /* Now byte swap the necessary fields in the response. */
2794 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2795 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2796 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2797 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2798 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2799 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2800 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2801 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2802 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2803
Eric Moore793955f2007-01-29 09:42:20 -07002804 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2805 pfacts->MaxDevices;
2806 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2807 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2808
2809 /*
2810 * Place all the devices on channels
2811 *
2812 * (for debuging)
2813 */
2814 if (mpt_channel_mapping) {
2815 ioc->devices_per_bus = 1;
2816 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2817 }
2818
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return 0;
2820}
2821
2822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002823/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 * SendIocInit - Send IOCInit request to MPT adapter.
2825 * @ioc: Pointer to MPT_ADAPTER structure
2826 * @sleepFlag: Specifies whether the process can sleep
2827 *
2828 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2829 *
2830 * Returns 0 for success, non-zero for failure.
2831 */
2832static int
2833SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2834{
2835 IOCInit_t ioc_init;
2836 MPIDefaultReply_t init_reply;
2837 u32 state;
2838 int r;
2839 int count;
2840 int cntdn;
2841
2842 memset(&ioc_init, 0, sizeof(ioc_init));
2843 memset(&init_reply, 0, sizeof(init_reply));
2844
2845 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2846 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2847
2848 /* If we are in a recovery mode and we uploaded the FW image,
2849 * then this pointer is not NULL. Skip the upload a second time.
2850 * Set this flag if cached_fw set for either IOC.
2851 */
2852 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2853 ioc->upload_fw = 1;
2854 else
2855 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302856 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2858
Eric Moore793955f2007-01-29 09:42:20 -07002859 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2860 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302861 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002862 ioc->name, ioc->facts.MsgVersion));
2863 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2864 // set MsgVersion and HeaderVersion host driver was built with
2865 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2866 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002868 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2869 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2870 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2871 return -99;
2872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2874
2875 if (sizeof(dma_addr_t) == sizeof(u64)) {
2876 /* Save the upper 32-bits of the request
2877 * (reply) and sense buffers.
2878 */
2879 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2880 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2881 } else {
2882 /* Force 32-bit addressing */
2883 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2884 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2885 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2888 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002889 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2890 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
Prakash, Sathya436ace72007-07-24 15:42:08 +05302892 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 ioc->name, &ioc_init));
2894
2895 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2896 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002897 if (r != 0) {
2898 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002903 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 */
2905
Prakash, Sathya436ace72007-07-24 15:42:08 +05302906 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002908
2909 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2910 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914 /* YIKES! SUPER IMPORTANT!!!
2915 * Poll IocState until _OPERATIONAL while IOC is doing
2916 * LoopInit and TargetDiscovery!
2917 */
2918 count = 0;
2919 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2920 state = mpt_GetIocState(ioc, 1);
2921 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2922 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002923 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 } else {
2925 mdelay(1);
2926 }
2927
2928 if (!cntdn) {
2929 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2930 ioc->name, (int)((count+5)/HZ));
2931 return -9;
2932 }
2933
2934 state = mpt_GetIocState(ioc, 1);
2935 count++;
2936 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302937 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 ioc->name, count));
2939
Eric Mooreba856d32006-07-11 17:34:01 -06002940 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 return r;
2942}
2943
2944/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002945/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 * SendPortEnable - Send PortEnable request to MPT adapter port.
2947 * @ioc: Pointer to MPT_ADAPTER structure
2948 * @portnum: Port number to enable
2949 * @sleepFlag: Specifies whether the process can sleep
2950 *
2951 * Send PortEnable to bring IOC to OPERATIONAL state.
2952 *
2953 * Returns 0 for success, non-zero for failure.
2954 */
2955static int
2956SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2957{
2958 PortEnable_t port_enable;
2959 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002960 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 int req_sz;
2962 int reply_sz;
2963
2964 /* Destination... */
2965 reply_sz = sizeof(MPIDefaultReply_t);
2966 memset(&reply_buf, 0, reply_sz);
2967
2968 req_sz = sizeof(PortEnable_t);
2969 memset(&port_enable, 0, req_sz);
2970
2971 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
2972 port_enable.PortNumber = portnum;
2973/* port_enable.ChainOffset = 0; */
2974/* port_enable.MsgFlags = 0; */
2975/* port_enable.MsgContext = 0; */
2976
Prakash, Sathya436ace72007-07-24 15:42:08 +05302977 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 ioc->name, portnum, &port_enable));
2979
2980 /* RAID FW may take a long time to enable
2981 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002982 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07002983 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2984 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2985 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002986 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07002987 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
2988 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
2989 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002991 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992}
2993
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002994/**
2995 * mpt_alloc_fw_memory - allocate firmware memory
2996 * @ioc: Pointer to MPT_ADAPTER structure
2997 * @size: total FW bytes
2998 *
2999 * If memory has already been allocated, the same (cached) value
3000 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 */
3002void
3003mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3004{
3005 if (ioc->cached_fw)
3006 return; /* use already allocated memory */
3007 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3008 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3009 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003010 ioc->alloc_total += size;
3011 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 } else {
3013 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3014 ioc->alloc_total += size;
3015 }
3016}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003017/**
3018 * mpt_free_fw_memory - free firmware memory
3019 * @ioc: Pointer to MPT_ADAPTER structure
3020 *
3021 * If alt_img is NULL, delete from ioc structure.
3022 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 */
3024void
3025mpt_free_fw_memory(MPT_ADAPTER *ioc)
3026{
3027 int sz;
3028
3029 sz = ioc->facts.FWImageSize;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303030 dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3032 pci_free_consistent(ioc->pcidev, sz,
3033 ioc->cached_fw, ioc->cached_fw_dma);
3034 ioc->cached_fw = NULL;
3035
3036 return;
3037}
3038
3039
3040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003041/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3043 * @ioc: Pointer to MPT_ADAPTER structure
3044 * @sleepFlag: Specifies whether the process can sleep
3045 *
3046 * Returns 0 for success, >0 for handshake failure
3047 * <0 for fw upload failure.
3048 *
3049 * Remark: If bound IOC and a successful FWUpload was performed
3050 * on the bound IOC, the second image is discarded
3051 * and memory is free'd. Both channels must upload to prevent
3052 * IOC from running in degraded mode.
3053 */
3054static int
3055mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3056{
3057 u8 request[ioc->req_sz];
3058 u8 reply[sizeof(FWUploadReply_t)];
3059 FWUpload_t *prequest;
3060 FWUploadReply_t *preply;
3061 FWUploadTCSGE_t *ptcsge;
3062 int sgeoffset;
3063 u32 flagsLength;
3064 int ii, sz, reply_sz;
3065 int cmdStatus;
3066
3067 /* If the image size is 0, we are done.
3068 */
3069 if ((sz = ioc->facts.FWImageSize) == 0)
3070 return 0;
3071
3072 mpt_alloc_fw_memory(ioc, sz);
3073
Prakash, Sathya436ace72007-07-24 15:42:08 +05303074 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003076
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 if (ioc->cached_fw == NULL) {
3078 /* Major Failure.
3079 */
3080 return -ENOMEM;
3081 }
3082
3083 prequest = (FWUpload_t *)&request;
3084 preply = (FWUploadReply_t *)&reply;
3085
3086 /* Destination... */
3087 memset(prequest, 0, ioc->req_sz);
3088
3089 reply_sz = sizeof(reply);
3090 memset(preply, 0, reply_sz);
3091
3092 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3093 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3094
3095 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3096 ptcsge->DetailsLength = 12;
3097 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3098 ptcsge->ImageSize = cpu_to_le32(sz);
3099
3100 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3101
3102 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3103 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3104
3105 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303106 dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 prequest, sgeoffset));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303108 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3111 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3112
Prakash, Sathya436ace72007-07-24 15:42:08 +05303113 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 cmdStatus = -EFAULT;
3116 if (ii == 0) {
3117 /* Handshake transfer was complete and successful.
3118 * Check the Reply Frame.
3119 */
3120 int status, transfer_sz;
3121 status = le16_to_cpu(preply->IOCStatus);
3122 if (status == MPI_IOCSTATUS_SUCCESS) {
3123 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3124 if (transfer_sz == sz)
3125 cmdStatus = 0;
3126 }
3127 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303128 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 ioc->name, cmdStatus));
3130
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003131
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 if (cmdStatus) {
3133
Prakash, Sathya436ace72007-07-24 15:42:08 +05303134 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 ioc->name));
3136 mpt_free_fw_memory(ioc);
3137 }
3138
3139 return cmdStatus;
3140}
3141
3142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003143/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 * mpt_downloadboot - DownloadBoot code
3145 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003146 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 * @sleepFlag: Specifies whether the process can sleep
3148 *
3149 * FwDownloadBoot requires Programmed IO access.
3150 *
3151 * Returns 0 for success
3152 * -1 FW Image size is 0
3153 * -2 No valid cached_fw Pointer
3154 * <0 for fw upload failure.
3155 */
3156static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003157mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 MpiExtImageHeader_t *pExtImage;
3160 u32 fwSize;
3161 u32 diag0val;
3162 int count;
3163 u32 *ptrFw;
3164 u32 diagRwData;
3165 u32 nextImage;
3166 u32 load_addr;
3167 u32 ioc_state=0;
3168
Prakash, Sathya436ace72007-07-24 15:42:08 +05303169 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003170 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003171
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3173 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3174 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3175 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3176 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3177 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3178
3179 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3180
3181 /* wait 1 msec */
3182 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003183 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 } else {
3185 mdelay (1);
3186 }
3187
3188 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3189 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3190
3191 for (count = 0; count < 30; count ++) {
3192 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3193 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303194 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 ioc->name, count));
3196 break;
3197 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003198 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003200 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003202 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 }
3204 }
3205
3206 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303207 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003208 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 ioc->name, diag0val));
3210 return -3;
3211 }
3212
3213 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3214 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3215 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3216 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3217 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3218 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3219
3220 /* Set the DiagRwEn and Disable ARM bits */
3221 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 fwSize = (pFwHeader->ImageSize + 3)/4;
3224 ptrFw = (u32 *) pFwHeader;
3225
3226 /* Write the LoadStartAddress to the DiagRw Address Register
3227 * using Programmed IO
3228 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003229 if (ioc->errata_flag_1064)
3230 pci_enable_io_access(ioc->pcidev);
3231
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303233 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 ioc->name, pFwHeader->LoadStartAddress));
3235
Prakash, Sathya436ace72007-07-24 15:42:08 +05303236 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 ioc->name, fwSize*4, ptrFw));
3238 while (fwSize--) {
3239 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3240 }
3241
3242 nextImage = pFwHeader->NextImageHeaderOffset;
3243 while (nextImage) {
3244 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3245
3246 load_addr = pExtImage->LoadStartAddress;
3247
3248 fwSize = (pExtImage->ImageSize + 3) >> 2;
3249 ptrFw = (u32 *)pExtImage;
3250
Prakash, Sathya436ace72007-07-24 15:42:08 +05303251 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003252 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3254
3255 while (fwSize--) {
3256 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3257 }
3258 nextImage = pExtImage->NextImageHeaderOffset;
3259 }
3260
3261 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303262 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3264
3265 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303266 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3268
3269 /* Clear the internal flash bad bit - autoincrementing register,
3270 * so must do two writes.
3271 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003272 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003273 /*
3274 * 1030 and 1035 H/W errata, workaround to access
3275 * the ClearFlashBadSignatureBit
3276 */
3277 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3278 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3279 diagRwData |= 0x40000000;
3280 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3281 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3282
3283 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3284 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3285 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3286 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3287
3288 /* wait 1 msec */
3289 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003290 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003291 } else {
3292 mdelay (1);
3293 }
3294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003296 if (ioc->errata_flag_1064)
3297 pci_disable_io_access(ioc->pcidev);
3298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303300 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003301 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003303 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303304 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 ioc->name, diag0val));
3306 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3307
3308 /* Write 0xFF to reset the sequencer */
3309 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3310
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003311 if (ioc->bus_type == SAS) {
3312 ioc_state = mpt_GetIocState(ioc, 0);
3313 if ( (GetIocFacts(ioc, sleepFlag,
3314 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303315 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003316 ioc->name, ioc_state));
3317 return -EFAULT;
3318 }
3319 }
3320
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 for (count=0; count<HZ*20; count++) {
3322 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303323 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3324 "downloadboot successful! (count=%d) IocState=%x\n",
3325 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003326 if (ioc->bus_type == SAS) {
3327 return 0;
3328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303330 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3331 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 ioc->name));
3333 return -EFAULT;
3334 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303335 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3336 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 ioc->name));
3338 return 0;
3339 }
3340 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003341 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 } else {
3343 mdelay (10);
3344 }
3345 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303346 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3347 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 return -EFAULT;
3349}
3350
3351/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003352/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 * KickStart - Perform hard reset of MPT adapter.
3354 * @ioc: Pointer to MPT_ADAPTER structure
3355 * @force: Force hard reset
3356 * @sleepFlag: Specifies whether the process can sleep
3357 *
3358 * This routine places MPT adapter in diagnostic mode via the
3359 * WriteSequence register, and then performs a hard reset of adapter
3360 * via the Diagnostic register.
3361 *
3362 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3363 * or NO_SLEEP (interrupt thread, use mdelay)
3364 * force - 1 if doorbell active, board fault state
3365 * board operational, IOC_RECOVERY or
3366 * IOC_BRINGUP and there is an alt_ioc.
3367 * 0 else
3368 *
3369 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003370 * 1 - hard reset, READY
3371 * 0 - no reset due to History bit, READY
3372 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 * OR reset but failed to come READY
3374 * -2 - no reset, could not enter DIAG mode
3375 * -3 - reset but bad FW bit
3376 */
3377static int
3378KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3379{
3380 int hard_reset_done = 0;
3381 u32 ioc_state=0;
3382 int cnt,cntdn;
3383
Prakash, Sathya436ace72007-07-24 15:42:08 +05303384 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003385 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 /* Always issue a Msg Unit Reset first. This will clear some
3387 * SCSI bus hang conditions.
3388 */
3389 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3390
3391 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003392 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 } else {
3394 mdelay (1000);
3395 }
3396 }
3397
3398 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3399 if (hard_reset_done < 0)
3400 return hard_reset_done;
3401
Prakash, Sathya436ace72007-07-24 15:42:08 +05303402 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 ioc->name));
3404
3405 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3406 for (cnt=0; cnt<cntdn; cnt++) {
3407 ioc_state = mpt_GetIocState(ioc, 1);
3408 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303409 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 ioc->name, cnt));
3411 return hard_reset_done;
3412 }
3413 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003414 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 } else {
3416 mdelay (10);
3417 }
3418 }
3419
3420 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3421 ioc->name, ioc_state);
3422 return -1;
3423}
3424
3425/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003426/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 * mpt_diag_reset - Perform hard reset of the adapter.
3428 * @ioc: Pointer to MPT_ADAPTER structure
3429 * @ignore: Set if to honor and clear to ignore
3430 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003431 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 * else set to NO_SLEEP (use mdelay instead)
3433 *
3434 * This routine places the adapter in diagnostic mode via the
3435 * WriteSequence register and then performs a hard reset of adapter
3436 * via the Diagnostic register. Adapter should be in ready state
3437 * upon successful completion.
3438 *
3439 * Returns: 1 hard reset successful
3440 * 0 no reset performed because reset history bit set
3441 * -2 enabling diagnostic mode failed
3442 * -3 diagnostic reset failed
3443 */
3444static int
3445mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3446{
Eric Moore0ccdb002006-07-11 17:33:13 -06003447 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 u32 diag0val;
3449 u32 doorbell;
3450 int hard_reset_done = 0;
3451 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
Eric Moorecd2c6192007-01-29 09:47:47 -07003454 /* Clear any existing interrupts */
3455 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3456
Eric Moore87cf8982006-06-27 16:09:26 -06003457 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303458 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003459 "address=%p\n", ioc->name, __FUNCTION__,
3460 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3461 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3462 if (sleepFlag == CAN_SLEEP)
3463 msleep(1);
3464 else
3465 mdelay(1);
3466
3467 for (count = 0; count < 60; count ++) {
3468 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3469 doorbell &= MPI_IOC_STATE_MASK;
3470
Prakash, Sathya436ace72007-07-24 15:42:08 +05303471 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003472 "looking for READY STATE: doorbell=%x"
3473 " count=%d\n",
3474 ioc->name, doorbell, count));
3475 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003476 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003477 }
3478
3479 /* wait 1 sec */
3480 if (sleepFlag == CAN_SLEEP)
3481 msleep(1000);
3482 else
3483 mdelay(1000);
3484 }
3485 return -1;
3486 }
3487
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* Use "Diagnostic reset" method! (only thing available!) */
3489 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3490
Prakash, Sathya436ace72007-07-24 15:42:08 +05303491 if (ioc->debug_level & MPT_DEBUG) {
3492 if (ioc->alt_ioc)
3493 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3494 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
3498 /* Do the reset if we are told to ignore the reset history
3499 * or if the reset history is 0
3500 */
3501 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3502 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3503 /* Write magic sequence to WriteSequence register
3504 * Loop until in diagnostic mode
3505 */
3506 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3507 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3508 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3509 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3510 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3511 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3512
3513 /* wait 100 msec */
3514 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003515 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 } else {
3517 mdelay (100);
3518 }
3519
3520 count++;
3521 if (count > 20) {
3522 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3523 ioc->name, diag0val);
3524 return -2;
3525
3526 }
3527
3528 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3529
Prakash, Sathya436ace72007-07-24 15:42:08 +05303530 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 ioc->name, diag0val));
3532 }
3533
Prakash, Sathya436ace72007-07-24 15:42:08 +05303534 if (ioc->debug_level & MPT_DEBUG) {
3535 if (ioc->alt_ioc)
3536 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3537 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 /*
3541 * Disable the ARM (Bug fix)
3542 *
3543 */
3544 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003545 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
3547 /*
3548 * Now hit the reset bit in the Diagnostic register
3549 * (THE BIG HAMMER!) (Clears DRWE bit).
3550 */
3551 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3552 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303553 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 ioc->name));
3555
3556 /*
3557 * Call each currently registered protocol IOC reset handler
3558 * with pre-reset indication.
3559 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3560 * MptResetHandlers[] registered yet.
3561 */
3562 {
3563 int ii;
3564 int r = 0;
3565
3566 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3567 if (MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303568 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3569 "Calling IOC pre_reset handler #%d\n",
3570 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003571 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303573 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3574 "Calling alt-%s pre_reset handler #%d\n",
3575 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003576 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 }
3578 }
3579 }
3580 /* FIXME? Examine results here? */
3581 }
3582
Eric Moore0ccdb002006-07-11 17:33:13 -06003583 if (ioc->cached_fw)
3584 iocp = ioc;
3585 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3586 iocp = ioc->alt_ioc;
3587 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 /* If the DownloadBoot operation fails, the
3589 * IOC will be left unusable. This is a fatal error
3590 * case. _diag_reset will return < 0
3591 */
3592 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003593 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3595 break;
3596 }
3597
Prakash, Sathya436ace72007-07-24 15:42:08 +05303598 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003599 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 /* wait 1 sec */
3601 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003602 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 } else {
3604 mdelay (1000);
3605 }
3606 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003607 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003608 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 printk(KERN_WARNING MYNAM
3610 ": firmware downloadboot failure (%d)!\n", count);
3611 }
3612
3613 } else {
3614 /* Wait for FW to reload and for board
3615 * to go to the READY state.
3616 * Maximum wait is 60 seconds.
3617 * If fail, no error will check again
3618 * with calling program.
3619 */
3620 for (count = 0; count < 60; count ++) {
3621 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3622 doorbell &= MPI_IOC_STATE_MASK;
3623
3624 if (doorbell == MPI_IOC_STATE_READY) {
3625 break;
3626 }
3627
3628 /* wait 1 sec */
3629 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003630 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 } else {
3632 mdelay (1000);
3633 }
3634 }
3635 }
3636 }
3637
3638 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303639 if (ioc->debug_level & MPT_DEBUG) {
3640 if (ioc->alt_ioc)
3641 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3642 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3643 ioc->name, diag0val, diag1val));
3644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
3646 /* Clear RESET_HISTORY bit! Place board in the
3647 * diagnostic mode to update the diag register.
3648 */
3649 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3650 count = 0;
3651 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3652 /* Write magic sequence to WriteSequence register
3653 * Loop until in diagnostic mode
3654 */
3655 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3656 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3657 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3658 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3659 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3660 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3661
3662 /* wait 100 msec */
3663 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003664 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 } else {
3666 mdelay (100);
3667 }
3668
3669 count++;
3670 if (count > 20) {
3671 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3672 ioc->name, diag0val);
3673 break;
3674 }
3675 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3676 }
3677 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3678 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3679 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3680 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3681 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3682 ioc->name);
3683 }
3684
3685 /* Disable Diagnostic Mode
3686 */
3687 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3688
3689 /* Check FW reload status flags.
3690 */
3691 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3692 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3693 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3694 ioc->name, diag0val);
3695 return -3;
3696 }
3697
Prakash, Sathya436ace72007-07-24 15:42:08 +05303698 if (ioc->debug_level & MPT_DEBUG) {
3699 if (ioc->alt_ioc)
3700 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3701 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704
3705 /*
3706 * Reset flag that says we've enabled event notification
3707 */
3708 ioc->facts.EventState = 0;
3709
3710 if (ioc->alt_ioc)
3711 ioc->alt_ioc->facts.EventState = 0;
3712
3713 return hard_reset_done;
3714}
3715
3716/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003717/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 * SendIocReset - Send IOCReset request to MPT adapter.
3719 * @ioc: Pointer to MPT_ADAPTER structure
3720 * @reset_type: reset type, expected values are
3721 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003722 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 *
3724 * Send IOCReset request to the MPT adapter.
3725 *
3726 * Returns 0 for success, non-zero for failure.
3727 */
3728static int
3729SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3730{
3731 int r;
3732 u32 state;
3733 int cntdn, count;
3734
Prakash, Sathya436ace72007-07-24 15:42:08 +05303735 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 ioc->name, reset_type));
3737 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3738 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3739 return r;
3740
3741 /* FW ACK'd request, wait for READY state
3742 */
3743 count = 0;
3744 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3745
3746 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3747 cntdn--;
3748 count++;
3749 if (!cntdn) {
3750 if (sleepFlag != CAN_SLEEP)
3751 count *= 10;
3752
3753 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3754 ioc->name, (int)((count+5)/HZ));
3755 return -ETIME;
3756 }
3757
3758 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003759 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 } else {
3761 mdelay (1); /* 1 msec delay */
3762 }
3763 }
3764
3765 /* TODO!
3766 * Cleanup all event stuff for this IOC; re-issue EventNotification
3767 * request if needed.
3768 */
3769 if (ioc->facts.Function)
3770 ioc->facts.EventState = 0;
3771
3772 return 0;
3773}
3774
3775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003776/**
3777 * initChainBuffers - Allocate memory for and initialize chain buffers
3778 * @ioc: Pointer to MPT_ADAPTER structure
3779 *
3780 * Allocates memory for and initializes chain buffers,
3781 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 */
3783static int
3784initChainBuffers(MPT_ADAPTER *ioc)
3785{
3786 u8 *mem;
3787 int sz, ii, num_chain;
3788 int scale, num_sge, numSGE;
3789
3790 /* ReqToChain size must equal the req_depth
3791 * index = req_idx
3792 */
3793 if (ioc->ReqToChain == NULL) {
3794 sz = ioc->req_depth * sizeof(int);
3795 mem = kmalloc(sz, GFP_ATOMIC);
3796 if (mem == NULL)
3797 return -1;
3798
3799 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303800 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 ioc->name, mem, sz));
3802 mem = kmalloc(sz, GFP_ATOMIC);
3803 if (mem == NULL)
3804 return -1;
3805
3806 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303807 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 ioc->name, mem, sz));
3809 }
3810 for (ii = 0; ii < ioc->req_depth; ii++) {
3811 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3812 }
3813
3814 /* ChainToChain size must equal the total number
3815 * of chain buffers to be allocated.
3816 * index = chain_idx
3817 *
3818 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003819 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 *
3821 * num_sge = num sge in request frame + last chain buffer
3822 * scale = num sge per chain buffer if no chain element
3823 */
3824 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3825 if (sizeof(dma_addr_t) == sizeof(u64))
3826 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3827 else
3828 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3829
3830 if (sizeof(dma_addr_t) == sizeof(u64)) {
3831 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3832 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3833 } else {
3834 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3835 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3836 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303837 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 ioc->name, num_sge, numSGE));
3839
3840 if ( numSGE > MPT_SCSI_SG_DEPTH )
3841 numSGE = MPT_SCSI_SG_DEPTH;
3842
3843 num_chain = 1;
3844 while (numSGE - num_sge > 0) {
3845 num_chain++;
3846 num_sge += (scale - 1);
3847 }
3848 num_chain++;
3849
Prakash, Sathya436ace72007-07-24 15:42:08 +05303850 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 ioc->name, numSGE, num_sge, num_chain));
3852
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003853 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 num_chain *= MPT_SCSI_CAN_QUEUE;
3855 else
3856 num_chain *= MPT_FC_CAN_QUEUE;
3857
3858 ioc->num_chain = num_chain;
3859
3860 sz = num_chain * sizeof(int);
3861 if (ioc->ChainToChain == NULL) {
3862 mem = kmalloc(sz, GFP_ATOMIC);
3863 if (mem == NULL)
3864 return -1;
3865
3866 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303867 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 ioc->name, mem, sz));
3869 } else {
3870 mem = (u8 *) ioc->ChainToChain;
3871 }
3872 memset(mem, 0xFF, sz);
3873 return num_chain;
3874}
3875
3876/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003877/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3879 * @ioc: Pointer to MPT_ADAPTER structure
3880 *
3881 * This routine allocates memory for the MPT reply and request frame
3882 * pools (if necessary), and primes the IOC reply FIFO with
3883 * reply frames.
3884 *
3885 * Returns 0 for success, non-zero for failure.
3886 */
3887static int
3888PrimeIocFifos(MPT_ADAPTER *ioc)
3889{
3890 MPT_FRAME_HDR *mf;
3891 unsigned long flags;
3892 dma_addr_t alloc_dma;
3893 u8 *mem;
3894 int i, reply_sz, sz, total_size, num_chain;
3895
3896 /* Prime reply FIFO... */
3897
3898 if (ioc->reply_frames == NULL) {
3899 if ( (num_chain = initChainBuffers(ioc)) < 0)
3900 return -1;
3901
3902 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303903 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303905 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 ioc->name, reply_sz, reply_sz));
3907
3908 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303909 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303911 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 ioc->name, sz, sz));
3913 total_size += sz;
3914
3915 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303916 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303918 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 ioc->name, sz, sz, num_chain));
3920
3921 total_size += sz;
3922 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3923 if (mem == NULL) {
3924 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3925 ioc->name);
3926 goto out_fail;
3927 }
3928
Prakash, Sathya436ace72007-07-24 15:42:08 +05303929 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3931
3932 memset(mem, 0, total_size);
3933 ioc->alloc_total += total_size;
3934 ioc->alloc = mem;
3935 ioc->alloc_dma = alloc_dma;
3936 ioc->alloc_sz = total_size;
3937 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3938 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3939
Prakash, Sathya436ace72007-07-24 15:42:08 +05303940 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003941 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3942
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 alloc_dma += reply_sz;
3944 mem += reply_sz;
3945
3946 /* Request FIFO - WE manage this! */
3947
3948 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3949 ioc->req_frames_dma = alloc_dma;
3950
Prakash, Sathya436ace72007-07-24 15:42:08 +05303951 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 ioc->name, mem, (void *)(ulong)alloc_dma));
3953
3954 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3955
3956#if defined(CONFIG_MTRR) && 0
3957 /*
3958 * Enable Write Combining MTRR for IOC's memory region.
3959 * (at least as much as we can; "size and base must be
3960 * multiples of 4 kiB"
3961 */
3962 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3963 sz,
3964 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 ioc->name, ioc->req_frames_dma, sz));
3967#endif
3968
3969 for (i = 0; i < ioc->req_depth; i++) {
3970 alloc_dma += ioc->req_sz;
3971 mem += ioc->req_sz;
3972 }
3973
3974 ioc->ChainBuffer = mem;
3975 ioc->ChainBufferDMA = alloc_dma;
3976
Prakash, Sathya436ace72007-07-24 15:42:08 +05303977 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
3979
3980 /* Initialize the free chain Q.
3981 */
3982
3983 INIT_LIST_HEAD(&ioc->FreeChainQ);
3984
3985 /* Post the chain buffers to the FreeChainQ.
3986 */
3987 mem = (u8 *)ioc->ChainBuffer;
3988 for (i=0; i < num_chain; i++) {
3989 mf = (MPT_FRAME_HDR *) mem;
3990 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
3991 mem += ioc->req_sz;
3992 }
3993
3994 /* Initialize Request frames linked list
3995 */
3996 alloc_dma = ioc->req_frames_dma;
3997 mem = (u8 *) ioc->req_frames;
3998
3999 spin_lock_irqsave(&ioc->FreeQlock, flags);
4000 INIT_LIST_HEAD(&ioc->FreeQ);
4001 for (i = 0; i < ioc->req_depth; i++) {
4002 mf = (MPT_FRAME_HDR *) mem;
4003
4004 /* Queue REQUESTs *internally*! */
4005 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4006
4007 mem += ioc->req_sz;
4008 }
4009 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4010
4011 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4012 ioc->sense_buf_pool =
4013 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4014 if (ioc->sense_buf_pool == NULL) {
4015 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4016 ioc->name);
4017 goto out_fail;
4018 }
4019
4020 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4021 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304022 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4024
4025 }
4026
4027 /* Post Reply frames to FIFO
4028 */
4029 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304030 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4032
4033 for (i = 0; i < ioc->reply_depth; i++) {
4034 /* Write each address to the IOC! */
4035 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4036 alloc_dma += ioc->reply_sz;
4037 }
4038
4039 return 0;
4040
4041out_fail:
4042 if (ioc->alloc != NULL) {
4043 sz = ioc->alloc_sz;
4044 pci_free_consistent(ioc->pcidev,
4045 sz,
4046 ioc->alloc, ioc->alloc_dma);
4047 ioc->reply_frames = NULL;
4048 ioc->req_frames = NULL;
4049 ioc->alloc_total -= sz;
4050 }
4051 if (ioc->sense_buf_pool != NULL) {
4052 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4053 pci_free_consistent(ioc->pcidev,
4054 sz,
4055 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4056 ioc->sense_buf_pool = NULL;
4057 }
4058 return -1;
4059}
4060
4061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4062/**
4063 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4064 * from IOC via doorbell handshake method.
4065 * @ioc: Pointer to MPT_ADAPTER structure
4066 * @reqBytes: Size of the request in bytes
4067 * @req: Pointer to MPT request frame
4068 * @replyBytes: Expected size of the reply in bytes
4069 * @u16reply: Pointer to area where reply should be written
4070 * @maxwait: Max wait time for a reply (in seconds)
4071 * @sleepFlag: Specifies whether the process can sleep
4072 *
4073 * NOTES: It is the callers responsibility to byte-swap fields in the
4074 * request which are greater than 1 byte in size. It is also the
4075 * callers responsibility to byte-swap response fields which are
4076 * greater than 1 byte in size.
4077 *
4078 * Returns 0 for success, non-zero for failure.
4079 */
4080static int
4081mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004082 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083{
4084 MPIDefaultReply_t *mptReply;
4085 int failcnt = 0;
4086 int t;
4087
4088 /*
4089 * Get ready to cache a handshake reply
4090 */
4091 ioc->hs_reply_idx = 0;
4092 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4093 mptReply->MsgLength = 0;
4094
4095 /*
4096 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4097 * then tell IOC that we want to handshake a request of N words.
4098 * (WRITE u32val to Doorbell reg).
4099 */
4100 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4101 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4102 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4103 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4104
4105 /*
4106 * Wait for IOC's doorbell handshake int
4107 */
4108 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4109 failcnt++;
4110
Prakash, Sathya436ace72007-07-24 15:42:08 +05304111 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4113
4114 /* Read doorbell and check for active bit */
4115 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4116 return -1;
4117
4118 /*
4119 * Clear doorbell int (WRITE 0 to IntStatus reg),
4120 * then wait for IOC to ACKnowledge that it's ready for
4121 * our handshake request.
4122 */
4123 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4124 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4125 failcnt++;
4126
4127 if (!failcnt) {
4128 int ii;
4129 u8 *req_as_bytes = (u8 *) req;
4130
4131 /*
4132 * Stuff request words via doorbell handshake,
4133 * with ACK from IOC for each.
4134 */
4135 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4136 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4137 (req_as_bytes[(ii*4) + 1] << 8) |
4138 (req_as_bytes[(ii*4) + 2] << 16) |
4139 (req_as_bytes[(ii*4) + 3] << 24));
4140
4141 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4142 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4143 failcnt++;
4144 }
4145
Prakash, Sathya436ace72007-07-24 15:42:08 +05304146 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
4147 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148
Prakash, Sathya436ace72007-07-24 15:42:08 +05304149 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4151
4152 /*
4153 * Wait for completion of doorbell handshake reply from the IOC
4154 */
4155 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4156 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004157
Prakash, Sathya436ace72007-07-24 15:42:08 +05304158 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4160
4161 /*
4162 * Copy out the cached reply...
4163 */
4164 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4165 u16reply[ii] = ioc->hs_reply[ii];
4166 } else {
4167 return -99;
4168 }
4169
4170 return -failcnt;
4171}
4172
4173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004174/**
4175 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 * @ioc: Pointer to MPT_ADAPTER structure
4177 * @howlong: How long to wait (in seconds)
4178 * @sleepFlag: Specifies whether the process can sleep
4179 *
4180 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004181 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4182 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 *
4184 * Returns a negative value on failure, else wait loop count.
4185 */
4186static int
4187WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4188{
4189 int cntdn;
4190 int count = 0;
4191 u32 intstat=0;
4192
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004193 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195 if (sleepFlag == CAN_SLEEP) {
4196 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004197 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4199 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4200 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 count++;
4202 }
4203 } else {
4204 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004205 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4207 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4208 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 count++;
4210 }
4211 }
4212
4213 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304214 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 ioc->name, count));
4216 return count;
4217 }
4218
4219 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4220 ioc->name, count, intstat);
4221 return -1;
4222}
4223
4224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004225/**
4226 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 * @ioc: Pointer to MPT_ADAPTER structure
4228 * @howlong: How long to wait (in seconds)
4229 * @sleepFlag: Specifies whether the process can sleep
4230 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004231 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4232 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 *
4234 * Returns a negative value on failure, else wait loop count.
4235 */
4236static int
4237WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4238{
4239 int cntdn;
4240 int count = 0;
4241 u32 intstat=0;
4242
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004243 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 if (sleepFlag == CAN_SLEEP) {
4245 while (--cntdn) {
4246 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4247 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4248 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004249 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 count++;
4251 }
4252 } else {
4253 while (--cntdn) {
4254 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4255 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4256 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004257 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 count++;
4259 }
4260 }
4261
4262 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304263 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 ioc->name, count, howlong));
4265 return count;
4266 }
4267
4268 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4269 ioc->name, count, intstat);
4270 return -1;
4271}
4272
4273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004274/**
4275 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 * @ioc: Pointer to MPT_ADAPTER structure
4277 * @howlong: How long to wait (in seconds)
4278 * @sleepFlag: Specifies whether the process can sleep
4279 *
4280 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4281 * Reply is cached to IOC private area large enough to hold a maximum
4282 * of 128 bytes of reply data.
4283 *
4284 * Returns a negative value on failure, else size of reply in WORDS.
4285 */
4286static int
4287WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4288{
4289 int u16cnt = 0;
4290 int failcnt = 0;
4291 int t;
4292 u16 *hs_reply = ioc->hs_reply;
4293 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4294 u16 hword;
4295
4296 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4297
4298 /*
4299 * Get first two u16's so we can look at IOC's intended reply MsgLength
4300 */
4301 u16cnt=0;
4302 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4303 failcnt++;
4304 } else {
4305 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4306 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4307 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4308 failcnt++;
4309 else {
4310 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4311 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4312 }
4313 }
4314
Prakash, Sathya436ace72007-07-24 15:42:08 +05304315 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004316 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4318
4319 /*
4320 * If no error (and IOC said MsgLength is > 0), piece together
4321 * reply 16 bits at a time.
4322 */
4323 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4324 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4325 failcnt++;
4326 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4327 /* don't overflow our IOC hs_reply[] buffer! */
4328 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4329 hs_reply[u16cnt] = hword;
4330 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4331 }
4332
4333 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4334 failcnt++;
4335 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4336
4337 if (failcnt) {
4338 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4339 ioc->name);
4340 return -failcnt;
4341 }
4342#if 0
4343 else if (u16cnt != (2 * mptReply->MsgLength)) {
4344 return -101;
4345 }
4346 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4347 return -102;
4348 }
4349#endif
4350
Prakash, Sathya436ace72007-07-24 15:42:08 +05304351 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
4352 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Prakash, Sathya436ace72007-07-24 15:42:08 +05304354 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 ioc->name, t, u16cnt/2));
4356 return u16cnt/2;
4357}
4358
4359/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004360/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 * GetLanConfigPages - Fetch LANConfig pages.
4362 * @ioc: Pointer to MPT_ADAPTER structure
4363 *
4364 * Return: 0 for success
4365 * -ENOMEM if no memory available
4366 * -EPERM if not allowed due to ISR context
4367 * -EAGAIN if no msg frames currently available
4368 * -EFAULT for non-successful reply or no reply (timeout)
4369 */
4370static int
4371GetLanConfigPages(MPT_ADAPTER *ioc)
4372{
4373 ConfigPageHeader_t hdr;
4374 CONFIGPARMS cfg;
4375 LANPage0_t *ppage0_alloc;
4376 dma_addr_t page0_dma;
4377 LANPage1_t *ppage1_alloc;
4378 dma_addr_t page1_dma;
4379 int rc = 0;
4380 int data_sz;
4381 int copy_sz;
4382
4383 /* Get LAN Page 0 header */
4384 hdr.PageVersion = 0;
4385 hdr.PageLength = 0;
4386 hdr.PageNumber = 0;
4387 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004388 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 cfg.physAddr = -1;
4390 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4391 cfg.dir = 0;
4392 cfg.pageAddr = 0;
4393 cfg.timeout = 0;
4394
4395 if ((rc = mpt_config(ioc, &cfg)) != 0)
4396 return rc;
4397
4398 if (hdr.PageLength > 0) {
4399 data_sz = hdr.PageLength * 4;
4400 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4401 rc = -ENOMEM;
4402 if (ppage0_alloc) {
4403 memset((u8 *)ppage0_alloc, 0, data_sz);
4404 cfg.physAddr = page0_dma;
4405 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4406
4407 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4408 /* save the data */
4409 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4410 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4411
4412 }
4413
4414 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4415
4416 /* FIXME!
4417 * Normalize endianness of structure data,
4418 * by byte-swapping all > 1 byte fields!
4419 */
4420
4421 }
4422
4423 if (rc)
4424 return rc;
4425 }
4426
4427 /* Get LAN Page 1 header */
4428 hdr.PageVersion = 0;
4429 hdr.PageLength = 0;
4430 hdr.PageNumber = 1;
4431 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004432 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 cfg.physAddr = -1;
4434 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4435 cfg.dir = 0;
4436 cfg.pageAddr = 0;
4437
4438 if ((rc = mpt_config(ioc, &cfg)) != 0)
4439 return rc;
4440
4441 if (hdr.PageLength == 0)
4442 return 0;
4443
4444 data_sz = hdr.PageLength * 4;
4445 rc = -ENOMEM;
4446 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4447 if (ppage1_alloc) {
4448 memset((u8 *)ppage1_alloc, 0, data_sz);
4449 cfg.physAddr = page1_dma;
4450 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4451
4452 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4453 /* save the data */
4454 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4455 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4456 }
4457
4458 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4459
4460 /* FIXME!
4461 * Normalize endianness of structure data,
4462 * by byte-swapping all > 1 byte fields!
4463 */
4464
4465 }
4466
4467 return rc;
4468}
4469
4470/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004471/**
4472 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004473 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004474 * @persist_opcode: see below
4475 *
4476 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4477 * devices not currently present.
4478 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4479 *
4480 * NOTE: Don't use not this function during interrupt time.
4481 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004482 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004483 */
4484
4485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4486int
4487mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4488{
4489 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4490 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4491 MPT_FRAME_HDR *mf = NULL;
4492 MPIHeader_t *mpi_hdr;
4493
4494
4495 /* insure garbage is not sent to fw */
4496 switch(persist_opcode) {
4497
4498 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4499 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4500 break;
4501
4502 default:
4503 return -1;
4504 break;
4505 }
4506
4507 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4508
4509 /* Get a MF for this command.
4510 */
4511 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4512 printk("%s: no msg frames!\n",__FUNCTION__);
4513 return -1;
4514 }
4515
4516 mpi_hdr = (MPIHeader_t *) mf;
4517 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4518 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4519 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4520 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4521 sasIoUnitCntrReq->Operation = persist_opcode;
4522
4523 init_timer(&ioc->persist_timer);
4524 ioc->persist_timer.data = (unsigned long) ioc;
4525 ioc->persist_timer.function = mpt_timer_expired;
4526 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4527 ioc->persist_wait_done=0;
4528 add_timer(&ioc->persist_timer);
4529 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4530 wait_event(mpt_waitq, ioc->persist_wait_done);
4531
4532 sasIoUnitCntrReply =
4533 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4534 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4535 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4536 __FUNCTION__,
4537 sasIoUnitCntrReply->IOCStatus,
4538 sasIoUnitCntrReply->IOCLogInfo);
4539 return -1;
4540 }
4541
4542 printk("%s: success\n",__FUNCTION__);
4543 return 0;
4544}
4545
4546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004547
4548static void
4549mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4550 MpiEventDataRaid_t * pRaidEventData)
4551{
4552 int volume;
4553 int reason;
4554 int disk;
4555 int status;
4556 int flags;
4557 int state;
4558
4559 volume = pRaidEventData->VolumeID;
4560 reason = pRaidEventData->ReasonCode;
4561 disk = pRaidEventData->PhysDiskNum;
4562 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4563 flags = (status >> 0) & 0xff;
4564 state = (status >> 8) & 0xff;
4565
4566 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4567 return;
4568 }
4569
4570 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4571 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4572 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004573 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4574 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004575 } else {
4576 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4577 ioc->name, volume);
4578 }
4579
4580 switch(reason) {
4581 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4582 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4583 ioc->name);
4584 break;
4585
4586 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4587
4588 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4589 ioc->name);
4590 break;
4591
4592 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4593 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4594 ioc->name);
4595 break;
4596
4597 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4598 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4599 ioc->name,
4600 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4601 ? "optimal"
4602 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4603 ? "degraded"
4604 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4605 ? "failed"
4606 : "state unknown",
4607 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4608 ? ", enabled" : "",
4609 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4610 ? ", quiesced" : "",
4611 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4612 ? ", resync in progress" : "" );
4613 break;
4614
4615 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4616 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4617 ioc->name, disk);
4618 break;
4619
4620 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4621 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4622 ioc->name);
4623 break;
4624
4625 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4626 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4627 ioc->name);
4628 break;
4629
4630 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4631 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4632 ioc->name);
4633 break;
4634
4635 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4636 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4637 ioc->name,
4638 state == MPI_PHYSDISK0_STATUS_ONLINE
4639 ? "online"
4640 : state == MPI_PHYSDISK0_STATUS_MISSING
4641 ? "missing"
4642 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4643 ? "not compatible"
4644 : state == MPI_PHYSDISK0_STATUS_FAILED
4645 ? "failed"
4646 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4647 ? "initializing"
4648 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4649 ? "offline requested"
4650 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4651 ? "failed requested"
4652 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4653 ? "offline"
4654 : "state unknown",
4655 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4656 ? ", out of sync" : "",
4657 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4658 ? ", quiesced" : "" );
4659 break;
4660
4661 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4662 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4663 ioc->name, disk);
4664 break;
4665
4666 case MPI_EVENT_RAID_RC_SMART_DATA:
4667 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4668 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4669 break;
4670
4671 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4672 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4673 ioc->name, disk);
4674 break;
4675 }
4676}
4677
4678/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004679/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4681 * @ioc: Pointer to MPT_ADAPTER structure
4682 *
4683 * Returns: 0 for success
4684 * -ENOMEM if no memory available
4685 * -EPERM if not allowed due to ISR context
4686 * -EAGAIN if no msg frames currently available
4687 * -EFAULT for non-successful reply or no reply (timeout)
4688 */
4689static int
4690GetIoUnitPage2(MPT_ADAPTER *ioc)
4691{
4692 ConfigPageHeader_t hdr;
4693 CONFIGPARMS cfg;
4694 IOUnitPage2_t *ppage_alloc;
4695 dma_addr_t page_dma;
4696 int data_sz;
4697 int rc;
4698
4699 /* Get the page header */
4700 hdr.PageVersion = 0;
4701 hdr.PageLength = 0;
4702 hdr.PageNumber = 2;
4703 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004704 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 cfg.physAddr = -1;
4706 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4707 cfg.dir = 0;
4708 cfg.pageAddr = 0;
4709 cfg.timeout = 0;
4710
4711 if ((rc = mpt_config(ioc, &cfg)) != 0)
4712 return rc;
4713
4714 if (hdr.PageLength == 0)
4715 return 0;
4716
4717 /* Read the config page */
4718 data_sz = hdr.PageLength * 4;
4719 rc = -ENOMEM;
4720 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4721 if (ppage_alloc) {
4722 memset((u8 *)ppage_alloc, 0, data_sz);
4723 cfg.physAddr = page_dma;
4724 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4725
4726 /* If Good, save data */
4727 if ((rc = mpt_config(ioc, &cfg)) == 0)
4728 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4729
4730 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4731 }
4732
4733 return rc;
4734}
4735
4736/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004737/**
4738 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 * @ioc: Pointer to a Adapter Strucutre
4740 * @portnum: IOC port number
4741 *
4742 * Return: -EFAULT if read of config page header fails
4743 * or if no nvram
4744 * If read of SCSI Port Page 0 fails,
4745 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4746 * Adapter settings: async, narrow
4747 * Return 1
4748 * If read of SCSI Port Page 2 fails,
4749 * Adapter settings valid
4750 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4751 * Return 1
4752 * Else
4753 * Both valid
4754 * Return 0
4755 * CHECK - what type of locking mechanisms should be used????
4756 */
4757static int
4758mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4759{
4760 u8 *pbuf;
4761 dma_addr_t buf_dma;
4762 CONFIGPARMS cfg;
4763 ConfigPageHeader_t header;
4764 int ii;
4765 int data, rc = 0;
4766
4767 /* Allocate memory
4768 */
4769 if (!ioc->spi_data.nvram) {
4770 int sz;
4771 u8 *mem;
4772 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4773 mem = kmalloc(sz, GFP_ATOMIC);
4774 if (mem == NULL)
4775 return -EFAULT;
4776
4777 ioc->spi_data.nvram = (int *) mem;
4778
Prakash, Sathya436ace72007-07-24 15:42:08 +05304779 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 ioc->name, ioc->spi_data.nvram, sz));
4781 }
4782
4783 /* Invalidate NVRAM information
4784 */
4785 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4786 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4787 }
4788
4789 /* Read SPP0 header, allocate memory, then read page.
4790 */
4791 header.PageVersion = 0;
4792 header.PageLength = 0;
4793 header.PageNumber = 0;
4794 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004795 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 cfg.physAddr = -1;
4797 cfg.pageAddr = portnum;
4798 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4799 cfg.dir = 0;
4800 cfg.timeout = 0; /* use default */
4801 if (mpt_config(ioc, &cfg) != 0)
4802 return -EFAULT;
4803
4804 if (header.PageLength > 0) {
4805 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4806 if (pbuf) {
4807 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4808 cfg.physAddr = buf_dma;
4809 if (mpt_config(ioc, &cfg) != 0) {
4810 ioc->spi_data.maxBusWidth = MPT_NARROW;
4811 ioc->spi_data.maxSyncOffset = 0;
4812 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4813 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4814 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304815 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4816 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004817 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 } else {
4819 /* Save the Port Page 0 data
4820 */
4821 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4822 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4823 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4824
4825 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4826 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304827 ddvprintk(ioc, printk(KERN_INFO MYNAM
4828 " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 ioc->name, pPP0->Capabilities));
4830 }
4831 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4832 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4833 if (data) {
4834 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4835 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4836 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304837 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4838 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004839 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 } else {
4841 ioc->spi_data.maxSyncOffset = 0;
4842 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4843 }
4844
4845 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4846
4847 /* Update the minSyncFactor based on bus type.
4848 */
4849 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4850 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4851
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004852 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304854 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4855 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004856 ioc->name, ioc->spi_data.minSyncFactor));
4857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 }
4859 }
4860 if (pbuf) {
4861 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4862 }
4863 }
4864 }
4865
4866 /* SCSI Port Page 2 - Read the header then the page.
4867 */
4868 header.PageVersion = 0;
4869 header.PageLength = 0;
4870 header.PageNumber = 2;
4871 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004872 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 cfg.physAddr = -1;
4874 cfg.pageAddr = portnum;
4875 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4876 cfg.dir = 0;
4877 if (mpt_config(ioc, &cfg) != 0)
4878 return -EFAULT;
4879
4880 if (header.PageLength > 0) {
4881 /* Allocate memory and read SCSI Port Page 2
4882 */
4883 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4884 if (pbuf) {
4885 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4886 cfg.physAddr = buf_dma;
4887 if (mpt_config(ioc, &cfg) != 0) {
4888 /* Nvram data is left with INVALID mark
4889 */
4890 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004891 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4892
4893 /* This is an ATTO adapter, read Page2 accordingly
4894 */
4895 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4896 ATTODeviceInfo_t *pdevice = NULL;
4897 u16 ATTOFlags;
4898
4899 /* Save the Port Page 2 data
4900 * (reformat into a 32bit quantity)
4901 */
4902 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4903 pdevice = &pPP2->DeviceSettings[ii];
4904 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4905 data = 0;
4906
4907 /* Translate ATTO device flags to LSI format
4908 */
4909 if (ATTOFlags & ATTOFLAG_DISC)
4910 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4911 if (ATTOFlags & ATTOFLAG_ID_ENB)
4912 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4913 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4914 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4915 if (ATTOFlags & ATTOFLAG_TAGGED)
4916 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4917 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4918 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4919
4920 data = (data << 16) | (pdevice->Period << 8) | 10;
4921 ioc->spi_data.nvram[ii] = data;
4922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 } else {
4924 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4925 MpiDeviceInfo_t *pdevice = NULL;
4926
Moore, Ericd8e925d2006-01-16 18:53:06 -07004927 /*
4928 * Save "Set to Avoid SCSI Bus Resets" flag
4929 */
4930 ioc->spi_data.bus_reset =
4931 (le32_to_cpu(pPP2->PortFlags) &
4932 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4933 0 : 1 ;
4934
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 /* Save the Port Page 2 data
4936 * (reformat into a 32bit quantity)
4937 */
4938 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4939 ioc->spi_data.PortFlags = data;
4940 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4941 pdevice = &pPP2->DeviceSettings[ii];
4942 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4943 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4944 ioc->spi_data.nvram[ii] = data;
4945 }
4946 }
4947
4948 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4949 }
4950 }
4951
4952 /* Update Adapter limits with those from NVRAM
4953 * Comment: Don't need to do this. Target performance
4954 * parameters will never exceed the adapters limits.
4955 */
4956
4957 return rc;
4958}
4959
4960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004961/**
4962 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 * @ioc: Pointer to a Adapter Strucutre
4964 * @portnum: IOC port number
4965 *
4966 * Return: -EFAULT if read of config page header fails
4967 * or 0 if success.
4968 */
4969static int
4970mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
4971{
4972 CONFIGPARMS cfg;
4973 ConfigPageHeader_t header;
4974
4975 /* Read the SCSI Device Page 1 header
4976 */
4977 header.PageVersion = 0;
4978 header.PageLength = 0;
4979 header.PageNumber = 1;
4980 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004981 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 cfg.physAddr = -1;
4983 cfg.pageAddr = portnum;
4984 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4985 cfg.dir = 0;
4986 cfg.timeout = 0;
4987 if (mpt_config(ioc, &cfg) != 0)
4988 return -EFAULT;
4989
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004990 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
4991 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992
4993 header.PageVersion = 0;
4994 header.PageLength = 0;
4995 header.PageNumber = 0;
4996 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
4997 if (mpt_config(ioc, &cfg) != 0)
4998 return -EFAULT;
4999
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005000 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5001 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002
Prakash, Sathya436ace72007-07-24 15:42:08 +05305003 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5005
Prakash, Sathya436ace72007-07-24 15:42:08 +05305006 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5008 return 0;
5009}
5010
Eric Mooreb506ade2007-01-29 09:45:37 -07005011/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005012 * mpt_inactive_raid_list_free - This clears this link list.
5013 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005014 **/
5015static void
5016mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5017{
5018 struct inactive_raid_component_info *component_info, *pNext;
5019
5020 if (list_empty(&ioc->raid_data.inactive_list))
5021 return;
5022
5023 down(&ioc->raid_data.inactive_list_mutex);
5024 list_for_each_entry_safe(component_info, pNext,
5025 &ioc->raid_data.inactive_list, list) {
5026 list_del(&component_info->list);
5027 kfree(component_info);
5028 }
5029 up(&ioc->raid_data.inactive_list_mutex);
5030}
5031
5032/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005033 * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
Eric Mooreb506ade2007-01-29 09:45:37 -07005034 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005035 * @ioc : pointer to per adapter structure
5036 * @channel : volume channel
5037 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005038 **/
5039static void
5040mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5041{
5042 CONFIGPARMS cfg;
5043 ConfigPageHeader_t hdr;
5044 dma_addr_t dma_handle;
5045 pRaidVolumePage0_t buffer = NULL;
5046 int i;
5047 RaidPhysDiskPage0_t phys_disk;
5048 struct inactive_raid_component_info *component_info;
5049 int handle_inactive_volumes;
5050
5051 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5052 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5053 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5054 cfg.pageAddr = (channel << 8) + id;
5055 cfg.cfghdr.hdr = &hdr;
5056 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5057
5058 if (mpt_config(ioc, &cfg) != 0)
5059 goto out;
5060
5061 if (!hdr.PageLength)
5062 goto out;
5063
5064 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5065 &dma_handle);
5066
5067 if (!buffer)
5068 goto out;
5069
5070 cfg.physAddr = dma_handle;
5071 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5072
5073 if (mpt_config(ioc, &cfg) != 0)
5074 goto out;
5075
5076 if (!buffer->NumPhysDisks)
5077 goto out;
5078
5079 handle_inactive_volumes =
5080 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5081 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5082 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5083 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5084
5085 if (!handle_inactive_volumes)
5086 goto out;
5087
5088 down(&ioc->raid_data.inactive_list_mutex);
5089 for (i = 0; i < buffer->NumPhysDisks; i++) {
5090 if(mpt_raid_phys_disk_pg0(ioc,
5091 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5092 continue;
5093
5094 if ((component_info = kmalloc(sizeof (*component_info),
5095 GFP_KERNEL)) == NULL)
5096 continue;
5097
5098 component_info->volumeID = id;
5099 component_info->volumeBus = channel;
5100 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5101 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5102 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5103 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5104
5105 list_add_tail(&component_info->list,
5106 &ioc->raid_data.inactive_list);
5107 }
5108 up(&ioc->raid_data.inactive_list_mutex);
5109
5110 out:
5111 if (buffer)
5112 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5113 dma_handle);
5114}
5115
5116/**
5117 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5118 * @ioc: Pointer to a Adapter Structure
5119 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5120 * @phys_disk: requested payload data returned
5121 *
5122 * Return:
5123 * 0 on success
5124 * -EFAULT if read of config page header fails or data pointer not NULL
5125 * -ENOMEM if pci_alloc failed
5126 **/
5127int
5128mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5129{
5130 CONFIGPARMS cfg;
5131 ConfigPageHeader_t hdr;
5132 dma_addr_t dma_handle;
5133 pRaidPhysDiskPage0_t buffer = NULL;
5134 int rc;
5135
5136 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5137 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5138
5139 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5140 cfg.cfghdr.hdr = &hdr;
5141 cfg.physAddr = -1;
5142 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5143
5144 if (mpt_config(ioc, &cfg) != 0) {
5145 rc = -EFAULT;
5146 goto out;
5147 }
5148
5149 if (!hdr.PageLength) {
5150 rc = -EFAULT;
5151 goto out;
5152 }
5153
5154 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5155 &dma_handle);
5156
5157 if (!buffer) {
5158 rc = -ENOMEM;
5159 goto out;
5160 }
5161
5162 cfg.physAddr = dma_handle;
5163 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5164 cfg.pageAddr = phys_disk_num;
5165
5166 if (mpt_config(ioc, &cfg) != 0) {
5167 rc = -EFAULT;
5168 goto out;
5169 }
5170
5171 rc = 0;
5172 memcpy(phys_disk, buffer, sizeof(*buffer));
5173 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5174
5175 out:
5176
5177 if (buffer)
5178 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5179 dma_handle);
5180
5181 return rc;
5182}
5183
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184/**
5185 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5186 * @ioc: Pointer to a Adapter Strucutre
5187 * @portnum: IOC port number
5188 *
5189 * Return:
5190 * 0 on success
5191 * -EFAULT if read of config page header fails or data pointer not NULL
5192 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005193 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194int
5195mpt_findImVolumes(MPT_ADAPTER *ioc)
5196{
5197 IOCPage2_t *pIoc2;
5198 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 dma_addr_t ioc2_dma;
5200 CONFIGPARMS cfg;
5201 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 int rc = 0;
5203 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005204 int i;
5205
5206 if (!ioc->ir_firmware)
5207 return 0;
5208
5209 /* Free the old page
5210 */
5211 kfree(ioc->raid_data.pIocPg2);
5212 ioc->raid_data.pIocPg2 = NULL;
5213 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
5215 /* Read IOCP2 header then the page.
5216 */
5217 header.PageVersion = 0;
5218 header.PageLength = 0;
5219 header.PageNumber = 2;
5220 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005221 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 cfg.physAddr = -1;
5223 cfg.pageAddr = 0;
5224 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5225 cfg.dir = 0;
5226 cfg.timeout = 0;
5227 if (mpt_config(ioc, &cfg) != 0)
5228 return -EFAULT;
5229
5230 if (header.PageLength == 0)
5231 return -EFAULT;
5232
5233 iocpage2sz = header.PageLength * 4;
5234 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5235 if (!pIoc2)
5236 return -ENOMEM;
5237
5238 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5239 cfg.physAddr = ioc2_dma;
5240 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005241 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242
Eric Mooreb506ade2007-01-29 09:45:37 -07005243 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5244 if (!mem)
5245 goto out;
5246
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005248 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249
Eric Mooreb506ade2007-01-29 09:45:37 -07005250 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251
Eric Mooreb506ade2007-01-29 09:45:37 -07005252 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5253 mpt_inactive_raid_volumes(ioc,
5254 pIoc2->RaidVolume[i].VolumeBus,
5255 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256
Eric Mooreb506ade2007-01-29 09:45:37 -07005257 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5259
5260 return rc;
5261}
5262
Moore, Ericc972c702006-03-14 09:14:06 -07005263static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5265{
5266 IOCPage3_t *pIoc3;
5267 u8 *mem;
5268 CONFIGPARMS cfg;
5269 ConfigPageHeader_t header;
5270 dma_addr_t ioc3_dma;
5271 int iocpage3sz = 0;
5272
5273 /* Free the old page
5274 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005275 kfree(ioc->raid_data.pIocPg3);
5276 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
5278 /* There is at least one physical disk.
5279 * Read and save IOC Page 3
5280 */
5281 header.PageVersion = 0;
5282 header.PageLength = 0;
5283 header.PageNumber = 3;
5284 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005285 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 cfg.physAddr = -1;
5287 cfg.pageAddr = 0;
5288 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5289 cfg.dir = 0;
5290 cfg.timeout = 0;
5291 if (mpt_config(ioc, &cfg) != 0)
5292 return 0;
5293
5294 if (header.PageLength == 0)
5295 return 0;
5296
5297 /* Read Header good, alloc memory
5298 */
5299 iocpage3sz = header.PageLength * 4;
5300 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5301 if (!pIoc3)
5302 return 0;
5303
5304 /* Read the Page and save the data
5305 * into malloc'd memory.
5306 */
5307 cfg.physAddr = ioc3_dma;
5308 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5309 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005310 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 if (mem) {
5312 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005313 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 }
5315 }
5316
5317 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5318
5319 return 0;
5320}
5321
5322static void
5323mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5324{
5325 IOCPage4_t *pIoc4;
5326 CONFIGPARMS cfg;
5327 ConfigPageHeader_t header;
5328 dma_addr_t ioc4_dma;
5329 int iocpage4sz;
5330
5331 /* Read and save IOC Page 4
5332 */
5333 header.PageVersion = 0;
5334 header.PageLength = 0;
5335 header.PageNumber = 4;
5336 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005337 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 cfg.physAddr = -1;
5339 cfg.pageAddr = 0;
5340 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5341 cfg.dir = 0;
5342 cfg.timeout = 0;
5343 if (mpt_config(ioc, &cfg) != 0)
5344 return;
5345
5346 if (header.PageLength == 0)
5347 return;
5348
5349 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5350 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5351 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5352 if (!pIoc4)
5353 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005354 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 } else {
5356 ioc4_dma = ioc->spi_data.IocPg4_dma;
5357 iocpage4sz = ioc->spi_data.IocPg4Sz;
5358 }
5359
5360 /* Read the Page into dma memory.
5361 */
5362 cfg.physAddr = ioc4_dma;
5363 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5364 if (mpt_config(ioc, &cfg) == 0) {
5365 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5366 ioc->spi_data.IocPg4_dma = ioc4_dma;
5367 ioc->spi_data.IocPg4Sz = iocpage4sz;
5368 } else {
5369 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5370 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005371 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 }
5373}
5374
5375static void
5376mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5377{
5378 IOCPage1_t *pIoc1;
5379 CONFIGPARMS cfg;
5380 ConfigPageHeader_t header;
5381 dma_addr_t ioc1_dma;
5382 int iocpage1sz = 0;
5383 u32 tmp;
5384
5385 /* Check the Coalescing Timeout in IOC Page 1
5386 */
5387 header.PageVersion = 0;
5388 header.PageLength = 0;
5389 header.PageNumber = 1;
5390 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005391 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 cfg.physAddr = -1;
5393 cfg.pageAddr = 0;
5394 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5395 cfg.dir = 0;
5396 cfg.timeout = 0;
5397 if (mpt_config(ioc, &cfg) != 0)
5398 return;
5399
5400 if (header.PageLength == 0)
5401 return;
5402
5403 /* Read Header good, alloc memory
5404 */
5405 iocpage1sz = header.PageLength * 4;
5406 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5407 if (!pIoc1)
5408 return;
5409
5410 /* Read the Page and check coalescing timeout
5411 */
5412 cfg.physAddr = ioc1_dma;
5413 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5414 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305415
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5417 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5418 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5419
Prakash, Sathya436ace72007-07-24 15:42:08 +05305420 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 ioc->name, tmp));
5422
5423 if (tmp > MPT_COALESCING_TIMEOUT) {
5424 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5425
5426 /* Write NVRAM and current
5427 */
5428 cfg.dir = 1;
5429 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5430 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305431 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 ioc->name, MPT_COALESCING_TIMEOUT));
5433
5434 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5435 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305436 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5437 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 ioc->name, MPT_COALESCING_TIMEOUT));
5439 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305440 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5441 "Reset NVRAM Coalescing Timeout Failed\n",
5442 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 }
5444
5445 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305446 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5447 "Reset of Current Coalescing Timeout Failed!\n",
5448 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 }
5450 }
5451
5452 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305453 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 }
5455 }
5456
5457 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5458
5459 return;
5460}
5461
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305462static void
5463mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5464{
5465 CONFIGPARMS cfg;
5466 ConfigPageHeader_t hdr;
5467 dma_addr_t buf_dma;
5468 ManufacturingPage0_t *pbuf = NULL;
5469
5470 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5471 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5472
5473 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5474 cfg.cfghdr.hdr = &hdr;
5475 cfg.physAddr = -1;
5476 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5477 cfg.timeout = 10;
5478
5479 if (mpt_config(ioc, &cfg) != 0)
5480 goto out;
5481
5482 if (!cfg.cfghdr.hdr->PageLength)
5483 goto out;
5484
5485 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5486 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5487 if (!pbuf)
5488 goto out;
5489
5490 cfg.physAddr = buf_dma;
5491
5492 if (mpt_config(ioc, &cfg) != 0)
5493 goto out;
5494
5495 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5496 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5497 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5498
5499 out:
5500
5501 if (pbuf)
5502 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5503}
5504
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005506/**
5507 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 * @ioc: Pointer to MPT_ADAPTER structure
5509 * @EvSwitch: Event switch flags
5510 */
5511static int
5512SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5513{
5514 EventNotification_t *evnp;
5515
5516 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5517 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305518 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 ioc->name));
5520 return 0;
5521 }
5522 memset(evnp, 0, sizeof(*evnp));
5523
Prakash, Sathya436ace72007-07-24 15:42:08 +05305524 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
5526 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5527 evnp->ChainOffset = 0;
5528 evnp->MsgFlags = 0;
5529 evnp->Switch = EvSwitch;
5530
5531 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5532
5533 return 0;
5534}
5535
5536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5537/**
5538 * SendEventAck - Send EventAck request to MPT adapter.
5539 * @ioc: Pointer to MPT_ADAPTER structure
5540 * @evnp: Pointer to original EventNotification request
5541 */
5542static int
5543SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5544{
5545 EventAck_t *pAck;
5546
5547 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305548 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005549 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 return -1;
5551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552
Prakash, Sathya436ace72007-07-24 15:42:08 +05305553 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
5555 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5556 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005557 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005559 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 pAck->Event = evnp->Event;
5561 pAck->EventContext = evnp->EventContext;
5562
5563 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5564
5565 return 0;
5566}
5567
5568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5569/**
5570 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005571 * @ioc: Pointer to an adapter structure
5572 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 * action, page address, direction, physical address
5574 * and pointer to a configuration page header
5575 * Page header is updated.
5576 *
5577 * Returns 0 for success
5578 * -EPERM if not allowed due to ISR context
5579 * -EAGAIN if no msg frames currently available
5580 * -EFAULT for non-successful reply or no reply (timeout)
5581 */
5582int
5583mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5584{
5585 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005586 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587 MPT_FRAME_HDR *mf;
5588 unsigned long flags;
5589 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005590 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 int in_isr;
5592
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005593 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 * to be in ISR context, because that is fatal!
5595 */
5596 in_isr = in_interrupt();
5597 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305598 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 ioc->name));
5600 return -EPERM;
5601 }
5602
5603 /* Get and Populate a free Frame
5604 */
5605 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305606 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 ioc->name));
5608 return -EAGAIN;
5609 }
5610 pReq = (Config_t *)mf;
5611 pReq->Action = pCfg->action;
5612 pReq->Reserved = 0;
5613 pReq->ChainOffset = 0;
5614 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005615
5616 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 pReq->ExtPageLength = 0;
5618 pReq->ExtPageType = 0;
5619 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005620
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 for (ii=0; ii < 8; ii++)
5622 pReq->Reserved2[ii] = 0;
5623
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005624 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5625 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5626 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5627 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5628
5629 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5630 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5631 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5632 pReq->ExtPageType = pExtHdr->ExtPageType;
5633 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5634
5635 /* Page Length must be treated as a reserved field for the extended header. */
5636 pReq->Header.PageLength = 0;
5637 }
5638
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5640
5641 /* Add a SGE to the config request.
5642 */
5643 if (pCfg->dir)
5644 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5645 else
5646 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5647
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005648 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5649 flagsLength |= pExtHdr->ExtPageLength * 4;
5650
Prakash, Sathya436ace72007-07-24 15:42:08 +05305651 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005652 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5653 }
5654 else {
5655 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5656
Prakash, Sathya436ace72007-07-24 15:42:08 +05305657 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005658 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660
5661 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5662
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 /* Append pCfg pointer to end of mf
5664 */
5665 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5666
5667 /* Initalize the timer
5668 */
5669 init_timer(&pCfg->timer);
5670 pCfg->timer.data = (unsigned long) ioc;
5671 pCfg->timer.function = mpt_timer_expired;
5672 pCfg->wait_done = 0;
5673
5674 /* Set the timer; ensure 10 second minimum */
5675 if (pCfg->timeout < 10)
5676 pCfg->timer.expires = jiffies + HZ*10;
5677 else
5678 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5679
5680 /* Add to end of Q, set timer and then issue this command */
5681 spin_lock_irqsave(&ioc->FreeQlock, flags);
5682 list_add_tail(&pCfg->linkage, &ioc->configQ);
5683 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5684
5685 add_timer(&pCfg->timer);
5686 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5687 wait_event(mpt_waitq, pCfg->wait_done);
5688
5689 /* mf has been freed - do not access */
5690
5691 rc = pCfg->status;
5692
5693 return rc;
5694}
5695
5696/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005697/**
5698 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 * Used only internal config functionality.
5700 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5701 */
5702static void
5703mpt_timer_expired(unsigned long data)
5704{
5705 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5706
Prakash, Sathya436ace72007-07-24 15:42:08 +05305707 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
5709 /* Perform a FW reload */
5710 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5711 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5712
5713 /* No more processing.
5714 * Hard reset clean-up will wake up
5715 * process and free all resources.
5716 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305717 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718
5719 return;
5720}
5721
5722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005723/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 * mpt_ioc_reset - Base cleanup for hard reset
5725 * @ioc: Pointer to the adapter structure
5726 * @reset_phase: Indicates pre- or post-reset functionality
5727 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005728 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 */
5730static int
5731mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5732{
5733 CONFIGPARMS *pCfg;
5734 unsigned long flags;
5735
Prakash, Sathya436ace72007-07-24 15:42:08 +05305736 dprintk(ioc, printk(KERN_DEBUG MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 ": IOC %s_reset routed to MPT base driver!\n",
5738 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5739 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5740
5741 if (reset_phase == MPT_IOC_SETUP_RESET) {
5742 ;
5743 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5744 /* If the internal config Q is not empty -
5745 * delete timer. MF resources will be freed when
5746 * the FIFO's are primed.
5747 */
5748 spin_lock_irqsave(&ioc->FreeQlock, flags);
5749 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5750 del_timer(&pCfg->timer);
5751 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5752
5753 } else {
5754 CONFIGPARMS *pNext;
5755
5756 /* Search the configQ for internal commands.
5757 * Flush the Q, and wake up all suspended threads.
5758 */
5759 spin_lock_irqsave(&ioc->FreeQlock, flags);
5760 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5761 list_del(&pCfg->linkage);
5762
5763 pCfg->status = MPT_CONFIG_ERROR;
5764 pCfg->wait_done = 1;
5765 wake_up(&mpt_waitq);
5766 }
5767 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5768 }
5769
5770 return 1; /* currently means nothing really */
5771}
5772
5773
5774#ifdef CONFIG_PROC_FS /* { */
5775/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5776/*
5777 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5778 */
5779/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005780/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5782 *
5783 * Returns 0 for success, non-zero for failure.
5784 */
5785static int
5786procmpt_create(void)
5787{
5788 struct proc_dir_entry *ent;
5789
5790 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5791 if (mpt_proc_root_dir == NULL)
5792 return -ENOTDIR;
5793
5794 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5795 if (ent)
5796 ent->read_proc = procmpt_summary_read;
5797
5798 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5799 if (ent)
5800 ent->read_proc = procmpt_version_read;
5801
5802 return 0;
5803}
5804
5805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005806/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5808 *
5809 * Returns 0 for success, non-zero for failure.
5810 */
5811static void
5812procmpt_destroy(void)
5813{
5814 remove_proc_entry("version", mpt_proc_root_dir);
5815 remove_proc_entry("summary", mpt_proc_root_dir);
5816 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5817}
5818
5819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005820/**
5821 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 * @buf: Pointer to area to write information
5823 * @start: Pointer to start pointer
5824 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005825 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 * @eof: Pointer to EOF integer
5827 * @data: Pointer
5828 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005829 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 * Returns number of characters written to process performing the read.
5831 */
5832static int
5833procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5834{
5835 MPT_ADAPTER *ioc;
5836 char *out = buf;
5837 int len;
5838
5839 if (data) {
5840 int more = 0;
5841
5842 ioc = data;
5843 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5844
5845 out += more;
5846 } else {
5847 list_for_each_entry(ioc, &ioc_list, list) {
5848 int more = 0;
5849
5850 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5851
5852 out += more;
5853 if ((out-buf) >= request)
5854 break;
5855 }
5856 }
5857
5858 len = out - buf;
5859
5860 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5861}
5862
5863/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005864/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865 * procmpt_version_read - Handle read request from /proc/mpt/version.
5866 * @buf: Pointer to area to write information
5867 * @start: Pointer to start pointer
5868 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005869 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 * @eof: Pointer to EOF integer
5871 * @data: Pointer
5872 *
5873 * Returns number of characters written to process performing the read.
5874 */
5875static int
5876procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5877{
5878 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005879 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 char *drvname;
5881 int len;
5882
5883 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5884 len += sprintf(buf+len, " Fusion MPT base driver\n");
5885
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005886 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5888 drvname = NULL;
5889 if (MptCallbacks[ii]) {
5890 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005891 case MPTSPI_DRIVER:
5892 if (!scsi++) drvname = "SPI host";
5893 break;
5894 case MPTFC_DRIVER:
5895 if (!fc++) drvname = "FC host";
5896 break;
5897 case MPTSAS_DRIVER:
5898 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 break;
5900 case MPTLAN_DRIVER:
5901 if (!lan++) drvname = "LAN";
5902 break;
5903 case MPTSTM_DRIVER:
5904 if (!targ++) drvname = "SCSI target";
5905 break;
5906 case MPTCTL_DRIVER:
5907 if (!ctl++) drvname = "ioctl";
5908 break;
5909 }
5910
5911 if (drvname)
5912 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5913 }
5914 }
5915
5916 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5917}
5918
5919/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005920/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5922 * @buf: Pointer to area to write information
5923 * @start: Pointer to start pointer
5924 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005925 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 * @eof: Pointer to EOF integer
5927 * @data: Pointer
5928 *
5929 * Returns number of characters written to process performing the read.
5930 */
5931static int
5932procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5933{
5934 MPT_ADAPTER *ioc = data;
5935 int len;
5936 char expVer[32];
5937 int sz;
5938 int p;
5939
5940 mpt_get_fw_exp_ver(expVer, ioc);
5941
5942 len = sprintf(buf, "%s:", ioc->name);
5943 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5944 len += sprintf(buf+len, " (f/w download boot flag set)");
5945// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5946// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5947
5948 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5949 ioc->facts.ProductID,
5950 ioc->prod_name);
5951 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5952 if (ioc->facts.FWImageSize)
5953 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5954 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5955 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5956 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5957
5958 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5959 ioc->facts.CurrentHostMfaHighAddr);
5960 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5961 ioc->facts.CurrentSenseBufferHighAddr);
5962
5963 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5964 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5965
5966 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5967 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
5968 /*
5969 * Rounding UP to nearest 4-kB boundary here...
5970 */
5971 sz = (ioc->req_sz * ioc->req_depth) + 128;
5972 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
5973 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
5974 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
5975 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
5976 4*ioc->facts.RequestFrameSize,
5977 ioc->facts.GlobalCredits);
5978
5979 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
5980 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
5981 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
5982 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
5983 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
5984 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
5985 ioc->facts.CurReplyFrameSize,
5986 ioc->facts.ReplyQueueDepth);
5987
5988 len += sprintf(buf+len, " MaxDevices = %d\n",
5989 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
5990 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
5991
5992 /* per-port info */
5993 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
5994 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
5995 p+1,
5996 ioc->facts.NumberOfPorts);
5997 if (ioc->bus_type == FC) {
5998 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
5999 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6000 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6001 a[5], a[4], a[3], a[2], a[1], a[0]);
6002 }
6003 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6004 ioc->fc_port_page0[p].WWNN.High,
6005 ioc->fc_port_page0[p].WWNN.Low,
6006 ioc->fc_port_page0[p].WWPN.High,
6007 ioc->fc_port_page0[p].WWPN.Low);
6008 }
6009 }
6010
6011 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6012}
6013
6014#endif /* CONFIG_PROC_FS } */
6015
6016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6017static void
6018mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6019{
6020 buf[0] ='\0';
6021 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6022 sprintf(buf, " (Exp %02d%02d)",
6023 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6024 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6025
6026 /* insider hack! */
6027 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6028 strcat(buf, " [MDBG]");
6029 }
6030}
6031
6032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6033/**
6034 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6035 * @ioc: Pointer to MPT_ADAPTER structure
6036 * @buffer: Pointer to buffer where IOC summary info should be written
6037 * @size: Pointer to number of bytes we wrote (set by this routine)
6038 * @len: Offset at which to start writing in buffer
6039 * @showlan: Display LAN stuff?
6040 *
6041 * This routine writes (english readable) ASCII text, which represents
6042 * a summary of IOC information, to a buffer.
6043 */
6044void
6045mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6046{
6047 char expVer[32];
6048 int y;
6049
6050 mpt_get_fw_exp_ver(expVer, ioc);
6051
6052 /*
6053 * Shorter summary of attached ioc's...
6054 */
6055 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6056 ioc->name,
6057 ioc->prod_name,
6058 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6059 ioc->facts.FWVersion.Word,
6060 expVer,
6061 ioc->facts.NumberOfPorts,
6062 ioc->req_depth);
6063
6064 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6065 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6066 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6067 a[5], a[4], a[3], a[2], a[1], a[0]);
6068 }
6069
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
6072 if (!ioc->active)
6073 y += sprintf(buffer+len+y, " (disabled)");
6074
6075 y += sprintf(buffer+len+y, "\n");
6076
6077 *size = y;
6078}
6079
6080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6081/*
6082 * Reset Handling
6083 */
6084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6085/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006086 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 * @ioc: Pointer to MPT_ADAPTER structure
6088 * @sleepFlag: Indicates if sleep or schedule must be called.
6089 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006090 * Issues SCSI Task Management call based on input arg values.
6091 * If TaskMgmt fails, returns associated SCSI request.
6092 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6094 * or a non-interrupt thread. In the former, must not call schedule().
6095 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006096 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 * FW reload/initialization failed.
6098 *
6099 * Returns 0 for SUCCESS or -1 if FAILED.
6100 */
6101int
6102mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6103{
6104 int rc;
6105 unsigned long flags;
6106
Prakash, Sathya436ace72007-07-24 15:42:08 +05306107 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108#ifdef MFCNT
6109 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6110 printk("MF count 0x%x !\n", ioc->mfcnt);
6111#endif
6112
6113 /* Reset the adapter. Prevent more than 1 call to
6114 * mpt_do_ioc_recovery at any instant in time.
6115 */
6116 spin_lock_irqsave(&ioc->diagLock, flags);
6117 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6118 spin_unlock_irqrestore(&ioc->diagLock, flags);
6119 return 0;
6120 } else {
6121 ioc->diagPending = 1;
6122 }
6123 spin_unlock_irqrestore(&ioc->diagLock, flags);
6124
6125 /* FIXME: If do_ioc_recovery fails, repeat....
6126 */
6127
6128 /* The SCSI driver needs to adjust timeouts on all current
6129 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006130 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 * For all other protocol drivers, this is a no-op.
6132 */
6133 {
6134 int ii;
6135 int r = 0;
6136
6137 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6138 if (MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306139 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006141 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306143 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006145 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147 }
6148 }
6149 }
6150
6151 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
6152 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
6153 rc, ioc->name);
6154 }
6155 ioc->reload_fw = 0;
6156 if (ioc->alt_ioc)
6157 ioc->alt_ioc->reload_fw = 0;
6158
6159 spin_lock_irqsave(&ioc->diagLock, flags);
6160 ioc->diagPending = 0;
6161 if (ioc->alt_ioc)
6162 ioc->alt_ioc->diagPending = 0;
6163 spin_unlock_irqrestore(&ioc->diagLock, flags);
6164
Prakash, Sathya436ace72007-07-24 15:42:08 +05306165 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
6167 return rc;
6168}
6169
6170/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006171static void
6172EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173{
Eric Moore509e5e52006-04-26 13:22:37 -06006174 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175
6176 switch(event) {
6177 case MPI_EVENT_NONE:
6178 ds = "None";
6179 break;
6180 case MPI_EVENT_LOG_DATA:
6181 ds = "Log Data";
6182 break;
6183 case MPI_EVENT_STATE_CHANGE:
6184 ds = "State Change";
6185 break;
6186 case MPI_EVENT_UNIT_ATTENTION:
6187 ds = "Unit Attention";
6188 break;
6189 case MPI_EVENT_IOC_BUS_RESET:
6190 ds = "IOC Bus Reset";
6191 break;
6192 case MPI_EVENT_EXT_BUS_RESET:
6193 ds = "External Bus Reset";
6194 break;
6195 case MPI_EVENT_RESCAN:
6196 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 break;
6198 case MPI_EVENT_LINK_STATUS_CHANGE:
6199 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6200 ds = "Link Status(FAILURE) Change";
6201 else
6202 ds = "Link Status(ACTIVE) Change";
6203 break;
6204 case MPI_EVENT_LOOP_STATE_CHANGE:
6205 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6206 ds = "Loop State(LIP) Change";
6207 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006208 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 else
Eric Moore509e5e52006-04-26 13:22:37 -06006210 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 break;
6212 case MPI_EVENT_LOGOUT:
6213 ds = "Logout";
6214 break;
6215 case MPI_EVENT_EVENT_CHANGE:
6216 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006217 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006219 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 break;
6221 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006222 {
6223 u8 ReasonCode = (u8)(evData0 >> 16);
6224 switch (ReasonCode) {
6225 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6226 ds = "Integrated Raid: Volume Created";
6227 break;
6228 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6229 ds = "Integrated Raid: Volume Deleted";
6230 break;
6231 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6232 ds = "Integrated Raid: Volume Settings Changed";
6233 break;
6234 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6235 ds = "Integrated Raid: Volume Status Changed";
6236 break;
6237 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6238 ds = "Integrated Raid: Volume Physdisk Changed";
6239 break;
6240 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6241 ds = "Integrated Raid: Physdisk Created";
6242 break;
6243 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6244 ds = "Integrated Raid: Physdisk Deleted";
6245 break;
6246 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6247 ds = "Integrated Raid: Physdisk Settings Changed";
6248 break;
6249 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6250 ds = "Integrated Raid: Physdisk Status Changed";
6251 break;
6252 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6253 ds = "Integrated Raid: Domain Validation Needed";
6254 break;
6255 case MPI_EVENT_RAID_RC_SMART_DATA :
6256 ds = "Integrated Raid; Smart Data";
6257 break;
6258 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6259 ds = "Integrated Raid: Replace Action Started";
6260 break;
6261 default:
6262 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006264 }
6265 break;
6266 }
6267 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6268 ds = "SCSI Device Status Change";
6269 break;
6270 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6271 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006272 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006273 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006274 u8 ReasonCode = (u8)(evData0 >> 16);
6275 switch (ReasonCode) {
6276 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006277 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006278 "SAS Device Status Change: Added: "
6279 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006280 break;
6281 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006282 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006283 "SAS Device Status Change: Deleted: "
6284 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006285 break;
6286 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006287 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006288 "SAS Device Status Change: SMART Data: "
6289 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006290 break;
6291 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006292 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006293 "SAS Device Status Change: No Persistancy: "
6294 "id=%d channel=%d", id, channel);
6295 break;
6296 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6297 snprintf(evStr, EVENT_DESCR_STR_SZ,
6298 "SAS Device Status Change: Unsupported Device "
6299 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006300 break;
6301 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6302 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006303 "SAS Device Status Change: Internal Device "
6304 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006305 break;
6306 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6307 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006308 "SAS Device Status Change: Internal Task "
6309 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006310 break;
6311 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6312 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006313 "SAS Device Status Change: Internal Abort "
6314 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006315 break;
6316 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6317 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006318 "SAS Device Status Change: Internal Clear "
6319 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006320 break;
6321 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6322 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006323 "SAS Device Status Change: Internal Query "
6324 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006325 break;
6326 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006327 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006328 "SAS Device Status Change: Unknown: "
6329 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006330 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006331 }
6332 break;
6333 }
6334 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6335 ds = "Bus Timer Expired";
6336 break;
6337 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006338 {
6339 u16 curr_depth = (u16)(evData0 >> 16);
6340 u8 channel = (u8)(evData0 >> 8);
6341 u8 id = (u8)(evData0);
6342
6343 snprintf(evStr, EVENT_DESCR_STR_SZ,
6344 "Queue Full: channel=%d id=%d depth=%d",
6345 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006346 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006347 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006348 case MPI_EVENT_SAS_SES:
6349 ds = "SAS SES Event";
6350 break;
6351 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6352 ds = "Persistent Table Full";
6353 break;
6354 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006355 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006356 u8 LinkRates = (u8)(evData0 >> 8);
6357 u8 PhyNumber = (u8)(evData0);
6358 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6359 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6360 switch (LinkRates) {
6361 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006362 snprintf(evStr, EVENT_DESCR_STR_SZ,
6363 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006364 " Rate Unknown",PhyNumber);
6365 break;
6366 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006367 snprintf(evStr, EVENT_DESCR_STR_SZ,
6368 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006369 " Phy Disabled",PhyNumber);
6370 break;
6371 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006372 snprintf(evStr, EVENT_DESCR_STR_SZ,
6373 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006374 " Failed Speed Nego",PhyNumber);
6375 break;
6376 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006377 snprintf(evStr, EVENT_DESCR_STR_SZ,
6378 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006379 " Sata OOB Completed",PhyNumber);
6380 break;
6381 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006382 snprintf(evStr, EVENT_DESCR_STR_SZ,
6383 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006384 " Rate 1.5 Gbps",PhyNumber);
6385 break;
6386 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006387 snprintf(evStr, EVENT_DESCR_STR_SZ,
6388 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006389 " Rate 3.0 Gpbs",PhyNumber);
6390 break;
6391 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006392 snprintf(evStr, EVENT_DESCR_STR_SZ,
6393 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006394 break;
6395 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006396 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006397 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006398 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6399 ds = "SAS Discovery Error";
6400 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006401 case MPI_EVENT_IR_RESYNC_UPDATE:
6402 {
6403 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006404 snprintf(evStr, EVENT_DESCR_STR_SZ,
6405 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006406 break;
6407 }
6408 case MPI_EVENT_IR2:
6409 {
6410 u8 ReasonCode = (u8)(evData0 >> 16);
6411 switch (ReasonCode) {
6412 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6413 ds = "IR2: LD State Changed";
6414 break;
6415 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6416 ds = "IR2: PD State Changed";
6417 break;
6418 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6419 ds = "IR2: Bad Block Table Full";
6420 break;
6421 case MPI_EVENT_IR2_RC_PD_INSERTED:
6422 ds = "IR2: PD Inserted";
6423 break;
6424 case MPI_EVENT_IR2_RC_PD_REMOVED:
6425 ds = "IR2: PD Removed";
6426 break;
6427 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6428 ds = "IR2: Foreign CFG Detected";
6429 break;
6430 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6431 ds = "IR2: Rebuild Medium Error";
6432 break;
6433 default:
6434 ds = "IR2";
6435 break;
6436 }
6437 break;
6438 }
6439 case MPI_EVENT_SAS_DISCOVERY:
6440 {
6441 if (evData0)
6442 ds = "SAS Discovery: Start";
6443 else
6444 ds = "SAS Discovery: Stop";
6445 break;
6446 }
6447 case MPI_EVENT_LOG_ENTRY_ADDED:
6448 ds = "SAS Log Entry Added";
6449 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006450
Eric Moorec6c727a2007-01-29 09:44:54 -07006451 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6452 {
6453 u8 phy_num = (u8)(evData0);
6454 u8 port_num = (u8)(evData0 >> 8);
6455 u8 port_width = (u8)(evData0 >> 16);
6456 u8 primative = (u8)(evData0 >> 24);
6457 snprintf(evStr, EVENT_DESCR_STR_SZ,
6458 "SAS Broadcase Primative: phy=%d port=%d "
6459 "width=%d primative=0x%02x",
6460 phy_num, port_num, port_width, primative);
6461 break;
6462 }
6463
6464 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6465 {
6466 u8 reason = (u8)(evData0);
6467 u8 port_num = (u8)(evData0 >> 8);
6468 u16 handle = le16_to_cpu(evData0 >> 16);
6469
6470 snprintf(evStr, EVENT_DESCR_STR_SZ,
6471 "SAS Initiator Device Status Change: reason=0x%02x "
6472 "port=%d handle=0x%04x",
6473 reason, port_num, handle);
6474 break;
6475 }
6476
6477 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6478 {
6479 u8 max_init = (u8)(evData0);
6480 u8 current_init = (u8)(evData0 >> 8);
6481
6482 snprintf(evStr, EVENT_DESCR_STR_SZ,
6483 "SAS Initiator Device Table Overflow: max initiators=%02d "
6484 "current initators=%02d",
6485 max_init, current_init);
6486 break;
6487 }
6488 case MPI_EVENT_SAS_SMP_ERROR:
6489 {
6490 u8 status = (u8)(evData0);
6491 u8 port_num = (u8)(evData0 >> 8);
6492 u8 result = (u8)(evData0 >> 16);
6493
6494 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6495 snprintf(evStr, EVENT_DESCR_STR_SZ,
6496 "SAS SMP Error: port=%d result=0x%02x",
6497 port_num, result);
6498 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6499 snprintf(evStr, EVENT_DESCR_STR_SZ,
6500 "SAS SMP Error: port=%d : CRC Error",
6501 port_num);
6502 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6503 snprintf(evStr, EVENT_DESCR_STR_SZ,
6504 "SAS SMP Error: port=%d : Timeout",
6505 port_num);
6506 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6507 snprintf(evStr, EVENT_DESCR_STR_SZ,
6508 "SAS SMP Error: port=%d : No Destination",
6509 port_num);
6510 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6511 snprintf(evStr, EVENT_DESCR_STR_SZ,
6512 "SAS SMP Error: port=%d : Bad Destination",
6513 port_num);
6514 else
6515 snprintf(evStr, EVENT_DESCR_STR_SZ,
6516 "SAS SMP Error: port=%d : status=0x%02x",
6517 port_num, status);
6518 break;
6519 }
6520
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521 /*
6522 * MPT base "custom" events may be added here...
6523 */
6524 default:
6525 ds = "Unknown";
6526 break;
6527 }
Eric Moore509e5e52006-04-26 13:22:37 -06006528 if (ds)
6529 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530}
6531
6532/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006533/**
6534 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535 * @ioc: Pointer to MPT_ADAPTER structure
6536 * @pEventReply: Pointer to EventNotification reply frame
6537 * @evHandlers: Pointer to integer, number of event handlers
6538 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006539 * Routes a received EventNotificationReply to all currently registered
6540 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541 * Returns sum of event handlers return values.
6542 */
6543static int
6544ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6545{
6546 u16 evDataLen;
6547 u32 evData0 = 0;
6548// u32 evCtx;
6549 int ii;
6550 int r = 0;
6551 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006552 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 u8 event;
6554
6555 /*
6556 * Do platform normalization of values
6557 */
6558 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6559// evCtx = le32_to_cpu(pEventReply->EventContext);
6560 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6561 if (evDataLen) {
6562 evData0 = le32_to_cpu(pEventReply->Data[0]);
6563 }
6564
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006565 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306566 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006568 event,
6569 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570
Prakash, Sathya436ace72007-07-24 15:42:08 +05306571#ifdef CONFIG_FUSION_LOGGING
6572 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
6573 ": Event data:\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306575 devtverboseprintk(ioc, printk(" %08x",
6576 le32_to_cpu(pEventReply->Data[ii])));
6577 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578#endif
6579
6580 /*
6581 * Do general / base driver event processing
6582 */
6583 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006584 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6585 if (evDataLen) {
6586 u8 evState = evData0 & 0xFF;
6587
6588 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6589
6590 /* Update EventState field in cached IocFacts */
6591 if (ioc->facts.Function) {
6592 ioc->facts.EventState = evState;
6593 }
6594 }
6595 break;
Moore, Ericece50912006-01-16 18:53:19 -07006596 case MPI_EVENT_INTEGRATED_RAID:
6597 mptbase_raid_process_event_data(ioc,
6598 (MpiEventDataRaid_t *)pEventReply->Data);
6599 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006600 default:
6601 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 }
6603
6604 /*
6605 * Should this event be logged? Events are written sequentially.
6606 * When buffer is full, start again at the top.
6607 */
6608 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6609 int idx;
6610
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006611 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006612
6613 ioc->events[idx].event = event;
6614 ioc->events[idx].eventContext = ioc->eventContext;
6615
6616 for (ii = 0; ii < 2; ii++) {
6617 if (ii < evDataLen)
6618 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6619 else
6620 ioc->events[idx].data[ii] = 0;
6621 }
6622
6623 ioc->eventContext++;
6624 }
6625
6626
6627 /*
6628 * Call each currently registered protocol event handler.
6629 */
6630 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6631 if (MptEvHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306632 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633 ioc->name, ii));
6634 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6635 handlers++;
6636 }
6637 }
6638 /* FIXME? Examine results here? */
6639
6640 /*
6641 * If needed, send (a single) EventAck.
6642 */
6643 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306644 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006645 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306647 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648 ioc->name, ii));
6649 }
6650 }
6651
6652 *evHandlers = handlers;
6653 return r;
6654}
6655
6656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006657/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6659 * @ioc: Pointer to MPT_ADAPTER structure
6660 * @log_info: U32 LogInfo reply word from the IOC
6661 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006662 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663 */
6664static void
6665mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6666{
Eric Moore7c431e52007-06-13 16:34:36 -06006667 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668
Eric Moore7c431e52007-06-13 16:34:36 -06006669 switch (log_info & 0xFF000000) {
6670 case MPI_IOCLOGINFO_FC_INIT_BASE:
6671 desc = "FCP Initiator";
6672 break;
6673 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6674 desc = "FCP Target";
6675 break;
6676 case MPI_IOCLOGINFO_FC_LAN_BASE:
6677 desc = "LAN";
6678 break;
6679 case MPI_IOCLOGINFO_FC_MSG_BASE:
6680 desc = "MPI Message Layer";
6681 break;
6682 case MPI_IOCLOGINFO_FC_LINK_BASE:
6683 desc = "FC Link";
6684 break;
6685 case MPI_IOCLOGINFO_FC_CTX_BASE:
6686 desc = "Context Manager";
6687 break;
6688 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6689 desc = "Invalid Field Offset";
6690 break;
6691 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6692 desc = "State Change Info";
6693 break;
6694 }
6695
6696 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6697 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698}
6699
6700/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006701/**
Moore, Eric335a9412006-01-17 17:06:23 -07006702 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 * @ioc: Pointer to MPT_ADAPTER structure
6704 * @mr: Pointer to MPT reply frame
6705 * @log_info: U32 LogInfo word from the IOC
6706 *
6707 * Refer to lsi/sp_log.h.
6708 */
6709static void
Moore, Eric335a9412006-01-17 17:06:23 -07006710mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711{
6712 u32 info = log_info & 0x00FF0000;
6713 char *desc = "unknown";
6714
6715 switch (info) {
6716 case 0x00010000:
6717 desc = "bug! MID not found";
6718 if (ioc->reload_fw == 0)
6719 ioc->reload_fw++;
6720 break;
6721
6722 case 0x00020000:
6723 desc = "Parity Error";
6724 break;
6725
6726 case 0x00030000:
6727 desc = "ASYNC Outbound Overrun";
6728 break;
6729
6730 case 0x00040000:
6731 desc = "SYNC Offset Error";
6732 break;
6733
6734 case 0x00050000:
6735 desc = "BM Change";
6736 break;
6737
6738 case 0x00060000:
6739 desc = "Msg In Overflow";
6740 break;
6741
6742 case 0x00070000:
6743 desc = "DMA Error";
6744 break;
6745
6746 case 0x00080000:
6747 desc = "Outbound DMA Overrun";
6748 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006749
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750 case 0x00090000:
6751 desc = "Task Management";
6752 break;
6753
6754 case 0x000A0000:
6755 desc = "Device Problem";
6756 break;
6757
6758 case 0x000B0000:
6759 desc = "Invalid Phase Change";
6760 break;
6761
6762 case 0x000C0000:
6763 desc = "Untagged Table Size";
6764 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006765
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766 }
6767
6768 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6769}
6770
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006771/* strings for sas loginfo */
6772 static char *originator_str[] = {
6773 "IOP", /* 00h */
6774 "PL", /* 01h */
6775 "IR" /* 02h */
6776 };
6777 static char *iop_code_str[] = {
6778 NULL, /* 00h */
6779 "Invalid SAS Address", /* 01h */
6780 NULL, /* 02h */
6781 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006782 "Diag Message Error", /* 04h */
6783 "Task Terminated", /* 05h */
6784 "Enclosure Management", /* 06h */
6785 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006786 };
6787 static char *pl_code_str[] = {
6788 NULL, /* 00h */
6789 "Open Failure", /* 01h */
6790 "Invalid Scatter Gather List", /* 02h */
6791 "Wrong Relative Offset or Frame Length", /* 03h */
6792 "Frame Transfer Error", /* 04h */
6793 "Transmit Frame Connected Low", /* 05h */
6794 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6795 "SATA Read Log Receive Data Error", /* 07h */
6796 "SATA NCQ Fail All Commands After Error", /* 08h */
6797 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6798 "Receive Frame Invalid Message", /* 0Ah */
6799 "Receive Context Message Valid Error", /* 0Bh */
6800 "Receive Frame Current Frame Error", /* 0Ch */
6801 "SATA Link Down", /* 0Dh */
6802 "Discovery SATA Init W IOS", /* 0Eh */
6803 "Config Invalid Page", /* 0Fh */
6804 "Discovery SATA Init Timeout", /* 10h */
6805 "Reset", /* 11h */
6806 "Abort", /* 12h */
6807 "IO Not Yet Executed", /* 13h */
6808 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006809 "Persistent Reservation Out Not Affiliation "
6810 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006811 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006812 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006813 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006814 NULL, /* 19h */
6815 NULL, /* 1Ah */
6816 NULL, /* 1Bh */
6817 NULL, /* 1Ch */
6818 NULL, /* 1Dh */
6819 NULL, /* 1Eh */
6820 NULL, /* 1Fh */
6821 "Enclosure Management" /* 20h */
6822 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006823 static char *ir_code_str[] = {
6824 "Raid Action Error", /* 00h */
6825 NULL, /* 00h */
6826 NULL, /* 01h */
6827 NULL, /* 02h */
6828 NULL, /* 03h */
6829 NULL, /* 04h */
6830 NULL, /* 05h */
6831 NULL, /* 06h */
6832 NULL /* 07h */
6833 };
6834 static char *raid_sub_code_str[] = {
6835 NULL, /* 00h */
6836 "Volume Creation Failed: Data Passed too "
6837 "Large", /* 01h */
6838 "Volume Creation Failed: Duplicate Volumes "
6839 "Attempted", /* 02h */
6840 "Volume Creation Failed: Max Number "
6841 "Supported Volumes Exceeded", /* 03h */
6842 "Volume Creation Failed: DMA Error", /* 04h */
6843 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6844 "Volume Creation Failed: Error Reading "
6845 "MFG Page 4", /* 06h */
6846 "Volume Creation Failed: Creating Internal "
6847 "Structures", /* 07h */
6848 NULL, /* 08h */
6849 NULL, /* 09h */
6850 NULL, /* 0Ah */
6851 NULL, /* 0Bh */
6852 NULL, /* 0Ch */
6853 NULL, /* 0Dh */
6854 NULL, /* 0Eh */
6855 NULL, /* 0Fh */
6856 "Activation failed: Already Active Volume", /* 10h */
6857 "Activation failed: Unsupported Volume Type", /* 11h */
6858 "Activation failed: Too Many Active Volumes", /* 12h */
6859 "Activation failed: Volume ID in Use", /* 13h */
6860 "Activation failed: Reported Failure", /* 14h */
6861 "Activation failed: Importing a Volume", /* 15h */
6862 NULL, /* 16h */
6863 NULL, /* 17h */
6864 NULL, /* 18h */
6865 NULL, /* 19h */
6866 NULL, /* 1Ah */
6867 NULL, /* 1Bh */
6868 NULL, /* 1Ch */
6869 NULL, /* 1Dh */
6870 NULL, /* 1Eh */
6871 NULL, /* 1Fh */
6872 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6873 "Phys Disk failed: Data Passed too Large", /* 21h */
6874 "Phys Disk failed: DMA Error", /* 22h */
6875 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6876 "Phys Disk failed: Creating Phys Disk Config "
6877 "Page", /* 24h */
6878 NULL, /* 25h */
6879 NULL, /* 26h */
6880 NULL, /* 27h */
6881 NULL, /* 28h */
6882 NULL, /* 29h */
6883 NULL, /* 2Ah */
6884 NULL, /* 2Bh */
6885 NULL, /* 2Ch */
6886 NULL, /* 2Dh */
6887 NULL, /* 2Eh */
6888 NULL, /* 2Fh */
6889 "Compatibility Error: IR Disabled", /* 30h */
6890 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6891 "Compatibility Error: Device not Direct Access "
6892 "Device ", /* 32h */
6893 "Compatibility Error: Removable Device Found", /* 33h */
6894 "Compatibility Error: Device SCSI Version not "
6895 "2 or Higher", /* 34h */
6896 "Compatibility Error: SATA Device, 48 BIT LBA "
6897 "not Supported", /* 35h */
6898 "Compatibility Error: Device doesn't have "
6899 "512 Byte Block Sizes", /* 36h */
6900 "Compatibility Error: Volume Type Check Failed", /* 37h */
6901 "Compatibility Error: Volume Type is "
6902 "Unsupported by FW", /* 38h */
6903 "Compatibility Error: Disk Drive too Small for "
6904 "use in Volume", /* 39h */
6905 "Compatibility Error: Phys Disk for Create "
6906 "Volume not Found", /* 3Ah */
6907 "Compatibility Error: Too Many or too Few "
6908 "Disks for Volume Type", /* 3Bh */
6909 "Compatibility Error: Disk stripe Sizes "
6910 "Must be 64KB", /* 3Ch */
6911 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6912 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006913
6914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006915/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006916 * mpt_sas_log_info - Log information returned from SAS IOC.
6917 * @ioc: Pointer to MPT_ADAPTER structure
6918 * @log_info: U32 LogInfo reply word from the IOC
6919 *
6920 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006921 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006922static void
6923mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6924{
6925union loginfo_type {
6926 u32 loginfo;
6927 struct {
6928 u32 subcode:16;
6929 u32 code:8;
6930 u32 originator:4;
6931 u32 bus_type:4;
6932 }dw;
6933};
6934 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006935 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006936 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006937 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006938
6939 sas_loginfo.loginfo = log_info;
6940 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6941 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6942 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006943
6944 originator_desc = originator_str[sas_loginfo.dw.originator];
6945
6946 switch (sas_loginfo.dw.originator) {
6947
6948 case 0: /* IOP */
6949 if (sas_loginfo.dw.code <
6950 sizeof(iop_code_str)/sizeof(char*))
6951 code_desc = iop_code_str[sas_loginfo.dw.code];
6952 break;
6953 case 1: /* PL */
6954 if (sas_loginfo.dw.code <
6955 sizeof(pl_code_str)/sizeof(char*))
6956 code_desc = pl_code_str[sas_loginfo.dw.code];
6957 break;
6958 case 2: /* IR */
6959 if (sas_loginfo.dw.code >=
6960 sizeof(ir_code_str)/sizeof(char*))
6961 break;
6962 code_desc = ir_code_str[sas_loginfo.dw.code];
6963 if (sas_loginfo.dw.subcode >=
6964 sizeof(raid_sub_code_str)/sizeof(char*))
6965 break;
6966 if (sas_loginfo.dw.code == 0)
6967 sub_code_desc =
6968 raid_sub_code_str[sas_loginfo.dw.subcode];
6969 break;
6970 default:
6971 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006972 }
6973
Eric Moorec6c727a2007-01-29 09:44:54 -07006974 if (sub_code_desc != NULL)
6975 printk(MYIOC_s_INFO_FMT
6976 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6977 " SubCode={%s}\n",
6978 ioc->name, log_info, originator_desc, code_desc,
6979 sub_code_desc);
6980 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006981 printk(MYIOC_s_INFO_FMT
6982 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
6983 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006984 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006985 sas_loginfo.dw.subcode);
6986 else
6987 printk(MYIOC_s_INFO_FMT
6988 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
6989 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07006990 ioc->name, log_info, originator_desc,
6991 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006992}
6993
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006995/**
Eric Moorec6c727a2007-01-29 09:44:54 -07006996 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
6997 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08006998 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07006999 * @mf: Pointer to MPT request frame
7000 *
7001 * Refer to lsi/mpi.h.
7002 **/
7003static void
7004mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7005{
7006 Config_t *pReq = (Config_t *)mf;
7007 char extend_desc[EVENT_DESCR_STR_SZ];
7008 char *desc = NULL;
7009 u32 form;
7010 u8 page_type;
7011
7012 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7013 page_type = pReq->ExtPageType;
7014 else
7015 page_type = pReq->Header.PageType;
7016
7017 /*
7018 * ignore invalid page messages for GET_NEXT_HANDLE
7019 */
7020 form = le32_to_cpu(pReq->PageAddress);
7021 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7022 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7023 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7024 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7025 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7026 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7027 return;
7028 }
7029 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7030 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7031 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7032 return;
7033 }
7034
7035 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7036 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7037 page_type, pReq->Header.PageNumber, pReq->Action, form);
7038
7039 switch (ioc_status) {
7040
7041 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7042 desc = "Config Page Invalid Action";
7043 break;
7044
7045 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7046 desc = "Config Page Invalid Type";
7047 break;
7048
7049 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7050 desc = "Config Page Invalid Page";
7051 break;
7052
7053 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7054 desc = "Config Page Invalid Data";
7055 break;
7056
7057 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7058 desc = "Config Page No Defaults";
7059 break;
7060
7061 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7062 desc = "Config Page Can't Commit";
7063 break;
7064 }
7065
7066 if (!desc)
7067 return;
7068
7069 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
7070 ioc->name, ioc_status, desc, extend_desc);
7071}
7072
7073/**
7074 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075 * @ioc: Pointer to MPT_ADAPTER structure
7076 * @ioc_status: U32 IOCStatus word from IOC
7077 * @mf: Pointer to MPT request frame
7078 *
7079 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007080 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007082mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083{
7084 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007085 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086
7087 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007088
7089/****************************************************************************/
7090/* Common IOCStatus values for all replies */
7091/****************************************************************************/
7092
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7094 desc = "Invalid Function";
7095 break;
7096
7097 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7098 desc = "Busy";
7099 break;
7100
7101 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7102 desc = "Invalid SGL";
7103 break;
7104
7105 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7106 desc = "Internal Error";
7107 break;
7108
7109 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7110 desc = "Reserved";
7111 break;
7112
7113 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7114 desc = "Insufficient Resources";
7115 break;
7116
7117 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7118 desc = "Invalid Field";
7119 break;
7120
7121 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7122 desc = "Invalid State";
7123 break;
7124
Eric Moorec6c727a2007-01-29 09:44:54 -07007125/****************************************************************************/
7126/* Config IOCStatus values */
7127/****************************************************************************/
7128
Linus Torvalds1da177e2005-04-16 15:20:36 -07007129 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7130 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7131 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7132 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7133 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7134 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007135 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136 break;
7137
Eric Moorec6c727a2007-01-29 09:44:54 -07007138/****************************************************************************/
7139/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7140/* */
7141/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7142/* */
7143/****************************************************************************/
7144
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007146 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007147 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7148 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7149 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7150 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007151 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007154 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007155 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007157 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158 break;
7159
Eric Moorec6c727a2007-01-29 09:44:54 -07007160/****************************************************************************/
7161/* SCSI Target values */
7162/****************************************************************************/
7163
7164 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7165 desc = "Target: Priority IO";
7166 break;
7167
7168 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7169 desc = "Target: Invalid Port";
7170 break;
7171
7172 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7173 desc = "Target Invalid IO Index:";
7174 break;
7175
7176 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7177 desc = "Target: Aborted";
7178 break;
7179
7180 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7181 desc = "Target: No Conn Retryable";
7182 break;
7183
7184 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7185 desc = "Target: No Connection";
7186 break;
7187
7188 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7189 desc = "Target: Transfer Count Mismatch";
7190 break;
7191
7192 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7193 desc = "Target: STS Data not Sent";
7194 break;
7195
7196 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7197 desc = "Target: Data Offset Error";
7198 break;
7199
7200 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7201 desc = "Target: Too Much Write Data";
7202 break;
7203
7204 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7205 desc = "Target: IU Too Short";
7206 break;
7207
7208 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7209 desc = "Target: ACK NAK Timeout";
7210 break;
7211
7212 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7213 desc = "Target: Nak Received";
7214 break;
7215
7216/****************************************************************************/
7217/* Fibre Channel Direct Access values */
7218/****************************************************************************/
7219
7220 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7221 desc = "FC: Aborted";
7222 break;
7223
7224 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7225 desc = "FC: RX ID Invalid";
7226 break;
7227
7228 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7229 desc = "FC: DID Invalid";
7230 break;
7231
7232 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7233 desc = "FC: Node Logged Out";
7234 break;
7235
7236 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7237 desc = "FC: Exchange Canceled";
7238 break;
7239
7240/****************************************************************************/
7241/* LAN values */
7242/****************************************************************************/
7243
7244 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7245 desc = "LAN: Device not Found";
7246 break;
7247
7248 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7249 desc = "LAN: Device Failure";
7250 break;
7251
7252 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7253 desc = "LAN: Transmit Error";
7254 break;
7255
7256 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7257 desc = "LAN: Transmit Aborted";
7258 break;
7259
7260 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7261 desc = "LAN: Receive Error";
7262 break;
7263
7264 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7265 desc = "LAN: Receive Aborted";
7266 break;
7267
7268 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7269 desc = "LAN: Partial Packet";
7270 break;
7271
7272 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7273 desc = "LAN: Canceled";
7274 break;
7275
7276/****************************************************************************/
7277/* Serial Attached SCSI values */
7278/****************************************************************************/
7279
7280 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7281 desc = "SAS: SMP Request Failed";
7282 break;
7283
7284 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7285 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007286 break;
7287
7288 default:
7289 desc = "Others";
7290 break;
7291 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007292
7293 if (!desc)
7294 return;
7295
7296 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297}
7298
7299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007300EXPORT_SYMBOL(mpt_attach);
7301EXPORT_SYMBOL(mpt_detach);
7302#ifdef CONFIG_PM
7303EXPORT_SYMBOL(mpt_resume);
7304EXPORT_SYMBOL(mpt_suspend);
7305#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007307EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007308EXPORT_SYMBOL(mpt_register);
7309EXPORT_SYMBOL(mpt_deregister);
7310EXPORT_SYMBOL(mpt_event_register);
7311EXPORT_SYMBOL(mpt_event_deregister);
7312EXPORT_SYMBOL(mpt_reset_register);
7313EXPORT_SYMBOL(mpt_reset_deregister);
7314EXPORT_SYMBOL(mpt_device_driver_register);
7315EXPORT_SYMBOL(mpt_device_driver_deregister);
7316EXPORT_SYMBOL(mpt_get_msg_frame);
7317EXPORT_SYMBOL(mpt_put_msg_frame);
7318EXPORT_SYMBOL(mpt_free_msg_frame);
7319EXPORT_SYMBOL(mpt_add_sge);
7320EXPORT_SYMBOL(mpt_send_handshake_request);
7321EXPORT_SYMBOL(mpt_verify_adapter);
7322EXPORT_SYMBOL(mpt_GetIocState);
7323EXPORT_SYMBOL(mpt_print_ioc_summary);
7324EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007325EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326EXPORT_SYMBOL(mpt_HardResetHandler);
7327EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007329EXPORT_SYMBOL(mpt_alloc_fw_memory);
7330EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007331EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007332EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007333
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007335/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007336 * fusion_init - Fusion MPT base driver initialization routine.
7337 *
7338 * Returns 0 for success, non-zero for failure.
7339 */
7340static int __init
7341fusion_init(void)
7342{
7343 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007344
7345 show_mptmod_ver(my_NAME, my_VERSION);
7346 printk(KERN_INFO COPYRIGHT "\n");
7347
7348 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
7349 MptCallbacks[i] = NULL;
7350 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
7351 MptEvHandlers[i] = NULL;
7352 MptResetHandlers[i] = NULL;
7353 }
7354
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007355 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007356 * EventNotification handling.
7357 */
7358 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7359
7360 /* Register for hard reset handling callbacks.
7361 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307362 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363
7364#ifdef CONFIG_PROC_FS
7365 (void) procmpt_create();
7366#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007367 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368}
7369
7370/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007371/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372 * fusion_exit - Perform driver unload cleanup.
7373 *
7374 * This routine frees all resources associated with each MPT adapter
7375 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7376 */
7377static void __exit
7378fusion_exit(void)
7379{
7380
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381 mpt_reset_deregister(mpt_base_index);
7382
7383#ifdef CONFIG_PROC_FS
7384 procmpt_destroy();
7385#endif
7386}
7387
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388module_init(fusion_init);
7389module_exit(fusion_exit);