blob: 7ef86cb3aa55764a233d11e12cec6b21b760cb35 [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
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530845/**
846 * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
847 * to a IOC using hi priority request queue.
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 posts a MPT request frame to the request post FIFO of a
853 * specific MPT adapter.
854 **/
855void
856mpt_put_msg_frame_hi_pri(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
857{
858 u32 mf_dma_addr;
859 int req_offset;
860 u16 req_idx; /* Request index */
861
862 /* ensure values are reset properly! */
863 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
864 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
865 req_idx = req_offset / ioc->req_sz;
866 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
867 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
868
869 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
870
871 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
872 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
873 ioc->name, mf_dma_addr, req_idx));
874 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
875}
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
878/**
879 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
880 * @handle: Handle of registered MPT protocol driver
881 * @ioc: Pointer to MPT adapter structure
882 * @mf: Pointer to MPT request frame
883 *
884 * This routine places a MPT request frame back on the MPT adapter's
885 * FreeQ.
886 */
887void
888mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
889{
890 unsigned long flags;
891
892 /* Put Request back on FreeQ! */
893 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200894 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
896#ifdef MFCNT
897 ioc->mfcnt--;
898#endif
899 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
900}
901
902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
903/**
904 * mpt_add_sge - Place a simple SGE at address pAddr.
905 * @pAddr: virtual address for SGE
906 * @flagslength: SGE flags and data transfer length
907 * @dma_addr: Physical address
908 *
909 * This routine places a MPT request frame back on the MPT adapter's
910 * FreeQ.
911 */
912void
913mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
914{
915 if (sizeof(dma_addr_t) == sizeof(u64)) {
916 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
917 u32 tmp = dma_addr & 0xFFFFFFFF;
918
919 pSge->FlagsLength = cpu_to_le32(flagslength);
920 pSge->Address.Low = cpu_to_le32(tmp);
921 tmp = (u32) ((u64)dma_addr >> 32);
922 pSge->Address.High = cpu_to_le32(tmp);
923
924 } else {
925 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
926 pSge->FlagsLength = cpu_to_le32(flagslength);
927 pSge->Address = cpu_to_le32(dma_addr);
928 }
929}
930
931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
932/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800933 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 * @handle: Handle of registered MPT protocol driver
935 * @ioc: Pointer to MPT adapter structure
936 * @reqBytes: Size of the request in bytes
937 * @req: Pointer to MPT request frame
938 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
939 *
940 * This routine is used exclusively to send MptScsiTaskMgmt
941 * requests since they are required to be sent via doorbell handshake.
942 *
943 * NOTE: It is the callers responsibility to byte-swap fields in the
944 * request which are greater than 1 byte in size.
945 *
946 * Returns 0 for success, non-zero for failure.
947 */
948int
949mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
950{
Eric Moorecd2c6192007-01-29 09:47:47 -0700951 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 u8 *req_as_bytes;
953 int ii;
954
955 /* State is known to be good upon entering
956 * this function so issue the bus reset
957 * request.
958 */
959
960 /*
961 * Emulate what mpt_put_msg_frame() does /wrt to sanity
962 * setting cb_idx/req_idx. But ONLY if this request
963 * is in proper (pre-alloc'd) request buffer range...
964 */
965 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
966 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
967 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
968 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
969 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
970 }
971
972 /* Make sure there are no doorbells */
973 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 CHIPREG_WRITE32(&ioc->chip->Doorbell,
976 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
977 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
978
979 /* Wait for IOC doorbell int */
980 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
981 return ii;
982 }
983
984 /* Read doorbell and check for active bit */
985 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
986 return -5;
987
Prakash, Sathya436ace72007-07-24 15:42:08 +0530988 dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200989 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
992
993 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
994 return -2;
995 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /* Send request via doorbell handshake */
998 req_as_bytes = (u8 *) req;
999 for (ii = 0; ii < reqBytes/4; ii++) {
1000 u32 word;
1001
1002 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1003 (req_as_bytes[(ii*4) + 1] << 8) |
1004 (req_as_bytes[(ii*4) + 2] << 16) |
1005 (req_as_bytes[(ii*4) + 3] << 24));
1006 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1007 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1008 r = -3;
1009 break;
1010 }
1011 }
1012
1013 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1014 r = 0;
1015 else
1016 r = -4;
1017
1018 /* Make sure there are no doorbells */
1019 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return r;
1022}
1023
1024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1025/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001026 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001027 * @ioc: Pointer to MPT adapter structure
1028 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001029 * @sleepFlag: Specifies whether the process can sleep
1030 *
1031 * Provides mechanism for the host driver to control the IOC's
1032 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001033 *
1034 * Access Control Value - bits[15:12]
1035 * 0h Reserved
1036 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1037 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1038 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1039 *
1040 * Returns 0 for success, non-zero for failure.
1041 */
1042
1043static int
1044mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1045{
1046 int r = 0;
1047
1048 /* return if in use */
1049 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1050 & MPI_DOORBELL_ACTIVE)
1051 return -1;
1052
1053 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1054
1055 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1056 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1057 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1058 (access_control_value<<12)));
1059
1060 /* Wait for IOC to clear Doorbell Status bit */
1061 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1062 return -2;
1063 }else
1064 return 0;
1065}
1066
1067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1068/**
1069 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001070 * @ioc: Pointer to pointer to IOC adapter
1071 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001072 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001073 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001074 * Returns 0 for success, non-zero for failure.
1075 */
1076static int
1077mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1078{
1079 char *psge;
1080 int flags_length;
1081 u32 host_page_buffer_sz=0;
1082
1083 if(!ioc->HostPageBuffer) {
1084
1085 host_page_buffer_sz =
1086 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1087
1088 if(!host_page_buffer_sz)
1089 return 0; /* fw doesn't need any host buffers */
1090
1091 /* spin till we get enough memory */
1092 while(host_page_buffer_sz > 0) {
1093
1094 if((ioc->HostPageBuffer = pci_alloc_consistent(
1095 ioc->pcidev,
1096 host_page_buffer_sz,
1097 &ioc->HostPageBuffer_dma)) != NULL) {
1098
Prakash, Sathya436ace72007-07-24 15:42:08 +05301099 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001100 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001101 ioc->name, ioc->HostPageBuffer,
1102 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001103 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001104 ioc->alloc_total += host_page_buffer_sz;
1105 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1106 break;
1107 }
1108
1109 host_page_buffer_sz -= (4*1024);
1110 }
1111 }
1112
1113 if(!ioc->HostPageBuffer) {
1114 printk(MYIOC_s_ERR_FMT
1115 "Failed to alloc memory for host_page_buffer!\n",
1116 ioc->name);
1117 return -999;
1118 }
1119
1120 psge = (char *)&ioc_init->HostPageBufferSGE;
1121 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1122 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1123 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1124 MPI_SGE_FLAGS_HOST_TO_IOC |
1125 MPI_SGE_FLAGS_END_OF_BUFFER;
1126 if (sizeof(dma_addr_t) == sizeof(u64)) {
1127 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1128 }
1129 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1130 flags_length |= ioc->HostPageBuffer_sz;
1131 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1132 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1133
1134return 0;
1135}
1136
1137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1138/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001139 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 * @iocid: IOC unique identifier (integer)
1141 * @iocpp: Pointer to pointer to IOC adapter
1142 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001143 * Given a unique IOC identifier, set pointer to the associated MPT
1144 * adapter structure.
1145 *
1146 * Returns iocid and sets iocpp if iocid is found.
1147 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 */
1149int
1150mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1151{
1152 MPT_ADAPTER *ioc;
1153
1154 list_for_each_entry(ioc,&ioc_list,list) {
1155 if (ioc->id == iocid) {
1156 *iocpp =ioc;
1157 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 *iocpp = NULL;
1162 return -1;
1163}
1164
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301165/**
1166 * mpt_get_product_name - returns product string
1167 * @vendor: pci vendor id
1168 * @device: pci device id
1169 * @revision: pci revision id
1170 * @prod_name: string returned
1171 *
1172 * Returns product string displayed when driver loads,
1173 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1174 *
1175 **/
1176static void
1177mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1178{
1179 char *product_str = NULL;
1180
1181 if (vendor == PCI_VENDOR_ID_BROCADE) {
1182 switch (device)
1183 {
1184 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1185 switch (revision)
1186 {
1187 case 0x00:
1188 product_str = "BRE040 A0";
1189 break;
1190 case 0x01:
1191 product_str = "BRE040 A1";
1192 break;
1193 default:
1194 product_str = "BRE040";
1195 break;
1196 }
1197 break;
1198 }
1199 goto out;
1200 }
1201
1202 switch (device)
1203 {
1204 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1205 product_str = "LSIFC909 B1";
1206 break;
1207 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1208 product_str = "LSIFC919 B0";
1209 break;
1210 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1211 product_str = "LSIFC929 B0";
1212 break;
1213 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1214 if (revision < 0x80)
1215 product_str = "LSIFC919X A0";
1216 else
1217 product_str = "LSIFC919XL A1";
1218 break;
1219 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1220 if (revision < 0x80)
1221 product_str = "LSIFC929X A0";
1222 else
1223 product_str = "LSIFC929XL A1";
1224 break;
1225 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1226 product_str = "LSIFC939X A1";
1227 break;
1228 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1229 product_str = "LSIFC949X A1";
1230 break;
1231 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1232 switch (revision)
1233 {
1234 case 0x00:
1235 product_str = "LSIFC949E A0";
1236 break;
1237 case 0x01:
1238 product_str = "LSIFC949E A1";
1239 break;
1240 default:
1241 product_str = "LSIFC949E";
1242 break;
1243 }
1244 break;
1245 case MPI_MANUFACTPAGE_DEVID_53C1030:
1246 switch (revision)
1247 {
1248 case 0x00:
1249 product_str = "LSI53C1030 A0";
1250 break;
1251 case 0x01:
1252 product_str = "LSI53C1030 B0";
1253 break;
1254 case 0x03:
1255 product_str = "LSI53C1030 B1";
1256 break;
1257 case 0x07:
1258 product_str = "LSI53C1030 B2";
1259 break;
1260 case 0x08:
1261 product_str = "LSI53C1030 C0";
1262 break;
1263 case 0x80:
1264 product_str = "LSI53C1030T A0";
1265 break;
1266 case 0x83:
1267 product_str = "LSI53C1030T A2";
1268 break;
1269 case 0x87:
1270 product_str = "LSI53C1030T A3";
1271 break;
1272 case 0xc1:
1273 product_str = "LSI53C1020A A1";
1274 break;
1275 default:
1276 product_str = "LSI53C1030";
1277 break;
1278 }
1279 break;
1280 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1281 switch (revision)
1282 {
1283 case 0x03:
1284 product_str = "LSI53C1035 A2";
1285 break;
1286 case 0x04:
1287 product_str = "LSI53C1035 B0";
1288 break;
1289 default:
1290 product_str = "LSI53C1035";
1291 break;
1292 }
1293 break;
1294 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1295 switch (revision)
1296 {
1297 case 0x00:
1298 product_str = "LSISAS1064 A1";
1299 break;
1300 case 0x01:
1301 product_str = "LSISAS1064 A2";
1302 break;
1303 case 0x02:
1304 product_str = "LSISAS1064 A3";
1305 break;
1306 case 0x03:
1307 product_str = "LSISAS1064 A4";
1308 break;
1309 default:
1310 product_str = "LSISAS1064";
1311 break;
1312 }
1313 break;
1314 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1315 switch (revision)
1316 {
1317 case 0x00:
1318 product_str = "LSISAS1064E A0";
1319 break;
1320 case 0x01:
1321 product_str = "LSISAS1064E B0";
1322 break;
1323 case 0x02:
1324 product_str = "LSISAS1064E B1";
1325 break;
1326 case 0x04:
1327 product_str = "LSISAS1064E B2";
1328 break;
1329 case 0x08:
1330 product_str = "LSISAS1064E B3";
1331 break;
1332 default:
1333 product_str = "LSISAS1064E";
1334 break;
1335 }
1336 break;
1337 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1338 switch (revision)
1339 {
1340 case 0x00:
1341 product_str = "LSISAS1068 A0";
1342 break;
1343 case 0x01:
1344 product_str = "LSISAS1068 B0";
1345 break;
1346 case 0x02:
1347 product_str = "LSISAS1068 B1";
1348 break;
1349 default:
1350 product_str = "LSISAS1068";
1351 break;
1352 }
1353 break;
1354 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1355 switch (revision)
1356 {
1357 case 0x00:
1358 product_str = "LSISAS1068E A0";
1359 break;
1360 case 0x01:
1361 product_str = "LSISAS1068E B0";
1362 break;
1363 case 0x02:
1364 product_str = "LSISAS1068E B1";
1365 break;
1366 case 0x04:
1367 product_str = "LSISAS1068E B2";
1368 break;
1369 case 0x08:
1370 product_str = "LSISAS1068E B3";
1371 break;
1372 default:
1373 product_str = "LSISAS1068E";
1374 break;
1375 }
1376 break;
1377 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1378 switch (revision)
1379 {
1380 case 0x00:
1381 product_str = "LSISAS1078 A0";
1382 break;
1383 case 0x01:
1384 product_str = "LSISAS1078 B0";
1385 break;
1386 case 0x02:
1387 product_str = "LSISAS1078 C0";
1388 break;
1389 case 0x03:
1390 product_str = "LSISAS1078 C1";
1391 break;
1392 case 0x04:
1393 product_str = "LSISAS1078 C2";
1394 break;
1395 default:
1396 product_str = "LSISAS1078";
1397 break;
1398 }
1399 break;
1400 }
1401
1402 out:
1403 if (product_str)
1404 sprintf(prod_name, "%s", product_str);
1405}
1406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001408/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001409 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001411 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 *
1413 * This routine performs all the steps necessary to bring the IOC of
1414 * a MPT adapter to a OPERATIONAL state. This includes registering
1415 * memory regions, registering the interrupt, and allocating request
1416 * and reply memory pools.
1417 *
1418 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1419 * MPT adapter.
1420 *
1421 * Returns 0 for success, non-zero for failure.
1422 *
1423 * TODO: Add support for polled controllers
1424 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001425int
1426mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427{
1428 MPT_ADAPTER *ioc;
1429 u8 __iomem *mem;
1430 unsigned long mem_phys;
1431 unsigned long port;
1432 u32 msize;
1433 u32 psize;
1434 int ii;
1435 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 u8 revision;
1437 u8 pcixcmd;
1438 static int mpt_ids = 0;
1439#ifdef CONFIG_PROC_FS
1440 struct proc_dir_entry *dent, *ent;
1441#endif
1442
Prakash, Sathya436ace72007-07-24 15:42:08 +05301443 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1444 if (ioc == NULL) {
1445 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1446 return -ENOMEM;
1447 }
1448
1449 ioc->debug_level = mpt_debug_level;
1450 if (mpt_debug_level)
1451 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (pci_enable_device(pdev))
1454 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001455
Prakash, Sathya436ace72007-07-24 15:42:08 +05301456 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001457
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001458 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301459 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001461 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1463 return r;
1464 }
1465
Prakash, Sathya436ace72007-07-24 15:42:08 +05301466 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1467 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 ": Using 64 bit consistent mask\n"));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301469 } else {
1470 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 ": Not using 64 bit consistent mask\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301473
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 ioc->alloc_total = sizeof(MPT_ADAPTER);
1475 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1476 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 ioc->pcidev = pdev;
1479 ioc->diagPending = 0;
1480 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001481 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
1483 /* Initialize the event logging.
1484 */
1485 ioc->eventTypes = 0; /* None */
1486 ioc->eventContext = 0;
1487 ioc->eventLogSize = 0;
1488 ioc->events = NULL;
1489
1490#ifdef MFCNT
1491 ioc->mfcnt = 0;
1492#endif
1493
1494 ioc->cached_fw = NULL;
1495
1496 /* Initilize SCSI Config Data structure
1497 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001498 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 /* Initialize the running configQ head.
1501 */
1502 INIT_LIST_HEAD(&ioc->configQ);
1503
Michael Reed05e8ec12006-01-13 14:31:54 -06001504 /* Initialize the fc rport list head.
1505 */
1506 INIT_LIST_HEAD(&ioc->fc_rports);
1507
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 /* Find lookup slot. */
1509 INIT_LIST_HEAD(&ioc->list);
1510 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001511
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 mem_phys = msize = 0;
1513 port = psize = 0;
1514 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1515 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001516 if (psize)
1517 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 /* Get I/O space! */
1519 port = pci_resource_start(pdev, ii);
1520 psize = pci_resource_len(pdev,ii);
1521 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001522 if (msize)
1523 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 /* Get memmap */
1525 mem_phys = pci_resource_start(pdev, ii);
1526 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
1528 }
1529 ioc->mem_size = msize;
1530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 mem = NULL;
1532 /* Get logical ptr for PciMem0 space */
1533 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001534 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 if (mem == NULL) {
1536 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1537 kfree(ioc);
1538 return -EINVAL;
1539 }
1540 ioc->memmap = mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301541 dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Prakash, Sathya436ace72007-07-24 15:42:08 +05301543 dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 &ioc->facts, &ioc->pfacts[0]));
1545
1546 ioc->mem_phys = mem_phys;
1547 ioc->chip = (SYSIF_REGS __iomem *)mem;
1548
1549 /* Save Port IO values in case we need to do downloadboot */
1550 {
1551 u8 *pmem = (u8*)port;
1552 ioc->pio_mem_phys = port;
1553 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1554 }
1555
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301556 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1557 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1558
1559 switch (pdev->device)
1560 {
1561 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1562 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1563 ioc->errata_flag_1064 = 1;
1564 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1565 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1566 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1567 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301569 break;
1570
1571 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 /* 929X Chip Fix. Set Split transactions level
1574 * for PCIX. Set MOST bits to zero.
1575 */
1576 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1577 pcixcmd &= 0x8F;
1578 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1579 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 /* 929XL Chip Fix. Set MMRBC to 0x08.
1581 */
1582 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1583 pcixcmd |= 0x08;
1584 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301587 break;
1588
1589 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 /* 919X Chip Fix. Set Split transactions level
1591 * for PCIX. Set MOST bits to zero.
1592 */
1593 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1594 pcixcmd &= 0x8F;
1595 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001596 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301597 break;
1598
1599 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 /* 1030 Chip Fix. Disable Split transactions
1601 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1602 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (revision < C0_1030) {
1604 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1605 pcixcmd &= 0x8F;
1606 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1607 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301608
1609 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001610 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301611 break;
1612
1613 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1614 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001615 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301616
1617 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1618 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1619 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001620 ioc->bus_type = SAS;
1621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001623 if (ioc->errata_flag_1064)
1624 pci_disable_io_access(pdev);
1625
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 sprintf(ioc->name, "ioc%d", ioc->id);
1627
1628 spin_lock_init(&ioc->FreeQlock);
1629
1630 /* Disable all! */
1631 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1632 ioc->active = 0;
1633 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1634
1635 /* Set lookup ptr. */
1636 list_add_tail(&ioc->list, &ioc_list);
1637
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001638 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 */
1640 mpt_detect_bound_ports(ioc, pdev);
1641
James Bottomleyc92f2222006-03-01 09:02:49 -06001642 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1643 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 printk(KERN_WARNING MYNAM
1645 ": WARNING - %s did not initialize properly! (%d)\n",
1646 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001649 if (ioc->alt_ioc)
1650 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 iounmap(mem);
1652 kfree(ioc);
1653 pci_set_drvdata(pdev, NULL);
1654 return r;
1655 }
1656
1657 /* call per device driver probe entry point */
1658 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1659 if(MptDeviceDriverHandlers[ii] &&
1660 MptDeviceDriverHandlers[ii]->probe) {
1661 MptDeviceDriverHandlers[ii]->probe(pdev,id);
1662 }
1663 }
1664
1665#ifdef CONFIG_PROC_FS
1666 /*
1667 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1668 */
1669 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1670 if (dent) {
1671 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1672 if (ent) {
1673 ent->read_proc = procmpt_iocinfo_read;
1674 ent->data = ioc;
1675 }
1676 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1677 if (ent) {
1678 ent->read_proc = procmpt_summary_read;
1679 ent->data = ioc;
1680 }
1681 }
1682#endif
1683
1684 return 0;
1685}
1686
1687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001688/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001689 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 */
1692
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001693void
1694mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695{
1696 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1697 char pname[32];
1698 int ii;
1699
1700 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1701 remove_proc_entry(pname, NULL);
1702 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1703 remove_proc_entry(pname, NULL);
1704 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1705 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 /* call per device driver remove entry point */
1708 for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
1709 if(MptDeviceDriverHandlers[ii] &&
1710 MptDeviceDriverHandlers[ii]->remove) {
1711 MptDeviceDriverHandlers[ii]->remove(pdev);
1712 }
1713 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 /* Disable interrupts! */
1716 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1717
1718 ioc->active = 0;
1719 synchronize_irq(pdev->irq);
1720
1721 /* Clear any lingering interrupt */
1722 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1723
1724 CHIPREG_READ32(&ioc->chip->IntStatus);
1725
1726 mpt_adapter_dispose(ioc);
1727
1728 pci_set_drvdata(pdev, NULL);
1729}
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731/**************************************************************************
1732 * Power Management
1733 */
1734#ifdef CONFIG_PM
1735/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001736/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001737 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001738 * @pdev: Pointer to pci_dev structure
1739 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001741int
1742mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743{
1744 u32 device_state;
1745 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
Pavel Machek2a569572005-07-07 17:56:40 -07001747 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 printk(MYIOC_s_INFO_FMT
1750 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1751 ioc->name, pdev, pci_name(pdev), device_state);
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 pci_save_state(pdev);
1754
1755 /* put ioc into READY_STATE */
1756 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1757 printk(MYIOC_s_ERR_FMT
1758 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1759 }
1760
1761 /* disable interrupts */
1762 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1763 ioc->active = 0;
1764
1765 /* Clear any lingering interrupt */
1766 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1767
1768 pci_disable_device(pdev);
1769 pci_set_power_state(pdev, device_state);
1770
1771 return 0;
1772}
1773
1774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001775/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001776 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001777 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001779int
1780mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
1782 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1783 u32 device_state = pdev->current_state;
1784 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001785 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 printk(MYIOC_s_INFO_FMT
1788 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1789 ioc->name, pdev, pci_name(pdev), device_state);
1790
1791 pci_set_power_state(pdev, 0);
1792 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001793 err = pci_enable_device(pdev);
1794 if (err)
1795 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001798 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->active = 1;
1800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 printk(MYIOC_s_INFO_FMT
1802 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1803 ioc->name,
1804 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1805 CHIPREG_READ32(&ioc->chip->Doorbell));
1806
1807 /* bring ioc to operational state */
1808 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1809 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1810 printk(MYIOC_s_INFO_FMT
1811 "pci-resume: Cannot recover, error:[%x]\n",
1812 ioc->name, recovery_state);
1813 } else {
1814 printk(MYIOC_s_INFO_FMT
1815 "pci-resume: success\n", ioc->name);
1816 }
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 return 0;
1819}
1820#endif
1821
James Bottomley4ff42a62006-05-17 18:06:52 -05001822static int
1823mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
1824{
1825 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1826 ioc->bus_type != SPI) ||
1827 (MptDriverClass[index] == MPTFC_DRIVER &&
1828 ioc->bus_type != FC) ||
1829 (MptDriverClass[index] == MPTSAS_DRIVER &&
1830 ioc->bus_type != SAS))
1831 /* make sure we only call the relevant reset handler
1832 * for the bus */
1833 return 0;
1834 return (MptResetHandlers[index])(ioc, reset_phase);
1835}
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001838/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1840 * @ioc: Pointer to MPT adapter structure
1841 * @reason: Event word / reason
1842 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1843 *
1844 * This routine performs all the steps necessary to bring the IOC
1845 * to a OPERATIONAL state.
1846 *
1847 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1848 * MPT adapter.
1849 *
1850 * Returns:
1851 * 0 for success
1852 * -1 if failed to get board READY
1853 * -2 if READY but IOCFacts Failed
1854 * -3 if READY but PrimeIOCFifos Failed
1855 * -4 if READY but IOCInit Failed
1856 */
1857static int
1858mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1859{
1860 int hard_reset_done = 0;
1861 int alt_ioc_ready = 0;
1862 int hard;
1863 int rc=0;
1864 int ii;
1865 int handlers;
1866 int ret = 0;
1867 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001868 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301869 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1872 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1873
1874 /* Disable reply interrupts (also blocks FreeQ) */
1875 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1876 ioc->active = 0;
1877
1878 if (ioc->alt_ioc) {
1879 if (ioc->alt_ioc->active)
1880 reset_alt_ioc_active = 1;
1881
1882 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1883 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1884 ioc->alt_ioc->active = 0;
1885 }
1886
1887 hard = 1;
1888 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1889 hard = 0;
1890
1891 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1892 if (hard_reset_done == -4) {
1893 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1894 ioc->name);
1895
1896 if (reset_alt_ioc_active && ioc->alt_ioc) {
1897 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05301898 dprintk(ioc, printk(KERN_INFO MYNAM
1899 ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001901 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 ioc->alt_ioc->active = 1;
1903 }
1904
1905 } else {
1906 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1907 ioc->name);
1908 }
1909 return -1;
1910 }
1911
1912 /* hard_reset_done = 0 if a soft reset was performed
1913 * and 1 if a hard reset was performed.
1914 */
1915 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1916 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1917 alt_ioc_ready = 1;
1918 else
1919 printk(KERN_WARNING MYNAM
1920 ": alt-%s: Not ready WARNING!\n",
1921 ioc->alt_ioc->name);
1922 }
1923
1924 for (ii=0; ii<5; ii++) {
1925 /* Get IOC facts! Allow 5 retries */
1926 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1927 break;
1928 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 if (ii == 5) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301932 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 ret = -2;
1934 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1935 MptDisplayIocCapabilities(ioc);
1936 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001937
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 if (alt_ioc_ready) {
1939 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301940 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1941 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 /* Retry - alt IOC was initialized once
1943 */
1944 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1945 }
1946 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301947 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1948 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 alt_ioc_ready = 0;
1950 reset_alt_ioc_active = 0;
1951 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1952 MptDisplayIocCapabilities(ioc->alt_ioc);
1953 }
1954 }
1955
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001956 /*
1957 * Device is reset now. It must have de-asserted the interrupt line
1958 * (if it was asserted) and it should be safe to register for the
1959 * interrupt now.
1960 */
1961 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1962 ioc->pci_irq = -1;
1963 if (ioc->pcidev->irq) {
1964 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1965 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1966 ioc->name);
1967 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001968 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001969 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001970 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1971 "interrupt %d!\n", ioc->name,
1972 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001973 if (mpt_msi_enable)
1974 pci_disable_msi(ioc->pcidev);
1975 return -EBUSY;
1976 }
1977 irq_allocated = 1;
1978 ioc->pci_irq = ioc->pcidev->irq;
1979 pci_set_master(ioc->pcidev); /* ?? */
1980 pci_set_drvdata(ioc->pcidev, ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05301981 dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001982 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001983 }
1984 }
1985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 /* Prime reply & request queues!
1987 * (mucho alloc's) Must be done prior to
1988 * init as upper addresses are needed for init.
1989 * If fails, continue with alt-ioc processing
1990 */
1991 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
1992 ret = -3;
1993
1994 /* May need to check/upload firmware & data here!
1995 * If fails, continue with alt-ioc processing
1996 */
1997 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
1998 ret = -4;
1999// NEW!
2000 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
2001 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
2002 ioc->alt_ioc->name, rc);
2003 alt_ioc_ready = 0;
2004 reset_alt_ioc_active = 0;
2005 }
2006
2007 if (alt_ioc_ready) {
2008 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2009 alt_ioc_ready = 0;
2010 reset_alt_ioc_active = 0;
2011 printk(KERN_WARNING MYNAM
2012 ": alt-%s: (%d) init failure WARNING!\n",
2013 ioc->alt_ioc->name, rc);
2014 }
2015 }
2016
2017 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2018 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302019 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 "firmware upload required!\n", ioc->name));
2021
2022 /* Controller is not operational, cannot do upload
2023 */
2024 if (ret == 0) {
2025 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002026 if (rc == 0) {
2027 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2028 /*
2029 * Maintain only one pointer to FW memory
2030 * so there will not be two attempt to
2031 * downloadboot onboard dual function
2032 * chips (mpt_adapter_disable,
2033 * mpt_diag_reset)
2034 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302035 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2036 ": mpt_upload: alt_%s has cached_fw=%p \n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002037 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002038 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002039 }
2040 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002042 ret = -5;
2043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045 }
2046 }
2047
2048 if (ret == 0) {
2049 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002050 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 ioc->active = 1;
2052 }
2053
2054 if (reset_alt_ioc_active && ioc->alt_ioc) {
2055 /* (re)Enable alt-IOC! (reply interrupt) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302056 dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002058 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 ioc->alt_ioc->active = 1;
2060 }
2061
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002062 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 * and EventAck handling.
2064 */
2065 if ((ret == 0) && (!ioc->facts.EventState))
2066 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2067
2068 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2069 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2070
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002071 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2073 * recursive scenario; GetLanConfigPages times out, timer expired
2074 * routine calls HardResetHandler, which calls into here again,
2075 * and we try GetLanConfigPages again...
2076 */
2077 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002078
2079 /*
2080 * Initalize link list for inactive raid volumes.
2081 */
2082 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2083 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2084
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002085 if (ioc->bus_type == SAS) {
2086
2087 /* clear persistency table */
2088 if(ioc->facts.IOCExceptions &
2089 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2090 ret = mptbase_sas_persist_operation(ioc,
2091 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2092 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002093 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002094 }
2095
2096 /* Find IM volumes
2097 */
2098 mpt_findImVolumes(ioc);
2099
2100 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2102 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2103 /*
2104 * Pre-fetch the ports LAN MAC address!
2105 * (LANPage1_t stuff)
2106 */
2107 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302108 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2109 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2110 "LanAddr = %02X:%02X:%02X:"
2111 "%02X:%02X:%02X\n",
2112 ioc->name, a[5], a[4],
2113 a[3], a[2], a[1], a[0] ));
2114
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
2116 } else {
2117 /* Get NVRAM and adapter maximums from SPP 0 and 2
2118 */
2119 mpt_GetScsiPortSettings(ioc, 0);
2120
2121 /* Get version and length of SDP 1
2122 */
2123 mpt_readScsiDevicePageHeaders(ioc, 0);
2124
2125 /* Find IM volumes
2126 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002127 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 mpt_findImVolumes(ioc);
2129
2130 /* Check, and possibly reset, the coalescing value
2131 */
2132 mpt_read_ioc_pg_1(ioc);
2133
2134 mpt_read_ioc_pg_4(ioc);
2135 }
2136
2137 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302138 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 }
2140
2141 /*
2142 * Call each currently registered protocol IOC reset handler
2143 * with post-reset indication.
2144 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2145 * MptResetHandlers[] registered yet.
2146 */
2147 if (hard_reset_done) {
2148 rc = handlers = 0;
2149 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
2150 if ((ret == 0) && MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302151 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2152 "Calling IOC post_reset handler #%d\n",
2153 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002154 rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 handlers++;
2156 }
2157
2158 if (alt_ioc_ready && MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302159 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2160 "Calling alt-%s post_reset handler #%d\n",
2161 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05002162 rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 handlers++;
2164 }
2165 }
2166 /* FIXME? Examine results here? */
2167 }
2168
Eric Moore0ccdb002006-07-11 17:33:13 -06002169 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002170 if ((ret != 0) && irq_allocated) {
2171 free_irq(ioc->pci_irq, ioc);
2172 if (mpt_msi_enable)
2173 pci_disable_msi(ioc->pcidev);
2174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return ret;
2176}
2177
2178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002179/**
2180 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 * @ioc: Pointer to MPT adapter structure
2182 * @pdev: Pointer to (struct pci_dev) structure
2183 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002184 * Search for PCI bus/dev_function which matches
2185 * PCI bus/dev_function (+/-1) for newly discovered 929,
2186 * 929X, 1030 or 1035.
2187 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2189 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2190 */
2191static void
2192mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2193{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002194 struct pci_dev *peer=NULL;
2195 unsigned int slot = PCI_SLOT(pdev->devfn);
2196 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 MPT_ADAPTER *ioc_srch;
2198
Prakash, Sathya436ace72007-07-24 15:42:08 +05302199 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002200 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002201 ioc->name, pci_name(pdev), pdev->bus->number,
2202 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002203
2204 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2205 if (!peer) {
2206 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2207 if (!peer)
2208 return;
2209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
2211 list_for_each_entry(ioc_srch, &ioc_list, list) {
2212 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002213 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 /* Paranoia checks */
2215 if (ioc->alt_ioc != NULL) {
2216 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002217 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 break;
2219 } else if (ioc_srch->alt_ioc != NULL) {
2220 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002221 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 break;
2223 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302224 dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002225 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 ioc_srch->alt_ioc = ioc;
2227 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 }
2229 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002230 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231}
2232
2233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002234/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002236 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 */
2238static void
2239mpt_adapter_disable(MPT_ADAPTER *ioc)
2240{
2241 int sz;
2242 int ret;
2243
2244 if (ioc->cached_fw != NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302245 ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002246 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 printk(KERN_WARNING MYNAM
2248 ": firmware downloadboot failure (%d)!\n", ret);
2249 }
2250 }
2251
2252 /* Disable adapter interrupts! */
2253 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2254 ioc->active = 0;
2255 /* Clear any lingering interrupt */
2256 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2257
2258 if (ioc->alloc != NULL) {
2259 sz = ioc->alloc_sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302260 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 ioc->name, ioc->alloc, ioc->alloc_sz));
2262 pci_free_consistent(ioc->pcidev, sz,
2263 ioc->alloc, ioc->alloc_dma);
2264 ioc->reply_frames = NULL;
2265 ioc->req_frames = NULL;
2266 ioc->alloc = NULL;
2267 ioc->alloc_total -= sz;
2268 }
2269
2270 if (ioc->sense_buf_pool != NULL) {
2271 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2272 pci_free_consistent(ioc->pcidev, sz,
2273 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2274 ioc->sense_buf_pool = NULL;
2275 ioc->alloc_total -= sz;
2276 }
2277
2278 if (ioc->events != NULL){
2279 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2280 kfree(ioc->events);
2281 ioc->events = NULL;
2282 ioc->alloc_total -= sz;
2283 }
2284
2285 if (ioc->cached_fw != NULL) {
2286 sz = ioc->facts.FWImageSize;
2287 pci_free_consistent(ioc->pcidev, sz,
2288 ioc->cached_fw, ioc->cached_fw_dma);
2289 ioc->cached_fw = NULL;
2290 ioc->alloc_total -= sz;
2291 }
2292
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002293 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002294 mpt_inactive_raid_list_free(ioc);
2295 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002296 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002297 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002298 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300 if (ioc->spi_data.pIocPg4 != NULL) {
2301 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302302 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 ioc->spi_data.pIocPg4,
2304 ioc->spi_data.IocPg4_dma);
2305 ioc->spi_data.pIocPg4 = NULL;
2306 ioc->alloc_total -= sz;
2307 }
2308
2309 if (ioc->ReqToChain != NULL) {
2310 kfree(ioc->ReqToChain);
2311 kfree(ioc->RequestNB);
2312 ioc->ReqToChain = NULL;
2313 }
2314
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002315 kfree(ioc->ChainToChain);
2316 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002317
2318 if (ioc->HostPageBuffer != NULL) {
2319 if((ret = mpt_host_page_access_control(ioc,
2320 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2321 printk(KERN_ERR MYNAM
2322 ": %s: host page buffers free failed (%d)!\n",
2323 __FUNCTION__, ret);
2324 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302325 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002326 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2327 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2328 ioc->HostPageBuffer,
2329 ioc->HostPageBuffer_dma);
2330 ioc->HostPageBuffer = NULL;
2331 ioc->HostPageBuffer_sz = 0;
2332 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334}
2335
2336/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002337/**
2338 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 * @ioc: Pointer to MPT adapter structure
2340 *
2341 * This routine unregisters h/w resources and frees all alloc'd memory
2342 * associated with a MPT adapter structure.
2343 */
2344static void
2345mpt_adapter_dispose(MPT_ADAPTER *ioc)
2346{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002347 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002349 if (ioc == NULL)
2350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002352 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002354 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002356 if (ioc->pci_irq != -1) {
2357 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002358 if (mpt_msi_enable)
2359 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002360 ioc->pci_irq = -1;
2361 }
2362
2363 if (ioc->memmap != NULL) {
2364 iounmap(ioc->memmap);
2365 ioc->memmap = NULL;
2366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
2368#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002369 if (ioc->mtrr_reg > 0) {
2370 mtrr_del(ioc->mtrr_reg, 0, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302371 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373#endif
2374
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002375 /* Zap the adapter lookup ptr! */
2376 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002378 sz_last = ioc->alloc_total;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302379 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002380 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002381
2382 if (ioc->alt_ioc)
2383 ioc->alt_ioc->alt_ioc = NULL;
2384
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002385 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386}
2387
2388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002389/**
2390 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 * @ioc: Pointer to MPT adapter structure
2392 */
2393static void
2394MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2395{
2396 int i = 0;
2397
2398 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302399 if (ioc->prod_name)
2400 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 printk("Capabilities={");
2402
2403 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2404 printk("Initiator");
2405 i++;
2406 }
2407
2408 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2409 printk("%sTarget", i ? "," : "");
2410 i++;
2411 }
2412
2413 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2414 printk("%sLAN", i ? "," : "");
2415 i++;
2416 }
2417
2418#if 0
2419 /*
2420 * This would probably evoke more questions than it's worth
2421 */
2422 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2423 printk("%sLogBusAddr", i ? "," : "");
2424 i++;
2425 }
2426#endif
2427
2428 printk("}\n");
2429}
2430
2431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002432/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2434 * @ioc: Pointer to MPT_ADAPTER structure
2435 * @force: Force hard KickStart of IOC
2436 * @sleepFlag: Specifies whether the process can sleep
2437 *
2438 * Returns:
2439 * 1 - DIAG reset and READY
2440 * 0 - READY initially OR soft reset and READY
2441 * -1 - Any failure on KickStart
2442 * -2 - Msg Unit Reset Failed
2443 * -3 - IO Unit Reset Failed
2444 * -4 - IOC owned by a PEER
2445 */
2446static int
2447MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2448{
2449 u32 ioc_state;
2450 int statefault = 0;
2451 int cntdn;
2452 int hard_reset_done = 0;
2453 int r;
2454 int ii;
2455 int whoinit;
2456
2457 /* Get current [raw] IOC state */
2458 ioc_state = mpt_GetIocState(ioc, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302459 dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 /*
2462 * Check to see if IOC got left/stuck in doorbell handshake
2463 * grip of death. If so, hard reset the IOC.
2464 */
2465 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2466 statefault = 1;
2467 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2468 ioc->name);
2469 }
2470
2471 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002472 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 return 0;
2474
2475 /*
2476 * Check to see if IOC is in FAULT state.
2477 */
2478 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2479 statefault = 2;
2480 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2481 ioc->name);
2482 printk(KERN_WARNING " FAULT code = %04xh\n",
2483 ioc_state & MPI_DOORBELL_DATA_MASK);
2484 }
2485
2486 /*
2487 * Hmmm... Did it get left operational?
2488 */
2489 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302490 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 ioc->name));
2492
2493 /* Check WhoInit.
2494 * If PCI Peer, exit.
2495 * Else, if no fault conditions are present, issue a MessageUnitReset
2496 * Else, fall through to KickStart case
2497 */
2498 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302499 dinitprintk(ioc, printk(KERN_INFO MYNAM
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002500 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 whoinit, statefault, force));
2502 if (whoinit == MPI_WHOINIT_PCI_PEER)
2503 return -4;
2504 else {
2505 if ((statefault == 0 ) && (force == 0)) {
2506 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2507 return 0;
2508 }
2509 statefault = 3;
2510 }
2511 }
2512
2513 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2514 if (hard_reset_done < 0)
2515 return -1;
2516
2517 /*
2518 * Loop here waiting for IOC to come READY.
2519 */
2520 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002521 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2524 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2525 /*
2526 * BIOS or previous driver load left IOC in OP state.
2527 * Reset messaging FIFOs.
2528 */
2529 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2530 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2531 return -2;
2532 }
2533 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2534 /*
2535 * Something is wrong. Try to get IOC back
2536 * to a known state.
2537 */
2538 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2539 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2540 return -3;
2541 }
2542 }
2543
2544 ii++; cntdn--;
2545 if (!cntdn) {
2546 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2547 ioc->name, (int)((ii+5)/HZ));
2548 return -ETIME;
2549 }
2550
2551 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002552 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 } else {
2554 mdelay (1); /* 1 msec delay */
2555 }
2556
2557 }
2558
2559 if (statefault < 3) {
2560 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2561 ioc->name,
2562 statefault==1 ? "stuck handshake" : "IOC FAULT");
2563 }
2564
2565 return hard_reset_done;
2566}
2567
2568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002569/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 * mpt_GetIocState - Get the current state of a MPT adapter.
2571 * @ioc: Pointer to MPT_ADAPTER structure
2572 * @cooked: Request raw or cooked IOC state
2573 *
2574 * Returns all IOC Doorbell register bits if cooked==0, else just the
2575 * Doorbell bits in MPI_IOC_STATE_MASK.
2576 */
2577u32
2578mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2579{
2580 u32 s, sc;
2581
2582 /* Get! */
2583 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2584// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2585 sc = s & MPI_IOC_STATE_MASK;
2586
2587 /* Save! */
2588 ioc->last_state = sc;
2589
2590 return cooked ? sc : s;
2591}
2592
2593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002594/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 * GetIocFacts - Send IOCFacts request to MPT adapter.
2596 * @ioc: Pointer to MPT_ADAPTER structure
2597 * @sleepFlag: Specifies whether the process can sleep
2598 * @reason: If recovery, only update facts.
2599 *
2600 * Returns 0 for success, non-zero for failure.
2601 */
2602static int
2603GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2604{
2605 IOCFacts_t get_facts;
2606 IOCFactsReply_t *facts;
2607 int r;
2608 int req_sz;
2609 int reply_sz;
2610 int sz;
2611 u32 status, vv;
2612 u8 shiftFactor=1;
2613
2614 /* IOC *must* NOT be in RESET state! */
2615 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2616 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2617 ioc->name,
2618 ioc->last_state );
2619 return -44;
2620 }
2621
2622 facts = &ioc->facts;
2623
2624 /* Destination (reply area)... */
2625 reply_sz = sizeof(*facts);
2626 memset(facts, 0, reply_sz);
2627
2628 /* Request area (get_facts on the stack right now!) */
2629 req_sz = sizeof(get_facts);
2630 memset(&get_facts, 0, req_sz);
2631
2632 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2633 /* Assert: All other get_facts fields are zero! */
2634
Prakash, Sathya436ace72007-07-24 15:42:08 +05302635 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002636 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 ioc->name, req_sz, reply_sz));
2638
2639 /* No non-zero fields in the get_facts request are greater than
2640 * 1 byte in size, so we can just fire it off as is.
2641 */
2642 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2643 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2644 if (r != 0)
2645 return r;
2646
2647 /*
2648 * Now byte swap (GRRR) the necessary fields before any further
2649 * inspection of reply contents.
2650 *
2651 * But need to do some sanity checks on MsgLength (byte) field
2652 * to make sure we don't zero IOC's req_sz!
2653 */
2654 /* Did we get a valid reply? */
2655 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2656 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2657 /*
2658 * If not been here, done that, save off first WhoInit value
2659 */
2660 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2661 ioc->FirstWhoInit = facts->WhoInit;
2662 }
2663
2664 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2665 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2666 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2667 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2668 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002669 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 /* CHECKME! IOCStatus, IOCLogInfo */
2671
2672 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2673 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2674
2675 /*
2676 * FC f/w version changed between 1.1 and 1.2
2677 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2678 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2679 */
2680 if (facts->MsgVersion < 0x0102) {
2681 /*
2682 * Handle old FC f/w style, convert to new...
2683 */
2684 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2685 facts->FWVersion.Word =
2686 ((oldv<<12) & 0xFF000000) |
2687 ((oldv<<8) & 0x000FFF00);
2688 } else
2689 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2690
2691 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002692 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2693 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2694 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 facts->CurrentHostMfaHighAddr =
2696 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2697 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2698 facts->CurrentSenseBufferHighAddr =
2699 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2700 facts->CurReplyFrameSize =
2701 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002702 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 /*
2705 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2706 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2707 * to 14 in MPI-1.01.0x.
2708 */
2709 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2710 facts->MsgVersion > 0x0100) {
2711 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2712 }
2713
2714 sz = facts->FWImageSize;
2715 if ( sz & 0x01 )
2716 sz += 1;
2717 if ( sz & 0x02 )
2718 sz += 2;
2719 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002720
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 if (!facts->RequestFrameSize) {
2722 /* Something is wrong! */
2723 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2724 ioc->name);
2725 return -55;
2726 }
2727
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002728 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 vv = ((63 / (sz * 4)) + 1) & 0x03;
2730 ioc->NB_for_64_byte_frame = vv;
2731 while ( sz )
2732 {
2733 shiftFactor++;
2734 sz = sz >> 1;
2735 }
2736 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302737 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2738 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2739 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002740
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2742 /*
2743 * Set values for this IOC's request & reply frame sizes,
2744 * and request & reply queue depths...
2745 */
2746 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2747 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2748 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2749 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2750
Prakash, Sathya436ace72007-07-24 15:42:08 +05302751 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302753 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 ioc->name, ioc->req_sz, ioc->req_depth));
2755
2756 /* Get port facts! */
2757 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2758 return r;
2759 }
2760 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002761 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2763 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2764 RequestFrameSize)/sizeof(u32)));
2765 return -66;
2766 }
2767
2768 return 0;
2769}
2770
2771/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002772/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 * GetPortFacts - Send PortFacts request to MPT adapter.
2774 * @ioc: Pointer to MPT_ADAPTER structure
2775 * @portnum: Port number
2776 * @sleepFlag: Specifies whether the process can sleep
2777 *
2778 * Returns 0 for success, non-zero for failure.
2779 */
2780static int
2781GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2782{
2783 PortFacts_t get_pfacts;
2784 PortFactsReply_t *pfacts;
2785 int ii;
2786 int req_sz;
2787 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002788 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 /* IOC *must* NOT be in RESET state! */
2791 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2792 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2793 ioc->name,
2794 ioc->last_state );
2795 return -4;
2796 }
2797
2798 pfacts = &ioc->pfacts[portnum];
2799
2800 /* Destination (reply area)... */
2801 reply_sz = sizeof(*pfacts);
2802 memset(pfacts, 0, reply_sz);
2803
2804 /* Request area (get_pfacts on the stack right now!) */
2805 req_sz = sizeof(get_pfacts);
2806 memset(&get_pfacts, 0, req_sz);
2807
2808 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2809 get_pfacts.PortNumber = portnum;
2810 /* Assert: All other get_pfacts fields are zero! */
2811
Prakash, Sathya436ace72007-07-24 15:42:08 +05302812 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 ioc->name, portnum));
2814
2815 /* No non-zero fields in the get_pfacts request are greater than
2816 * 1 byte in size, so we can just fire it off as is.
2817 */
2818 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2819 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2820 if (ii != 0)
2821 return ii;
2822
2823 /* Did we get a valid reply? */
2824
2825 /* Now byte swap the necessary fields in the response. */
2826 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2827 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2828 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2829 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2830 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2831 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2832 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2833 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2834 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2835
Eric Moore793955f2007-01-29 09:42:20 -07002836 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2837 pfacts->MaxDevices;
2838 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2839 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2840
2841 /*
2842 * Place all the devices on channels
2843 *
2844 * (for debuging)
2845 */
2846 if (mpt_channel_mapping) {
2847 ioc->devices_per_bus = 1;
2848 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2849 }
2850
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 return 0;
2852}
2853
2854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002855/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 * SendIocInit - Send IOCInit request to MPT adapter.
2857 * @ioc: Pointer to MPT_ADAPTER structure
2858 * @sleepFlag: Specifies whether the process can sleep
2859 *
2860 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2861 *
2862 * Returns 0 for success, non-zero for failure.
2863 */
2864static int
2865SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2866{
2867 IOCInit_t ioc_init;
2868 MPIDefaultReply_t init_reply;
2869 u32 state;
2870 int r;
2871 int count;
2872 int cntdn;
2873
2874 memset(&ioc_init, 0, sizeof(ioc_init));
2875 memset(&init_reply, 0, sizeof(init_reply));
2876
2877 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2878 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2879
2880 /* If we are in a recovery mode and we uploaded the FW image,
2881 * then this pointer is not NULL. Skip the upload a second time.
2882 * Set this flag if cached_fw set for either IOC.
2883 */
2884 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2885 ioc->upload_fw = 1;
2886 else
2887 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302888 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2890
Eric Moore793955f2007-01-29 09:42:20 -07002891 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2892 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302893 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002894 ioc->name, ioc->facts.MsgVersion));
2895 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2896 // set MsgVersion and HeaderVersion host driver was built with
2897 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2898 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002900 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2901 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2902 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2903 return -99;
2904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2906
2907 if (sizeof(dma_addr_t) == sizeof(u64)) {
2908 /* Save the upper 32-bits of the request
2909 * (reply) and sense buffers.
2910 */
2911 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2912 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2913 } else {
2914 /* Force 32-bit addressing */
2915 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2916 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2917 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002918
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2920 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002921 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2922 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Prakash, Sathya436ace72007-07-24 15:42:08 +05302924 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 ioc->name, &ioc_init));
2926
2927 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2928 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002929 if (r != 0) {
2930 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
2934 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002935 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 */
2937
Prakash, Sathya436ace72007-07-24 15:42:08 +05302938 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002940
2941 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2942 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
2946 /* YIKES! SUPER IMPORTANT!!!
2947 * Poll IocState until _OPERATIONAL while IOC is doing
2948 * LoopInit and TargetDiscovery!
2949 */
2950 count = 0;
2951 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2952 state = mpt_GetIocState(ioc, 1);
2953 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2954 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002955 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 } else {
2957 mdelay(1);
2958 }
2959
2960 if (!cntdn) {
2961 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2962 ioc->name, (int)((count+5)/HZ));
2963 return -9;
2964 }
2965
2966 state = mpt_GetIocState(ioc, 1);
2967 count++;
2968 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302969 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 ioc->name, count));
2971
Eric Mooreba856d32006-07-11 17:34:01 -06002972 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 return r;
2974}
2975
2976/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002977/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 * SendPortEnable - Send PortEnable request to MPT adapter port.
2979 * @ioc: Pointer to MPT_ADAPTER structure
2980 * @portnum: Port number to enable
2981 * @sleepFlag: Specifies whether the process can sleep
2982 *
2983 * Send PortEnable to bring IOC to OPERATIONAL state.
2984 *
2985 * Returns 0 for success, non-zero for failure.
2986 */
2987static int
2988SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2989{
2990 PortEnable_t port_enable;
2991 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002992 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 int req_sz;
2994 int reply_sz;
2995
2996 /* Destination... */
2997 reply_sz = sizeof(MPIDefaultReply_t);
2998 memset(&reply_buf, 0, reply_sz);
2999
3000 req_sz = sizeof(PortEnable_t);
3001 memset(&port_enable, 0, req_sz);
3002
3003 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3004 port_enable.PortNumber = portnum;
3005/* port_enable.ChainOffset = 0; */
3006/* port_enable.MsgFlags = 0; */
3007/* port_enable.MsgContext = 0; */
3008
Prakash, Sathya436ace72007-07-24 15:42:08 +05303009 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 ioc->name, portnum, &port_enable));
3011
3012 /* RAID FW may take a long time to enable
3013 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003014 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003015 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3016 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3017 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003018 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003019 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3020 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3021 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003023 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024}
3025
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003026/**
3027 * mpt_alloc_fw_memory - allocate firmware memory
3028 * @ioc: Pointer to MPT_ADAPTER structure
3029 * @size: total FW bytes
3030 *
3031 * If memory has already been allocated, the same (cached) value
3032 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 */
3034void
3035mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3036{
3037 if (ioc->cached_fw)
3038 return; /* use already allocated memory */
3039 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3040 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3041 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003042 ioc->alloc_total += size;
3043 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 } else {
3045 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3046 ioc->alloc_total += size;
3047 }
3048}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003049/**
3050 * mpt_free_fw_memory - free firmware memory
3051 * @ioc: Pointer to MPT_ADAPTER structure
3052 *
3053 * If alt_img is NULL, delete from ioc structure.
3054 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 */
3056void
3057mpt_free_fw_memory(MPT_ADAPTER *ioc)
3058{
3059 int sz;
3060
3061 sz = ioc->facts.FWImageSize;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303062 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 -07003063 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3064 pci_free_consistent(ioc->pcidev, sz,
3065 ioc->cached_fw, ioc->cached_fw_dma);
3066 ioc->cached_fw = NULL;
3067
3068 return;
3069}
3070
3071
3072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003073/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3075 * @ioc: Pointer to MPT_ADAPTER structure
3076 * @sleepFlag: Specifies whether the process can sleep
3077 *
3078 * Returns 0 for success, >0 for handshake failure
3079 * <0 for fw upload failure.
3080 *
3081 * Remark: If bound IOC and a successful FWUpload was performed
3082 * on the bound IOC, the second image is discarded
3083 * and memory is free'd. Both channels must upload to prevent
3084 * IOC from running in degraded mode.
3085 */
3086static int
3087mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3088{
3089 u8 request[ioc->req_sz];
3090 u8 reply[sizeof(FWUploadReply_t)];
3091 FWUpload_t *prequest;
3092 FWUploadReply_t *preply;
3093 FWUploadTCSGE_t *ptcsge;
3094 int sgeoffset;
3095 u32 flagsLength;
3096 int ii, sz, reply_sz;
3097 int cmdStatus;
3098
3099 /* If the image size is 0, we are done.
3100 */
3101 if ((sz = ioc->facts.FWImageSize) == 0)
3102 return 0;
3103
3104 mpt_alloc_fw_memory(ioc, sz);
3105
Prakash, Sathya436ace72007-07-24 15:42:08 +05303106 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003108
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 if (ioc->cached_fw == NULL) {
3110 /* Major Failure.
3111 */
3112 return -ENOMEM;
3113 }
3114
3115 prequest = (FWUpload_t *)&request;
3116 preply = (FWUploadReply_t *)&reply;
3117
3118 /* Destination... */
3119 memset(prequest, 0, ioc->req_sz);
3120
3121 reply_sz = sizeof(reply);
3122 memset(preply, 0, reply_sz);
3123
3124 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3125 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3126
3127 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3128 ptcsge->DetailsLength = 12;
3129 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3130 ptcsge->ImageSize = cpu_to_le32(sz);
3131
3132 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3133
3134 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3135 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3136
3137 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303138 dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 prequest, sgeoffset));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303140 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3143 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3144
Prakash, Sathya436ace72007-07-24 15:42:08 +05303145 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
3147 cmdStatus = -EFAULT;
3148 if (ii == 0) {
3149 /* Handshake transfer was complete and successful.
3150 * Check the Reply Frame.
3151 */
3152 int status, transfer_sz;
3153 status = le16_to_cpu(preply->IOCStatus);
3154 if (status == MPI_IOCSTATUS_SUCCESS) {
3155 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3156 if (transfer_sz == sz)
3157 cmdStatus = 0;
3158 }
3159 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303160 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 ioc->name, cmdStatus));
3162
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003163
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 if (cmdStatus) {
3165
Prakash, Sathya436ace72007-07-24 15:42:08 +05303166 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 ioc->name));
3168 mpt_free_fw_memory(ioc);
3169 }
3170
3171 return cmdStatus;
3172}
3173
3174/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003175/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 * mpt_downloadboot - DownloadBoot code
3177 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003178 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 * @sleepFlag: Specifies whether the process can sleep
3180 *
3181 * FwDownloadBoot requires Programmed IO access.
3182 *
3183 * Returns 0 for success
3184 * -1 FW Image size is 0
3185 * -2 No valid cached_fw Pointer
3186 * <0 for fw upload failure.
3187 */
3188static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003189mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 MpiExtImageHeader_t *pExtImage;
3192 u32 fwSize;
3193 u32 diag0val;
3194 int count;
3195 u32 *ptrFw;
3196 u32 diagRwData;
3197 u32 nextImage;
3198 u32 load_addr;
3199 u32 ioc_state=0;
3200
Prakash, Sathya436ace72007-07-24 15:42:08 +05303201 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003202 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003203
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3205 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3206 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3207 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3208 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3209 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3210
3211 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3212
3213 /* wait 1 msec */
3214 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003215 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 } else {
3217 mdelay (1);
3218 }
3219
3220 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3221 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3222
3223 for (count = 0; count < 30; count ++) {
3224 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3225 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303226 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 ioc->name, count));
3228 break;
3229 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003230 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003232 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003234 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 }
3236 }
3237
3238 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303239 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003240 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 ioc->name, diag0val));
3242 return -3;
3243 }
3244
3245 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3246 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3247 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3248 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3249 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3250 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3251
3252 /* Set the DiagRwEn and Disable ARM bits */
3253 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3254
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 fwSize = (pFwHeader->ImageSize + 3)/4;
3256 ptrFw = (u32 *) pFwHeader;
3257
3258 /* Write the LoadStartAddress to the DiagRw Address Register
3259 * using Programmed IO
3260 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003261 if (ioc->errata_flag_1064)
3262 pci_enable_io_access(ioc->pcidev);
3263
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303265 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 ioc->name, pFwHeader->LoadStartAddress));
3267
Prakash, Sathya436ace72007-07-24 15:42:08 +05303268 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 ioc->name, fwSize*4, ptrFw));
3270 while (fwSize--) {
3271 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3272 }
3273
3274 nextImage = pFwHeader->NextImageHeaderOffset;
3275 while (nextImage) {
3276 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3277
3278 load_addr = pExtImage->LoadStartAddress;
3279
3280 fwSize = (pExtImage->ImageSize + 3) >> 2;
3281 ptrFw = (u32 *)pExtImage;
3282
Prakash, Sathya436ace72007-07-24 15:42:08 +05303283 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 +02003284 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3286
3287 while (fwSize--) {
3288 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3289 }
3290 nextImage = pExtImage->NextImageHeaderOffset;
3291 }
3292
3293 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303294 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3296
3297 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303298 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3300
3301 /* Clear the internal flash bad bit - autoincrementing register,
3302 * so must do two writes.
3303 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003304 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003305 /*
3306 * 1030 and 1035 H/W errata, workaround to access
3307 * the ClearFlashBadSignatureBit
3308 */
3309 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3310 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3311 diagRwData |= 0x40000000;
3312 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3313 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3314
3315 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3316 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3317 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3318 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3319
3320 /* wait 1 msec */
3321 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003322 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003323 } else {
3324 mdelay (1);
3325 }
3326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003328 if (ioc->errata_flag_1064)
3329 pci_disable_io_access(ioc->pcidev);
3330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303332 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003333 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003335 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303336 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 ioc->name, diag0val));
3338 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3339
3340 /* Write 0xFF to reset the sequencer */
3341 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3342
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003343 if (ioc->bus_type == SAS) {
3344 ioc_state = mpt_GetIocState(ioc, 0);
3345 if ( (GetIocFacts(ioc, sleepFlag,
3346 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303347 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003348 ioc->name, ioc_state));
3349 return -EFAULT;
3350 }
3351 }
3352
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 for (count=0; count<HZ*20; count++) {
3354 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303355 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3356 "downloadboot successful! (count=%d) IocState=%x\n",
3357 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003358 if (ioc->bus_type == SAS) {
3359 return 0;
3360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303362 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3363 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 ioc->name));
3365 return -EFAULT;
3366 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303367 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3368 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 ioc->name));
3370 return 0;
3371 }
3372 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003373 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 } else {
3375 mdelay (10);
3376 }
3377 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303378 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3379 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 return -EFAULT;
3381}
3382
3383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003384/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 * KickStart - Perform hard reset of MPT adapter.
3386 * @ioc: Pointer to MPT_ADAPTER structure
3387 * @force: Force hard reset
3388 * @sleepFlag: Specifies whether the process can sleep
3389 *
3390 * This routine places MPT adapter in diagnostic mode via the
3391 * WriteSequence register, and then performs a hard reset of adapter
3392 * via the Diagnostic register.
3393 *
3394 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3395 * or NO_SLEEP (interrupt thread, use mdelay)
3396 * force - 1 if doorbell active, board fault state
3397 * board operational, IOC_RECOVERY or
3398 * IOC_BRINGUP and there is an alt_ioc.
3399 * 0 else
3400 *
3401 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003402 * 1 - hard reset, READY
3403 * 0 - no reset due to History bit, READY
3404 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 * OR reset but failed to come READY
3406 * -2 - no reset, could not enter DIAG mode
3407 * -3 - reset but bad FW bit
3408 */
3409static int
3410KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3411{
3412 int hard_reset_done = 0;
3413 u32 ioc_state=0;
3414 int cnt,cntdn;
3415
Prakash, Sathya436ace72007-07-24 15:42:08 +05303416 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003417 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 /* Always issue a Msg Unit Reset first. This will clear some
3419 * SCSI bus hang conditions.
3420 */
3421 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3422
3423 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003424 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 } else {
3426 mdelay (1000);
3427 }
3428 }
3429
3430 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3431 if (hard_reset_done < 0)
3432 return hard_reset_done;
3433
Prakash, Sathya436ace72007-07-24 15:42:08 +05303434 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 ioc->name));
3436
3437 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3438 for (cnt=0; cnt<cntdn; cnt++) {
3439 ioc_state = mpt_GetIocState(ioc, 1);
3440 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303441 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 ioc->name, cnt));
3443 return hard_reset_done;
3444 }
3445 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003446 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 } else {
3448 mdelay (10);
3449 }
3450 }
3451
3452 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3453 ioc->name, ioc_state);
3454 return -1;
3455}
3456
3457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003458/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 * mpt_diag_reset - Perform hard reset of the adapter.
3460 * @ioc: Pointer to MPT_ADAPTER structure
3461 * @ignore: Set if to honor and clear to ignore
3462 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003463 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 * else set to NO_SLEEP (use mdelay instead)
3465 *
3466 * This routine places the adapter in diagnostic mode via the
3467 * WriteSequence register and then performs a hard reset of adapter
3468 * via the Diagnostic register. Adapter should be in ready state
3469 * upon successful completion.
3470 *
3471 * Returns: 1 hard reset successful
3472 * 0 no reset performed because reset history bit set
3473 * -2 enabling diagnostic mode failed
3474 * -3 diagnostic reset failed
3475 */
3476static int
3477mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3478{
Eric Moore0ccdb002006-07-11 17:33:13 -06003479 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 u32 diag0val;
3481 u32 doorbell;
3482 int hard_reset_done = 0;
3483 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485
Eric Moorecd2c6192007-01-29 09:47:47 -07003486 /* Clear any existing interrupts */
3487 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3488
Eric Moore87cf8982006-06-27 16:09:26 -06003489 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303490 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003491 "address=%p\n", ioc->name, __FUNCTION__,
3492 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3493 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3494 if (sleepFlag == CAN_SLEEP)
3495 msleep(1);
3496 else
3497 mdelay(1);
3498
3499 for (count = 0; count < 60; count ++) {
3500 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3501 doorbell &= MPI_IOC_STATE_MASK;
3502
Prakash, Sathya436ace72007-07-24 15:42:08 +05303503 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003504 "looking for READY STATE: doorbell=%x"
3505 " count=%d\n",
3506 ioc->name, doorbell, count));
3507 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003508 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003509 }
3510
3511 /* wait 1 sec */
3512 if (sleepFlag == CAN_SLEEP)
3513 msleep(1000);
3514 else
3515 mdelay(1000);
3516 }
3517 return -1;
3518 }
3519
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 /* Use "Diagnostic reset" method! (only thing available!) */
3521 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3522
Prakash, Sathya436ace72007-07-24 15:42:08 +05303523 if (ioc->debug_level & MPT_DEBUG) {
3524 if (ioc->alt_ioc)
3525 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3526 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
3530 /* Do the reset if we are told to ignore the reset history
3531 * or if the reset history is 0
3532 */
3533 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3534 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3535 /* Write magic sequence to WriteSequence register
3536 * Loop until in diagnostic mode
3537 */
3538 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3539 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3540 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3541 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3542 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3543 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3544
3545 /* wait 100 msec */
3546 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003547 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 } else {
3549 mdelay (100);
3550 }
3551
3552 count++;
3553 if (count > 20) {
3554 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3555 ioc->name, diag0val);
3556 return -2;
3557
3558 }
3559
3560 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3561
Prakash, Sathya436ace72007-07-24 15:42:08 +05303562 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 ioc->name, diag0val));
3564 }
3565
Prakash, Sathya436ace72007-07-24 15:42:08 +05303566 if (ioc->debug_level & MPT_DEBUG) {
3567 if (ioc->alt_ioc)
3568 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3569 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 /*
3573 * Disable the ARM (Bug fix)
3574 *
3575 */
3576 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003577 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578
3579 /*
3580 * Now hit the reset bit in the Diagnostic register
3581 * (THE BIG HAMMER!) (Clears DRWE bit).
3582 */
3583 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3584 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303585 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 ioc->name));
3587
3588 /*
3589 * Call each currently registered protocol IOC reset handler
3590 * with pre-reset indication.
3591 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3592 * MptResetHandlers[] registered yet.
3593 */
3594 {
3595 int ii;
3596 int r = 0;
3597
3598 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
3599 if (MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303600 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3601 "Calling IOC pre_reset handler #%d\n",
3602 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003603 r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303605 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3606 "Calling alt-%s pre_reset handler #%d\n",
3607 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05003608 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610 }
3611 }
3612 /* FIXME? Examine results here? */
3613 }
3614
Eric Moore0ccdb002006-07-11 17:33:13 -06003615 if (ioc->cached_fw)
3616 iocp = ioc;
3617 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3618 iocp = ioc->alt_ioc;
3619 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 /* If the DownloadBoot operation fails, the
3621 * IOC will be left unusable. This is a fatal error
3622 * case. _diag_reset will return < 0
3623 */
3624 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003625 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3627 break;
3628 }
3629
Prakash, Sathya436ace72007-07-24 15:42:08 +05303630 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003631 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 /* wait 1 sec */
3633 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003634 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 } else {
3636 mdelay (1000);
3637 }
3638 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003639 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003640 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 printk(KERN_WARNING MYNAM
3642 ": firmware downloadboot failure (%d)!\n", count);
3643 }
3644
3645 } else {
3646 /* Wait for FW to reload and for board
3647 * to go to the READY state.
3648 * Maximum wait is 60 seconds.
3649 * If fail, no error will check again
3650 * with calling program.
3651 */
3652 for (count = 0; count < 60; count ++) {
3653 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3654 doorbell &= MPI_IOC_STATE_MASK;
3655
3656 if (doorbell == MPI_IOC_STATE_READY) {
3657 break;
3658 }
3659
3660 /* wait 1 sec */
3661 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003662 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 } else {
3664 mdelay (1000);
3665 }
3666 }
3667 }
3668 }
3669
3670 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303671 if (ioc->debug_level & MPT_DEBUG) {
3672 if (ioc->alt_ioc)
3673 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3674 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3675 ioc->name, diag0val, diag1val));
3676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
3678 /* Clear RESET_HISTORY bit! Place board in the
3679 * diagnostic mode to update the diag register.
3680 */
3681 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3682 count = 0;
3683 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3684 /* Write magic sequence to WriteSequence register
3685 * Loop until in diagnostic mode
3686 */
3687 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3688 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3689 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3690 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3691 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3692 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3693
3694 /* wait 100 msec */
3695 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003696 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 } else {
3698 mdelay (100);
3699 }
3700
3701 count++;
3702 if (count > 20) {
3703 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3704 ioc->name, diag0val);
3705 break;
3706 }
3707 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3708 }
3709 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3710 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3711 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3712 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3713 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3714 ioc->name);
3715 }
3716
3717 /* Disable Diagnostic Mode
3718 */
3719 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3720
3721 /* Check FW reload status flags.
3722 */
3723 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3724 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3725 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3726 ioc->name, diag0val);
3727 return -3;
3728 }
3729
Prakash, Sathya436ace72007-07-24 15:42:08 +05303730 if (ioc->debug_level & MPT_DEBUG) {
3731 if (ioc->alt_ioc)
3732 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3733 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736
3737 /*
3738 * Reset flag that says we've enabled event notification
3739 */
3740 ioc->facts.EventState = 0;
3741
3742 if (ioc->alt_ioc)
3743 ioc->alt_ioc->facts.EventState = 0;
3744
3745 return hard_reset_done;
3746}
3747
3748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003749/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 * SendIocReset - Send IOCReset request to MPT adapter.
3751 * @ioc: Pointer to MPT_ADAPTER structure
3752 * @reset_type: reset type, expected values are
3753 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003754 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 *
3756 * Send IOCReset request to the MPT adapter.
3757 *
3758 * Returns 0 for success, non-zero for failure.
3759 */
3760static int
3761SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3762{
3763 int r;
3764 u32 state;
3765 int cntdn, count;
3766
Prakash, Sathya436ace72007-07-24 15:42:08 +05303767 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 ioc->name, reset_type));
3769 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3770 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3771 return r;
3772
3773 /* FW ACK'd request, wait for READY state
3774 */
3775 count = 0;
3776 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3777
3778 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3779 cntdn--;
3780 count++;
3781 if (!cntdn) {
3782 if (sleepFlag != CAN_SLEEP)
3783 count *= 10;
3784
3785 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3786 ioc->name, (int)((count+5)/HZ));
3787 return -ETIME;
3788 }
3789
3790 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003791 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 } else {
3793 mdelay (1); /* 1 msec delay */
3794 }
3795 }
3796
3797 /* TODO!
3798 * Cleanup all event stuff for this IOC; re-issue EventNotification
3799 * request if needed.
3800 */
3801 if (ioc->facts.Function)
3802 ioc->facts.EventState = 0;
3803
3804 return 0;
3805}
3806
3807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003808/**
3809 * initChainBuffers - Allocate memory for and initialize chain buffers
3810 * @ioc: Pointer to MPT_ADAPTER structure
3811 *
3812 * Allocates memory for and initializes chain buffers,
3813 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 */
3815static int
3816initChainBuffers(MPT_ADAPTER *ioc)
3817{
3818 u8 *mem;
3819 int sz, ii, num_chain;
3820 int scale, num_sge, numSGE;
3821
3822 /* ReqToChain size must equal the req_depth
3823 * index = req_idx
3824 */
3825 if (ioc->ReqToChain == NULL) {
3826 sz = ioc->req_depth * sizeof(int);
3827 mem = kmalloc(sz, GFP_ATOMIC);
3828 if (mem == NULL)
3829 return -1;
3830
3831 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303832 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 ioc->name, mem, sz));
3834 mem = kmalloc(sz, GFP_ATOMIC);
3835 if (mem == NULL)
3836 return -1;
3837
3838 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303839 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 ioc->name, mem, sz));
3841 }
3842 for (ii = 0; ii < ioc->req_depth; ii++) {
3843 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3844 }
3845
3846 /* ChainToChain size must equal the total number
3847 * of chain buffers to be allocated.
3848 * index = chain_idx
3849 *
3850 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003851 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 *
3853 * num_sge = num sge in request frame + last chain buffer
3854 * scale = num sge per chain buffer if no chain element
3855 */
3856 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3857 if (sizeof(dma_addr_t) == sizeof(u64))
3858 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3859 else
3860 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3861
3862 if (sizeof(dma_addr_t) == sizeof(u64)) {
3863 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3864 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3865 } else {
3866 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3867 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3868 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303869 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 ioc->name, num_sge, numSGE));
3871
3872 if ( numSGE > MPT_SCSI_SG_DEPTH )
3873 numSGE = MPT_SCSI_SG_DEPTH;
3874
3875 num_chain = 1;
3876 while (numSGE - num_sge > 0) {
3877 num_chain++;
3878 num_sge += (scale - 1);
3879 }
3880 num_chain++;
3881
Prakash, Sathya436ace72007-07-24 15:42:08 +05303882 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 ioc->name, numSGE, num_sge, num_chain));
3884
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003885 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 num_chain *= MPT_SCSI_CAN_QUEUE;
3887 else
3888 num_chain *= MPT_FC_CAN_QUEUE;
3889
3890 ioc->num_chain = num_chain;
3891
3892 sz = num_chain * sizeof(int);
3893 if (ioc->ChainToChain == NULL) {
3894 mem = kmalloc(sz, GFP_ATOMIC);
3895 if (mem == NULL)
3896 return -1;
3897
3898 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303899 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 ioc->name, mem, sz));
3901 } else {
3902 mem = (u8 *) ioc->ChainToChain;
3903 }
3904 memset(mem, 0xFF, sz);
3905 return num_chain;
3906}
3907
3908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003909/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3911 * @ioc: Pointer to MPT_ADAPTER structure
3912 *
3913 * This routine allocates memory for the MPT reply and request frame
3914 * pools (if necessary), and primes the IOC reply FIFO with
3915 * reply frames.
3916 *
3917 * Returns 0 for success, non-zero for failure.
3918 */
3919static int
3920PrimeIocFifos(MPT_ADAPTER *ioc)
3921{
3922 MPT_FRAME_HDR *mf;
3923 unsigned long flags;
3924 dma_addr_t alloc_dma;
3925 u8 *mem;
3926 int i, reply_sz, sz, total_size, num_chain;
3927
3928 /* Prime reply FIFO... */
3929
3930 if (ioc->reply_frames == NULL) {
3931 if ( (num_chain = initChainBuffers(ioc)) < 0)
3932 return -1;
3933
3934 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303935 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303937 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 ioc->name, reply_sz, reply_sz));
3939
3940 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303941 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303943 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 ioc->name, sz, sz));
3945 total_size += sz;
3946
3947 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303948 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303950 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 ioc->name, sz, sz, num_chain));
3952
3953 total_size += sz;
3954 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3955 if (mem == NULL) {
3956 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3957 ioc->name);
3958 goto out_fail;
3959 }
3960
Prakash, Sathya436ace72007-07-24 15:42:08 +05303961 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3963
3964 memset(mem, 0, total_size);
3965 ioc->alloc_total += total_size;
3966 ioc->alloc = mem;
3967 ioc->alloc_dma = alloc_dma;
3968 ioc->alloc_sz = total_size;
3969 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3970 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3971
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003973 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3974
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 alloc_dma += reply_sz;
3976 mem += reply_sz;
3977
3978 /* Request FIFO - WE manage this! */
3979
3980 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3981 ioc->req_frames_dma = alloc_dma;
3982
Prakash, Sathya436ace72007-07-24 15:42:08 +05303983 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 ioc->name, mem, (void *)(ulong)alloc_dma));
3985
3986 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3987
3988#if defined(CONFIG_MTRR) && 0
3989 /*
3990 * Enable Write Combining MTRR for IOC's memory region.
3991 * (at least as much as we can; "size and base must be
3992 * multiples of 4 kiB"
3993 */
3994 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
3995 sz,
3996 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303997 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 ioc->name, ioc->req_frames_dma, sz));
3999#endif
4000
4001 for (i = 0; i < ioc->req_depth; i++) {
4002 alloc_dma += ioc->req_sz;
4003 mem += ioc->req_sz;
4004 }
4005
4006 ioc->ChainBuffer = mem;
4007 ioc->ChainBufferDMA = alloc_dma;
4008
Prakash, Sathya436ace72007-07-24 15:42:08 +05304009 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4011
4012 /* Initialize the free chain Q.
4013 */
4014
4015 INIT_LIST_HEAD(&ioc->FreeChainQ);
4016
4017 /* Post the chain buffers to the FreeChainQ.
4018 */
4019 mem = (u8 *)ioc->ChainBuffer;
4020 for (i=0; i < num_chain; i++) {
4021 mf = (MPT_FRAME_HDR *) mem;
4022 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4023 mem += ioc->req_sz;
4024 }
4025
4026 /* Initialize Request frames linked list
4027 */
4028 alloc_dma = ioc->req_frames_dma;
4029 mem = (u8 *) ioc->req_frames;
4030
4031 spin_lock_irqsave(&ioc->FreeQlock, flags);
4032 INIT_LIST_HEAD(&ioc->FreeQ);
4033 for (i = 0; i < ioc->req_depth; i++) {
4034 mf = (MPT_FRAME_HDR *) mem;
4035
4036 /* Queue REQUESTs *internally*! */
4037 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4038
4039 mem += ioc->req_sz;
4040 }
4041 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4042
4043 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4044 ioc->sense_buf_pool =
4045 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4046 if (ioc->sense_buf_pool == NULL) {
4047 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4048 ioc->name);
4049 goto out_fail;
4050 }
4051
4052 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4053 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304054 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4056
4057 }
4058
4059 /* Post Reply frames to FIFO
4060 */
4061 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4064
4065 for (i = 0; i < ioc->reply_depth; i++) {
4066 /* Write each address to the IOC! */
4067 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4068 alloc_dma += ioc->reply_sz;
4069 }
4070
4071 return 0;
4072
4073out_fail:
4074 if (ioc->alloc != NULL) {
4075 sz = ioc->alloc_sz;
4076 pci_free_consistent(ioc->pcidev,
4077 sz,
4078 ioc->alloc, ioc->alloc_dma);
4079 ioc->reply_frames = NULL;
4080 ioc->req_frames = NULL;
4081 ioc->alloc_total -= sz;
4082 }
4083 if (ioc->sense_buf_pool != NULL) {
4084 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4085 pci_free_consistent(ioc->pcidev,
4086 sz,
4087 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4088 ioc->sense_buf_pool = NULL;
4089 }
4090 return -1;
4091}
4092
4093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4094/**
4095 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4096 * from IOC via doorbell handshake method.
4097 * @ioc: Pointer to MPT_ADAPTER structure
4098 * @reqBytes: Size of the request in bytes
4099 * @req: Pointer to MPT request frame
4100 * @replyBytes: Expected size of the reply in bytes
4101 * @u16reply: Pointer to area where reply should be written
4102 * @maxwait: Max wait time for a reply (in seconds)
4103 * @sleepFlag: Specifies whether the process can sleep
4104 *
4105 * NOTES: It is the callers responsibility to byte-swap fields in the
4106 * request which are greater than 1 byte in size. It is also the
4107 * callers responsibility to byte-swap response fields which are
4108 * greater than 1 byte in size.
4109 *
4110 * Returns 0 for success, non-zero for failure.
4111 */
4112static int
4113mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004114 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115{
4116 MPIDefaultReply_t *mptReply;
4117 int failcnt = 0;
4118 int t;
4119
4120 /*
4121 * Get ready to cache a handshake reply
4122 */
4123 ioc->hs_reply_idx = 0;
4124 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4125 mptReply->MsgLength = 0;
4126
4127 /*
4128 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4129 * then tell IOC that we want to handshake a request of N words.
4130 * (WRITE u32val to Doorbell reg).
4131 */
4132 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4133 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4134 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4135 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4136
4137 /*
4138 * Wait for IOC's doorbell handshake int
4139 */
4140 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4141 failcnt++;
4142
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4145
4146 /* Read doorbell and check for active bit */
4147 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4148 return -1;
4149
4150 /*
4151 * Clear doorbell int (WRITE 0 to IntStatus reg),
4152 * then wait for IOC to ACKnowledge that it's ready for
4153 * our handshake request.
4154 */
4155 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4156 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4157 failcnt++;
4158
4159 if (!failcnt) {
4160 int ii;
4161 u8 *req_as_bytes = (u8 *) req;
4162
4163 /*
4164 * Stuff request words via doorbell handshake,
4165 * with ACK from IOC for each.
4166 */
4167 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4168 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4169 (req_as_bytes[(ii*4) + 1] << 8) |
4170 (req_as_bytes[(ii*4) + 2] << 16) |
4171 (req_as_bytes[(ii*4) + 3] << 24));
4172
4173 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4174 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4175 failcnt++;
4176 }
4177
Prakash, Sathya436ace72007-07-24 15:42:08 +05304178 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
4179 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Prakash, Sathya436ace72007-07-24 15:42:08 +05304181 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4183
4184 /*
4185 * Wait for completion of doorbell handshake reply from the IOC
4186 */
4187 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4188 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004189
Prakash, Sathya436ace72007-07-24 15:42:08 +05304190 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4192
4193 /*
4194 * Copy out the cached reply...
4195 */
4196 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4197 u16reply[ii] = ioc->hs_reply[ii];
4198 } else {
4199 return -99;
4200 }
4201
4202 return -failcnt;
4203}
4204
4205/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004206/**
4207 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 * @ioc: Pointer to MPT_ADAPTER structure
4209 * @howlong: How long to wait (in seconds)
4210 * @sleepFlag: Specifies whether the process can sleep
4211 *
4212 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004213 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4214 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 *
4216 * Returns a negative value on failure, else wait loop count.
4217 */
4218static int
4219WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4220{
4221 int cntdn;
4222 int count = 0;
4223 u32 intstat=0;
4224
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004225 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
4227 if (sleepFlag == CAN_SLEEP) {
4228 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004229 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4231 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4232 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 count++;
4234 }
4235 } else {
4236 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004237 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4239 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4240 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 count++;
4242 }
4243 }
4244
4245 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304246 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 ioc->name, count));
4248 return count;
4249 }
4250
4251 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4252 ioc->name, count, intstat);
4253 return -1;
4254}
4255
4256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004257/**
4258 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 * @ioc: Pointer to MPT_ADAPTER structure
4260 * @howlong: How long to wait (in seconds)
4261 * @sleepFlag: Specifies whether the process can sleep
4262 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004263 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4264 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 *
4266 * Returns a negative value on failure, else wait loop count.
4267 */
4268static int
4269WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4270{
4271 int cntdn;
4272 int count = 0;
4273 u32 intstat=0;
4274
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004275 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 if (sleepFlag == CAN_SLEEP) {
4277 while (--cntdn) {
4278 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4279 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4280 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004281 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 count++;
4283 }
4284 } else {
4285 while (--cntdn) {
4286 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4287 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4288 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004289 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 count++;
4291 }
4292 }
4293
4294 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304295 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 ioc->name, count, howlong));
4297 return count;
4298 }
4299
4300 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4301 ioc->name, count, intstat);
4302 return -1;
4303}
4304
4305/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004306/**
4307 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 * @ioc: Pointer to MPT_ADAPTER structure
4309 * @howlong: How long to wait (in seconds)
4310 * @sleepFlag: Specifies whether the process can sleep
4311 *
4312 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4313 * Reply is cached to IOC private area large enough to hold a maximum
4314 * of 128 bytes of reply data.
4315 *
4316 * Returns a negative value on failure, else size of reply in WORDS.
4317 */
4318static int
4319WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4320{
4321 int u16cnt = 0;
4322 int failcnt = 0;
4323 int t;
4324 u16 *hs_reply = ioc->hs_reply;
4325 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4326 u16 hword;
4327
4328 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4329
4330 /*
4331 * Get first two u16's so we can look at IOC's intended reply MsgLength
4332 */
4333 u16cnt=0;
4334 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4335 failcnt++;
4336 } else {
4337 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4338 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4339 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4340 failcnt++;
4341 else {
4342 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4343 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4344 }
4345 }
4346
Prakash, Sathya436ace72007-07-24 15:42:08 +05304347 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004348 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4350
4351 /*
4352 * If no error (and IOC said MsgLength is > 0), piece together
4353 * reply 16 bits at a time.
4354 */
4355 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4356 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4357 failcnt++;
4358 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4359 /* don't overflow our IOC hs_reply[] buffer! */
4360 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4361 hs_reply[u16cnt] = hword;
4362 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4363 }
4364
4365 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4366 failcnt++;
4367 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4368
4369 if (failcnt) {
4370 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4371 ioc->name);
4372 return -failcnt;
4373 }
4374#if 0
4375 else if (u16cnt != (2 * mptReply->MsgLength)) {
4376 return -101;
4377 }
4378 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4379 return -102;
4380 }
4381#endif
4382
Prakash, Sathya436ace72007-07-24 15:42:08 +05304383 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
4384 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
Prakash, Sathya436ace72007-07-24 15:42:08 +05304386 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 ioc->name, t, u16cnt/2));
4388 return u16cnt/2;
4389}
4390
4391/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004392/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 * GetLanConfigPages - Fetch LANConfig pages.
4394 * @ioc: Pointer to MPT_ADAPTER structure
4395 *
4396 * Return: 0 for success
4397 * -ENOMEM if no memory available
4398 * -EPERM if not allowed due to ISR context
4399 * -EAGAIN if no msg frames currently available
4400 * -EFAULT for non-successful reply or no reply (timeout)
4401 */
4402static int
4403GetLanConfigPages(MPT_ADAPTER *ioc)
4404{
4405 ConfigPageHeader_t hdr;
4406 CONFIGPARMS cfg;
4407 LANPage0_t *ppage0_alloc;
4408 dma_addr_t page0_dma;
4409 LANPage1_t *ppage1_alloc;
4410 dma_addr_t page1_dma;
4411 int rc = 0;
4412 int data_sz;
4413 int copy_sz;
4414
4415 /* Get LAN Page 0 header */
4416 hdr.PageVersion = 0;
4417 hdr.PageLength = 0;
4418 hdr.PageNumber = 0;
4419 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004420 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 cfg.physAddr = -1;
4422 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4423 cfg.dir = 0;
4424 cfg.pageAddr = 0;
4425 cfg.timeout = 0;
4426
4427 if ((rc = mpt_config(ioc, &cfg)) != 0)
4428 return rc;
4429
4430 if (hdr.PageLength > 0) {
4431 data_sz = hdr.PageLength * 4;
4432 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4433 rc = -ENOMEM;
4434 if (ppage0_alloc) {
4435 memset((u8 *)ppage0_alloc, 0, data_sz);
4436 cfg.physAddr = page0_dma;
4437 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4438
4439 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4440 /* save the data */
4441 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4442 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4443
4444 }
4445
4446 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4447
4448 /* FIXME!
4449 * Normalize endianness of structure data,
4450 * by byte-swapping all > 1 byte fields!
4451 */
4452
4453 }
4454
4455 if (rc)
4456 return rc;
4457 }
4458
4459 /* Get LAN Page 1 header */
4460 hdr.PageVersion = 0;
4461 hdr.PageLength = 0;
4462 hdr.PageNumber = 1;
4463 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004464 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 cfg.physAddr = -1;
4466 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4467 cfg.dir = 0;
4468 cfg.pageAddr = 0;
4469
4470 if ((rc = mpt_config(ioc, &cfg)) != 0)
4471 return rc;
4472
4473 if (hdr.PageLength == 0)
4474 return 0;
4475
4476 data_sz = hdr.PageLength * 4;
4477 rc = -ENOMEM;
4478 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4479 if (ppage1_alloc) {
4480 memset((u8 *)ppage1_alloc, 0, data_sz);
4481 cfg.physAddr = page1_dma;
4482 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4483
4484 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4485 /* save the data */
4486 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4487 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4488 }
4489
4490 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4491
4492 /* FIXME!
4493 * Normalize endianness of structure data,
4494 * by byte-swapping all > 1 byte fields!
4495 */
4496
4497 }
4498
4499 return rc;
4500}
4501
4502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004503/**
4504 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004505 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004506 * @persist_opcode: see below
4507 *
4508 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4509 * devices not currently present.
4510 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4511 *
4512 * NOTE: Don't use not this function during interrupt time.
4513 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004514 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004515 */
4516
4517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4518int
4519mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4520{
4521 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4522 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4523 MPT_FRAME_HDR *mf = NULL;
4524 MPIHeader_t *mpi_hdr;
4525
4526
4527 /* insure garbage is not sent to fw */
4528 switch(persist_opcode) {
4529
4530 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4531 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4532 break;
4533
4534 default:
4535 return -1;
4536 break;
4537 }
4538
4539 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4540
4541 /* Get a MF for this command.
4542 */
4543 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4544 printk("%s: no msg frames!\n",__FUNCTION__);
4545 return -1;
4546 }
4547
4548 mpi_hdr = (MPIHeader_t *) mf;
4549 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4550 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4551 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4552 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4553 sasIoUnitCntrReq->Operation = persist_opcode;
4554
4555 init_timer(&ioc->persist_timer);
4556 ioc->persist_timer.data = (unsigned long) ioc;
4557 ioc->persist_timer.function = mpt_timer_expired;
4558 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4559 ioc->persist_wait_done=0;
4560 add_timer(&ioc->persist_timer);
4561 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4562 wait_event(mpt_waitq, ioc->persist_wait_done);
4563
4564 sasIoUnitCntrReply =
4565 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4566 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4567 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4568 __FUNCTION__,
4569 sasIoUnitCntrReply->IOCStatus,
4570 sasIoUnitCntrReply->IOCLogInfo);
4571 return -1;
4572 }
4573
4574 printk("%s: success\n",__FUNCTION__);
4575 return 0;
4576}
4577
4578/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004579
4580static void
4581mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4582 MpiEventDataRaid_t * pRaidEventData)
4583{
4584 int volume;
4585 int reason;
4586 int disk;
4587 int status;
4588 int flags;
4589 int state;
4590
4591 volume = pRaidEventData->VolumeID;
4592 reason = pRaidEventData->ReasonCode;
4593 disk = pRaidEventData->PhysDiskNum;
4594 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4595 flags = (status >> 0) & 0xff;
4596 state = (status >> 8) & 0xff;
4597
4598 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4599 return;
4600 }
4601
4602 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4603 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4604 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004605 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4606 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004607 } else {
4608 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4609 ioc->name, volume);
4610 }
4611
4612 switch(reason) {
4613 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4614 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4615 ioc->name);
4616 break;
4617
4618 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4619
4620 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4621 ioc->name);
4622 break;
4623
4624 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4625 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4626 ioc->name);
4627 break;
4628
4629 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4630 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4631 ioc->name,
4632 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4633 ? "optimal"
4634 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4635 ? "degraded"
4636 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4637 ? "failed"
4638 : "state unknown",
4639 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4640 ? ", enabled" : "",
4641 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4642 ? ", quiesced" : "",
4643 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4644 ? ", resync in progress" : "" );
4645 break;
4646
4647 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4648 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4649 ioc->name, disk);
4650 break;
4651
4652 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4653 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4654 ioc->name);
4655 break;
4656
4657 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4658 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4659 ioc->name);
4660 break;
4661
4662 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4663 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4664 ioc->name);
4665 break;
4666
4667 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4668 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4669 ioc->name,
4670 state == MPI_PHYSDISK0_STATUS_ONLINE
4671 ? "online"
4672 : state == MPI_PHYSDISK0_STATUS_MISSING
4673 ? "missing"
4674 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4675 ? "not compatible"
4676 : state == MPI_PHYSDISK0_STATUS_FAILED
4677 ? "failed"
4678 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4679 ? "initializing"
4680 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4681 ? "offline requested"
4682 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4683 ? "failed requested"
4684 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4685 ? "offline"
4686 : "state unknown",
4687 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4688 ? ", out of sync" : "",
4689 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4690 ? ", quiesced" : "" );
4691 break;
4692
4693 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4694 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4695 ioc->name, disk);
4696 break;
4697
4698 case MPI_EVENT_RAID_RC_SMART_DATA:
4699 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4700 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4701 break;
4702
4703 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4704 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4705 ioc->name, disk);
4706 break;
4707 }
4708}
4709
4710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004711/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4713 * @ioc: Pointer to MPT_ADAPTER structure
4714 *
4715 * Returns: 0 for success
4716 * -ENOMEM if no memory available
4717 * -EPERM if not allowed due to ISR context
4718 * -EAGAIN if no msg frames currently available
4719 * -EFAULT for non-successful reply or no reply (timeout)
4720 */
4721static int
4722GetIoUnitPage2(MPT_ADAPTER *ioc)
4723{
4724 ConfigPageHeader_t hdr;
4725 CONFIGPARMS cfg;
4726 IOUnitPage2_t *ppage_alloc;
4727 dma_addr_t page_dma;
4728 int data_sz;
4729 int rc;
4730
4731 /* Get the page header */
4732 hdr.PageVersion = 0;
4733 hdr.PageLength = 0;
4734 hdr.PageNumber = 2;
4735 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004736 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 cfg.physAddr = -1;
4738 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4739 cfg.dir = 0;
4740 cfg.pageAddr = 0;
4741 cfg.timeout = 0;
4742
4743 if ((rc = mpt_config(ioc, &cfg)) != 0)
4744 return rc;
4745
4746 if (hdr.PageLength == 0)
4747 return 0;
4748
4749 /* Read the config page */
4750 data_sz = hdr.PageLength * 4;
4751 rc = -ENOMEM;
4752 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4753 if (ppage_alloc) {
4754 memset((u8 *)ppage_alloc, 0, data_sz);
4755 cfg.physAddr = page_dma;
4756 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4757
4758 /* If Good, save data */
4759 if ((rc = mpt_config(ioc, &cfg)) == 0)
4760 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4761
4762 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4763 }
4764
4765 return rc;
4766}
4767
4768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004769/**
4770 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 * @ioc: Pointer to a Adapter Strucutre
4772 * @portnum: IOC port number
4773 *
4774 * Return: -EFAULT if read of config page header fails
4775 * or if no nvram
4776 * If read of SCSI Port Page 0 fails,
4777 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4778 * Adapter settings: async, narrow
4779 * Return 1
4780 * If read of SCSI Port Page 2 fails,
4781 * Adapter settings valid
4782 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4783 * Return 1
4784 * Else
4785 * Both valid
4786 * Return 0
4787 * CHECK - what type of locking mechanisms should be used????
4788 */
4789static int
4790mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4791{
4792 u8 *pbuf;
4793 dma_addr_t buf_dma;
4794 CONFIGPARMS cfg;
4795 ConfigPageHeader_t header;
4796 int ii;
4797 int data, rc = 0;
4798
4799 /* Allocate memory
4800 */
4801 if (!ioc->spi_data.nvram) {
4802 int sz;
4803 u8 *mem;
4804 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4805 mem = kmalloc(sz, GFP_ATOMIC);
4806 if (mem == NULL)
4807 return -EFAULT;
4808
4809 ioc->spi_data.nvram = (int *) mem;
4810
Prakash, Sathya436ace72007-07-24 15:42:08 +05304811 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 ioc->name, ioc->spi_data.nvram, sz));
4813 }
4814
4815 /* Invalidate NVRAM information
4816 */
4817 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4818 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4819 }
4820
4821 /* Read SPP0 header, allocate memory, then read page.
4822 */
4823 header.PageVersion = 0;
4824 header.PageLength = 0;
4825 header.PageNumber = 0;
4826 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004827 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 cfg.physAddr = -1;
4829 cfg.pageAddr = portnum;
4830 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4831 cfg.dir = 0;
4832 cfg.timeout = 0; /* use default */
4833 if (mpt_config(ioc, &cfg) != 0)
4834 return -EFAULT;
4835
4836 if (header.PageLength > 0) {
4837 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4838 if (pbuf) {
4839 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4840 cfg.physAddr = buf_dma;
4841 if (mpt_config(ioc, &cfg) != 0) {
4842 ioc->spi_data.maxBusWidth = MPT_NARROW;
4843 ioc->spi_data.maxSyncOffset = 0;
4844 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4845 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4846 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304847 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4848 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004849 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 } else {
4851 /* Save the Port Page 0 data
4852 */
4853 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4854 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4855 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4856
4857 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4858 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304859 ddvprintk(ioc, printk(KERN_INFO MYNAM
4860 " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 ioc->name, pPP0->Capabilities));
4862 }
4863 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4864 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4865 if (data) {
4866 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4867 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4868 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304869 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4870 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004871 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 } else {
4873 ioc->spi_data.maxSyncOffset = 0;
4874 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4875 }
4876
4877 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4878
4879 /* Update the minSyncFactor based on bus type.
4880 */
4881 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4882 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4883
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004884 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304886 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4887 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004888 ioc->name, ioc->spi_data.minSyncFactor));
4889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 }
4891 }
4892 if (pbuf) {
4893 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4894 }
4895 }
4896 }
4897
4898 /* SCSI Port Page 2 - Read the header then the page.
4899 */
4900 header.PageVersion = 0;
4901 header.PageLength = 0;
4902 header.PageNumber = 2;
4903 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004904 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 cfg.physAddr = -1;
4906 cfg.pageAddr = portnum;
4907 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4908 cfg.dir = 0;
4909 if (mpt_config(ioc, &cfg) != 0)
4910 return -EFAULT;
4911
4912 if (header.PageLength > 0) {
4913 /* Allocate memory and read SCSI Port Page 2
4914 */
4915 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4916 if (pbuf) {
4917 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4918 cfg.physAddr = buf_dma;
4919 if (mpt_config(ioc, &cfg) != 0) {
4920 /* Nvram data is left with INVALID mark
4921 */
4922 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004923 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4924
4925 /* This is an ATTO adapter, read Page2 accordingly
4926 */
4927 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4928 ATTODeviceInfo_t *pdevice = NULL;
4929 u16 ATTOFlags;
4930
4931 /* Save the Port Page 2 data
4932 * (reformat into a 32bit quantity)
4933 */
4934 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4935 pdevice = &pPP2->DeviceSettings[ii];
4936 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4937 data = 0;
4938
4939 /* Translate ATTO device flags to LSI format
4940 */
4941 if (ATTOFlags & ATTOFLAG_DISC)
4942 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4943 if (ATTOFlags & ATTOFLAG_ID_ENB)
4944 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4945 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4946 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4947 if (ATTOFlags & ATTOFLAG_TAGGED)
4948 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4949 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4950 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4951
4952 data = (data << 16) | (pdevice->Period << 8) | 10;
4953 ioc->spi_data.nvram[ii] = data;
4954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 } else {
4956 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4957 MpiDeviceInfo_t *pdevice = NULL;
4958
Moore, Ericd8e925d2006-01-16 18:53:06 -07004959 /*
4960 * Save "Set to Avoid SCSI Bus Resets" flag
4961 */
4962 ioc->spi_data.bus_reset =
4963 (le32_to_cpu(pPP2->PortFlags) &
4964 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4965 0 : 1 ;
4966
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 /* Save the Port Page 2 data
4968 * (reformat into a 32bit quantity)
4969 */
4970 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4971 ioc->spi_data.PortFlags = data;
4972 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4973 pdevice = &pPP2->DeviceSettings[ii];
4974 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4975 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4976 ioc->spi_data.nvram[ii] = data;
4977 }
4978 }
4979
4980 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4981 }
4982 }
4983
4984 /* Update Adapter limits with those from NVRAM
4985 * Comment: Don't need to do this. Target performance
4986 * parameters will never exceed the adapters limits.
4987 */
4988
4989 return rc;
4990}
4991
4992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004993/**
4994 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 * @ioc: Pointer to a Adapter Strucutre
4996 * @portnum: IOC port number
4997 *
4998 * Return: -EFAULT if read of config page header fails
4999 * or 0 if success.
5000 */
5001static int
5002mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5003{
5004 CONFIGPARMS cfg;
5005 ConfigPageHeader_t header;
5006
5007 /* Read the SCSI Device Page 1 header
5008 */
5009 header.PageVersion = 0;
5010 header.PageLength = 0;
5011 header.PageNumber = 1;
5012 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005013 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 cfg.physAddr = -1;
5015 cfg.pageAddr = portnum;
5016 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5017 cfg.dir = 0;
5018 cfg.timeout = 0;
5019 if (mpt_config(ioc, &cfg) != 0)
5020 return -EFAULT;
5021
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005022 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5023 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024
5025 header.PageVersion = 0;
5026 header.PageLength = 0;
5027 header.PageNumber = 0;
5028 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5029 if (mpt_config(ioc, &cfg) != 0)
5030 return -EFAULT;
5031
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005032 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5033 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034
Prakash, Sathya436ace72007-07-24 15:42:08 +05305035 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5037
Prakash, Sathya436ace72007-07-24 15:42:08 +05305038 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5040 return 0;
5041}
5042
Eric Mooreb506ade2007-01-29 09:45:37 -07005043/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005044 * mpt_inactive_raid_list_free - This clears this link list.
5045 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005046 **/
5047static void
5048mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5049{
5050 struct inactive_raid_component_info *component_info, *pNext;
5051
5052 if (list_empty(&ioc->raid_data.inactive_list))
5053 return;
5054
5055 down(&ioc->raid_data.inactive_list_mutex);
5056 list_for_each_entry_safe(component_info, pNext,
5057 &ioc->raid_data.inactive_list, list) {
5058 list_del(&component_info->list);
5059 kfree(component_info);
5060 }
5061 up(&ioc->raid_data.inactive_list_mutex);
5062}
5063
5064/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005065 * 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 -07005066 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005067 * @ioc : pointer to per adapter structure
5068 * @channel : volume channel
5069 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005070 **/
5071static void
5072mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5073{
5074 CONFIGPARMS cfg;
5075 ConfigPageHeader_t hdr;
5076 dma_addr_t dma_handle;
5077 pRaidVolumePage0_t buffer = NULL;
5078 int i;
5079 RaidPhysDiskPage0_t phys_disk;
5080 struct inactive_raid_component_info *component_info;
5081 int handle_inactive_volumes;
5082
5083 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5084 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5085 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5086 cfg.pageAddr = (channel << 8) + id;
5087 cfg.cfghdr.hdr = &hdr;
5088 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5089
5090 if (mpt_config(ioc, &cfg) != 0)
5091 goto out;
5092
5093 if (!hdr.PageLength)
5094 goto out;
5095
5096 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5097 &dma_handle);
5098
5099 if (!buffer)
5100 goto out;
5101
5102 cfg.physAddr = dma_handle;
5103 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5104
5105 if (mpt_config(ioc, &cfg) != 0)
5106 goto out;
5107
5108 if (!buffer->NumPhysDisks)
5109 goto out;
5110
5111 handle_inactive_volumes =
5112 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5113 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5114 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5115 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5116
5117 if (!handle_inactive_volumes)
5118 goto out;
5119
5120 down(&ioc->raid_data.inactive_list_mutex);
5121 for (i = 0; i < buffer->NumPhysDisks; i++) {
5122 if(mpt_raid_phys_disk_pg0(ioc,
5123 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5124 continue;
5125
5126 if ((component_info = kmalloc(sizeof (*component_info),
5127 GFP_KERNEL)) == NULL)
5128 continue;
5129
5130 component_info->volumeID = id;
5131 component_info->volumeBus = channel;
5132 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5133 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5134 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5135 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5136
5137 list_add_tail(&component_info->list,
5138 &ioc->raid_data.inactive_list);
5139 }
5140 up(&ioc->raid_data.inactive_list_mutex);
5141
5142 out:
5143 if (buffer)
5144 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5145 dma_handle);
5146}
5147
5148/**
5149 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5150 * @ioc: Pointer to a Adapter Structure
5151 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5152 * @phys_disk: requested payload data returned
5153 *
5154 * Return:
5155 * 0 on success
5156 * -EFAULT if read of config page header fails or data pointer not NULL
5157 * -ENOMEM if pci_alloc failed
5158 **/
5159int
5160mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5161{
5162 CONFIGPARMS cfg;
5163 ConfigPageHeader_t hdr;
5164 dma_addr_t dma_handle;
5165 pRaidPhysDiskPage0_t buffer = NULL;
5166 int rc;
5167
5168 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5169 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5170
5171 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5172 cfg.cfghdr.hdr = &hdr;
5173 cfg.physAddr = -1;
5174 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5175
5176 if (mpt_config(ioc, &cfg) != 0) {
5177 rc = -EFAULT;
5178 goto out;
5179 }
5180
5181 if (!hdr.PageLength) {
5182 rc = -EFAULT;
5183 goto out;
5184 }
5185
5186 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5187 &dma_handle);
5188
5189 if (!buffer) {
5190 rc = -ENOMEM;
5191 goto out;
5192 }
5193
5194 cfg.physAddr = dma_handle;
5195 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5196 cfg.pageAddr = phys_disk_num;
5197
5198 if (mpt_config(ioc, &cfg) != 0) {
5199 rc = -EFAULT;
5200 goto out;
5201 }
5202
5203 rc = 0;
5204 memcpy(phys_disk, buffer, sizeof(*buffer));
5205 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5206
5207 out:
5208
5209 if (buffer)
5210 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5211 dma_handle);
5212
5213 return rc;
5214}
5215
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216/**
5217 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5218 * @ioc: Pointer to a Adapter Strucutre
5219 * @portnum: IOC port number
5220 *
5221 * Return:
5222 * 0 on success
5223 * -EFAULT if read of config page header fails or data pointer not NULL
5224 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005225 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226int
5227mpt_findImVolumes(MPT_ADAPTER *ioc)
5228{
5229 IOCPage2_t *pIoc2;
5230 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 dma_addr_t ioc2_dma;
5232 CONFIGPARMS cfg;
5233 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 int rc = 0;
5235 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005236 int i;
5237
5238 if (!ioc->ir_firmware)
5239 return 0;
5240
5241 /* Free the old page
5242 */
5243 kfree(ioc->raid_data.pIocPg2);
5244 ioc->raid_data.pIocPg2 = NULL;
5245 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
5247 /* Read IOCP2 header then the page.
5248 */
5249 header.PageVersion = 0;
5250 header.PageLength = 0;
5251 header.PageNumber = 2;
5252 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005253 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 cfg.physAddr = -1;
5255 cfg.pageAddr = 0;
5256 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5257 cfg.dir = 0;
5258 cfg.timeout = 0;
5259 if (mpt_config(ioc, &cfg) != 0)
5260 return -EFAULT;
5261
5262 if (header.PageLength == 0)
5263 return -EFAULT;
5264
5265 iocpage2sz = header.PageLength * 4;
5266 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5267 if (!pIoc2)
5268 return -ENOMEM;
5269
5270 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5271 cfg.physAddr = ioc2_dma;
5272 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005273 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274
Eric Mooreb506ade2007-01-29 09:45:37 -07005275 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5276 if (!mem)
5277 goto out;
5278
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005280 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281
Eric Mooreb506ade2007-01-29 09:45:37 -07005282 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283
Eric Mooreb506ade2007-01-29 09:45:37 -07005284 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5285 mpt_inactive_raid_volumes(ioc,
5286 pIoc2->RaidVolume[i].VolumeBus,
5287 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288
Eric Mooreb506ade2007-01-29 09:45:37 -07005289 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5291
5292 return rc;
5293}
5294
Moore, Ericc972c702006-03-14 09:14:06 -07005295static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5297{
5298 IOCPage3_t *pIoc3;
5299 u8 *mem;
5300 CONFIGPARMS cfg;
5301 ConfigPageHeader_t header;
5302 dma_addr_t ioc3_dma;
5303 int iocpage3sz = 0;
5304
5305 /* Free the old page
5306 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005307 kfree(ioc->raid_data.pIocPg3);
5308 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
5310 /* There is at least one physical disk.
5311 * Read and save IOC Page 3
5312 */
5313 header.PageVersion = 0;
5314 header.PageLength = 0;
5315 header.PageNumber = 3;
5316 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005317 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 cfg.physAddr = -1;
5319 cfg.pageAddr = 0;
5320 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5321 cfg.dir = 0;
5322 cfg.timeout = 0;
5323 if (mpt_config(ioc, &cfg) != 0)
5324 return 0;
5325
5326 if (header.PageLength == 0)
5327 return 0;
5328
5329 /* Read Header good, alloc memory
5330 */
5331 iocpage3sz = header.PageLength * 4;
5332 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5333 if (!pIoc3)
5334 return 0;
5335
5336 /* Read the Page and save the data
5337 * into malloc'd memory.
5338 */
5339 cfg.physAddr = ioc3_dma;
5340 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5341 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005342 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 if (mem) {
5344 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005345 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 }
5347 }
5348
5349 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5350
5351 return 0;
5352}
5353
5354static void
5355mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5356{
5357 IOCPage4_t *pIoc4;
5358 CONFIGPARMS cfg;
5359 ConfigPageHeader_t header;
5360 dma_addr_t ioc4_dma;
5361 int iocpage4sz;
5362
5363 /* Read and save IOC Page 4
5364 */
5365 header.PageVersion = 0;
5366 header.PageLength = 0;
5367 header.PageNumber = 4;
5368 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005369 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 cfg.physAddr = -1;
5371 cfg.pageAddr = 0;
5372 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5373 cfg.dir = 0;
5374 cfg.timeout = 0;
5375 if (mpt_config(ioc, &cfg) != 0)
5376 return;
5377
5378 if (header.PageLength == 0)
5379 return;
5380
5381 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5382 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5383 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5384 if (!pIoc4)
5385 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005386 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 } else {
5388 ioc4_dma = ioc->spi_data.IocPg4_dma;
5389 iocpage4sz = ioc->spi_data.IocPg4Sz;
5390 }
5391
5392 /* Read the Page into dma memory.
5393 */
5394 cfg.physAddr = ioc4_dma;
5395 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5396 if (mpt_config(ioc, &cfg) == 0) {
5397 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5398 ioc->spi_data.IocPg4_dma = ioc4_dma;
5399 ioc->spi_data.IocPg4Sz = iocpage4sz;
5400 } else {
5401 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5402 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005403 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 }
5405}
5406
5407static void
5408mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5409{
5410 IOCPage1_t *pIoc1;
5411 CONFIGPARMS cfg;
5412 ConfigPageHeader_t header;
5413 dma_addr_t ioc1_dma;
5414 int iocpage1sz = 0;
5415 u32 tmp;
5416
5417 /* Check the Coalescing Timeout in IOC Page 1
5418 */
5419 header.PageVersion = 0;
5420 header.PageLength = 0;
5421 header.PageNumber = 1;
5422 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005423 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 cfg.physAddr = -1;
5425 cfg.pageAddr = 0;
5426 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5427 cfg.dir = 0;
5428 cfg.timeout = 0;
5429 if (mpt_config(ioc, &cfg) != 0)
5430 return;
5431
5432 if (header.PageLength == 0)
5433 return;
5434
5435 /* Read Header good, alloc memory
5436 */
5437 iocpage1sz = header.PageLength * 4;
5438 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5439 if (!pIoc1)
5440 return;
5441
5442 /* Read the Page and check coalescing timeout
5443 */
5444 cfg.physAddr = ioc1_dma;
5445 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5446 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305447
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5449 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5450 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5451
Prakash, Sathya436ace72007-07-24 15:42:08 +05305452 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 ioc->name, tmp));
5454
5455 if (tmp > MPT_COALESCING_TIMEOUT) {
5456 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5457
5458 /* Write NVRAM and current
5459 */
5460 cfg.dir = 1;
5461 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5462 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305463 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 ioc->name, MPT_COALESCING_TIMEOUT));
5465
5466 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5467 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305468 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5469 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 ioc->name, MPT_COALESCING_TIMEOUT));
5471 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305472 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5473 "Reset NVRAM Coalescing Timeout Failed\n",
5474 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 }
5476
5477 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305478 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5479 "Reset of Current Coalescing Timeout Failed!\n",
5480 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 }
5482 }
5483
5484 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305485 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 }
5487 }
5488
5489 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5490
5491 return;
5492}
5493
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305494static void
5495mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5496{
5497 CONFIGPARMS cfg;
5498 ConfigPageHeader_t hdr;
5499 dma_addr_t buf_dma;
5500 ManufacturingPage0_t *pbuf = NULL;
5501
5502 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5503 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5504
5505 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5506 cfg.cfghdr.hdr = &hdr;
5507 cfg.physAddr = -1;
5508 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5509 cfg.timeout = 10;
5510
5511 if (mpt_config(ioc, &cfg) != 0)
5512 goto out;
5513
5514 if (!cfg.cfghdr.hdr->PageLength)
5515 goto out;
5516
5517 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5518 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5519 if (!pbuf)
5520 goto out;
5521
5522 cfg.physAddr = buf_dma;
5523
5524 if (mpt_config(ioc, &cfg) != 0)
5525 goto out;
5526
5527 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5528 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5529 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5530
5531 out:
5532
5533 if (pbuf)
5534 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5535}
5536
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005538/**
5539 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 * @ioc: Pointer to MPT_ADAPTER structure
5541 * @EvSwitch: Event switch flags
5542 */
5543static int
5544SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5545{
5546 EventNotification_t *evnp;
5547
5548 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5549 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305550 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 ioc->name));
5552 return 0;
5553 }
5554 memset(evnp, 0, sizeof(*evnp));
5555
Prakash, Sathya436ace72007-07-24 15:42:08 +05305556 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557
5558 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5559 evnp->ChainOffset = 0;
5560 evnp->MsgFlags = 0;
5561 evnp->Switch = EvSwitch;
5562
5563 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5564
5565 return 0;
5566}
5567
5568/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5569/**
5570 * SendEventAck - Send EventAck request to MPT adapter.
5571 * @ioc: Pointer to MPT_ADAPTER structure
5572 * @evnp: Pointer to original EventNotification request
5573 */
5574static int
5575SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5576{
5577 EventAck_t *pAck;
5578
5579 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305580 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005581 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 return -1;
5583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584
Prakash, Sathya436ace72007-07-24 15:42:08 +05305585 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586
5587 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5588 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005589 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005591 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 pAck->Event = evnp->Event;
5593 pAck->EventContext = evnp->EventContext;
5594
5595 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5596
5597 return 0;
5598}
5599
5600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5601/**
5602 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005603 * @ioc: Pointer to an adapter structure
5604 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 * action, page address, direction, physical address
5606 * and pointer to a configuration page header
5607 * Page header is updated.
5608 *
5609 * Returns 0 for success
5610 * -EPERM if not allowed due to ISR context
5611 * -EAGAIN if no msg frames currently available
5612 * -EFAULT for non-successful reply or no reply (timeout)
5613 */
5614int
5615mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5616{
5617 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005618 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 MPT_FRAME_HDR *mf;
5620 unsigned long flags;
5621 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005622 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 int in_isr;
5624
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005625 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 * to be in ISR context, because that is fatal!
5627 */
5628 in_isr = in_interrupt();
5629 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305630 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 ioc->name));
5632 return -EPERM;
5633 }
5634
5635 /* Get and Populate a free Frame
5636 */
5637 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305638 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 ioc->name));
5640 return -EAGAIN;
5641 }
5642 pReq = (Config_t *)mf;
5643 pReq->Action = pCfg->action;
5644 pReq->Reserved = 0;
5645 pReq->ChainOffset = 0;
5646 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005647
5648 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 pReq->ExtPageLength = 0;
5650 pReq->ExtPageType = 0;
5651 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005652
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 for (ii=0; ii < 8; ii++)
5654 pReq->Reserved2[ii] = 0;
5655
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005656 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5657 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5658 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5659 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5660
5661 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5662 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5663 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5664 pReq->ExtPageType = pExtHdr->ExtPageType;
5665 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5666
5667 /* Page Length must be treated as a reserved field for the extended header. */
5668 pReq->Header.PageLength = 0;
5669 }
5670
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5672
5673 /* Add a SGE to the config request.
5674 */
5675 if (pCfg->dir)
5676 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5677 else
5678 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5679
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005680 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5681 flagsLength |= pExtHdr->ExtPageLength * 4;
5682
Prakash, Sathya436ace72007-07-24 15:42:08 +05305683 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 +02005684 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5685 }
5686 else {
5687 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5688
Prakash, Sathya436ace72007-07-24 15:42:08 +05305689 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 +02005690 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
5693 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5694
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 /* Append pCfg pointer to end of mf
5696 */
5697 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5698
5699 /* Initalize the timer
5700 */
5701 init_timer(&pCfg->timer);
5702 pCfg->timer.data = (unsigned long) ioc;
5703 pCfg->timer.function = mpt_timer_expired;
5704 pCfg->wait_done = 0;
5705
5706 /* Set the timer; ensure 10 second minimum */
5707 if (pCfg->timeout < 10)
5708 pCfg->timer.expires = jiffies + HZ*10;
5709 else
5710 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5711
5712 /* Add to end of Q, set timer and then issue this command */
5713 spin_lock_irqsave(&ioc->FreeQlock, flags);
5714 list_add_tail(&pCfg->linkage, &ioc->configQ);
5715 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5716
5717 add_timer(&pCfg->timer);
5718 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5719 wait_event(mpt_waitq, pCfg->wait_done);
5720
5721 /* mf has been freed - do not access */
5722
5723 rc = pCfg->status;
5724
5725 return rc;
5726}
5727
5728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005729/**
5730 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 * Used only internal config functionality.
5732 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5733 */
5734static void
5735mpt_timer_expired(unsigned long data)
5736{
5737 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5738
Prakash, Sathya436ace72007-07-24 15:42:08 +05305739 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
5741 /* Perform a FW reload */
5742 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5743 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5744
5745 /* No more processing.
5746 * Hard reset clean-up will wake up
5747 * process and free all resources.
5748 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305749 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750
5751 return;
5752}
5753
5754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005755/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 * mpt_ioc_reset - Base cleanup for hard reset
5757 * @ioc: Pointer to the adapter structure
5758 * @reset_phase: Indicates pre- or post-reset functionality
5759 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005760 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 */
5762static int
5763mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5764{
5765 CONFIGPARMS *pCfg;
5766 unsigned long flags;
5767
Prakash, Sathya436ace72007-07-24 15:42:08 +05305768 dprintk(ioc, printk(KERN_DEBUG MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 ": IOC %s_reset routed to MPT base driver!\n",
5770 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5771 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5772
5773 if (reset_phase == MPT_IOC_SETUP_RESET) {
5774 ;
5775 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5776 /* If the internal config Q is not empty -
5777 * delete timer. MF resources will be freed when
5778 * the FIFO's are primed.
5779 */
5780 spin_lock_irqsave(&ioc->FreeQlock, flags);
5781 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5782 del_timer(&pCfg->timer);
5783 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5784
5785 } else {
5786 CONFIGPARMS *pNext;
5787
5788 /* Search the configQ for internal commands.
5789 * Flush the Q, and wake up all suspended threads.
5790 */
5791 spin_lock_irqsave(&ioc->FreeQlock, flags);
5792 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5793 list_del(&pCfg->linkage);
5794
5795 pCfg->status = MPT_CONFIG_ERROR;
5796 pCfg->wait_done = 1;
5797 wake_up(&mpt_waitq);
5798 }
5799 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5800 }
5801
5802 return 1; /* currently means nothing really */
5803}
5804
5805
5806#ifdef CONFIG_PROC_FS /* { */
5807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5808/*
5809 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5810 */
5811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005812/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5814 *
5815 * Returns 0 for success, non-zero for failure.
5816 */
5817static int
5818procmpt_create(void)
5819{
5820 struct proc_dir_entry *ent;
5821
5822 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5823 if (mpt_proc_root_dir == NULL)
5824 return -ENOTDIR;
5825
5826 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5827 if (ent)
5828 ent->read_proc = procmpt_summary_read;
5829
5830 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5831 if (ent)
5832 ent->read_proc = procmpt_version_read;
5833
5834 return 0;
5835}
5836
5837/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005838/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5840 *
5841 * Returns 0 for success, non-zero for failure.
5842 */
5843static void
5844procmpt_destroy(void)
5845{
5846 remove_proc_entry("version", mpt_proc_root_dir);
5847 remove_proc_entry("summary", mpt_proc_root_dir);
5848 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5849}
5850
5851/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005852/**
5853 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 * @buf: Pointer to area to write information
5855 * @start: Pointer to start pointer
5856 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005857 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 * @eof: Pointer to EOF integer
5859 * @data: Pointer
5860 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005861 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 * Returns number of characters written to process performing the read.
5863 */
5864static int
5865procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5866{
5867 MPT_ADAPTER *ioc;
5868 char *out = buf;
5869 int len;
5870
5871 if (data) {
5872 int more = 0;
5873
5874 ioc = data;
5875 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5876
5877 out += more;
5878 } else {
5879 list_for_each_entry(ioc, &ioc_list, list) {
5880 int more = 0;
5881
5882 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5883
5884 out += more;
5885 if ((out-buf) >= request)
5886 break;
5887 }
5888 }
5889
5890 len = out - buf;
5891
5892 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5893}
5894
5895/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005896/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 * procmpt_version_read - Handle read request from /proc/mpt/version.
5898 * @buf: Pointer to area to write information
5899 * @start: Pointer to start pointer
5900 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005901 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 * @eof: Pointer to EOF integer
5903 * @data: Pointer
5904 *
5905 * Returns number of characters written to process performing the read.
5906 */
5907static int
5908procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5909{
5910 int ii;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005911 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 char *drvname;
5913 int len;
5914
5915 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5916 len += sprintf(buf+len, " Fusion MPT base driver\n");
5917
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005918 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
5920 drvname = NULL;
5921 if (MptCallbacks[ii]) {
5922 switch (MptDriverClass[ii]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005923 case MPTSPI_DRIVER:
5924 if (!scsi++) drvname = "SPI host";
5925 break;
5926 case MPTFC_DRIVER:
5927 if (!fc++) drvname = "FC host";
5928 break;
5929 case MPTSAS_DRIVER:
5930 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 break;
5932 case MPTLAN_DRIVER:
5933 if (!lan++) drvname = "LAN";
5934 break;
5935 case MPTSTM_DRIVER:
5936 if (!targ++) drvname = "SCSI target";
5937 break;
5938 case MPTCTL_DRIVER:
5939 if (!ctl++) drvname = "ioctl";
5940 break;
5941 }
5942
5943 if (drvname)
5944 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5945 }
5946 }
5947
5948 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5949}
5950
5951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005952/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5954 * @buf: Pointer to area to write information
5955 * @start: Pointer to start pointer
5956 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005957 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 * @eof: Pointer to EOF integer
5959 * @data: Pointer
5960 *
5961 * Returns number of characters written to process performing the read.
5962 */
5963static int
5964procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5965{
5966 MPT_ADAPTER *ioc = data;
5967 int len;
5968 char expVer[32];
5969 int sz;
5970 int p;
5971
5972 mpt_get_fw_exp_ver(expVer, ioc);
5973
5974 len = sprintf(buf, "%s:", ioc->name);
5975 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5976 len += sprintf(buf+len, " (f/w download boot flag set)");
5977// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5978// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5979
5980 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5981 ioc->facts.ProductID,
5982 ioc->prod_name);
5983 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
5984 if (ioc->facts.FWImageSize)
5985 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
5986 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
5987 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
5988 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
5989
5990 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
5991 ioc->facts.CurrentHostMfaHighAddr);
5992 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
5993 ioc->facts.CurrentSenseBufferHighAddr);
5994
5995 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
5996 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
5997
5998 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
5999 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6000 /*
6001 * Rounding UP to nearest 4-kB boundary here...
6002 */
6003 sz = (ioc->req_sz * ioc->req_depth) + 128;
6004 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6005 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6006 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6007 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6008 4*ioc->facts.RequestFrameSize,
6009 ioc->facts.GlobalCredits);
6010
6011 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6012 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6013 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6014 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6015 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6016 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6017 ioc->facts.CurReplyFrameSize,
6018 ioc->facts.ReplyQueueDepth);
6019
6020 len += sprintf(buf+len, " MaxDevices = %d\n",
6021 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6022 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6023
6024 /* per-port info */
6025 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6026 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6027 p+1,
6028 ioc->facts.NumberOfPorts);
6029 if (ioc->bus_type == FC) {
6030 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6031 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6032 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6033 a[5], a[4], a[3], a[2], a[1], a[0]);
6034 }
6035 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6036 ioc->fc_port_page0[p].WWNN.High,
6037 ioc->fc_port_page0[p].WWNN.Low,
6038 ioc->fc_port_page0[p].WWPN.High,
6039 ioc->fc_port_page0[p].WWPN.Low);
6040 }
6041 }
6042
6043 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6044}
6045
6046#endif /* CONFIG_PROC_FS } */
6047
6048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6049static void
6050mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6051{
6052 buf[0] ='\0';
6053 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6054 sprintf(buf, " (Exp %02d%02d)",
6055 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6056 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6057
6058 /* insider hack! */
6059 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6060 strcat(buf, " [MDBG]");
6061 }
6062}
6063
6064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6065/**
6066 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6067 * @ioc: Pointer to MPT_ADAPTER structure
6068 * @buffer: Pointer to buffer where IOC summary info should be written
6069 * @size: Pointer to number of bytes we wrote (set by this routine)
6070 * @len: Offset at which to start writing in buffer
6071 * @showlan: Display LAN stuff?
6072 *
6073 * This routine writes (english readable) ASCII text, which represents
6074 * a summary of IOC information, to a buffer.
6075 */
6076void
6077mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6078{
6079 char expVer[32];
6080 int y;
6081
6082 mpt_get_fw_exp_ver(expVer, ioc);
6083
6084 /*
6085 * Shorter summary of attached ioc's...
6086 */
6087 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6088 ioc->name,
6089 ioc->prod_name,
6090 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6091 ioc->facts.FWVersion.Word,
6092 expVer,
6093 ioc->facts.NumberOfPorts,
6094 ioc->req_depth);
6095
6096 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6097 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6098 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6099 a[5], a[4], a[3], a[2], a[1], a[0]);
6100 }
6101
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103
6104 if (!ioc->active)
6105 y += sprintf(buffer+len+y, " (disabled)");
6106
6107 y += sprintf(buffer+len+y, "\n");
6108
6109 *size = y;
6110}
6111
6112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6113/*
6114 * Reset Handling
6115 */
6116/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6117/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006118 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 * @ioc: Pointer to MPT_ADAPTER structure
6120 * @sleepFlag: Indicates if sleep or schedule must be called.
6121 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006122 * Issues SCSI Task Management call based on input arg values.
6123 * If TaskMgmt fails, returns associated SCSI request.
6124 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6126 * or a non-interrupt thread. In the former, must not call schedule().
6127 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006128 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 * FW reload/initialization failed.
6130 *
6131 * Returns 0 for SUCCESS or -1 if FAILED.
6132 */
6133int
6134mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6135{
6136 int rc;
6137 unsigned long flags;
6138
Prakash, Sathya436ace72007-07-24 15:42:08 +05306139 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140#ifdef MFCNT
6141 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6142 printk("MF count 0x%x !\n", ioc->mfcnt);
6143#endif
6144
6145 /* Reset the adapter. Prevent more than 1 call to
6146 * mpt_do_ioc_recovery at any instant in time.
6147 */
6148 spin_lock_irqsave(&ioc->diagLock, flags);
6149 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6150 spin_unlock_irqrestore(&ioc->diagLock, flags);
6151 return 0;
6152 } else {
6153 ioc->diagPending = 1;
6154 }
6155 spin_unlock_irqrestore(&ioc->diagLock, flags);
6156
6157 /* FIXME: If do_ioc_recovery fails, repeat....
6158 */
6159
6160 /* The SCSI driver needs to adjust timeouts on all current
6161 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006162 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 * For all other protocol drivers, this is a no-op.
6164 */
6165 {
6166 int ii;
6167 int r = 0;
6168
6169 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6170 if (MptResetHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306171 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006173 r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306175 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 ioc->name, ioc->alt_ioc->name, ii));
James Bottomley4ff42a62006-05-17 18:06:52 -05006177 r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178 }
6179 }
6180 }
6181 }
6182
6183 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
6184 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
6185 rc, ioc->name);
6186 }
6187 ioc->reload_fw = 0;
6188 if (ioc->alt_ioc)
6189 ioc->alt_ioc->reload_fw = 0;
6190
6191 spin_lock_irqsave(&ioc->diagLock, flags);
6192 ioc->diagPending = 0;
6193 if (ioc->alt_ioc)
6194 ioc->alt_ioc->diagPending = 0;
6195 spin_unlock_irqrestore(&ioc->diagLock, flags);
6196
Prakash, Sathya436ace72007-07-24 15:42:08 +05306197 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
6199 return rc;
6200}
6201
6202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006203static void
6204EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205{
Eric Moore509e5e52006-04-26 13:22:37 -06006206 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207
6208 switch(event) {
6209 case MPI_EVENT_NONE:
6210 ds = "None";
6211 break;
6212 case MPI_EVENT_LOG_DATA:
6213 ds = "Log Data";
6214 break;
6215 case MPI_EVENT_STATE_CHANGE:
6216 ds = "State Change";
6217 break;
6218 case MPI_EVENT_UNIT_ATTENTION:
6219 ds = "Unit Attention";
6220 break;
6221 case MPI_EVENT_IOC_BUS_RESET:
6222 ds = "IOC Bus Reset";
6223 break;
6224 case MPI_EVENT_EXT_BUS_RESET:
6225 ds = "External Bus Reset";
6226 break;
6227 case MPI_EVENT_RESCAN:
6228 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 break;
6230 case MPI_EVENT_LINK_STATUS_CHANGE:
6231 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6232 ds = "Link Status(FAILURE) Change";
6233 else
6234 ds = "Link Status(ACTIVE) Change";
6235 break;
6236 case MPI_EVENT_LOOP_STATE_CHANGE:
6237 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6238 ds = "Loop State(LIP) Change";
6239 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006240 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 else
Eric Moore509e5e52006-04-26 13:22:37 -06006242 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 break;
6244 case MPI_EVENT_LOGOUT:
6245 ds = "Logout";
6246 break;
6247 case MPI_EVENT_EVENT_CHANGE:
6248 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006249 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006251 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 break;
6253 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006254 {
6255 u8 ReasonCode = (u8)(evData0 >> 16);
6256 switch (ReasonCode) {
6257 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6258 ds = "Integrated Raid: Volume Created";
6259 break;
6260 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6261 ds = "Integrated Raid: Volume Deleted";
6262 break;
6263 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6264 ds = "Integrated Raid: Volume Settings Changed";
6265 break;
6266 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6267 ds = "Integrated Raid: Volume Status Changed";
6268 break;
6269 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6270 ds = "Integrated Raid: Volume Physdisk Changed";
6271 break;
6272 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6273 ds = "Integrated Raid: Physdisk Created";
6274 break;
6275 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6276 ds = "Integrated Raid: Physdisk Deleted";
6277 break;
6278 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6279 ds = "Integrated Raid: Physdisk Settings Changed";
6280 break;
6281 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6282 ds = "Integrated Raid: Physdisk Status Changed";
6283 break;
6284 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6285 ds = "Integrated Raid: Domain Validation Needed";
6286 break;
6287 case MPI_EVENT_RAID_RC_SMART_DATA :
6288 ds = "Integrated Raid; Smart Data";
6289 break;
6290 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6291 ds = "Integrated Raid: Replace Action Started";
6292 break;
6293 default:
6294 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006296 }
6297 break;
6298 }
6299 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6300 ds = "SCSI Device Status Change";
6301 break;
6302 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6303 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006304 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006305 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006306 u8 ReasonCode = (u8)(evData0 >> 16);
6307 switch (ReasonCode) {
6308 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006309 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006310 "SAS Device Status Change: Added: "
6311 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006312 break;
6313 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006314 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006315 "SAS Device Status Change: Deleted: "
6316 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006317 break;
6318 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006319 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006320 "SAS Device Status Change: SMART Data: "
6321 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006322 break;
6323 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006324 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006325 "SAS Device Status Change: No Persistancy: "
6326 "id=%d channel=%d", id, channel);
6327 break;
6328 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6329 snprintf(evStr, EVENT_DESCR_STR_SZ,
6330 "SAS Device Status Change: Unsupported Device "
6331 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006332 break;
6333 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6334 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006335 "SAS Device Status Change: Internal Device "
6336 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006337 break;
6338 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6339 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006340 "SAS Device Status Change: Internal Task "
6341 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006342 break;
6343 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6344 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006345 "SAS Device Status Change: Internal Abort "
6346 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006347 break;
6348 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6349 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006350 "SAS Device Status Change: Internal Clear "
6351 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006352 break;
6353 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6354 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006355 "SAS Device Status Change: Internal Query "
6356 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006357 break;
6358 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006359 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006360 "SAS Device Status Change: Unknown: "
6361 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006362 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006363 }
6364 break;
6365 }
6366 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6367 ds = "Bus Timer Expired";
6368 break;
6369 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006370 {
6371 u16 curr_depth = (u16)(evData0 >> 16);
6372 u8 channel = (u8)(evData0 >> 8);
6373 u8 id = (u8)(evData0);
6374
6375 snprintf(evStr, EVENT_DESCR_STR_SZ,
6376 "Queue Full: channel=%d id=%d depth=%d",
6377 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006378 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006379 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006380 case MPI_EVENT_SAS_SES:
6381 ds = "SAS SES Event";
6382 break;
6383 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6384 ds = "Persistent Table Full";
6385 break;
6386 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006387 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006388 u8 LinkRates = (u8)(evData0 >> 8);
6389 u8 PhyNumber = (u8)(evData0);
6390 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6391 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6392 switch (LinkRates) {
6393 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006394 snprintf(evStr, EVENT_DESCR_STR_SZ,
6395 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006396 " Rate Unknown",PhyNumber);
6397 break;
6398 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006399 snprintf(evStr, EVENT_DESCR_STR_SZ,
6400 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006401 " Phy Disabled",PhyNumber);
6402 break;
6403 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006404 snprintf(evStr, EVENT_DESCR_STR_SZ,
6405 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006406 " Failed Speed Nego",PhyNumber);
6407 break;
6408 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006409 snprintf(evStr, EVENT_DESCR_STR_SZ,
6410 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006411 " Sata OOB Completed",PhyNumber);
6412 break;
6413 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006414 snprintf(evStr, EVENT_DESCR_STR_SZ,
6415 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006416 " Rate 1.5 Gbps",PhyNumber);
6417 break;
6418 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006419 snprintf(evStr, EVENT_DESCR_STR_SZ,
6420 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006421 " Rate 3.0 Gpbs",PhyNumber);
6422 break;
6423 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006424 snprintf(evStr, EVENT_DESCR_STR_SZ,
6425 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006426 break;
6427 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006428 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006429 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006430 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6431 ds = "SAS Discovery Error";
6432 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006433 case MPI_EVENT_IR_RESYNC_UPDATE:
6434 {
6435 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006436 snprintf(evStr, EVENT_DESCR_STR_SZ,
6437 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006438 break;
6439 }
6440 case MPI_EVENT_IR2:
6441 {
6442 u8 ReasonCode = (u8)(evData0 >> 16);
6443 switch (ReasonCode) {
6444 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6445 ds = "IR2: LD State Changed";
6446 break;
6447 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6448 ds = "IR2: PD State Changed";
6449 break;
6450 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6451 ds = "IR2: Bad Block Table Full";
6452 break;
6453 case MPI_EVENT_IR2_RC_PD_INSERTED:
6454 ds = "IR2: PD Inserted";
6455 break;
6456 case MPI_EVENT_IR2_RC_PD_REMOVED:
6457 ds = "IR2: PD Removed";
6458 break;
6459 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6460 ds = "IR2: Foreign CFG Detected";
6461 break;
6462 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6463 ds = "IR2: Rebuild Medium Error";
6464 break;
6465 default:
6466 ds = "IR2";
6467 break;
6468 }
6469 break;
6470 }
6471 case MPI_EVENT_SAS_DISCOVERY:
6472 {
6473 if (evData0)
6474 ds = "SAS Discovery: Start";
6475 else
6476 ds = "SAS Discovery: Stop";
6477 break;
6478 }
6479 case MPI_EVENT_LOG_ENTRY_ADDED:
6480 ds = "SAS Log Entry Added";
6481 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006482
Eric Moorec6c727a2007-01-29 09:44:54 -07006483 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6484 {
6485 u8 phy_num = (u8)(evData0);
6486 u8 port_num = (u8)(evData0 >> 8);
6487 u8 port_width = (u8)(evData0 >> 16);
6488 u8 primative = (u8)(evData0 >> 24);
6489 snprintf(evStr, EVENT_DESCR_STR_SZ,
6490 "SAS Broadcase Primative: phy=%d port=%d "
6491 "width=%d primative=0x%02x",
6492 phy_num, port_num, port_width, primative);
6493 break;
6494 }
6495
6496 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6497 {
6498 u8 reason = (u8)(evData0);
6499 u8 port_num = (u8)(evData0 >> 8);
6500 u16 handle = le16_to_cpu(evData0 >> 16);
6501
6502 snprintf(evStr, EVENT_DESCR_STR_SZ,
6503 "SAS Initiator Device Status Change: reason=0x%02x "
6504 "port=%d handle=0x%04x",
6505 reason, port_num, handle);
6506 break;
6507 }
6508
6509 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6510 {
6511 u8 max_init = (u8)(evData0);
6512 u8 current_init = (u8)(evData0 >> 8);
6513
6514 snprintf(evStr, EVENT_DESCR_STR_SZ,
6515 "SAS Initiator Device Table Overflow: max initiators=%02d "
6516 "current initators=%02d",
6517 max_init, current_init);
6518 break;
6519 }
6520 case MPI_EVENT_SAS_SMP_ERROR:
6521 {
6522 u8 status = (u8)(evData0);
6523 u8 port_num = (u8)(evData0 >> 8);
6524 u8 result = (u8)(evData0 >> 16);
6525
6526 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6527 snprintf(evStr, EVENT_DESCR_STR_SZ,
6528 "SAS SMP Error: port=%d result=0x%02x",
6529 port_num, result);
6530 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6531 snprintf(evStr, EVENT_DESCR_STR_SZ,
6532 "SAS SMP Error: port=%d : CRC Error",
6533 port_num);
6534 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6535 snprintf(evStr, EVENT_DESCR_STR_SZ,
6536 "SAS SMP Error: port=%d : Timeout",
6537 port_num);
6538 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6539 snprintf(evStr, EVENT_DESCR_STR_SZ,
6540 "SAS SMP Error: port=%d : No Destination",
6541 port_num);
6542 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6543 snprintf(evStr, EVENT_DESCR_STR_SZ,
6544 "SAS SMP Error: port=%d : Bad Destination",
6545 port_num);
6546 else
6547 snprintf(evStr, EVENT_DESCR_STR_SZ,
6548 "SAS SMP Error: port=%d : status=0x%02x",
6549 port_num, status);
6550 break;
6551 }
6552
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 /*
6554 * MPT base "custom" events may be added here...
6555 */
6556 default:
6557 ds = "Unknown";
6558 break;
6559 }
Eric Moore509e5e52006-04-26 13:22:37 -06006560 if (ds)
6561 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562}
6563
6564/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006565/**
6566 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567 * @ioc: Pointer to MPT_ADAPTER structure
6568 * @pEventReply: Pointer to EventNotification reply frame
6569 * @evHandlers: Pointer to integer, number of event handlers
6570 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006571 * Routes a received EventNotificationReply to all currently registered
6572 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 * Returns sum of event handlers return values.
6574 */
6575static int
6576ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6577{
6578 u16 evDataLen;
6579 u32 evData0 = 0;
6580// u32 evCtx;
6581 int ii;
6582 int r = 0;
6583 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006584 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006585 u8 event;
6586
6587 /*
6588 * Do platform normalization of values
6589 */
6590 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6591// evCtx = le32_to_cpu(pEventReply->EventContext);
6592 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6593 if (evDataLen) {
6594 evData0 = le32_to_cpu(pEventReply->Data[0]);
6595 }
6596
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006597 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306598 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006600 event,
6601 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602
Prakash, Sathya436ace72007-07-24 15:42:08 +05306603#ifdef CONFIG_FUSION_LOGGING
6604 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
6605 ": Event data:\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306607 devtverboseprintk(ioc, printk(" %08x",
6608 le32_to_cpu(pEventReply->Data[ii])));
6609 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610#endif
6611
6612 /*
6613 * Do general / base driver event processing
6614 */
6615 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6617 if (evDataLen) {
6618 u8 evState = evData0 & 0xFF;
6619
6620 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6621
6622 /* Update EventState field in cached IocFacts */
6623 if (ioc->facts.Function) {
6624 ioc->facts.EventState = evState;
6625 }
6626 }
6627 break;
Moore, Ericece50912006-01-16 18:53:19 -07006628 case MPI_EVENT_INTEGRATED_RAID:
6629 mptbase_raid_process_event_data(ioc,
6630 (MpiEventDataRaid_t *)pEventReply->Data);
6631 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006632 default:
6633 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634 }
6635
6636 /*
6637 * Should this event be logged? Events are written sequentially.
6638 * When buffer is full, start again at the top.
6639 */
6640 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6641 int idx;
6642
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006643 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644
6645 ioc->events[idx].event = event;
6646 ioc->events[idx].eventContext = ioc->eventContext;
6647
6648 for (ii = 0; ii < 2; ii++) {
6649 if (ii < evDataLen)
6650 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6651 else
6652 ioc->events[idx].data[ii] = 0;
6653 }
6654
6655 ioc->eventContext++;
6656 }
6657
6658
6659 /*
6660 * Call each currently registered protocol event handler.
6661 */
6662 for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
6663 if (MptEvHandlers[ii]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306664 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665 ioc->name, ii));
6666 r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
6667 handlers++;
6668 }
6669 }
6670 /* FIXME? Examine results here? */
6671
6672 /*
6673 * If needed, send (a single) EventAck.
6674 */
6675 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306676 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006677 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306679 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680 ioc->name, ii));
6681 }
6682 }
6683
6684 *evHandlers = handlers;
6685 return r;
6686}
6687
6688/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006689/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006690 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6691 * @ioc: Pointer to MPT_ADAPTER structure
6692 * @log_info: U32 LogInfo reply word from the IOC
6693 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006694 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 */
6696static void
6697mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6698{
Eric Moore7c431e52007-06-13 16:34:36 -06006699 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700
Eric Moore7c431e52007-06-13 16:34:36 -06006701 switch (log_info & 0xFF000000) {
6702 case MPI_IOCLOGINFO_FC_INIT_BASE:
6703 desc = "FCP Initiator";
6704 break;
6705 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6706 desc = "FCP Target";
6707 break;
6708 case MPI_IOCLOGINFO_FC_LAN_BASE:
6709 desc = "LAN";
6710 break;
6711 case MPI_IOCLOGINFO_FC_MSG_BASE:
6712 desc = "MPI Message Layer";
6713 break;
6714 case MPI_IOCLOGINFO_FC_LINK_BASE:
6715 desc = "FC Link";
6716 break;
6717 case MPI_IOCLOGINFO_FC_CTX_BASE:
6718 desc = "Context Manager";
6719 break;
6720 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6721 desc = "Invalid Field Offset";
6722 break;
6723 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6724 desc = "State Change Info";
6725 break;
6726 }
6727
6728 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6729 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730}
6731
6732/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006733/**
Moore, Eric335a9412006-01-17 17:06:23 -07006734 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 * @ioc: Pointer to MPT_ADAPTER structure
6736 * @mr: Pointer to MPT reply frame
6737 * @log_info: U32 LogInfo word from the IOC
6738 *
6739 * Refer to lsi/sp_log.h.
6740 */
6741static void
Moore, Eric335a9412006-01-17 17:06:23 -07006742mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743{
6744 u32 info = log_info & 0x00FF0000;
6745 char *desc = "unknown";
6746
6747 switch (info) {
6748 case 0x00010000:
6749 desc = "bug! MID not found";
6750 if (ioc->reload_fw == 0)
6751 ioc->reload_fw++;
6752 break;
6753
6754 case 0x00020000:
6755 desc = "Parity Error";
6756 break;
6757
6758 case 0x00030000:
6759 desc = "ASYNC Outbound Overrun";
6760 break;
6761
6762 case 0x00040000:
6763 desc = "SYNC Offset Error";
6764 break;
6765
6766 case 0x00050000:
6767 desc = "BM Change";
6768 break;
6769
6770 case 0x00060000:
6771 desc = "Msg In Overflow";
6772 break;
6773
6774 case 0x00070000:
6775 desc = "DMA Error";
6776 break;
6777
6778 case 0x00080000:
6779 desc = "Outbound DMA Overrun";
6780 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006781
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 case 0x00090000:
6783 desc = "Task Management";
6784 break;
6785
6786 case 0x000A0000:
6787 desc = "Device Problem";
6788 break;
6789
6790 case 0x000B0000:
6791 desc = "Invalid Phase Change";
6792 break;
6793
6794 case 0x000C0000:
6795 desc = "Untagged Table Size";
6796 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006797
Linus Torvalds1da177e2005-04-16 15:20:36 -07006798 }
6799
6800 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6801}
6802
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006803/* strings for sas loginfo */
6804 static char *originator_str[] = {
6805 "IOP", /* 00h */
6806 "PL", /* 01h */
6807 "IR" /* 02h */
6808 };
6809 static char *iop_code_str[] = {
6810 NULL, /* 00h */
6811 "Invalid SAS Address", /* 01h */
6812 NULL, /* 02h */
6813 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006814 "Diag Message Error", /* 04h */
6815 "Task Terminated", /* 05h */
6816 "Enclosure Management", /* 06h */
6817 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006818 };
6819 static char *pl_code_str[] = {
6820 NULL, /* 00h */
6821 "Open Failure", /* 01h */
6822 "Invalid Scatter Gather List", /* 02h */
6823 "Wrong Relative Offset or Frame Length", /* 03h */
6824 "Frame Transfer Error", /* 04h */
6825 "Transmit Frame Connected Low", /* 05h */
6826 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6827 "SATA Read Log Receive Data Error", /* 07h */
6828 "SATA NCQ Fail All Commands After Error", /* 08h */
6829 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6830 "Receive Frame Invalid Message", /* 0Ah */
6831 "Receive Context Message Valid Error", /* 0Bh */
6832 "Receive Frame Current Frame Error", /* 0Ch */
6833 "SATA Link Down", /* 0Dh */
6834 "Discovery SATA Init W IOS", /* 0Eh */
6835 "Config Invalid Page", /* 0Fh */
6836 "Discovery SATA Init Timeout", /* 10h */
6837 "Reset", /* 11h */
6838 "Abort", /* 12h */
6839 "IO Not Yet Executed", /* 13h */
6840 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006841 "Persistent Reservation Out Not Affiliation "
6842 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006843 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006844 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006845 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006846 NULL, /* 19h */
6847 NULL, /* 1Ah */
6848 NULL, /* 1Bh */
6849 NULL, /* 1Ch */
6850 NULL, /* 1Dh */
6851 NULL, /* 1Eh */
6852 NULL, /* 1Fh */
6853 "Enclosure Management" /* 20h */
6854 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006855 static char *ir_code_str[] = {
6856 "Raid Action Error", /* 00h */
6857 NULL, /* 00h */
6858 NULL, /* 01h */
6859 NULL, /* 02h */
6860 NULL, /* 03h */
6861 NULL, /* 04h */
6862 NULL, /* 05h */
6863 NULL, /* 06h */
6864 NULL /* 07h */
6865 };
6866 static char *raid_sub_code_str[] = {
6867 NULL, /* 00h */
6868 "Volume Creation Failed: Data Passed too "
6869 "Large", /* 01h */
6870 "Volume Creation Failed: Duplicate Volumes "
6871 "Attempted", /* 02h */
6872 "Volume Creation Failed: Max Number "
6873 "Supported Volumes Exceeded", /* 03h */
6874 "Volume Creation Failed: DMA Error", /* 04h */
6875 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6876 "Volume Creation Failed: Error Reading "
6877 "MFG Page 4", /* 06h */
6878 "Volume Creation Failed: Creating Internal "
6879 "Structures", /* 07h */
6880 NULL, /* 08h */
6881 NULL, /* 09h */
6882 NULL, /* 0Ah */
6883 NULL, /* 0Bh */
6884 NULL, /* 0Ch */
6885 NULL, /* 0Dh */
6886 NULL, /* 0Eh */
6887 NULL, /* 0Fh */
6888 "Activation failed: Already Active Volume", /* 10h */
6889 "Activation failed: Unsupported Volume Type", /* 11h */
6890 "Activation failed: Too Many Active Volumes", /* 12h */
6891 "Activation failed: Volume ID in Use", /* 13h */
6892 "Activation failed: Reported Failure", /* 14h */
6893 "Activation failed: Importing a Volume", /* 15h */
6894 NULL, /* 16h */
6895 NULL, /* 17h */
6896 NULL, /* 18h */
6897 NULL, /* 19h */
6898 NULL, /* 1Ah */
6899 NULL, /* 1Bh */
6900 NULL, /* 1Ch */
6901 NULL, /* 1Dh */
6902 NULL, /* 1Eh */
6903 NULL, /* 1Fh */
6904 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6905 "Phys Disk failed: Data Passed too Large", /* 21h */
6906 "Phys Disk failed: DMA Error", /* 22h */
6907 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6908 "Phys Disk failed: Creating Phys Disk Config "
6909 "Page", /* 24h */
6910 NULL, /* 25h */
6911 NULL, /* 26h */
6912 NULL, /* 27h */
6913 NULL, /* 28h */
6914 NULL, /* 29h */
6915 NULL, /* 2Ah */
6916 NULL, /* 2Bh */
6917 NULL, /* 2Ch */
6918 NULL, /* 2Dh */
6919 NULL, /* 2Eh */
6920 NULL, /* 2Fh */
6921 "Compatibility Error: IR Disabled", /* 30h */
6922 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6923 "Compatibility Error: Device not Direct Access "
6924 "Device ", /* 32h */
6925 "Compatibility Error: Removable Device Found", /* 33h */
6926 "Compatibility Error: Device SCSI Version not "
6927 "2 or Higher", /* 34h */
6928 "Compatibility Error: SATA Device, 48 BIT LBA "
6929 "not Supported", /* 35h */
6930 "Compatibility Error: Device doesn't have "
6931 "512 Byte Block Sizes", /* 36h */
6932 "Compatibility Error: Volume Type Check Failed", /* 37h */
6933 "Compatibility Error: Volume Type is "
6934 "Unsupported by FW", /* 38h */
6935 "Compatibility Error: Disk Drive too Small for "
6936 "use in Volume", /* 39h */
6937 "Compatibility Error: Phys Disk for Create "
6938 "Volume not Found", /* 3Ah */
6939 "Compatibility Error: Too Many or too Few "
6940 "Disks for Volume Type", /* 3Bh */
6941 "Compatibility Error: Disk stripe Sizes "
6942 "Must be 64KB", /* 3Ch */
6943 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6944 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006945
6946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006947/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006948 * mpt_sas_log_info - Log information returned from SAS IOC.
6949 * @ioc: Pointer to MPT_ADAPTER structure
6950 * @log_info: U32 LogInfo reply word from the IOC
6951 *
6952 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006953 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006954static void
6955mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6956{
6957union loginfo_type {
6958 u32 loginfo;
6959 struct {
6960 u32 subcode:16;
6961 u32 code:8;
6962 u32 originator:4;
6963 u32 bus_type:4;
6964 }dw;
6965};
6966 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006967 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006968 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006969 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006970
6971 sas_loginfo.loginfo = log_info;
6972 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6973 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6974 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006975
6976 originator_desc = originator_str[sas_loginfo.dw.originator];
6977
6978 switch (sas_loginfo.dw.originator) {
6979
6980 case 0: /* IOP */
6981 if (sas_loginfo.dw.code <
6982 sizeof(iop_code_str)/sizeof(char*))
6983 code_desc = iop_code_str[sas_loginfo.dw.code];
6984 break;
6985 case 1: /* PL */
6986 if (sas_loginfo.dw.code <
6987 sizeof(pl_code_str)/sizeof(char*))
6988 code_desc = pl_code_str[sas_loginfo.dw.code];
6989 break;
6990 case 2: /* IR */
6991 if (sas_loginfo.dw.code >=
6992 sizeof(ir_code_str)/sizeof(char*))
6993 break;
6994 code_desc = ir_code_str[sas_loginfo.dw.code];
6995 if (sas_loginfo.dw.subcode >=
6996 sizeof(raid_sub_code_str)/sizeof(char*))
6997 break;
6998 if (sas_loginfo.dw.code == 0)
6999 sub_code_desc =
7000 raid_sub_code_str[sas_loginfo.dw.subcode];
7001 break;
7002 default:
7003 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007004 }
7005
Eric Moorec6c727a2007-01-29 09:44:54 -07007006 if (sub_code_desc != NULL)
7007 printk(MYIOC_s_INFO_FMT
7008 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7009 " SubCode={%s}\n",
7010 ioc->name, log_info, originator_desc, code_desc,
7011 sub_code_desc);
7012 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007013 printk(MYIOC_s_INFO_FMT
7014 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7015 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007016 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007017 sas_loginfo.dw.subcode);
7018 else
7019 printk(MYIOC_s_INFO_FMT
7020 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7021 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007022 ioc->name, log_info, originator_desc,
7023 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007024}
7025
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007027/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007028 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7029 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007030 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007031 * @mf: Pointer to MPT request frame
7032 *
7033 * Refer to lsi/mpi.h.
7034 **/
7035static void
7036mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7037{
7038 Config_t *pReq = (Config_t *)mf;
7039 char extend_desc[EVENT_DESCR_STR_SZ];
7040 char *desc = NULL;
7041 u32 form;
7042 u8 page_type;
7043
7044 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7045 page_type = pReq->ExtPageType;
7046 else
7047 page_type = pReq->Header.PageType;
7048
7049 /*
7050 * ignore invalid page messages for GET_NEXT_HANDLE
7051 */
7052 form = le32_to_cpu(pReq->PageAddress);
7053 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7054 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7055 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7056 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7057 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7058 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7059 return;
7060 }
7061 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7062 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7063 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7064 return;
7065 }
7066
7067 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7068 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7069 page_type, pReq->Header.PageNumber, pReq->Action, form);
7070
7071 switch (ioc_status) {
7072
7073 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7074 desc = "Config Page Invalid Action";
7075 break;
7076
7077 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7078 desc = "Config Page Invalid Type";
7079 break;
7080
7081 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7082 desc = "Config Page Invalid Page";
7083 break;
7084
7085 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7086 desc = "Config Page Invalid Data";
7087 break;
7088
7089 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7090 desc = "Config Page No Defaults";
7091 break;
7092
7093 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7094 desc = "Config Page Can't Commit";
7095 break;
7096 }
7097
7098 if (!desc)
7099 return;
7100
7101 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
7102 ioc->name, ioc_status, desc, extend_desc);
7103}
7104
7105/**
7106 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 * @ioc: Pointer to MPT_ADAPTER structure
7108 * @ioc_status: U32 IOCStatus word from IOC
7109 * @mf: Pointer to MPT request frame
7110 *
7111 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007112 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007114mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115{
7116 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007117 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118
7119 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007120
7121/****************************************************************************/
7122/* Common IOCStatus values for all replies */
7123/****************************************************************************/
7124
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7126 desc = "Invalid Function";
7127 break;
7128
7129 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7130 desc = "Busy";
7131 break;
7132
7133 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7134 desc = "Invalid SGL";
7135 break;
7136
7137 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7138 desc = "Internal Error";
7139 break;
7140
7141 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7142 desc = "Reserved";
7143 break;
7144
7145 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7146 desc = "Insufficient Resources";
7147 break;
7148
7149 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7150 desc = "Invalid Field";
7151 break;
7152
7153 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7154 desc = "Invalid State";
7155 break;
7156
Eric Moorec6c727a2007-01-29 09:44:54 -07007157/****************************************************************************/
7158/* Config IOCStatus values */
7159/****************************************************************************/
7160
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7162 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7163 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7164 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7165 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7166 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007167 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007168 break;
7169
Eric Moorec6c727a2007-01-29 09:44:54 -07007170/****************************************************************************/
7171/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7172/* */
7173/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7174/* */
7175/****************************************************************************/
7176
Linus Torvalds1da177e2005-04-16 15:20:36 -07007177 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007178 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007179 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7180 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7181 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7182 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007189 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190 break;
7191
Eric Moorec6c727a2007-01-29 09:44:54 -07007192/****************************************************************************/
7193/* SCSI Target values */
7194/****************************************************************************/
7195
7196 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7197 desc = "Target: Priority IO";
7198 break;
7199
7200 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7201 desc = "Target: Invalid Port";
7202 break;
7203
7204 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7205 desc = "Target Invalid IO Index:";
7206 break;
7207
7208 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7209 desc = "Target: Aborted";
7210 break;
7211
7212 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7213 desc = "Target: No Conn Retryable";
7214 break;
7215
7216 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7217 desc = "Target: No Connection";
7218 break;
7219
7220 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7221 desc = "Target: Transfer Count Mismatch";
7222 break;
7223
7224 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7225 desc = "Target: STS Data not Sent";
7226 break;
7227
7228 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7229 desc = "Target: Data Offset Error";
7230 break;
7231
7232 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7233 desc = "Target: Too Much Write Data";
7234 break;
7235
7236 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7237 desc = "Target: IU Too Short";
7238 break;
7239
7240 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7241 desc = "Target: ACK NAK Timeout";
7242 break;
7243
7244 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7245 desc = "Target: Nak Received";
7246 break;
7247
7248/****************************************************************************/
7249/* Fibre Channel Direct Access values */
7250/****************************************************************************/
7251
7252 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7253 desc = "FC: Aborted";
7254 break;
7255
7256 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7257 desc = "FC: RX ID Invalid";
7258 break;
7259
7260 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7261 desc = "FC: DID Invalid";
7262 break;
7263
7264 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7265 desc = "FC: Node Logged Out";
7266 break;
7267
7268 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7269 desc = "FC: Exchange Canceled";
7270 break;
7271
7272/****************************************************************************/
7273/* LAN values */
7274/****************************************************************************/
7275
7276 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7277 desc = "LAN: Device not Found";
7278 break;
7279
7280 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7281 desc = "LAN: Device Failure";
7282 break;
7283
7284 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7285 desc = "LAN: Transmit Error";
7286 break;
7287
7288 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7289 desc = "LAN: Transmit Aborted";
7290 break;
7291
7292 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7293 desc = "LAN: Receive Error";
7294 break;
7295
7296 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7297 desc = "LAN: Receive Aborted";
7298 break;
7299
7300 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7301 desc = "LAN: Partial Packet";
7302 break;
7303
7304 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7305 desc = "LAN: Canceled";
7306 break;
7307
7308/****************************************************************************/
7309/* Serial Attached SCSI values */
7310/****************************************************************************/
7311
7312 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7313 desc = "SAS: SMP Request Failed";
7314 break;
7315
7316 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7317 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007318 break;
7319
7320 default:
7321 desc = "Others";
7322 break;
7323 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007324
7325 if (!desc)
7326 return;
7327
7328 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007329}
7330
7331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007332EXPORT_SYMBOL(mpt_attach);
7333EXPORT_SYMBOL(mpt_detach);
7334#ifdef CONFIG_PM
7335EXPORT_SYMBOL(mpt_resume);
7336EXPORT_SYMBOL(mpt_suspend);
7337#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007338EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007339EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340EXPORT_SYMBOL(mpt_register);
7341EXPORT_SYMBOL(mpt_deregister);
7342EXPORT_SYMBOL(mpt_event_register);
7343EXPORT_SYMBOL(mpt_event_deregister);
7344EXPORT_SYMBOL(mpt_reset_register);
7345EXPORT_SYMBOL(mpt_reset_deregister);
7346EXPORT_SYMBOL(mpt_device_driver_register);
7347EXPORT_SYMBOL(mpt_device_driver_deregister);
7348EXPORT_SYMBOL(mpt_get_msg_frame);
7349EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307350EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351EXPORT_SYMBOL(mpt_free_msg_frame);
7352EXPORT_SYMBOL(mpt_add_sge);
7353EXPORT_SYMBOL(mpt_send_handshake_request);
7354EXPORT_SYMBOL(mpt_verify_adapter);
7355EXPORT_SYMBOL(mpt_GetIocState);
7356EXPORT_SYMBOL(mpt_print_ioc_summary);
7357EXPORT_SYMBOL(mpt_lan_index);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007358EXPORT_SYMBOL(mpt_stm_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359EXPORT_SYMBOL(mpt_HardResetHandler);
7360EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007362EXPORT_SYMBOL(mpt_alloc_fw_memory);
7363EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007364EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007365EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007366
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007368/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369 * fusion_init - Fusion MPT base driver initialization routine.
7370 *
7371 * Returns 0 for success, non-zero for failure.
7372 */
7373static int __init
7374fusion_init(void)
7375{
7376 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377
7378 show_mptmod_ver(my_NAME, my_VERSION);
7379 printk(KERN_INFO COPYRIGHT "\n");
7380
7381 for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
7382 MptCallbacks[i] = NULL;
7383 MptDriverClass[i] = MPTUNKNOWN_DRIVER;
7384 MptEvHandlers[i] = NULL;
7385 MptResetHandlers[i] = NULL;
7386 }
7387
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007388 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007389 * EventNotification handling.
7390 */
7391 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7392
7393 /* Register for hard reset handling callbacks.
7394 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307395 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396
7397#ifdef CONFIG_PROC_FS
7398 (void) procmpt_create();
7399#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007400 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007401}
7402
7403/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007404/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405 * fusion_exit - Perform driver unload cleanup.
7406 *
7407 * This routine frees all resources associated with each MPT adapter
7408 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7409 */
7410static void __exit
7411fusion_exit(void)
7412{
7413
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414 mpt_reset_deregister(mpt_base_index);
7415
7416#ifdef CONFIG_PROC_FS
7417 procmpt_destroy();
7418#endif
7419}
7420
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421module_init(fusion_init);
7422module_exit(fusion_exit);