blob: d381c38ccbafcc16e479d81910bdd795692a6ee0 [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.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05308 * Copyright (c) 1999-2007 LSI 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600256/*
257 * Process turbo (context) reply...
258 */
259static void
260mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
261{
262 MPT_FRAME_HDR *mf = NULL;
263 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264 u16 req_idx = 0;
265 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600266
Prakash, Sathya436ace72007-07-24 15:42:08 +0530267 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600268 ioc->name, pa));
269
270 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
271 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
272 req_idx = pa & 0x0000FFFF;
273 cb_idx = (pa & 0x00FF0000) >> 16;
274 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
275 break;
276 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530277 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600278 /*
279 * Blind set of mf to NULL here was fatal
280 * after lan_reply says "freeme"
281 * Fix sort of combined with an optimization here;
282 * added explicit check for case where lan_reply
283 * was just returning 1 and doing nothing else.
284 * For this case skip the callback, but set up
285 * proper mf value first here:-)
286 */
287 if ((pa & 0x58000000) == 0x58000000) {
288 req_idx = pa & 0x0000FFFF;
289 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
290 mpt_free_msg_frame(ioc, mf);
291 mb();
292 return;
293 break;
294 }
295 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
296 break;
297 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530298 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600299 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
300 break;
301 default:
302 cb_idx = 0;
303 BUG();
304 }
305
306 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530307 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600308 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600309 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
310 __FUNCTION__, ioc->name, cb_idx);
311 goto out;
312 }
313
314 if (MptCallbacks[cb_idx](ioc, mf, mr))
315 mpt_free_msg_frame(ioc, mf);
316 out:
317 mb();
318}
319
320static void
321mpt_reply(MPT_ADAPTER *ioc, u32 pa)
322{
323 MPT_FRAME_HDR *mf;
324 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530325 u16 req_idx;
326 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 int freeme;
328
329 u32 reply_dma_low;
330 u16 ioc_stat;
331
332 /* non-TURBO reply! Hmmm, something may be up...
333 * Newest turbo reply mechanism; get address
334 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
335 */
336
337 /* Map DMA address of reply header to cpu address.
338 * pa is 32 bits - but the dma address may be 32 or 64 bits
339 * get offset based only only the low addresses
340 */
341
342 reply_dma_low = (pa <<= 1);
343 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
344 (reply_dma_low - ioc->reply_frames_low_dma));
345
346 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
347 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
348 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
349
Prakash, Sathya436ace72007-07-24 15:42:08 +0530350 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 -0600351 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600352 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600353
354 /* Check/log IOC log info
355 */
356 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
357 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
358 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
359 if (ioc->bus_type == FC)
360 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700361 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700362 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600363 else if (ioc->bus_type == SAS)
364 mpt_sas_log_info(ioc, log_info);
365 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600366
Eric Moorec6c727a2007-01-29 09:44:54 -0700367 if (ioc_stat & MPI_IOCSTATUS_MASK)
368 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600369
370 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530371 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600372 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
374 __FUNCTION__, ioc->name, cb_idx);
375 freeme = 0;
376 goto out;
377 }
378
379 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
380
381 out:
382 /* Flush (non-TURBO) reply with a WRITE! */
383 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
384
385 if (freeme)
386 mpt_free_msg_frame(ioc, mf);
387 mb();
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
393 * @irq: irq number (not used)
394 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 *
396 * This routine is registered via the request_irq() kernel API call,
397 * and handles all interrupts generated from a specific MPT adapter
398 * (also referred to as a IO Controller or IOC).
399 * This routine must clear the interrupt from the adapter and does
400 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 *
403 * This routine handles register-level access of the adapter but
404 * dispatches (calls) a protocol-specific callback routine to handle
405 * the protocol-specific details of the MPT request completion.
406 */
407static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100408mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600410 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600411 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
412
413 if (pa == 0xFFFFFFFF)
414 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 /*
417 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600419 do {
420 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600421 mpt_reply(ioc, pa);
422 else
423 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600424 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
425 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 return IRQ_HANDLED;
428}
429
430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800431/**
432 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 * @ioc: Pointer to MPT_ADAPTER structure
434 * @mf: Pointer to original MPT request frame
435 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
436 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800437 * MPT base driver's callback routine; all base driver
438 * "internal" request/reply processing is routed here.
439 * Currently used for EventNotification and EventAck handling.
440 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 * should be freed, or 0 if it shouldn't.
443 */
444static int
445mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
446{
447 int freereq = 1;
448 u8 func;
449
Prakash, Sathya436ace72007-07-24 15:42:08 +0530450 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
451#ifdef CONFIG_FUSION_LOGGING
452 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
453 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
455 ioc->name, mf));
456 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530461 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 ioc->name, func));
463
464 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
465 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
466 int evHandlers = 0;
467 int results;
468
469 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
470 if (results != evHandlers) {
471 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530472 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 ioc->name, evHandlers, results));
474 }
475
476 /*
477 * Hmmm... It seems that EventNotificationReply is an exception
478 * to the rule of one reply per request.
479 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200480 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200482 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530483 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200484 ioc->name, pEvReply));
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487#ifdef CONFIG_PROC_FS
488// LogEvent(ioc, pEvReply);
489#endif
490
491 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530492 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700494 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 CONFIGPARMS *pCfg;
496 unsigned long flags;
497
Prakash, Sathya436ace72007-07-24 15:42:08 +0530498 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ioc->name, mf, reply));
500
501 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
502
503 if (pCfg) {
504 /* disable timer and remove from linked list */
505 del_timer(&pCfg->timer);
506
507 spin_lock_irqsave(&ioc->FreeQlock, flags);
508 list_del(&pCfg->linkage);
509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
510
511 /*
512 * If IOC Status is SUCCESS, save the header
513 * and set the status code to GOOD.
514 */
515 pCfg->status = MPT_CONFIG_ERROR;
516 if (reply) {
517 ConfigReply_t *pReply = (ConfigReply_t *)reply;
518 u16 status;
519
520 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600521 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
522 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 pCfg->status = status;
525 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200526 if ((pReply->Header.PageType &
527 MPI_CONFIG_PAGETYPE_MASK) ==
528 MPI_CONFIG_PAGETYPE_EXTENDED) {
529 pCfg->cfghdr.ehdr->ExtPageLength =
530 le16_to_cpu(pReply->ExtPageLength);
531 pCfg->cfghdr.ehdr->ExtPageType =
532 pReply->ExtPageType;
533 }
534 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
535
536 /* If this is a regular header, save PageLength. */
537 /* LMP Do this better so not using a reserved field! */
538 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
539 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
540 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542 }
543
544 /*
545 * Wake up the original calling thread
546 */
547 pCfg->wait_done = 1;
548 wake_up(&mpt_waitq);
549 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200550 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
551 /* we should be always getting a reply frame */
552 memcpy(ioc->persist_reply_frame, reply,
553 min(MPT_DEFAULT_FRAME_SIZE,
554 4*reply->u.reply.MsgLength));
555 del_timer(&ioc->persist_timer);
556 ioc->persist_wait_done = 1;
557 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
559 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
560 ioc->name, func);
561 }
562
563 /*
564 * Conditionally tell caller to free the original
565 * EventNotification/EventAck/unexpected request frame!
566 */
567 return freereq;
568}
569
570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
571/**
572 * mpt_register - Register protocol-specific main callback handler.
573 * @cbfunc: callback function pointer
574 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
575 *
576 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800577 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 * protocol-specific driver must do this before it will be able to
579 * use any IOC resources, such as obtaining request frames.
580 *
581 * NOTES: The SCSI protocol driver currently calls this routine thrice
582 * in order to register separate callbacks; one for "normal" SCSI IO;
583 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
584 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530585 * Returns u8 valued "handle" in the range (and S.O.D. order)
586 * {N,...,7,6,5,...,1} if successful.
587 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
588 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530590u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
592{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530593 u8 cb_idx;
594 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /*
597 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
598 * (slot/handle 0 is reserved!)
599 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530600 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
601 if (MptCallbacks[cb_idx] == NULL) {
602 MptCallbacks[cb_idx] = cbfunc;
603 MptDriverClass[cb_idx] = dclass;
604 MptEvHandlers[cb_idx] = NULL;
605 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 break;
607 }
608 }
609
610 return last_drv_idx;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
614/**
615 * mpt_deregister - Deregister a protocol drivers resources.
616 * @cb_idx: previously registered callback handle
617 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800618 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 * module is unloaded.
620 */
621void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530622mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600624 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 MptCallbacks[cb_idx] = NULL;
626 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
627 MptEvHandlers[cb_idx] = NULL;
628
629 last_drv_idx++;
630 }
631}
632
633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
634/**
635 * mpt_event_register - Register protocol-specific event callback
636 * handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @ev_cbfunc: callback function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of MPT events.
642 *
643 * Returns 0 for success.
644 */
645int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600648 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -1;
650
651 MptEvHandlers[cb_idx] = ev_cbfunc;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_event_deregister - Deregister protocol-specific event callback
658 * handler.
659 * @cb_idx: previously registered callback handle
660 *
661 * Each protocol-specific driver should call this routine
662 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800663 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 */
665void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530666mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600668 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return;
670
671 MptEvHandlers[cb_idx] = NULL;
672}
673
674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
675/**
676 * mpt_reset_register - Register protocol-specific IOC reset handler.
677 * @cb_idx: previously registered (via mpt_register) callback handle
678 * @reset_func: reset function
679 *
680 * This routine can be called by one or more protocol-specific drivers
681 * if/when they choose to be notified of IOC resets.
682 *
683 * Returns 0 for success.
684 */
685int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530688 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return -1;
690
691 MptResetHandlers[cb_idx] = reset_func;
692 return 0;
693}
694
695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
696/**
697 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
698 * @cb_idx: previously registered callback handle
699 *
700 * Each protocol-specific driver should call this routine
701 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800702 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 */
704void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530705mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530707 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
710 MptResetHandlers[cb_idx] = NULL;
711}
712
713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
714/**
715 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * @dd_cbfunc: driver callbacks struct
717 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600723 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Eric Moore8d6d83e2007-09-14 18:47:40 -0600725 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400726 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
729
730 /* call per pci device probe entry point */
731 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600732 id = ioc->pcidev->driver ?
733 ioc->pcidev->driver->id_table : NULL;
734 if (dd_cbfunc->probe)
735 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400738 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
742/**
743 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800744 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 */
746void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530747mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 struct mpt_pci_driver *dd_cbfunc;
750 MPT_ADAPTER *ioc;
751
Eric Moore8d6d83e2007-09-14 18:47:40 -0600752 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return;
754
755 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
756
757 list_for_each_entry(ioc, &ioc_list, list) {
758 if (dd_cbfunc->remove)
759 dd_cbfunc->remove(ioc->pcidev);
760 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 MptDeviceDriverHandlers[cb_idx] = NULL;
763}
764
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
769 * allocated per MPT adapter.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530770 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 * @ioc: Pointer to MPT adapter structure
772 *
773 * Returns pointer to a MPT request frame or %NULL if none are available
774 * or IOC is not active.
775 */
776MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 MPT_FRAME_HDR *mf;
780 unsigned long flags;
781 u16 req_idx; /* Request index */
782
783 /* validate handle and ioc identifier */
784
785#ifdef MFCNT
786 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600787 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
788 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789#endif
790
791 /* If interrupts are not attached, do not return a request frame */
792 if (!ioc->active)
793 return NULL;
794
795 spin_lock_irqsave(&ioc->FreeQlock, flags);
796 if (!list_empty(&ioc->FreeQ)) {
797 int req_offset;
798
799 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
800 u.frame.linkage.list);
801 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200802 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530803 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
805 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500806 req_idx = req_offset / ioc->req_sz;
807 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 /* Default, will be changed if necessary in SG generation */
810 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811#ifdef MFCNT
812 ioc->mfcnt++;
813#endif
814 }
815 else
816 mf = NULL;
817 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
818
819#ifdef MFCNT
820 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600821 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
822 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
823 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 mfcounter++;
825 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600826 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
827 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828#endif
829
Eric Moore29dd3602007-09-14 18:46:51 -0600830 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
831 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return mf;
833}
834
835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
836/**
837 * mpt_put_msg_frame - Send a protocol specific MPT request frame
838 * to a IOC.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530839 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 * @ioc: Pointer to MPT adapter structure
841 * @mf: Pointer to MPT request frame
842 *
843 * This routine posts a MPT request frame to the request post FIFO of a
844 * specific MPT adapter.
845 */
846void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530847mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 u32 mf_dma_addr;
850 int req_offset;
851 u16 req_idx; /* Request index */
852
853 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530854 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
856 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500857 req_idx = req_offset / ioc->req_sz;
858 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
860
Prakash, Sathya436ace72007-07-24 15:42:08 +0530861 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200863 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600864 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
865 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
866 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
868}
869
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530870/**
871 * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
872 * to a IOC using hi priority request queue.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530873 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530874 * @ioc: Pointer to MPT adapter structure
875 * @mf: Pointer to MPT request frame
876 *
877 * This routine posts a MPT request frame to the request post FIFO of a
878 * specific MPT adapter.
879 **/
880void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530881mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530882{
883 u32 mf_dma_addr;
884 int req_offset;
885 u16 req_idx; /* Request index */
886
887 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530888 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530889 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
890 req_idx = req_offset / ioc->req_sz;
891 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
892 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
893
894 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
895
896 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
897 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
898 ioc->name, mf_dma_addr, req_idx));
899 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
900}
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
903/**
904 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
905 * @handle: Handle of registered MPT protocol driver
906 * @ioc: Pointer to MPT adapter structure
907 * @mf: Pointer to MPT request frame
908 *
909 * This routine places a MPT request frame back on the MPT adapter's
910 * FreeQ.
911 */
912void
913mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
914{
915 unsigned long flags;
916
917 /* Put Request back on FreeQ! */
918 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200919 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
921#ifdef MFCNT
922 ioc->mfcnt--;
923#endif
924 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
925}
926
927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
928/**
929 * mpt_add_sge - Place a simple SGE at address pAddr.
930 * @pAddr: virtual address for SGE
931 * @flagslength: SGE flags and data transfer length
932 * @dma_addr: Physical address
933 *
934 * This routine places a MPT request frame back on the MPT adapter's
935 * FreeQ.
936 */
937void
938mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
939{
940 if (sizeof(dma_addr_t) == sizeof(u64)) {
941 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
942 u32 tmp = dma_addr & 0xFFFFFFFF;
943
944 pSge->FlagsLength = cpu_to_le32(flagslength);
945 pSge->Address.Low = cpu_to_le32(tmp);
946 tmp = (u32) ((u64)dma_addr >> 32);
947 pSge->Address.High = cpu_to_le32(tmp);
948
949 } else {
950 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
951 pSge->FlagsLength = cpu_to_le32(flagslength);
952 pSge->Address = cpu_to_le32(dma_addr);
953 }
954}
955
956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
957/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800958 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530959 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 * @ioc: Pointer to MPT adapter structure
961 * @reqBytes: Size of the request in bytes
962 * @req: Pointer to MPT request frame
963 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
964 *
965 * This routine is used exclusively to send MptScsiTaskMgmt
966 * requests since they are required to be sent via doorbell handshake.
967 *
968 * NOTE: It is the callers responsibility to byte-swap fields in the
969 * request which are greater than 1 byte in size.
970 *
971 * Returns 0 for success, non-zero for failure.
972 */
973int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530974mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Eric Moorecd2c6192007-01-29 09:47:47 -0700976 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 u8 *req_as_bytes;
978 int ii;
979
980 /* State is known to be good upon entering
981 * this function so issue the bus reset
982 * request.
983 */
984
985 /*
986 * Emulate what mpt_put_msg_frame() does /wrt to sanity
987 * setting cb_idx/req_idx. But ONLY if this request
988 * is in proper (pre-alloc'd) request buffer range...
989 */
990 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
991 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
992 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
993 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530994 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
996
997 /* Make sure there are no doorbells */
998 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1001 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1002 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1003
1004 /* Wait for IOC doorbell int */
1005 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1006 return ii;
1007 }
1008
1009 /* Read doorbell and check for active bit */
1010 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1011 return -5;
1012
Eric Moore29dd3602007-09-14 18:46:51 -06001013 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001014 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1017
1018 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1019 return -2;
1020 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 /* Send request via doorbell handshake */
1023 req_as_bytes = (u8 *) req;
1024 for (ii = 0; ii < reqBytes/4; ii++) {
1025 u32 word;
1026
1027 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1028 (req_as_bytes[(ii*4) + 1] << 8) |
1029 (req_as_bytes[(ii*4) + 2] << 16) |
1030 (req_as_bytes[(ii*4) + 3] << 24));
1031 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1032 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1033 r = -3;
1034 break;
1035 }
1036 }
1037
1038 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1039 r = 0;
1040 else
1041 r = -4;
1042
1043 /* Make sure there are no doorbells */
1044 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return r;
1047}
1048
1049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1050/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001051 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001052 * @ioc: Pointer to MPT adapter structure
1053 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001054 * @sleepFlag: Specifies whether the process can sleep
1055 *
1056 * Provides mechanism for the host driver to control the IOC's
1057 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001058 *
1059 * Access Control Value - bits[15:12]
1060 * 0h Reserved
1061 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1062 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1063 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1064 *
1065 * Returns 0 for success, non-zero for failure.
1066 */
1067
1068static int
1069mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1070{
1071 int r = 0;
1072
1073 /* return if in use */
1074 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1075 & MPI_DOORBELL_ACTIVE)
1076 return -1;
1077
1078 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1079
1080 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1081 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1082 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1083 (access_control_value<<12)));
1084
1085 /* Wait for IOC to clear Doorbell Status bit */
1086 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1087 return -2;
1088 }else
1089 return 0;
1090}
1091
1092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1093/**
1094 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001095 * @ioc: Pointer to pointer to IOC adapter
1096 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001098 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001099 * Returns 0 for success, non-zero for failure.
1100 */
1101static int
1102mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1103{
1104 char *psge;
1105 int flags_length;
1106 u32 host_page_buffer_sz=0;
1107
1108 if(!ioc->HostPageBuffer) {
1109
1110 host_page_buffer_sz =
1111 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1112
1113 if(!host_page_buffer_sz)
1114 return 0; /* fw doesn't need any host buffers */
1115
1116 /* spin till we get enough memory */
1117 while(host_page_buffer_sz > 0) {
1118
1119 if((ioc->HostPageBuffer = pci_alloc_consistent(
1120 ioc->pcidev,
1121 host_page_buffer_sz,
1122 &ioc->HostPageBuffer_dma)) != NULL) {
1123
Prakash, Sathya436ace72007-07-24 15:42:08 +05301124 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001125 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001126 ioc->name, ioc->HostPageBuffer,
1127 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001128 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001129 ioc->alloc_total += host_page_buffer_sz;
1130 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1131 break;
1132 }
1133
1134 host_page_buffer_sz -= (4*1024);
1135 }
1136 }
1137
1138 if(!ioc->HostPageBuffer) {
1139 printk(MYIOC_s_ERR_FMT
1140 "Failed to alloc memory for host_page_buffer!\n",
1141 ioc->name);
1142 return -999;
1143 }
1144
1145 psge = (char *)&ioc_init->HostPageBufferSGE;
1146 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1147 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1148 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1149 MPI_SGE_FLAGS_HOST_TO_IOC |
1150 MPI_SGE_FLAGS_END_OF_BUFFER;
1151 if (sizeof(dma_addr_t) == sizeof(u64)) {
1152 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1153 }
1154 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1155 flags_length |= ioc->HostPageBuffer_sz;
1156 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1157 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1158
1159return 0;
1160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001164 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 * @iocid: IOC unique identifier (integer)
1166 * @iocpp: Pointer to pointer to IOC adapter
1167 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001168 * Given a unique IOC identifier, set pointer to the associated MPT
1169 * adapter structure.
1170 *
1171 * Returns iocid and sets iocpp if iocid is found.
1172 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 */
1174int
1175mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1176{
1177 MPT_ADAPTER *ioc;
1178
1179 list_for_each_entry(ioc,&ioc_list,list) {
1180 if (ioc->id == iocid) {
1181 *iocpp =ioc;
1182 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 *iocpp = NULL;
1187 return -1;
1188}
1189
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301190/**
1191 * mpt_get_product_name - returns product string
1192 * @vendor: pci vendor id
1193 * @device: pci device id
1194 * @revision: pci revision id
1195 * @prod_name: string returned
1196 *
1197 * Returns product string displayed when driver loads,
1198 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1199 *
1200 **/
1201static void
1202mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1203{
1204 char *product_str = NULL;
1205
1206 if (vendor == PCI_VENDOR_ID_BROCADE) {
1207 switch (device)
1208 {
1209 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1210 switch (revision)
1211 {
1212 case 0x00:
1213 product_str = "BRE040 A0";
1214 break;
1215 case 0x01:
1216 product_str = "BRE040 A1";
1217 break;
1218 default:
1219 product_str = "BRE040";
1220 break;
1221 }
1222 break;
1223 }
1224 goto out;
1225 }
1226
1227 switch (device)
1228 {
1229 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1230 product_str = "LSIFC909 B1";
1231 break;
1232 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1233 product_str = "LSIFC919 B0";
1234 break;
1235 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1236 product_str = "LSIFC929 B0";
1237 break;
1238 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1239 if (revision < 0x80)
1240 product_str = "LSIFC919X A0";
1241 else
1242 product_str = "LSIFC919XL A1";
1243 break;
1244 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1245 if (revision < 0x80)
1246 product_str = "LSIFC929X A0";
1247 else
1248 product_str = "LSIFC929XL A1";
1249 break;
1250 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1251 product_str = "LSIFC939X A1";
1252 break;
1253 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1254 product_str = "LSIFC949X A1";
1255 break;
1256 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1257 switch (revision)
1258 {
1259 case 0x00:
1260 product_str = "LSIFC949E A0";
1261 break;
1262 case 0x01:
1263 product_str = "LSIFC949E A1";
1264 break;
1265 default:
1266 product_str = "LSIFC949E";
1267 break;
1268 }
1269 break;
1270 case MPI_MANUFACTPAGE_DEVID_53C1030:
1271 switch (revision)
1272 {
1273 case 0x00:
1274 product_str = "LSI53C1030 A0";
1275 break;
1276 case 0x01:
1277 product_str = "LSI53C1030 B0";
1278 break;
1279 case 0x03:
1280 product_str = "LSI53C1030 B1";
1281 break;
1282 case 0x07:
1283 product_str = "LSI53C1030 B2";
1284 break;
1285 case 0x08:
1286 product_str = "LSI53C1030 C0";
1287 break;
1288 case 0x80:
1289 product_str = "LSI53C1030T A0";
1290 break;
1291 case 0x83:
1292 product_str = "LSI53C1030T A2";
1293 break;
1294 case 0x87:
1295 product_str = "LSI53C1030T A3";
1296 break;
1297 case 0xc1:
1298 product_str = "LSI53C1020A A1";
1299 break;
1300 default:
1301 product_str = "LSI53C1030";
1302 break;
1303 }
1304 break;
1305 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1306 switch (revision)
1307 {
1308 case 0x03:
1309 product_str = "LSI53C1035 A2";
1310 break;
1311 case 0x04:
1312 product_str = "LSI53C1035 B0";
1313 break;
1314 default:
1315 product_str = "LSI53C1035";
1316 break;
1317 }
1318 break;
1319 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1320 switch (revision)
1321 {
1322 case 0x00:
1323 product_str = "LSISAS1064 A1";
1324 break;
1325 case 0x01:
1326 product_str = "LSISAS1064 A2";
1327 break;
1328 case 0x02:
1329 product_str = "LSISAS1064 A3";
1330 break;
1331 case 0x03:
1332 product_str = "LSISAS1064 A4";
1333 break;
1334 default:
1335 product_str = "LSISAS1064";
1336 break;
1337 }
1338 break;
1339 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1340 switch (revision)
1341 {
1342 case 0x00:
1343 product_str = "LSISAS1064E A0";
1344 break;
1345 case 0x01:
1346 product_str = "LSISAS1064E B0";
1347 break;
1348 case 0x02:
1349 product_str = "LSISAS1064E B1";
1350 break;
1351 case 0x04:
1352 product_str = "LSISAS1064E B2";
1353 break;
1354 case 0x08:
1355 product_str = "LSISAS1064E B3";
1356 break;
1357 default:
1358 product_str = "LSISAS1064E";
1359 break;
1360 }
1361 break;
1362 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "LSISAS1068 A0";
1367 break;
1368 case 0x01:
1369 product_str = "LSISAS1068 B0";
1370 break;
1371 case 0x02:
1372 product_str = "LSISAS1068 B1";
1373 break;
1374 default:
1375 product_str = "LSISAS1068";
1376 break;
1377 }
1378 break;
1379 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1380 switch (revision)
1381 {
1382 case 0x00:
1383 product_str = "LSISAS1068E A0";
1384 break;
1385 case 0x01:
1386 product_str = "LSISAS1068E B0";
1387 break;
1388 case 0x02:
1389 product_str = "LSISAS1068E B1";
1390 break;
1391 case 0x04:
1392 product_str = "LSISAS1068E B2";
1393 break;
1394 case 0x08:
1395 product_str = "LSISAS1068E B3";
1396 break;
1397 default:
1398 product_str = "LSISAS1068E";
1399 break;
1400 }
1401 break;
1402 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1403 switch (revision)
1404 {
1405 case 0x00:
1406 product_str = "LSISAS1078 A0";
1407 break;
1408 case 0x01:
1409 product_str = "LSISAS1078 B0";
1410 break;
1411 case 0x02:
1412 product_str = "LSISAS1078 C0";
1413 break;
1414 case 0x03:
1415 product_str = "LSISAS1078 C1";
1416 break;
1417 case 0x04:
1418 product_str = "LSISAS1078 C2";
1419 break;
1420 default:
1421 product_str = "LSISAS1078";
1422 break;
1423 }
1424 break;
1425 }
1426
1427 out:
1428 if (product_str)
1429 sprintf(prod_name, "%s", product_str);
1430}
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001433/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001434 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *
1438 * This routine performs all the steps necessary to bring the IOC of
1439 * a MPT adapter to a OPERATIONAL state. This includes registering
1440 * memory regions, registering the interrupt, and allocating request
1441 * and reply memory pools.
1442 *
1443 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1444 * MPT adapter.
1445 *
1446 * Returns 0 for success, non-zero for failure.
1447 *
1448 * TODO: Add support for polled controllers
1449 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001450int
1451mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 MPT_ADAPTER *ioc;
1454 u8 __iomem *mem;
Eric Moorebc6e0892007-09-29 10:16:28 -06001455 u8 __iomem *pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long mem_phys;
1457 unsigned long port;
1458 u32 msize;
1459 u32 psize;
1460 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301461 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 u8 revision;
1464 u8 pcixcmd;
1465 static int mpt_ids = 0;
1466#ifdef CONFIG_PROC_FS
1467 struct proc_dir_entry *dent, *ent;
1468#endif
1469
Prakash, Sathya436ace72007-07-24 15:42:08 +05301470 if (mpt_debug_level)
1471 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (pci_enable_device(pdev))
1474 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001475
Jesper Juhl56876192007-08-10 14:50:51 -07001476 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1477 if (ioc == NULL) {
1478 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1479 return -ENOMEM;
1480 }
1481 ioc->debug_level = mpt_debug_level;
Eric Moore29dd3602007-09-14 18:46:51 -06001482 ioc->id = mpt_ids++;
1483 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001484
Eric Moore29dd3602007-09-14 18:46:51 -06001485 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001486
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001487 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001488 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1489 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001490 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001491 printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
1492 ioc->name);
Jesper Juhl56876192007-08-10 14:50:51 -07001493 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 return r;
1495 }
1496
Prakash, Sathya436ace72007-07-24 15:42:08 +05301497 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001498 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1499 ": Using 64 bit consistent mask\n", ioc->name));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301500 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001501 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1502 ": Not using 64 bit consistent mask\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 ioc->alloc_total = sizeof(MPT_ADAPTER);
1506 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1507 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 ioc->pcidev = pdev;
1510 ioc->diagPending = 0;
1511 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001512 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 /* Initialize the event logging.
1515 */
1516 ioc->eventTypes = 0; /* None */
1517 ioc->eventContext = 0;
1518 ioc->eventLogSize = 0;
1519 ioc->events = NULL;
1520
1521#ifdef MFCNT
1522 ioc->mfcnt = 0;
1523#endif
1524
1525 ioc->cached_fw = NULL;
1526
1527 /* Initilize SCSI Config Data structure
1528 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001529 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 /* Initialize the running configQ head.
1532 */
1533 INIT_LIST_HEAD(&ioc->configQ);
1534
Michael Reed05e8ec12006-01-13 14:31:54 -06001535 /* Initialize the fc rport list head.
1536 */
1537 INIT_LIST_HEAD(&ioc->fc_rports);
1538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 /* Find lookup slot. */
1540 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 mem_phys = msize = 0;
1543 port = psize = 0;
1544 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1545 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001546 if (psize)
1547 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 /* Get I/O space! */
1549 port = pci_resource_start(pdev, ii);
1550 psize = pci_resource_len(pdev,ii);
1551 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001552 if (msize)
1553 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* Get memmap */
1555 mem_phys = pci_resource_start(pdev, ii);
1556 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 }
1559 ioc->mem_size = msize;
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 mem = NULL;
1562 /* Get logical ptr for PciMem0 space */
1563 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001564 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (mem == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001566 printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 kfree(ioc);
1568 return -EINVAL;
1569 }
1570 ioc->memmap = mem;
Eric Moore29dd3602007-09-14 18:46:51 -06001571 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Eric Moore29dd3602007-09-14 18:46:51 -06001573 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1574 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 ioc->mem_phys = mem_phys;
1577 ioc->chip = (SYSIF_REGS __iomem *)mem;
1578
1579 /* Save Port IO values in case we need to do downloadboot */
Eric Moorebc6e0892007-09-29 10:16:28 -06001580 ioc->pio_mem_phys = port;
1581 pmem = (u8 __iomem *)port;
1582 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301584 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1585 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1586
1587 switch (pdev->device)
1588 {
1589 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1590 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1591 ioc->errata_flag_1064 = 1;
1592 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1593 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1594 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1595 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301597 break;
1598
1599 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* 929X Chip Fix. Set Split transactions level
1602 * for PCIX. Set MOST bits to zero.
1603 */
1604 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1605 pcixcmd &= 0x8F;
1606 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1607 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* 929XL Chip Fix. Set MMRBC to 0x08.
1609 */
1610 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1611 pcixcmd |= 0x08;
1612 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301615 break;
1616
1617 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* 919X Chip Fix. Set Split transactions level
1619 * for PCIX. Set MOST bits to zero.
1620 */
1621 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1622 pcixcmd &= 0x8F;
1623 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001624 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301625 break;
1626
1627 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* 1030 Chip Fix. Disable Split transactions
1629 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1630 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (revision < C0_1030) {
1632 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1633 pcixcmd &= 0x8F;
1634 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1635 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301636
1637 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001638 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301639 break;
1640
1641 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1642 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001643 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301644
1645 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1646 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1647 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001648 ioc->bus_type = SAS;
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001651 if (ioc->errata_flag_1064)
1652 pci_disable_io_access(pdev);
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 spin_lock_init(&ioc->FreeQlock);
1655
1656 /* Disable all! */
1657 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1658 ioc->active = 0;
1659 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1660
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301661 /* Set IOC ptr in the pcidev's driver data. */
1662 pci_set_drvdata(ioc->pcidev, ioc);
1663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 /* Set lookup ptr. */
1665 list_add_tail(&ioc->list, &ioc_list);
1666
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001667 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 */
1669 mpt_detect_bound_ports(ioc, pdev);
1670
James Bottomleyc92f2222006-03-01 09:02:49 -06001671 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1672 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001673 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1674 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001677 if (ioc->alt_ioc)
1678 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 iounmap(mem);
1680 kfree(ioc);
1681 pci_set_drvdata(pdev, NULL);
1682 return r;
1683 }
1684
1685 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001686 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301687 if(MptDeviceDriverHandlers[cb_idx] &&
1688 MptDeviceDriverHandlers[cb_idx]->probe) {
1689 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691 }
1692
1693#ifdef CONFIG_PROC_FS
1694 /*
1695 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1696 */
1697 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1698 if (dent) {
1699 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1700 if (ent) {
1701 ent->read_proc = procmpt_iocinfo_read;
1702 ent->data = ioc;
1703 }
1704 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1705 if (ent) {
1706 ent->read_proc = procmpt_summary_read;
1707 ent->data = ioc;
1708 }
1709 }
1710#endif
1711
1712 return 0;
1713}
1714
1715/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001716/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001717 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 */
1720
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001721void
1722mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723{
1724 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1725 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301726 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1729 remove_proc_entry(pname, NULL);
1730 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1731 remove_proc_entry(pname, NULL);
1732 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1733 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001734
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001736 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301737 if(MptDeviceDriverHandlers[cb_idx] &&
1738 MptDeviceDriverHandlers[cb_idx]->remove) {
1739 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 }
1741 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 /* Disable interrupts! */
1744 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1745
1746 ioc->active = 0;
1747 synchronize_irq(pdev->irq);
1748
1749 /* Clear any lingering interrupt */
1750 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1751
1752 CHIPREG_READ32(&ioc->chip->IntStatus);
1753
1754 mpt_adapter_dispose(ioc);
1755
1756 pci_set_drvdata(pdev, NULL);
1757}
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759/**************************************************************************
1760 * Power Management
1761 */
1762#ifdef CONFIG_PM
1763/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001764/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001765 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001766 * @pdev: Pointer to pci_dev structure
1767 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001769int
1770mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 u32 device_state;
1773 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Pavel Machek2a569572005-07-07 17:56:40 -07001775 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 printk(MYIOC_s_INFO_FMT
1778 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1779 ioc->name, pdev, pci_name(pdev), device_state);
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 pci_save_state(pdev);
1782
1783 /* put ioc into READY_STATE */
1784 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1785 printk(MYIOC_s_ERR_FMT
1786 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1787 }
1788
1789 /* disable interrupts */
1790 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1791 ioc->active = 0;
1792
1793 /* Clear any lingering interrupt */
1794 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1795
1796 pci_disable_device(pdev);
1797 pci_set_power_state(pdev, device_state);
1798
1799 return 0;
1800}
1801
1802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001803/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001804 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001805 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001807int
1808mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809{
1810 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1811 u32 device_state = pdev->current_state;
1812 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001813 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 printk(MYIOC_s_INFO_FMT
1816 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1817 ioc->name, pdev, pci_name(pdev), device_state);
1818
1819 pci_set_power_state(pdev, 0);
1820 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001821 err = pci_enable_device(pdev);
1822 if (err)
1823 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
1825 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001826 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 ioc->active = 1;
1828
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 printk(MYIOC_s_INFO_FMT
1830 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1831 ioc->name,
1832 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1833 CHIPREG_READ32(&ioc->chip->Doorbell));
1834
1835 /* bring ioc to operational state */
1836 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1837 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1838 printk(MYIOC_s_INFO_FMT
1839 "pci-resume: Cannot recover, error:[%x]\n",
1840 ioc->name, recovery_state);
1841 } else {
1842 printk(MYIOC_s_INFO_FMT
1843 "pci-resume: success\n", ioc->name);
1844 }
1845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 return 0;
1847}
1848#endif
1849
James Bottomley4ff42a62006-05-17 18:06:52 -05001850static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301851mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001852{
1853 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1854 ioc->bus_type != SPI) ||
1855 (MptDriverClass[index] == MPTFC_DRIVER &&
1856 ioc->bus_type != FC) ||
1857 (MptDriverClass[index] == MPTSAS_DRIVER &&
1858 ioc->bus_type != SAS))
1859 /* make sure we only call the relevant reset handler
1860 * for the bus */
1861 return 0;
1862 return (MptResetHandlers[index])(ioc, reset_phase);
1863}
1864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001866/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1868 * @ioc: Pointer to MPT adapter structure
1869 * @reason: Event word / reason
1870 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1871 *
1872 * This routine performs all the steps necessary to bring the IOC
1873 * to a OPERATIONAL state.
1874 *
1875 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1876 * MPT adapter.
1877 *
1878 * Returns:
1879 * 0 for success
1880 * -1 if failed to get board READY
1881 * -2 if READY but IOCFacts Failed
1882 * -3 if READY but PrimeIOCFifos Failed
1883 * -4 if READY but IOCInit Failed
1884 */
1885static int
1886mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1887{
1888 int hard_reset_done = 0;
1889 int alt_ioc_ready = 0;
1890 int hard;
1891 int rc=0;
1892 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301893 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 int handlers;
1895 int ret = 0;
1896 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001897 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301898 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Eric Moore29dd3602007-09-14 18:46:51 -06001900 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1901 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
1903 /* Disable reply interrupts (also blocks FreeQ) */
1904 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1905 ioc->active = 0;
1906
1907 if (ioc->alt_ioc) {
1908 if (ioc->alt_ioc->active)
1909 reset_alt_ioc_active = 1;
1910
1911 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1912 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1913 ioc->alt_ioc->active = 0;
1914 }
1915
1916 hard = 1;
1917 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1918 hard = 0;
1919
1920 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1921 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001922 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1923 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 if (reset_alt_ioc_active && ioc->alt_ioc) {
1926 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001927 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1928 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001929 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 ioc->alt_ioc->active = 1;
1931 }
1932
1933 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001934 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 }
1936 return -1;
1937 }
1938
1939 /* hard_reset_done = 0 if a soft reset was performed
1940 * and 1 if a hard reset was performed.
1941 */
1942 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1943 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1944 alt_ioc_ready = 1;
1945 else
Eric Moore29dd3602007-09-14 18:46:51 -06001946 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 }
1948
1949 for (ii=0; ii<5; ii++) {
1950 /* Get IOC facts! Allow 5 retries */
1951 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1952 break;
1953 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
1956 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06001957 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1958 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 ret = -2;
1960 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1961 MptDisplayIocCapabilities(ioc);
1962 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 if (alt_ioc_ready) {
1965 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301966 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001967 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 /* Retry - alt IOC was initialized once
1969 */
1970 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1971 }
1972 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301973 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001974 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 alt_ioc_ready = 0;
1976 reset_alt_ioc_active = 0;
1977 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1978 MptDisplayIocCapabilities(ioc->alt_ioc);
1979 }
1980 }
1981
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001982 /*
1983 * Device is reset now. It must have de-asserted the interrupt line
1984 * (if it was asserted) and it should be safe to register for the
1985 * interrupt now.
1986 */
1987 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1988 ioc->pci_irq = -1;
1989 if (ioc->pcidev->irq) {
1990 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1991 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001992 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001993 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06001994 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001995 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001996 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06001997 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001998 if (mpt_msi_enable)
1999 pci_disable_msi(ioc->pcidev);
2000 return -EBUSY;
2001 }
2002 irq_allocated = 1;
2003 ioc->pci_irq = ioc->pcidev->irq;
2004 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002005 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2006 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002007 }
2008 }
2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 /* Prime reply & request queues!
2011 * (mucho alloc's) Must be done prior to
2012 * init as upper addresses are needed for init.
2013 * If fails, continue with alt-ioc processing
2014 */
2015 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2016 ret = -3;
2017
2018 /* May need to check/upload firmware & data here!
2019 * If fails, continue with alt-ioc processing
2020 */
2021 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2022 ret = -4;
2023// NEW!
2024 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002025 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2026 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 alt_ioc_ready = 0;
2028 reset_alt_ioc_active = 0;
2029 }
2030
2031 if (alt_ioc_ready) {
2032 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2033 alt_ioc_ready = 0;
2034 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002035 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2036 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
2038 }
2039
2040 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2041 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302042 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002043 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
2045 /* Controller is not operational, cannot do upload
2046 */
2047 if (ret == 0) {
2048 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002049 if (rc == 0) {
2050 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2051 /*
2052 * Maintain only one pointer to FW memory
2053 * so there will not be two attempt to
2054 * downloadboot onboard dual function
2055 * chips (mpt_adapter_disable,
2056 * mpt_diag_reset)
2057 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302058 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002059 "mpt_upload: alt_%s has cached_fw=%p \n",
2060 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302061 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002062 }
2063 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002064 printk(MYIOC_s_WARN_FMT
2065 "firmware upload failure!\n", ioc->name);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002066 ret = -5;
2067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 }
2069 }
2070 }
2071
2072 if (ret == 0) {
2073 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002074 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 ioc->active = 1;
2076 }
2077
2078 if (reset_alt_ioc_active && ioc->alt_ioc) {
2079 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002080 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2081 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002082 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 ioc->alt_ioc->active = 1;
2084 }
2085
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002086 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 * and EventAck handling.
2088 */
2089 if ((ret == 0) && (!ioc->facts.EventState))
2090 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2091
2092 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2093 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2094
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002095 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2097 * recursive scenario; GetLanConfigPages times out, timer expired
2098 * routine calls HardResetHandler, which calls into here again,
2099 * and we try GetLanConfigPages again...
2100 */
2101 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002102
2103 /*
2104 * Initalize link list for inactive raid volumes.
2105 */
2106 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2107 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2108
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002109 if (ioc->bus_type == SAS) {
2110
2111 /* clear persistency table */
2112 if(ioc->facts.IOCExceptions &
2113 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2114 ret = mptbase_sas_persist_operation(ioc,
2115 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2116 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002117 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002118 }
2119
2120 /* Find IM volumes
2121 */
2122 mpt_findImVolumes(ioc);
2123
2124 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2126 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2127 /*
2128 * Pre-fetch the ports LAN MAC address!
2129 * (LANPage1_t stuff)
2130 */
2131 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302132 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2133 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002134 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2135 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302136
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 }
2138 } else {
2139 /* Get NVRAM and adapter maximums from SPP 0 and 2
2140 */
2141 mpt_GetScsiPortSettings(ioc, 0);
2142
2143 /* Get version and length of SDP 1
2144 */
2145 mpt_readScsiDevicePageHeaders(ioc, 0);
2146
2147 /* Find IM volumes
2148 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002149 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 mpt_findImVolumes(ioc);
2151
2152 /* Check, and possibly reset, the coalescing value
2153 */
2154 mpt_read_ioc_pg_1(ioc);
2155
2156 mpt_read_ioc_pg_4(ioc);
2157 }
2158
2159 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302160 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 }
2162
2163 /*
2164 * Call each currently registered protocol IOC reset handler
2165 * with post-reset indication.
2166 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2167 * MptResetHandlers[] registered yet.
2168 */
2169 if (hard_reset_done) {
2170 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302171 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2172 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302173 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002174 "Calling IOC post_reset handler #%d\n",
2175 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302176 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 handlers++;
2178 }
2179
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302180 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302181 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002182 "Calling IOC post_reset handler #%d\n",
2183 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302184 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 handlers++;
2186 }
2187 }
2188 /* FIXME? Examine results here? */
2189 }
2190
Eric Moore0ccdb002006-07-11 17:33:13 -06002191 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002192 if ((ret != 0) && irq_allocated) {
2193 free_irq(ioc->pci_irq, ioc);
2194 if (mpt_msi_enable)
2195 pci_disable_msi(ioc->pcidev);
2196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 return ret;
2198}
2199
2200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002201/**
2202 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 * @ioc: Pointer to MPT adapter structure
2204 * @pdev: Pointer to (struct pci_dev) structure
2205 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002206 * Search for PCI bus/dev_function which matches
2207 * PCI bus/dev_function (+/-1) for newly discovered 929,
2208 * 929X, 1030 or 1035.
2209 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2211 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2212 */
2213static void
2214mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2215{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002216 struct pci_dev *peer=NULL;
2217 unsigned int slot = PCI_SLOT(pdev->devfn);
2218 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 MPT_ADAPTER *ioc_srch;
2220
Prakash, Sathya436ace72007-07-24 15:42:08 +05302221 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002222 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002223 ioc->name, pci_name(pdev), pdev->bus->number,
2224 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002225
2226 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2227 if (!peer) {
2228 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2229 if (!peer)
2230 return;
2231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 list_for_each_entry(ioc_srch, &ioc_list, list) {
2234 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002235 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 /* Paranoia checks */
2237 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002238 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002239 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 break;
2241 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002242 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002243 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 break;
2245 }
Eric Moore29dd3602007-09-14 18:46:51 -06002246 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002247 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 ioc_srch->alt_ioc = ioc;
2249 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
2251 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002252 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253}
2254
2255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002256/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002258 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 */
2260static void
2261mpt_adapter_disable(MPT_ADAPTER *ioc)
2262{
2263 int sz;
2264 int ret;
2265
2266 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302267 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2268 "adapter\n", __FUNCTION__, ioc->name));
2269 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2270 ioc->cached_fw, CAN_SLEEP)) < 0) {
2271 printk(MYIOC_s_WARN_FMT
2272 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002273 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
2275 }
2276
2277 /* Disable adapter interrupts! */
2278 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2279 ioc->active = 0;
2280 /* Clear any lingering interrupt */
2281 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2282
2283 if (ioc->alloc != NULL) {
2284 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002285 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2286 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 pci_free_consistent(ioc->pcidev, sz,
2288 ioc->alloc, ioc->alloc_dma);
2289 ioc->reply_frames = NULL;
2290 ioc->req_frames = NULL;
2291 ioc->alloc = NULL;
2292 ioc->alloc_total -= sz;
2293 }
2294
2295 if (ioc->sense_buf_pool != NULL) {
2296 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2297 pci_free_consistent(ioc->pcidev, sz,
2298 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2299 ioc->sense_buf_pool = NULL;
2300 ioc->alloc_total -= sz;
2301 }
2302
2303 if (ioc->events != NULL){
2304 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2305 kfree(ioc->events);
2306 ioc->events = NULL;
2307 ioc->alloc_total -= sz;
2308 }
2309
Prakash, Sathya984621b2008-01-11 14:42:17 +05302310 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002312 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002313 mpt_inactive_raid_list_free(ioc);
2314 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002315 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002316 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002317 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 if (ioc->spi_data.pIocPg4 != NULL) {
2320 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302321 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 ioc->spi_data.pIocPg4,
2323 ioc->spi_data.IocPg4_dma);
2324 ioc->spi_data.pIocPg4 = NULL;
2325 ioc->alloc_total -= sz;
2326 }
2327
2328 if (ioc->ReqToChain != NULL) {
2329 kfree(ioc->ReqToChain);
2330 kfree(ioc->RequestNB);
2331 ioc->ReqToChain = NULL;
2332 }
2333
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002334 kfree(ioc->ChainToChain);
2335 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002336
2337 if (ioc->HostPageBuffer != NULL) {
2338 if((ret = mpt_host_page_access_control(ioc,
2339 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002340 printk(MYIOC_s_ERR_FMT
2341 "host page buffers free failed (%d)!\n",
2342 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002343 }
Eric Moore29dd3602007-09-14 18:46:51 -06002344 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002345 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2346 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002347 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002348 ioc->HostPageBuffer = NULL;
2349 ioc->HostPageBuffer_sz = 0;
2350 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352}
2353
2354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002355/**
2356 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 * @ioc: Pointer to MPT adapter structure
2358 *
2359 * This routine unregisters h/w resources and frees all alloc'd memory
2360 * associated with a MPT adapter structure.
2361 */
2362static void
2363mpt_adapter_dispose(MPT_ADAPTER *ioc)
2364{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002365 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002367 if (ioc == NULL)
2368 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002370 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002374 if (ioc->pci_irq != -1) {
2375 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002376 if (mpt_msi_enable)
2377 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002378 ioc->pci_irq = -1;
2379 }
2380
2381 if (ioc->memmap != NULL) {
2382 iounmap(ioc->memmap);
2383 ioc->memmap = NULL;
2384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
2386#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002387 if (ioc->mtrr_reg > 0) {
2388 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002389 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391#endif
2392
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002393 /* Zap the adapter lookup ptr! */
2394 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002396 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002397 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2398 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002399
2400 if (ioc->alt_ioc)
2401 ioc->alt_ioc->alt_ioc = NULL;
2402
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002403 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404}
2405
2406/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002407/**
2408 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 * @ioc: Pointer to MPT adapter structure
2410 */
2411static void
2412MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2413{
2414 int i = 0;
2415
2416 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302417 if (ioc->prod_name)
2418 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 printk("Capabilities={");
2420
2421 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2422 printk("Initiator");
2423 i++;
2424 }
2425
2426 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2427 printk("%sTarget", i ? "," : "");
2428 i++;
2429 }
2430
2431 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2432 printk("%sLAN", i ? "," : "");
2433 i++;
2434 }
2435
2436#if 0
2437 /*
2438 * This would probably evoke more questions than it's worth
2439 */
2440 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2441 printk("%sLogBusAddr", i ? "," : "");
2442 i++;
2443 }
2444#endif
2445
2446 printk("}\n");
2447}
2448
2449/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002450/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2452 * @ioc: Pointer to MPT_ADAPTER structure
2453 * @force: Force hard KickStart of IOC
2454 * @sleepFlag: Specifies whether the process can sleep
2455 *
2456 * Returns:
2457 * 1 - DIAG reset and READY
2458 * 0 - READY initially OR soft reset and READY
2459 * -1 - Any failure on KickStart
2460 * -2 - Msg Unit Reset Failed
2461 * -3 - IO Unit Reset Failed
2462 * -4 - IOC owned by a PEER
2463 */
2464static int
2465MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2466{
2467 u32 ioc_state;
2468 int statefault = 0;
2469 int cntdn;
2470 int hard_reset_done = 0;
2471 int r;
2472 int ii;
2473 int whoinit;
2474
2475 /* Get current [raw] IOC state */
2476 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002477 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 /*
2480 * Check to see if IOC got left/stuck in doorbell handshake
2481 * grip of death. If so, hard reset the IOC.
2482 */
2483 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2484 statefault = 1;
2485 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2486 ioc->name);
2487 }
2488
2489 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002490 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 return 0;
2492
2493 /*
2494 * Check to see if IOC is in FAULT state.
2495 */
2496 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2497 statefault = 2;
2498 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002499 ioc->name);
2500 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2501 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 }
2503
2504 /*
2505 * Hmmm... Did it get left operational?
2506 */
2507 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302508 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 ioc->name));
2510
2511 /* Check WhoInit.
2512 * If PCI Peer, exit.
2513 * Else, if no fault conditions are present, issue a MessageUnitReset
2514 * Else, fall through to KickStart case
2515 */
2516 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002517 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2518 "whoinit 0x%x statefault %d force %d\n",
2519 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 if (whoinit == MPI_WHOINIT_PCI_PEER)
2521 return -4;
2522 else {
2523 if ((statefault == 0 ) && (force == 0)) {
2524 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2525 return 0;
2526 }
2527 statefault = 3;
2528 }
2529 }
2530
2531 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2532 if (hard_reset_done < 0)
2533 return -1;
2534
2535 /*
2536 * Loop here waiting for IOC to come READY.
2537 */
2538 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002539 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2542 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2543 /*
2544 * BIOS or previous driver load left IOC in OP state.
2545 * Reset messaging FIFOs.
2546 */
2547 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2548 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2549 return -2;
2550 }
2551 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2552 /*
2553 * Something is wrong. Try to get IOC back
2554 * to a known state.
2555 */
2556 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2557 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2558 return -3;
2559 }
2560 }
2561
2562 ii++; cntdn--;
2563 if (!cntdn) {
2564 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2565 ioc->name, (int)((ii+5)/HZ));
2566 return -ETIME;
2567 }
2568
2569 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002570 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 } else {
2572 mdelay (1); /* 1 msec delay */
2573 }
2574
2575 }
2576
2577 if (statefault < 3) {
2578 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2579 ioc->name,
2580 statefault==1 ? "stuck handshake" : "IOC FAULT");
2581 }
2582
2583 return hard_reset_done;
2584}
2585
2586/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002587/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 * mpt_GetIocState - Get the current state of a MPT adapter.
2589 * @ioc: Pointer to MPT_ADAPTER structure
2590 * @cooked: Request raw or cooked IOC state
2591 *
2592 * Returns all IOC Doorbell register bits if cooked==0, else just the
2593 * Doorbell bits in MPI_IOC_STATE_MASK.
2594 */
2595u32
2596mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2597{
2598 u32 s, sc;
2599
2600 /* Get! */
2601 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 sc = s & MPI_IOC_STATE_MASK;
2603
2604 /* Save! */
2605 ioc->last_state = sc;
2606
2607 return cooked ? sc : s;
2608}
2609
2610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002611/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 * GetIocFacts - Send IOCFacts request to MPT adapter.
2613 * @ioc: Pointer to MPT_ADAPTER structure
2614 * @sleepFlag: Specifies whether the process can sleep
2615 * @reason: If recovery, only update facts.
2616 *
2617 * Returns 0 for success, non-zero for failure.
2618 */
2619static int
2620GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2621{
2622 IOCFacts_t get_facts;
2623 IOCFactsReply_t *facts;
2624 int r;
2625 int req_sz;
2626 int reply_sz;
2627 int sz;
2628 u32 status, vv;
2629 u8 shiftFactor=1;
2630
2631 /* IOC *must* NOT be in RESET state! */
2632 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002633 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2634 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 return -44;
2636 }
2637
2638 facts = &ioc->facts;
2639
2640 /* Destination (reply area)... */
2641 reply_sz = sizeof(*facts);
2642 memset(facts, 0, reply_sz);
2643
2644 /* Request area (get_facts on the stack right now!) */
2645 req_sz = sizeof(get_facts);
2646 memset(&get_facts, 0, req_sz);
2647
2648 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2649 /* Assert: All other get_facts fields are zero! */
2650
Prakash, Sathya436ace72007-07-24 15:42:08 +05302651 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002652 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 ioc->name, req_sz, reply_sz));
2654
2655 /* No non-zero fields in the get_facts request are greater than
2656 * 1 byte in size, so we can just fire it off as is.
2657 */
2658 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2659 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2660 if (r != 0)
2661 return r;
2662
2663 /*
2664 * Now byte swap (GRRR) the necessary fields before any further
2665 * inspection of reply contents.
2666 *
2667 * But need to do some sanity checks on MsgLength (byte) field
2668 * to make sure we don't zero IOC's req_sz!
2669 */
2670 /* Did we get a valid reply? */
2671 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2672 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2673 /*
2674 * If not been here, done that, save off first WhoInit value
2675 */
2676 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2677 ioc->FirstWhoInit = facts->WhoInit;
2678 }
2679
2680 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2681 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2682 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2683 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2684 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002685 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 /* CHECKME! IOCStatus, IOCLogInfo */
2687
2688 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2689 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2690
2691 /*
2692 * FC f/w version changed between 1.1 and 1.2
2693 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2694 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2695 */
2696 if (facts->MsgVersion < 0x0102) {
2697 /*
2698 * Handle old FC f/w style, convert to new...
2699 */
2700 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2701 facts->FWVersion.Word =
2702 ((oldv<<12) & 0xFF000000) |
2703 ((oldv<<8) & 0x000FFF00);
2704 } else
2705 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2706
2707 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002708 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2709 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2710 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 facts->CurrentHostMfaHighAddr =
2712 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2713 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2714 facts->CurrentSenseBufferHighAddr =
2715 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2716 facts->CurReplyFrameSize =
2717 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002718 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
2720 /*
2721 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2722 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2723 * to 14 in MPI-1.01.0x.
2724 */
2725 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2726 facts->MsgVersion > 0x0100) {
2727 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2728 }
2729
2730 sz = facts->FWImageSize;
2731 if ( sz & 0x01 )
2732 sz += 1;
2733 if ( sz & 0x02 )
2734 sz += 2;
2735 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002736
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 if (!facts->RequestFrameSize) {
2738 /* Something is wrong! */
2739 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2740 ioc->name);
2741 return -55;
2742 }
2743
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002744 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 vv = ((63 / (sz * 4)) + 1) & 0x03;
2746 ioc->NB_for_64_byte_frame = vv;
2747 while ( sz )
2748 {
2749 shiftFactor++;
2750 sz = sz >> 1;
2751 }
2752 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302753 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002754 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2755 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002756
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2758 /*
2759 * Set values for this IOC's request & reply frame sizes,
2760 * and request & reply queue depths...
2761 */
2762 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2763 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2764 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2765 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2766
Prakash, Sathya436ace72007-07-24 15:42:08 +05302767 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302769 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 ioc->name, ioc->req_sz, ioc->req_depth));
2771
2772 /* Get port facts! */
2773 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2774 return r;
2775 }
2776 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2779 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2780 RequestFrameSize)/sizeof(u32)));
2781 return -66;
2782 }
2783
2784 return 0;
2785}
2786
2787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002788/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 * GetPortFacts - Send PortFacts request to MPT adapter.
2790 * @ioc: Pointer to MPT_ADAPTER structure
2791 * @portnum: Port number
2792 * @sleepFlag: Specifies whether the process can sleep
2793 *
2794 * Returns 0 for success, non-zero for failure.
2795 */
2796static int
2797GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2798{
2799 PortFacts_t get_pfacts;
2800 PortFactsReply_t *pfacts;
2801 int ii;
2802 int req_sz;
2803 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002804 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805
2806 /* IOC *must* NOT be in RESET state! */
2807 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002808 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2809 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return -4;
2811 }
2812
2813 pfacts = &ioc->pfacts[portnum];
2814
2815 /* Destination (reply area)... */
2816 reply_sz = sizeof(*pfacts);
2817 memset(pfacts, 0, reply_sz);
2818
2819 /* Request area (get_pfacts on the stack right now!) */
2820 req_sz = sizeof(get_pfacts);
2821 memset(&get_pfacts, 0, req_sz);
2822
2823 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2824 get_pfacts.PortNumber = portnum;
2825 /* Assert: All other get_pfacts fields are zero! */
2826
Prakash, Sathya436ace72007-07-24 15:42:08 +05302827 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 ioc->name, portnum));
2829
2830 /* No non-zero fields in the get_pfacts request are greater than
2831 * 1 byte in size, so we can just fire it off as is.
2832 */
2833 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2834 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2835 if (ii != 0)
2836 return ii;
2837
2838 /* Did we get a valid reply? */
2839
2840 /* Now byte swap the necessary fields in the response. */
2841 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2842 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2843 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2844 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2845 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2846 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2847 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2848 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2849 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2850
Eric Moore793955f2007-01-29 09:42:20 -07002851 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2852 pfacts->MaxDevices;
2853 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2854 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2855
2856 /*
2857 * Place all the devices on channels
2858 *
2859 * (for debuging)
2860 */
2861 if (mpt_channel_mapping) {
2862 ioc->devices_per_bus = 1;
2863 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2864 }
2865
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 return 0;
2867}
2868
2869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002870/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 * SendIocInit - Send IOCInit request to MPT adapter.
2872 * @ioc: Pointer to MPT_ADAPTER structure
2873 * @sleepFlag: Specifies whether the process can sleep
2874 *
2875 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2876 *
2877 * Returns 0 for success, non-zero for failure.
2878 */
2879static int
2880SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2881{
2882 IOCInit_t ioc_init;
2883 MPIDefaultReply_t init_reply;
2884 u32 state;
2885 int r;
2886 int count;
2887 int cntdn;
2888
2889 memset(&ioc_init, 0, sizeof(ioc_init));
2890 memset(&init_reply, 0, sizeof(init_reply));
2891
2892 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2893 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2894
2895 /* If we are in a recovery mode and we uploaded the FW image,
2896 * then this pointer is not NULL. Skip the upload a second time.
2897 * Set this flag if cached_fw set for either IOC.
2898 */
2899 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2900 ioc->upload_fw = 1;
2901 else
2902 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302903 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2905
Eric Moore793955f2007-01-29 09:42:20 -07002906 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2907 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302908 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002909 ioc->name, ioc->facts.MsgVersion));
2910 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2911 // set MsgVersion and HeaderVersion host driver was built with
2912 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2913 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002915 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2916 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2917 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2918 return -99;
2919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2921
2922 if (sizeof(dma_addr_t) == sizeof(u64)) {
2923 /* Save the upper 32-bits of the request
2924 * (reply) and sense buffers.
2925 */
2926 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2927 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2928 } else {
2929 /* Force 32-bit addressing */
2930 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2931 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2932 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002933
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2935 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002936 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2937 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
Prakash, Sathya436ace72007-07-24 15:42:08 +05302939 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 ioc->name, &ioc_init));
2941
2942 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2943 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002944 if (r != 0) {
2945 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
2949 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002950 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 */
2952
Prakash, Sathya436ace72007-07-24 15:42:08 +05302953 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002955
2956 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2957 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960
2961 /* YIKES! SUPER IMPORTANT!!!
2962 * Poll IocState until _OPERATIONAL while IOC is doing
2963 * LoopInit and TargetDiscovery!
2964 */
2965 count = 0;
2966 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2967 state = mpt_GetIocState(ioc, 1);
2968 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2969 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002970 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 } else {
2972 mdelay(1);
2973 }
2974
2975 if (!cntdn) {
2976 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2977 ioc->name, (int)((count+5)/HZ));
2978 return -9;
2979 }
2980
2981 state = mpt_GetIocState(ioc, 1);
2982 count++;
2983 }
Eric Moore29dd3602007-09-14 18:46:51 -06002984 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 ioc->name, count));
2986
Eric Mooreba856d32006-07-11 17:34:01 -06002987 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return r;
2989}
2990
2991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002992/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 * SendPortEnable - Send PortEnable request to MPT adapter port.
2994 * @ioc: Pointer to MPT_ADAPTER structure
2995 * @portnum: Port number to enable
2996 * @sleepFlag: Specifies whether the process can sleep
2997 *
2998 * Send PortEnable to bring IOC to OPERATIONAL state.
2999 *
3000 * Returns 0 for success, non-zero for failure.
3001 */
3002static int
3003SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3004{
3005 PortEnable_t port_enable;
3006 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003007 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 int req_sz;
3009 int reply_sz;
3010
3011 /* Destination... */
3012 reply_sz = sizeof(MPIDefaultReply_t);
3013 memset(&reply_buf, 0, reply_sz);
3014
3015 req_sz = sizeof(PortEnable_t);
3016 memset(&port_enable, 0, req_sz);
3017
3018 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3019 port_enable.PortNumber = portnum;
3020/* port_enable.ChainOffset = 0; */
3021/* port_enable.MsgFlags = 0; */
3022/* port_enable.MsgContext = 0; */
3023
Prakash, Sathya436ace72007-07-24 15:42:08 +05303024 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 ioc->name, portnum, &port_enable));
3026
3027 /* RAID FW may take a long time to enable
3028 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003029 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003030 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3031 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3032 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003033 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003034 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3035 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3036 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003038 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039}
3040
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003041/**
3042 * mpt_alloc_fw_memory - allocate firmware memory
3043 * @ioc: Pointer to MPT_ADAPTER structure
3044 * @size: total FW bytes
3045 *
3046 * If memory has already been allocated, the same (cached) value
3047 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303048 *
3049 * Return 0 if successfull, or non-zero for failure
3050 **/
3051int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3053{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303054 int rc;
3055
3056 if (ioc->cached_fw) {
3057 rc = 0; /* use already allocated memory */
3058 goto out;
3059 }
3060 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3062 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303063 rc = 0;
3064 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303066 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3067 if (!ioc->cached_fw) {
3068 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3069 ioc->name);
3070 rc = -1;
3071 } else {
3072 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3073 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3074 ioc->alloc_total += size;
3075 rc = 0;
3076 }
3077 out:
3078 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303080
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003081/**
3082 * mpt_free_fw_memory - free firmware memory
3083 * @ioc: Pointer to MPT_ADAPTER structure
3084 *
3085 * If alt_img is NULL, delete from ioc structure.
3086 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303087 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088void
3089mpt_free_fw_memory(MPT_ADAPTER *ioc)
3090{
3091 int sz;
3092
Prakash, Sathya984621b2008-01-11 14:42:17 +05303093 if (!ioc->cached_fw)
3094 return;
3095
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303097 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3098 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003099 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303100 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102}
3103
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003105/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3107 * @ioc: Pointer to MPT_ADAPTER structure
3108 * @sleepFlag: Specifies whether the process can sleep
3109 *
3110 * Returns 0 for success, >0 for handshake failure
3111 * <0 for fw upload failure.
3112 *
3113 * Remark: If bound IOC and a successful FWUpload was performed
3114 * on the bound IOC, the second image is discarded
3115 * and memory is free'd. Both channels must upload to prevent
3116 * IOC from running in degraded mode.
3117 */
3118static int
3119mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3120{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 u8 reply[sizeof(FWUploadReply_t)];
3122 FWUpload_t *prequest;
3123 FWUploadReply_t *preply;
3124 FWUploadTCSGE_t *ptcsge;
3125 int sgeoffset;
3126 u32 flagsLength;
3127 int ii, sz, reply_sz;
3128 int cmdStatus;
3129
3130 /* If the image size is 0, we are done.
3131 */
3132 if ((sz = ioc->facts.FWImageSize) == 0)
3133 return 0;
3134
Prakash, Sathya984621b2008-01-11 14:42:17 +05303135 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3136 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
Eric Moore29dd3602007-09-14 18:46:51 -06003138 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3139 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003140
Eric Moorebc6e0892007-09-29 10:16:28 -06003141 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3142 kzalloc(ioc->req_sz, GFP_KERNEL);
3143 if (!prequest) {
3144 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3145 "while allocating memory \n", ioc->name));
3146 mpt_free_fw_memory(ioc);
3147 return -ENOMEM;
3148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
Eric Moorebc6e0892007-09-29 10:16:28 -06003150 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
3152 reply_sz = sizeof(reply);
3153 memset(preply, 0, reply_sz);
3154
3155 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3156 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3157
3158 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3159 ptcsge->DetailsLength = 12;
3160 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3161 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003162 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3165
3166 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003167 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003170 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3171 ioc->name, prequest, sgeoffset));
3172 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173
3174 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3175 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3176
Eric Moore29dd3602007-09-14 18:46:51 -06003177 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
3179 cmdStatus = -EFAULT;
3180 if (ii == 0) {
3181 /* Handshake transfer was complete and successful.
3182 * Check the Reply Frame.
3183 */
3184 int status, transfer_sz;
3185 status = le16_to_cpu(preply->IOCStatus);
3186 if (status == MPI_IOCSTATUS_SUCCESS) {
3187 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3188 if (transfer_sz == sz)
3189 cmdStatus = 0;
3190 }
3191 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303192 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 ioc->name, cmdStatus));
3194
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003195
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 if (cmdStatus) {
3197
Prakash, Sathya436ace72007-07-24 15:42:08 +05303198 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 ioc->name));
3200 mpt_free_fw_memory(ioc);
3201 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003202 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 return cmdStatus;
3205}
3206
3207/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003208/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 * mpt_downloadboot - DownloadBoot code
3210 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003211 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 * @sleepFlag: Specifies whether the process can sleep
3213 *
3214 * FwDownloadBoot requires Programmed IO access.
3215 *
3216 * Returns 0 for success
3217 * -1 FW Image size is 0
3218 * -2 No valid cached_fw Pointer
3219 * <0 for fw upload failure.
3220 */
3221static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003222mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 MpiExtImageHeader_t *pExtImage;
3225 u32 fwSize;
3226 u32 diag0val;
3227 int count;
3228 u32 *ptrFw;
3229 u32 diagRwData;
3230 u32 nextImage;
3231 u32 load_addr;
3232 u32 ioc_state=0;
3233
Prakash, Sathya436ace72007-07-24 15:42:08 +05303234 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003235 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3238 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3239 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3240 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3241 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3242 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3243
3244 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3245
3246 /* wait 1 msec */
3247 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003248 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 } else {
3250 mdelay (1);
3251 }
3252
3253 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3254 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3255
3256 for (count = 0; count < 30; count ++) {
3257 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3258 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303259 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 ioc->name, count));
3261 break;
3262 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003263 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003265 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003267 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 }
3269 }
3270
3271 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303272 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003273 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 ioc->name, diag0val));
3275 return -3;
3276 }
3277
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3279 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3280 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3281 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3282 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3283 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3284
3285 /* Set the DiagRwEn and Disable ARM bits */
3286 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3287
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 fwSize = (pFwHeader->ImageSize + 3)/4;
3289 ptrFw = (u32 *) pFwHeader;
3290
3291 /* Write the LoadStartAddress to the DiagRw Address Register
3292 * using Programmed IO
3293 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003294 if (ioc->errata_flag_1064)
3295 pci_enable_io_access(ioc->pcidev);
3296
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303298 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 ioc->name, pFwHeader->LoadStartAddress));
3300
Prakash, Sathya436ace72007-07-24 15:42:08 +05303301 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 ioc->name, fwSize*4, ptrFw));
3303 while (fwSize--) {
3304 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3305 }
3306
3307 nextImage = pFwHeader->NextImageHeaderOffset;
3308 while (nextImage) {
3309 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3310
3311 load_addr = pExtImage->LoadStartAddress;
3312
3313 fwSize = (pExtImage->ImageSize + 3) >> 2;
3314 ptrFw = (u32 *)pExtImage;
3315
Prakash, Sathya436ace72007-07-24 15:42:08 +05303316 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 +02003317 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3319
3320 while (fwSize--) {
3321 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3322 }
3323 nextImage = pExtImage->NextImageHeaderOffset;
3324 }
3325
3326 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303327 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3329
3330 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303331 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3333
3334 /* Clear the internal flash bad bit - autoincrementing register,
3335 * so must do two writes.
3336 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003337 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003338 /*
3339 * 1030 and 1035 H/W errata, workaround to access
3340 * the ClearFlashBadSignatureBit
3341 */
3342 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3343 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3344 diagRwData |= 0x40000000;
3345 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3346 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3347
3348 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3349 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3350 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3351 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3352
3353 /* wait 1 msec */
3354 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003355 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003356 } else {
3357 mdelay (1);
3358 }
3359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003361 if (ioc->errata_flag_1064)
3362 pci_disable_io_access(ioc->pcidev);
3363
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303365 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003366 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003368 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303369 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 ioc->name, diag0val));
3371 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3372
3373 /* Write 0xFF to reset the sequencer */
3374 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3375
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003376 if (ioc->bus_type == SAS) {
3377 ioc_state = mpt_GetIocState(ioc, 0);
3378 if ( (GetIocFacts(ioc, sleepFlag,
3379 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303380 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003381 ioc->name, ioc_state));
3382 return -EFAULT;
3383 }
3384 }
3385
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 for (count=0; count<HZ*20; count++) {
3387 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303388 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3389 "downloadboot successful! (count=%d) IocState=%x\n",
3390 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003391 if (ioc->bus_type == SAS) {
3392 return 0;
3393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303395 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3396 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 ioc->name));
3398 return -EFAULT;
3399 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303400 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3401 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 ioc->name));
3403 return 0;
3404 }
3405 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003406 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 } else {
3408 mdelay (10);
3409 }
3410 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303411 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3412 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 return -EFAULT;
3414}
3415
3416/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003417/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 * KickStart - Perform hard reset of MPT adapter.
3419 * @ioc: Pointer to MPT_ADAPTER structure
3420 * @force: Force hard reset
3421 * @sleepFlag: Specifies whether the process can sleep
3422 *
3423 * This routine places MPT adapter in diagnostic mode via the
3424 * WriteSequence register, and then performs a hard reset of adapter
3425 * via the Diagnostic register.
3426 *
3427 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3428 * or NO_SLEEP (interrupt thread, use mdelay)
3429 * force - 1 if doorbell active, board fault state
3430 * board operational, IOC_RECOVERY or
3431 * IOC_BRINGUP and there is an alt_ioc.
3432 * 0 else
3433 *
3434 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003435 * 1 - hard reset, READY
3436 * 0 - no reset due to History bit, READY
3437 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 * OR reset but failed to come READY
3439 * -2 - no reset, could not enter DIAG mode
3440 * -3 - reset but bad FW bit
3441 */
3442static int
3443KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3444{
3445 int hard_reset_done = 0;
3446 u32 ioc_state=0;
3447 int cnt,cntdn;
3448
Eric Moore29dd3602007-09-14 18:46:51 -06003449 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003450 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 /* Always issue a Msg Unit Reset first. This will clear some
3452 * SCSI bus hang conditions.
3453 */
3454 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3455
3456 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003457 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 } else {
3459 mdelay (1000);
3460 }
3461 }
3462
3463 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3464 if (hard_reset_done < 0)
3465 return hard_reset_done;
3466
Prakash, Sathya436ace72007-07-24 15:42:08 +05303467 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003468 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
3470 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3471 for (cnt=0; cnt<cntdn; cnt++) {
3472 ioc_state = mpt_GetIocState(ioc, 1);
3473 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303474 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 ioc->name, cnt));
3476 return hard_reset_done;
3477 }
3478 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003479 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 } else {
3481 mdelay (10);
3482 }
3483 }
3484
Eric Moore29dd3602007-09-14 18:46:51 -06003485 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3486 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 return -1;
3488}
3489
3490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003491/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 * mpt_diag_reset - Perform hard reset of the adapter.
3493 * @ioc: Pointer to MPT_ADAPTER structure
3494 * @ignore: Set if to honor and clear to ignore
3495 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003496 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 * else set to NO_SLEEP (use mdelay instead)
3498 *
3499 * This routine places the adapter in diagnostic mode via the
3500 * WriteSequence register and then performs a hard reset of adapter
3501 * via the Diagnostic register. Adapter should be in ready state
3502 * upon successful completion.
3503 *
3504 * Returns: 1 hard reset successful
3505 * 0 no reset performed because reset history bit set
3506 * -2 enabling diagnostic mode failed
3507 * -3 diagnostic reset failed
3508 */
3509static int
3510mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3511{
3512 u32 diag0val;
3513 u32 doorbell;
3514 int hard_reset_done = 0;
3515 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303517 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
Eric Moorecd2c6192007-01-29 09:47:47 -07003519 /* Clear any existing interrupts */
3520 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3521
Eric Moore87cf8982006-06-27 16:09:26 -06003522 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303523 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003524 "address=%p\n", ioc->name, __FUNCTION__,
3525 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3526 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3527 if (sleepFlag == CAN_SLEEP)
3528 msleep(1);
3529 else
3530 mdelay(1);
3531
3532 for (count = 0; count < 60; count ++) {
3533 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3534 doorbell &= MPI_IOC_STATE_MASK;
3535
Prakash, Sathya436ace72007-07-24 15:42:08 +05303536 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003537 "looking for READY STATE: doorbell=%x"
3538 " count=%d\n",
3539 ioc->name, doorbell, count));
3540 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003541 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003542 }
3543
3544 /* wait 1 sec */
3545 if (sleepFlag == CAN_SLEEP)
3546 msleep(1000);
3547 else
3548 mdelay(1000);
3549 }
3550 return -1;
3551 }
3552
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 /* Use "Diagnostic reset" method! (only thing available!) */
3554 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3555
Prakash, Sathya436ace72007-07-24 15:42:08 +05303556 if (ioc->debug_level & MPT_DEBUG) {
3557 if (ioc->alt_ioc)
3558 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3559 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
3563 /* Do the reset if we are told to ignore the reset history
3564 * or if the reset history is 0
3565 */
3566 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3567 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3568 /* Write magic sequence to WriteSequence register
3569 * Loop until in diagnostic mode
3570 */
3571 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3572 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3573 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3574 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3575 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3576 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3577
3578 /* wait 100 msec */
3579 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003580 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 } else {
3582 mdelay (100);
3583 }
3584
3585 count++;
3586 if (count > 20) {
3587 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3588 ioc->name, diag0val);
3589 return -2;
3590
3591 }
3592
3593 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3594
Prakash, Sathya436ace72007-07-24 15:42:08 +05303595 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 ioc->name, diag0val));
3597 }
3598
Prakash, Sathya436ace72007-07-24 15:42:08 +05303599 if (ioc->debug_level & MPT_DEBUG) {
3600 if (ioc->alt_ioc)
3601 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3602 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 /*
3606 * Disable the ARM (Bug fix)
3607 *
3608 */
3609 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003610 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
3612 /*
3613 * Now hit the reset bit in the Diagnostic register
3614 * (THE BIG HAMMER!) (Clears DRWE bit).
3615 */
3616 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3617 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303618 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 ioc->name));
3620
3621 /*
3622 * Call each currently registered protocol IOC reset handler
3623 * with pre-reset indication.
3624 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3625 * MptResetHandlers[] registered yet.
3626 */
3627 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303628 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 int r = 0;
3630
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303631 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3632 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303633 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3634 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303635 ioc->name, cb_idx));
3636 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303638 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3639 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303640 ioc->name, ioc->alt_ioc->name, cb_idx));
3641 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 }
3643 }
3644 }
3645 /* FIXME? Examine results here? */
3646 }
3647
Eric Moore0ccdb002006-07-11 17:33:13 -06003648 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303649 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003650 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303651 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3652 else
3653 cached_fw = NULL;
3654 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 /* If the DownloadBoot operation fails, the
3656 * IOC will be left unusable. This is a fatal error
3657 * case. _diag_reset will return < 0
3658 */
3659 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303660 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3662 break;
3663 }
3664
Prakash, Sathya436ace72007-07-24 15:42:08 +05303665 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303666 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 /* wait 1 sec */
3668 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003669 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 } else {
3671 mdelay (1000);
3672 }
3673 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303674 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003675 printk(MYIOC_s_WARN_FMT
3676 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 }
3678
3679 } else {
3680 /* Wait for FW to reload and for board
3681 * to go to the READY state.
3682 * Maximum wait is 60 seconds.
3683 * If fail, no error will check again
3684 * with calling program.
3685 */
3686 for (count = 0; count < 60; count ++) {
3687 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3688 doorbell &= MPI_IOC_STATE_MASK;
3689
3690 if (doorbell == MPI_IOC_STATE_READY) {
3691 break;
3692 }
3693
3694 /* wait 1 sec */
3695 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003696 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 } else {
3698 mdelay (1000);
3699 }
3700 }
3701 }
3702 }
3703
3704 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303705 if (ioc->debug_level & MPT_DEBUG) {
3706 if (ioc->alt_ioc)
3707 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3708 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3709 ioc->name, diag0val, diag1val));
3710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711
3712 /* Clear RESET_HISTORY bit! Place board in the
3713 * diagnostic mode to update the diag register.
3714 */
3715 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3716 count = 0;
3717 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3718 /* Write magic sequence to WriteSequence register
3719 * Loop until in diagnostic mode
3720 */
3721 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3722 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3723 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3724 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3725 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3726 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3727
3728 /* wait 100 msec */
3729 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003730 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 } else {
3732 mdelay (100);
3733 }
3734
3735 count++;
3736 if (count > 20) {
3737 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3738 ioc->name, diag0val);
3739 break;
3740 }
3741 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3742 }
3743 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3744 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3745 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3746 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3747 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3748 ioc->name);
3749 }
3750
3751 /* Disable Diagnostic Mode
3752 */
3753 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3754
3755 /* Check FW reload status flags.
3756 */
3757 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3758 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3759 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3760 ioc->name, diag0val);
3761 return -3;
3762 }
3763
Prakash, Sathya436ace72007-07-24 15:42:08 +05303764 if (ioc->debug_level & MPT_DEBUG) {
3765 if (ioc->alt_ioc)
3766 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3767 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
3771 /*
3772 * Reset flag that says we've enabled event notification
3773 */
3774 ioc->facts.EventState = 0;
3775
3776 if (ioc->alt_ioc)
3777 ioc->alt_ioc->facts.EventState = 0;
3778
3779 return hard_reset_done;
3780}
3781
3782/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003783/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 * SendIocReset - Send IOCReset request to MPT adapter.
3785 * @ioc: Pointer to MPT_ADAPTER structure
3786 * @reset_type: reset type, expected values are
3787 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003788 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 *
3790 * Send IOCReset request to the MPT adapter.
3791 *
3792 * Returns 0 for success, non-zero for failure.
3793 */
3794static int
3795SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3796{
3797 int r;
3798 u32 state;
3799 int cntdn, count;
3800
Prakash, Sathya436ace72007-07-24 15:42:08 +05303801 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 ioc->name, reset_type));
3803 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3804 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3805 return r;
3806
3807 /* FW ACK'd request, wait for READY state
3808 */
3809 count = 0;
3810 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3811
3812 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3813 cntdn--;
3814 count++;
3815 if (!cntdn) {
3816 if (sleepFlag != CAN_SLEEP)
3817 count *= 10;
3818
Eric Moore29dd3602007-09-14 18:46:51 -06003819 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3820 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 return -ETIME;
3822 }
3823
3824 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003825 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 } else {
3827 mdelay (1); /* 1 msec delay */
3828 }
3829 }
3830
3831 /* TODO!
3832 * Cleanup all event stuff for this IOC; re-issue EventNotification
3833 * request if needed.
3834 */
3835 if (ioc->facts.Function)
3836 ioc->facts.EventState = 0;
3837
3838 return 0;
3839}
3840
3841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003842/**
3843 * initChainBuffers - Allocate memory for and initialize chain buffers
3844 * @ioc: Pointer to MPT_ADAPTER structure
3845 *
3846 * Allocates memory for and initializes chain buffers,
3847 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 */
3849static int
3850initChainBuffers(MPT_ADAPTER *ioc)
3851{
3852 u8 *mem;
3853 int sz, ii, num_chain;
3854 int scale, num_sge, numSGE;
3855
3856 /* ReqToChain size must equal the req_depth
3857 * index = req_idx
3858 */
3859 if (ioc->ReqToChain == NULL) {
3860 sz = ioc->req_depth * sizeof(int);
3861 mem = kmalloc(sz, GFP_ATOMIC);
3862 if (mem == NULL)
3863 return -1;
3864
3865 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303866 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 ioc->name, mem, sz));
3868 mem = kmalloc(sz, GFP_ATOMIC);
3869 if (mem == NULL)
3870 return -1;
3871
3872 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303873 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 ioc->name, mem, sz));
3875 }
3876 for (ii = 0; ii < ioc->req_depth; ii++) {
3877 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3878 }
3879
3880 /* ChainToChain size must equal the total number
3881 * of chain buffers to be allocated.
3882 * index = chain_idx
3883 *
3884 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003885 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 *
3887 * num_sge = num sge in request frame + last chain buffer
3888 * scale = num sge per chain buffer if no chain element
3889 */
3890 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3891 if (sizeof(dma_addr_t) == sizeof(u64))
3892 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3893 else
3894 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3895
3896 if (sizeof(dma_addr_t) == sizeof(u64)) {
3897 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3898 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3899 } else {
3900 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3901 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3902 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303903 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 ioc->name, num_sge, numSGE));
3905
3906 if ( numSGE > MPT_SCSI_SG_DEPTH )
3907 numSGE = MPT_SCSI_SG_DEPTH;
3908
3909 num_chain = 1;
3910 while (numSGE - num_sge > 0) {
3911 num_chain++;
3912 num_sge += (scale - 1);
3913 }
3914 num_chain++;
3915
Prakash, Sathya436ace72007-07-24 15:42:08 +05303916 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 ioc->name, numSGE, num_sge, num_chain));
3918
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003919 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 num_chain *= MPT_SCSI_CAN_QUEUE;
3921 else
3922 num_chain *= MPT_FC_CAN_QUEUE;
3923
3924 ioc->num_chain = num_chain;
3925
3926 sz = num_chain * sizeof(int);
3927 if (ioc->ChainToChain == NULL) {
3928 mem = kmalloc(sz, GFP_ATOMIC);
3929 if (mem == NULL)
3930 return -1;
3931
3932 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303933 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 ioc->name, mem, sz));
3935 } else {
3936 mem = (u8 *) ioc->ChainToChain;
3937 }
3938 memset(mem, 0xFF, sz);
3939 return num_chain;
3940}
3941
3942/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003943/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3945 * @ioc: Pointer to MPT_ADAPTER structure
3946 *
3947 * This routine allocates memory for the MPT reply and request frame
3948 * pools (if necessary), and primes the IOC reply FIFO with
3949 * reply frames.
3950 *
3951 * Returns 0 for success, non-zero for failure.
3952 */
3953static int
3954PrimeIocFifos(MPT_ADAPTER *ioc)
3955{
3956 MPT_FRAME_HDR *mf;
3957 unsigned long flags;
3958 dma_addr_t alloc_dma;
3959 u8 *mem;
3960 int i, reply_sz, sz, total_size, num_chain;
3961
3962 /* Prime reply FIFO... */
3963
3964 if (ioc->reply_frames == NULL) {
3965 if ( (num_chain = initChainBuffers(ioc)) < 0)
3966 return -1;
3967
3968 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303971 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 ioc->name, reply_sz, reply_sz));
3973
3974 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303975 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303977 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 ioc->name, sz, sz));
3979 total_size += sz;
3980
3981 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303982 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303984 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 ioc->name, sz, sz, num_chain));
3986
3987 total_size += sz;
3988 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3989 if (mem == NULL) {
3990 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3991 ioc->name);
3992 goto out_fail;
3993 }
3994
Prakash, Sathya436ace72007-07-24 15:42:08 +05303995 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3997
3998 memset(mem, 0, total_size);
3999 ioc->alloc_total += total_size;
4000 ioc->alloc = mem;
4001 ioc->alloc_dma = alloc_dma;
4002 ioc->alloc_sz = total_size;
4003 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4004 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4005
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004007 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4008
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 alloc_dma += reply_sz;
4010 mem += reply_sz;
4011
4012 /* Request FIFO - WE manage this! */
4013
4014 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4015 ioc->req_frames_dma = alloc_dma;
4016
Prakash, Sathya436ace72007-07-24 15:42:08 +05304017 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 ioc->name, mem, (void *)(ulong)alloc_dma));
4019
4020 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4021
4022#if defined(CONFIG_MTRR) && 0
4023 /*
4024 * Enable Write Combining MTRR for IOC's memory region.
4025 * (at least as much as we can; "size and base must be
4026 * multiples of 4 kiB"
4027 */
4028 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4029 sz,
4030 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304031 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, ioc->req_frames_dma, sz));
4033#endif
4034
4035 for (i = 0; i < ioc->req_depth; i++) {
4036 alloc_dma += ioc->req_sz;
4037 mem += ioc->req_sz;
4038 }
4039
4040 ioc->ChainBuffer = mem;
4041 ioc->ChainBufferDMA = alloc_dma;
4042
Prakash, Sathya436ace72007-07-24 15:42:08 +05304043 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4045
4046 /* Initialize the free chain Q.
4047 */
4048
4049 INIT_LIST_HEAD(&ioc->FreeChainQ);
4050
4051 /* Post the chain buffers to the FreeChainQ.
4052 */
4053 mem = (u8 *)ioc->ChainBuffer;
4054 for (i=0; i < num_chain; i++) {
4055 mf = (MPT_FRAME_HDR *) mem;
4056 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4057 mem += ioc->req_sz;
4058 }
4059
4060 /* Initialize Request frames linked list
4061 */
4062 alloc_dma = ioc->req_frames_dma;
4063 mem = (u8 *) ioc->req_frames;
4064
4065 spin_lock_irqsave(&ioc->FreeQlock, flags);
4066 INIT_LIST_HEAD(&ioc->FreeQ);
4067 for (i = 0; i < ioc->req_depth; i++) {
4068 mf = (MPT_FRAME_HDR *) mem;
4069
4070 /* Queue REQUESTs *internally*! */
4071 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4072
4073 mem += ioc->req_sz;
4074 }
4075 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4076
4077 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4078 ioc->sense_buf_pool =
4079 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4080 if (ioc->sense_buf_pool == NULL) {
4081 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4082 ioc->name);
4083 goto out_fail;
4084 }
4085
4086 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4087 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304088 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4090
4091 }
4092
4093 /* Post Reply frames to FIFO
4094 */
4095 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304096 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4098
4099 for (i = 0; i < ioc->reply_depth; i++) {
4100 /* Write each address to the IOC! */
4101 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4102 alloc_dma += ioc->reply_sz;
4103 }
4104
4105 return 0;
4106
4107out_fail:
4108 if (ioc->alloc != NULL) {
4109 sz = ioc->alloc_sz;
4110 pci_free_consistent(ioc->pcidev,
4111 sz,
4112 ioc->alloc, ioc->alloc_dma);
4113 ioc->reply_frames = NULL;
4114 ioc->req_frames = NULL;
4115 ioc->alloc_total -= sz;
4116 }
4117 if (ioc->sense_buf_pool != NULL) {
4118 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4119 pci_free_consistent(ioc->pcidev,
4120 sz,
4121 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4122 ioc->sense_buf_pool = NULL;
4123 }
4124 return -1;
4125}
4126
4127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4128/**
4129 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4130 * from IOC via doorbell handshake method.
4131 * @ioc: Pointer to MPT_ADAPTER structure
4132 * @reqBytes: Size of the request in bytes
4133 * @req: Pointer to MPT request frame
4134 * @replyBytes: Expected size of the reply in bytes
4135 * @u16reply: Pointer to area where reply should be written
4136 * @maxwait: Max wait time for a reply (in seconds)
4137 * @sleepFlag: Specifies whether the process can sleep
4138 *
4139 * NOTES: It is the callers responsibility to byte-swap fields in the
4140 * request which are greater than 1 byte in size. It is also the
4141 * callers responsibility to byte-swap response fields which are
4142 * greater than 1 byte in size.
4143 *
4144 * Returns 0 for success, non-zero for failure.
4145 */
4146static int
4147mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004148 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149{
4150 MPIDefaultReply_t *mptReply;
4151 int failcnt = 0;
4152 int t;
4153
4154 /*
4155 * Get ready to cache a handshake reply
4156 */
4157 ioc->hs_reply_idx = 0;
4158 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4159 mptReply->MsgLength = 0;
4160
4161 /*
4162 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4163 * then tell IOC that we want to handshake a request of N words.
4164 * (WRITE u32val to Doorbell reg).
4165 */
4166 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4167 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4168 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4169 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4170
4171 /*
4172 * Wait for IOC's doorbell handshake int
4173 */
4174 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4175 failcnt++;
4176
Prakash, Sathya436ace72007-07-24 15:42:08 +05304177 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4179
4180 /* Read doorbell and check for active bit */
4181 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4182 return -1;
4183
4184 /*
4185 * Clear doorbell int (WRITE 0 to IntStatus reg),
4186 * then wait for IOC to ACKnowledge that it's ready for
4187 * our handshake request.
4188 */
4189 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4190 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4191 failcnt++;
4192
4193 if (!failcnt) {
4194 int ii;
4195 u8 *req_as_bytes = (u8 *) req;
4196
4197 /*
4198 * Stuff request words via doorbell handshake,
4199 * with ACK from IOC for each.
4200 */
4201 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4202 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4203 (req_as_bytes[(ii*4) + 1] << 8) |
4204 (req_as_bytes[(ii*4) + 2] << 16) |
4205 (req_as_bytes[(ii*4) + 3] << 24));
4206
4207 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4208 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4209 failcnt++;
4210 }
4211
Prakash, Sathya436ace72007-07-24 15:42:08 +05304212 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004213 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
Prakash, Sathya436ace72007-07-24 15:42:08 +05304215 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4217
4218 /*
4219 * Wait for completion of doorbell handshake reply from the IOC
4220 */
4221 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4222 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004223
Prakash, Sathya436ace72007-07-24 15:42:08 +05304224 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4226
4227 /*
4228 * Copy out the cached reply...
4229 */
4230 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4231 u16reply[ii] = ioc->hs_reply[ii];
4232 } else {
4233 return -99;
4234 }
4235
4236 return -failcnt;
4237}
4238
4239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004240/**
4241 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 * @ioc: Pointer to MPT_ADAPTER structure
4243 * @howlong: How long to wait (in seconds)
4244 * @sleepFlag: Specifies whether the process can sleep
4245 *
4246 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004247 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4248 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 *
4250 * Returns a negative value on failure, else wait loop count.
4251 */
4252static int
4253WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4254{
4255 int cntdn;
4256 int count = 0;
4257 u32 intstat=0;
4258
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004259 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
4261 if (sleepFlag == CAN_SLEEP) {
4262 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004263 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4265 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4266 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 count++;
4268 }
4269 } else {
4270 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004271 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4273 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4274 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 count++;
4276 }
4277 }
4278
4279 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304280 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 ioc->name, count));
4282 return count;
4283 }
4284
4285 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4286 ioc->name, count, intstat);
4287 return -1;
4288}
4289
4290/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004291/**
4292 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 * @ioc: Pointer to MPT_ADAPTER structure
4294 * @howlong: How long to wait (in seconds)
4295 * @sleepFlag: Specifies whether the process can sleep
4296 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004297 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4298 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 *
4300 * Returns a negative value on failure, else wait loop count.
4301 */
4302static int
4303WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4304{
4305 int cntdn;
4306 int count = 0;
4307 u32 intstat=0;
4308
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004309 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 if (sleepFlag == CAN_SLEEP) {
4311 while (--cntdn) {
4312 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4313 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4314 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004315 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 count++;
4317 }
4318 } else {
4319 while (--cntdn) {
4320 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4321 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4322 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004323 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 count++;
4325 }
4326 }
4327
4328 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304329 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 ioc->name, count, howlong));
4331 return count;
4332 }
4333
4334 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4335 ioc->name, count, intstat);
4336 return -1;
4337}
4338
4339/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004340/**
4341 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 * @ioc: Pointer to MPT_ADAPTER structure
4343 * @howlong: How long to wait (in seconds)
4344 * @sleepFlag: Specifies whether the process can sleep
4345 *
4346 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4347 * Reply is cached to IOC private area large enough to hold a maximum
4348 * of 128 bytes of reply data.
4349 *
4350 * Returns a negative value on failure, else size of reply in WORDS.
4351 */
4352static int
4353WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4354{
4355 int u16cnt = 0;
4356 int failcnt = 0;
4357 int t;
4358 u16 *hs_reply = ioc->hs_reply;
4359 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4360 u16 hword;
4361
4362 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4363
4364 /*
4365 * Get first two u16's so we can look at IOC's intended reply MsgLength
4366 */
4367 u16cnt=0;
4368 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4369 failcnt++;
4370 } else {
4371 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4372 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4373 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4374 failcnt++;
4375 else {
4376 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4377 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4378 }
4379 }
4380
Prakash, Sathya436ace72007-07-24 15:42:08 +05304381 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004382 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4384
4385 /*
4386 * If no error (and IOC said MsgLength is > 0), piece together
4387 * reply 16 bits at a time.
4388 */
4389 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4390 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4391 failcnt++;
4392 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4393 /* don't overflow our IOC hs_reply[] buffer! */
4394 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4395 hs_reply[u16cnt] = hword;
4396 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4397 }
4398
4399 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4400 failcnt++;
4401 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4402
4403 if (failcnt) {
4404 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4405 ioc->name);
4406 return -failcnt;
4407 }
4408#if 0
4409 else if (u16cnt != (2 * mptReply->MsgLength)) {
4410 return -101;
4411 }
4412 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4413 return -102;
4414 }
4415#endif
4416
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004418 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
Prakash, Sathya436ace72007-07-24 15:42:08 +05304420 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 ioc->name, t, u16cnt/2));
4422 return u16cnt/2;
4423}
4424
4425/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004426/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 * GetLanConfigPages - Fetch LANConfig pages.
4428 * @ioc: Pointer to MPT_ADAPTER structure
4429 *
4430 * Return: 0 for success
4431 * -ENOMEM if no memory available
4432 * -EPERM if not allowed due to ISR context
4433 * -EAGAIN if no msg frames currently available
4434 * -EFAULT for non-successful reply or no reply (timeout)
4435 */
4436static int
4437GetLanConfigPages(MPT_ADAPTER *ioc)
4438{
4439 ConfigPageHeader_t hdr;
4440 CONFIGPARMS cfg;
4441 LANPage0_t *ppage0_alloc;
4442 dma_addr_t page0_dma;
4443 LANPage1_t *ppage1_alloc;
4444 dma_addr_t page1_dma;
4445 int rc = 0;
4446 int data_sz;
4447 int copy_sz;
4448
4449 /* Get LAN Page 0 header */
4450 hdr.PageVersion = 0;
4451 hdr.PageLength = 0;
4452 hdr.PageNumber = 0;
4453 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004454 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 cfg.physAddr = -1;
4456 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4457 cfg.dir = 0;
4458 cfg.pageAddr = 0;
4459 cfg.timeout = 0;
4460
4461 if ((rc = mpt_config(ioc, &cfg)) != 0)
4462 return rc;
4463
4464 if (hdr.PageLength > 0) {
4465 data_sz = hdr.PageLength * 4;
4466 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4467 rc = -ENOMEM;
4468 if (ppage0_alloc) {
4469 memset((u8 *)ppage0_alloc, 0, data_sz);
4470 cfg.physAddr = page0_dma;
4471 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4472
4473 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4474 /* save the data */
4475 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4476 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4477
4478 }
4479
4480 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4481
4482 /* FIXME!
4483 * Normalize endianness of structure data,
4484 * by byte-swapping all > 1 byte fields!
4485 */
4486
4487 }
4488
4489 if (rc)
4490 return rc;
4491 }
4492
4493 /* Get LAN Page 1 header */
4494 hdr.PageVersion = 0;
4495 hdr.PageLength = 0;
4496 hdr.PageNumber = 1;
4497 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004498 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 cfg.physAddr = -1;
4500 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4501 cfg.dir = 0;
4502 cfg.pageAddr = 0;
4503
4504 if ((rc = mpt_config(ioc, &cfg)) != 0)
4505 return rc;
4506
4507 if (hdr.PageLength == 0)
4508 return 0;
4509
4510 data_sz = hdr.PageLength * 4;
4511 rc = -ENOMEM;
4512 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4513 if (ppage1_alloc) {
4514 memset((u8 *)ppage1_alloc, 0, data_sz);
4515 cfg.physAddr = page1_dma;
4516 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4517
4518 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4519 /* save the data */
4520 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4521 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4522 }
4523
4524 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4525
4526 /* FIXME!
4527 * Normalize endianness of structure data,
4528 * by byte-swapping all > 1 byte fields!
4529 */
4530
4531 }
4532
4533 return rc;
4534}
4535
4536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004537/**
4538 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004539 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004540 * @persist_opcode: see below
4541 *
4542 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4543 * devices not currently present.
4544 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4545 *
4546 * NOTE: Don't use not this function during interrupt time.
4547 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004548 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004549 */
4550
4551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4552int
4553mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4554{
4555 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4556 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4557 MPT_FRAME_HDR *mf = NULL;
4558 MPIHeader_t *mpi_hdr;
4559
4560
4561 /* insure garbage is not sent to fw */
4562 switch(persist_opcode) {
4563
4564 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4565 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4566 break;
4567
4568 default:
4569 return -1;
4570 break;
4571 }
4572
4573 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4574
4575 /* Get a MF for this command.
4576 */
4577 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4578 printk("%s: no msg frames!\n",__FUNCTION__);
4579 return -1;
4580 }
4581
4582 mpi_hdr = (MPIHeader_t *) mf;
4583 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4584 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4585 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4586 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4587 sasIoUnitCntrReq->Operation = persist_opcode;
4588
4589 init_timer(&ioc->persist_timer);
4590 ioc->persist_timer.data = (unsigned long) ioc;
4591 ioc->persist_timer.function = mpt_timer_expired;
4592 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4593 ioc->persist_wait_done=0;
4594 add_timer(&ioc->persist_timer);
4595 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4596 wait_event(mpt_waitq, ioc->persist_wait_done);
4597
4598 sasIoUnitCntrReply =
4599 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4600 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4601 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4602 __FUNCTION__,
4603 sasIoUnitCntrReply->IOCStatus,
4604 sasIoUnitCntrReply->IOCLogInfo);
4605 return -1;
4606 }
4607
4608 printk("%s: success\n",__FUNCTION__);
4609 return 0;
4610}
4611
4612/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004613
4614static void
4615mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4616 MpiEventDataRaid_t * pRaidEventData)
4617{
4618 int volume;
4619 int reason;
4620 int disk;
4621 int status;
4622 int flags;
4623 int state;
4624
4625 volume = pRaidEventData->VolumeID;
4626 reason = pRaidEventData->ReasonCode;
4627 disk = pRaidEventData->PhysDiskNum;
4628 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4629 flags = (status >> 0) & 0xff;
4630 state = (status >> 8) & 0xff;
4631
4632 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4633 return;
4634 }
4635
4636 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4637 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4638 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004639 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4640 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004641 } else {
4642 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4643 ioc->name, volume);
4644 }
4645
4646 switch(reason) {
4647 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4648 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4649 ioc->name);
4650 break;
4651
4652 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4653
4654 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4655 ioc->name);
4656 break;
4657
4658 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4659 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4660 ioc->name);
4661 break;
4662
4663 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4664 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4665 ioc->name,
4666 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4667 ? "optimal"
4668 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4669 ? "degraded"
4670 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4671 ? "failed"
4672 : "state unknown",
4673 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4674 ? ", enabled" : "",
4675 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4676 ? ", quiesced" : "",
4677 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4678 ? ", resync in progress" : "" );
4679 break;
4680
4681 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4682 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4683 ioc->name, disk);
4684 break;
4685
4686 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4687 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4688 ioc->name);
4689 break;
4690
4691 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4692 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4693 ioc->name);
4694 break;
4695
4696 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4697 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4698 ioc->name);
4699 break;
4700
4701 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4702 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4703 ioc->name,
4704 state == MPI_PHYSDISK0_STATUS_ONLINE
4705 ? "online"
4706 : state == MPI_PHYSDISK0_STATUS_MISSING
4707 ? "missing"
4708 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4709 ? "not compatible"
4710 : state == MPI_PHYSDISK0_STATUS_FAILED
4711 ? "failed"
4712 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4713 ? "initializing"
4714 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4715 ? "offline requested"
4716 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4717 ? "failed requested"
4718 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4719 ? "offline"
4720 : "state unknown",
4721 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4722 ? ", out of sync" : "",
4723 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4724 ? ", quiesced" : "" );
4725 break;
4726
4727 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4728 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4729 ioc->name, disk);
4730 break;
4731
4732 case MPI_EVENT_RAID_RC_SMART_DATA:
4733 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4734 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4735 break;
4736
4737 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4738 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4739 ioc->name, disk);
4740 break;
4741 }
4742}
4743
4744/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004745/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4747 * @ioc: Pointer to MPT_ADAPTER structure
4748 *
4749 * Returns: 0 for success
4750 * -ENOMEM if no memory available
4751 * -EPERM if not allowed due to ISR context
4752 * -EAGAIN if no msg frames currently available
4753 * -EFAULT for non-successful reply or no reply (timeout)
4754 */
4755static int
4756GetIoUnitPage2(MPT_ADAPTER *ioc)
4757{
4758 ConfigPageHeader_t hdr;
4759 CONFIGPARMS cfg;
4760 IOUnitPage2_t *ppage_alloc;
4761 dma_addr_t page_dma;
4762 int data_sz;
4763 int rc;
4764
4765 /* Get the page header */
4766 hdr.PageVersion = 0;
4767 hdr.PageLength = 0;
4768 hdr.PageNumber = 2;
4769 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004770 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 cfg.physAddr = -1;
4772 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4773 cfg.dir = 0;
4774 cfg.pageAddr = 0;
4775 cfg.timeout = 0;
4776
4777 if ((rc = mpt_config(ioc, &cfg)) != 0)
4778 return rc;
4779
4780 if (hdr.PageLength == 0)
4781 return 0;
4782
4783 /* Read the config page */
4784 data_sz = hdr.PageLength * 4;
4785 rc = -ENOMEM;
4786 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4787 if (ppage_alloc) {
4788 memset((u8 *)ppage_alloc, 0, data_sz);
4789 cfg.physAddr = page_dma;
4790 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4791
4792 /* If Good, save data */
4793 if ((rc = mpt_config(ioc, &cfg)) == 0)
4794 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4795
4796 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4797 }
4798
4799 return rc;
4800}
4801
4802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004803/**
4804 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 * @ioc: Pointer to a Adapter Strucutre
4806 * @portnum: IOC port number
4807 *
4808 * Return: -EFAULT if read of config page header fails
4809 * or if no nvram
4810 * If read of SCSI Port Page 0 fails,
4811 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4812 * Adapter settings: async, narrow
4813 * Return 1
4814 * If read of SCSI Port Page 2 fails,
4815 * Adapter settings valid
4816 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4817 * Return 1
4818 * Else
4819 * Both valid
4820 * Return 0
4821 * CHECK - what type of locking mechanisms should be used????
4822 */
4823static int
4824mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4825{
4826 u8 *pbuf;
4827 dma_addr_t buf_dma;
4828 CONFIGPARMS cfg;
4829 ConfigPageHeader_t header;
4830 int ii;
4831 int data, rc = 0;
4832
4833 /* Allocate memory
4834 */
4835 if (!ioc->spi_data.nvram) {
4836 int sz;
4837 u8 *mem;
4838 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4839 mem = kmalloc(sz, GFP_ATOMIC);
4840 if (mem == NULL)
4841 return -EFAULT;
4842
4843 ioc->spi_data.nvram = (int *) mem;
4844
Prakash, Sathya436ace72007-07-24 15:42:08 +05304845 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 ioc->name, ioc->spi_data.nvram, sz));
4847 }
4848
4849 /* Invalidate NVRAM information
4850 */
4851 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4852 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4853 }
4854
4855 /* Read SPP0 header, allocate memory, then read page.
4856 */
4857 header.PageVersion = 0;
4858 header.PageLength = 0;
4859 header.PageNumber = 0;
4860 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004861 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 cfg.physAddr = -1;
4863 cfg.pageAddr = portnum;
4864 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4865 cfg.dir = 0;
4866 cfg.timeout = 0; /* use default */
4867 if (mpt_config(ioc, &cfg) != 0)
4868 return -EFAULT;
4869
4870 if (header.PageLength > 0) {
4871 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4872 if (pbuf) {
4873 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4874 cfg.physAddr = buf_dma;
4875 if (mpt_config(ioc, &cfg) != 0) {
4876 ioc->spi_data.maxBusWidth = MPT_NARROW;
4877 ioc->spi_data.maxSyncOffset = 0;
4878 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4879 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4880 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304881 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4882 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004883 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 } else {
4885 /* Save the Port Page 0 data
4886 */
4887 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4888 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4889 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4890
4891 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4892 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004893 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4894 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 ioc->name, pPP0->Capabilities));
4896 }
4897 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4898 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4899 if (data) {
4900 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4901 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4902 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304903 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4904 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004905 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 } else {
4907 ioc->spi_data.maxSyncOffset = 0;
4908 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4909 }
4910
4911 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4912
4913 /* Update the minSyncFactor based on bus type.
4914 */
4915 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4916 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4917
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004918 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304920 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4921 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004922 ioc->name, ioc->spi_data.minSyncFactor));
4923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 }
4925 }
4926 if (pbuf) {
4927 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4928 }
4929 }
4930 }
4931
4932 /* SCSI Port Page 2 - Read the header then the page.
4933 */
4934 header.PageVersion = 0;
4935 header.PageLength = 0;
4936 header.PageNumber = 2;
4937 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004938 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 cfg.physAddr = -1;
4940 cfg.pageAddr = portnum;
4941 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4942 cfg.dir = 0;
4943 if (mpt_config(ioc, &cfg) != 0)
4944 return -EFAULT;
4945
4946 if (header.PageLength > 0) {
4947 /* Allocate memory and read SCSI Port Page 2
4948 */
4949 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4950 if (pbuf) {
4951 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4952 cfg.physAddr = buf_dma;
4953 if (mpt_config(ioc, &cfg) != 0) {
4954 /* Nvram data is left with INVALID mark
4955 */
4956 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004957 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4958
4959 /* This is an ATTO adapter, read Page2 accordingly
4960 */
4961 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4962 ATTODeviceInfo_t *pdevice = NULL;
4963 u16 ATTOFlags;
4964
4965 /* Save the Port Page 2 data
4966 * (reformat into a 32bit quantity)
4967 */
4968 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4969 pdevice = &pPP2->DeviceSettings[ii];
4970 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4971 data = 0;
4972
4973 /* Translate ATTO device flags to LSI format
4974 */
4975 if (ATTOFlags & ATTOFLAG_DISC)
4976 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4977 if (ATTOFlags & ATTOFLAG_ID_ENB)
4978 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4979 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4980 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4981 if (ATTOFlags & ATTOFLAG_TAGGED)
4982 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4983 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4984 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4985
4986 data = (data << 16) | (pdevice->Period << 8) | 10;
4987 ioc->spi_data.nvram[ii] = data;
4988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 } else {
4990 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4991 MpiDeviceInfo_t *pdevice = NULL;
4992
Moore, Ericd8e925d2006-01-16 18:53:06 -07004993 /*
4994 * Save "Set to Avoid SCSI Bus Resets" flag
4995 */
4996 ioc->spi_data.bus_reset =
4997 (le32_to_cpu(pPP2->PortFlags) &
4998 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4999 0 : 1 ;
5000
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 /* Save the Port Page 2 data
5002 * (reformat into a 32bit quantity)
5003 */
5004 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5005 ioc->spi_data.PortFlags = data;
5006 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5007 pdevice = &pPP2->DeviceSettings[ii];
5008 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5009 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5010 ioc->spi_data.nvram[ii] = data;
5011 }
5012 }
5013
5014 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5015 }
5016 }
5017
5018 /* Update Adapter limits with those from NVRAM
5019 * Comment: Don't need to do this. Target performance
5020 * parameters will never exceed the adapters limits.
5021 */
5022
5023 return rc;
5024}
5025
5026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005027/**
5028 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 * @ioc: Pointer to a Adapter Strucutre
5030 * @portnum: IOC port number
5031 *
5032 * Return: -EFAULT if read of config page header fails
5033 * or 0 if success.
5034 */
5035static int
5036mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5037{
5038 CONFIGPARMS cfg;
5039 ConfigPageHeader_t header;
5040
5041 /* Read the SCSI Device Page 1 header
5042 */
5043 header.PageVersion = 0;
5044 header.PageLength = 0;
5045 header.PageNumber = 1;
5046 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005047 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 cfg.physAddr = -1;
5049 cfg.pageAddr = portnum;
5050 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5051 cfg.dir = 0;
5052 cfg.timeout = 0;
5053 if (mpt_config(ioc, &cfg) != 0)
5054 return -EFAULT;
5055
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005056 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5057 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058
5059 header.PageVersion = 0;
5060 header.PageLength = 0;
5061 header.PageNumber = 0;
5062 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5063 if (mpt_config(ioc, &cfg) != 0)
5064 return -EFAULT;
5065
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005066 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5067 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068
Prakash, Sathya436ace72007-07-24 15:42:08 +05305069 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5071
Prakash, Sathya436ace72007-07-24 15:42:08 +05305072 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5074 return 0;
5075}
5076
Eric Mooreb506ade2007-01-29 09:45:37 -07005077/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005078 * mpt_inactive_raid_list_free - This clears this link list.
5079 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005080 **/
5081static void
5082mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5083{
5084 struct inactive_raid_component_info *component_info, *pNext;
5085
5086 if (list_empty(&ioc->raid_data.inactive_list))
5087 return;
5088
5089 down(&ioc->raid_data.inactive_list_mutex);
5090 list_for_each_entry_safe(component_info, pNext,
5091 &ioc->raid_data.inactive_list, list) {
5092 list_del(&component_info->list);
5093 kfree(component_info);
5094 }
5095 up(&ioc->raid_data.inactive_list_mutex);
5096}
5097
5098/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005099 * 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 -07005100 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005101 * @ioc : pointer to per adapter structure
5102 * @channel : volume channel
5103 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005104 **/
5105static void
5106mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5107{
5108 CONFIGPARMS cfg;
5109 ConfigPageHeader_t hdr;
5110 dma_addr_t dma_handle;
5111 pRaidVolumePage0_t buffer = NULL;
5112 int i;
5113 RaidPhysDiskPage0_t phys_disk;
5114 struct inactive_raid_component_info *component_info;
5115 int handle_inactive_volumes;
5116
5117 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5118 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5119 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5120 cfg.pageAddr = (channel << 8) + id;
5121 cfg.cfghdr.hdr = &hdr;
5122 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5123
5124 if (mpt_config(ioc, &cfg) != 0)
5125 goto out;
5126
5127 if (!hdr.PageLength)
5128 goto out;
5129
5130 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5131 &dma_handle);
5132
5133 if (!buffer)
5134 goto out;
5135
5136 cfg.physAddr = dma_handle;
5137 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5138
5139 if (mpt_config(ioc, &cfg) != 0)
5140 goto out;
5141
5142 if (!buffer->NumPhysDisks)
5143 goto out;
5144
5145 handle_inactive_volumes =
5146 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5147 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5148 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5149 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5150
5151 if (!handle_inactive_volumes)
5152 goto out;
5153
5154 down(&ioc->raid_data.inactive_list_mutex);
5155 for (i = 0; i < buffer->NumPhysDisks; i++) {
5156 if(mpt_raid_phys_disk_pg0(ioc,
5157 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5158 continue;
5159
5160 if ((component_info = kmalloc(sizeof (*component_info),
5161 GFP_KERNEL)) == NULL)
5162 continue;
5163
5164 component_info->volumeID = id;
5165 component_info->volumeBus = channel;
5166 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5167 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5168 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5169 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5170
5171 list_add_tail(&component_info->list,
5172 &ioc->raid_data.inactive_list);
5173 }
5174 up(&ioc->raid_data.inactive_list_mutex);
5175
5176 out:
5177 if (buffer)
5178 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5179 dma_handle);
5180}
5181
5182/**
5183 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5184 * @ioc: Pointer to a Adapter Structure
5185 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5186 * @phys_disk: requested payload data returned
5187 *
5188 * Return:
5189 * 0 on success
5190 * -EFAULT if read of config page header fails or data pointer not NULL
5191 * -ENOMEM if pci_alloc failed
5192 **/
5193int
5194mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5195{
5196 CONFIGPARMS cfg;
5197 ConfigPageHeader_t hdr;
5198 dma_addr_t dma_handle;
5199 pRaidPhysDiskPage0_t buffer = NULL;
5200 int rc;
5201
5202 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5203 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5204
5205 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5206 cfg.cfghdr.hdr = &hdr;
5207 cfg.physAddr = -1;
5208 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5209
5210 if (mpt_config(ioc, &cfg) != 0) {
5211 rc = -EFAULT;
5212 goto out;
5213 }
5214
5215 if (!hdr.PageLength) {
5216 rc = -EFAULT;
5217 goto out;
5218 }
5219
5220 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5221 &dma_handle);
5222
5223 if (!buffer) {
5224 rc = -ENOMEM;
5225 goto out;
5226 }
5227
5228 cfg.physAddr = dma_handle;
5229 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5230 cfg.pageAddr = phys_disk_num;
5231
5232 if (mpt_config(ioc, &cfg) != 0) {
5233 rc = -EFAULT;
5234 goto out;
5235 }
5236
5237 rc = 0;
5238 memcpy(phys_disk, buffer, sizeof(*buffer));
5239 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5240
5241 out:
5242
5243 if (buffer)
5244 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5245 dma_handle);
5246
5247 return rc;
5248}
5249
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250/**
5251 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5252 * @ioc: Pointer to a Adapter Strucutre
5253 * @portnum: IOC port number
5254 *
5255 * Return:
5256 * 0 on success
5257 * -EFAULT if read of config page header fails or data pointer not NULL
5258 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005259 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260int
5261mpt_findImVolumes(MPT_ADAPTER *ioc)
5262{
5263 IOCPage2_t *pIoc2;
5264 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 dma_addr_t ioc2_dma;
5266 CONFIGPARMS cfg;
5267 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 int rc = 0;
5269 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005270 int i;
5271
5272 if (!ioc->ir_firmware)
5273 return 0;
5274
5275 /* Free the old page
5276 */
5277 kfree(ioc->raid_data.pIocPg2);
5278 ioc->raid_data.pIocPg2 = NULL;
5279 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280
5281 /* Read IOCP2 header then the page.
5282 */
5283 header.PageVersion = 0;
5284 header.PageLength = 0;
5285 header.PageNumber = 2;
5286 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005287 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 cfg.physAddr = -1;
5289 cfg.pageAddr = 0;
5290 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5291 cfg.dir = 0;
5292 cfg.timeout = 0;
5293 if (mpt_config(ioc, &cfg) != 0)
5294 return -EFAULT;
5295
5296 if (header.PageLength == 0)
5297 return -EFAULT;
5298
5299 iocpage2sz = header.PageLength * 4;
5300 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5301 if (!pIoc2)
5302 return -ENOMEM;
5303
5304 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5305 cfg.physAddr = ioc2_dma;
5306 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005307 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
Eric Mooreb506ade2007-01-29 09:45:37 -07005309 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5310 if (!mem)
5311 goto out;
5312
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005314 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
Eric Mooreb506ade2007-01-29 09:45:37 -07005316 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317
Eric Mooreb506ade2007-01-29 09:45:37 -07005318 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5319 mpt_inactive_raid_volumes(ioc,
5320 pIoc2->RaidVolume[i].VolumeBus,
5321 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Eric Mooreb506ade2007-01-29 09:45:37 -07005323 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5325
5326 return rc;
5327}
5328
Moore, Ericc972c702006-03-14 09:14:06 -07005329static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5331{
5332 IOCPage3_t *pIoc3;
5333 u8 *mem;
5334 CONFIGPARMS cfg;
5335 ConfigPageHeader_t header;
5336 dma_addr_t ioc3_dma;
5337 int iocpage3sz = 0;
5338
5339 /* Free the old page
5340 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005341 kfree(ioc->raid_data.pIocPg3);
5342 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
5344 /* There is at least one physical disk.
5345 * Read and save IOC Page 3
5346 */
5347 header.PageVersion = 0;
5348 header.PageLength = 0;
5349 header.PageNumber = 3;
5350 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005351 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 cfg.physAddr = -1;
5353 cfg.pageAddr = 0;
5354 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5355 cfg.dir = 0;
5356 cfg.timeout = 0;
5357 if (mpt_config(ioc, &cfg) != 0)
5358 return 0;
5359
5360 if (header.PageLength == 0)
5361 return 0;
5362
5363 /* Read Header good, alloc memory
5364 */
5365 iocpage3sz = header.PageLength * 4;
5366 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5367 if (!pIoc3)
5368 return 0;
5369
5370 /* Read the Page and save the data
5371 * into malloc'd memory.
5372 */
5373 cfg.physAddr = ioc3_dma;
5374 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5375 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005376 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 if (mem) {
5378 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005379 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 }
5381 }
5382
5383 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5384
5385 return 0;
5386}
5387
5388static void
5389mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5390{
5391 IOCPage4_t *pIoc4;
5392 CONFIGPARMS cfg;
5393 ConfigPageHeader_t header;
5394 dma_addr_t ioc4_dma;
5395 int iocpage4sz;
5396
5397 /* Read and save IOC Page 4
5398 */
5399 header.PageVersion = 0;
5400 header.PageLength = 0;
5401 header.PageNumber = 4;
5402 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005403 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 cfg.physAddr = -1;
5405 cfg.pageAddr = 0;
5406 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5407 cfg.dir = 0;
5408 cfg.timeout = 0;
5409 if (mpt_config(ioc, &cfg) != 0)
5410 return;
5411
5412 if (header.PageLength == 0)
5413 return;
5414
5415 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5416 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5417 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5418 if (!pIoc4)
5419 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005420 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 } else {
5422 ioc4_dma = ioc->spi_data.IocPg4_dma;
5423 iocpage4sz = ioc->spi_data.IocPg4Sz;
5424 }
5425
5426 /* Read the Page into dma memory.
5427 */
5428 cfg.physAddr = ioc4_dma;
5429 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5430 if (mpt_config(ioc, &cfg) == 0) {
5431 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5432 ioc->spi_data.IocPg4_dma = ioc4_dma;
5433 ioc->spi_data.IocPg4Sz = iocpage4sz;
5434 } else {
5435 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5436 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005437 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 }
5439}
5440
5441static void
5442mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5443{
5444 IOCPage1_t *pIoc1;
5445 CONFIGPARMS cfg;
5446 ConfigPageHeader_t header;
5447 dma_addr_t ioc1_dma;
5448 int iocpage1sz = 0;
5449 u32 tmp;
5450
5451 /* Check the Coalescing Timeout in IOC Page 1
5452 */
5453 header.PageVersion = 0;
5454 header.PageLength = 0;
5455 header.PageNumber = 1;
5456 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005457 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 cfg.physAddr = -1;
5459 cfg.pageAddr = 0;
5460 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5461 cfg.dir = 0;
5462 cfg.timeout = 0;
5463 if (mpt_config(ioc, &cfg) != 0)
5464 return;
5465
5466 if (header.PageLength == 0)
5467 return;
5468
5469 /* Read Header good, alloc memory
5470 */
5471 iocpage1sz = header.PageLength * 4;
5472 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5473 if (!pIoc1)
5474 return;
5475
5476 /* Read the Page and check coalescing timeout
5477 */
5478 cfg.physAddr = ioc1_dma;
5479 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5480 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305481
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5483 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5484 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5485
Prakash, Sathya436ace72007-07-24 15:42:08 +05305486 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 ioc->name, tmp));
5488
5489 if (tmp > MPT_COALESCING_TIMEOUT) {
5490 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5491
5492 /* Write NVRAM and current
5493 */
5494 cfg.dir = 1;
5495 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5496 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305497 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 ioc->name, MPT_COALESCING_TIMEOUT));
5499
5500 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5501 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305502 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5503 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 ioc->name, MPT_COALESCING_TIMEOUT));
5505 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305506 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5507 "Reset NVRAM Coalescing Timeout Failed\n",
5508 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 }
5510
5511 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305512 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5513 "Reset of Current Coalescing Timeout Failed!\n",
5514 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 }
5516 }
5517
5518 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305519 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 }
5521 }
5522
5523 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5524
5525 return;
5526}
5527
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305528static void
5529mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5530{
5531 CONFIGPARMS cfg;
5532 ConfigPageHeader_t hdr;
5533 dma_addr_t buf_dma;
5534 ManufacturingPage0_t *pbuf = NULL;
5535
5536 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5537 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5538
5539 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5540 cfg.cfghdr.hdr = &hdr;
5541 cfg.physAddr = -1;
5542 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5543 cfg.timeout = 10;
5544
5545 if (mpt_config(ioc, &cfg) != 0)
5546 goto out;
5547
5548 if (!cfg.cfghdr.hdr->PageLength)
5549 goto out;
5550
5551 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5552 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5553 if (!pbuf)
5554 goto out;
5555
5556 cfg.physAddr = buf_dma;
5557
5558 if (mpt_config(ioc, &cfg) != 0)
5559 goto out;
5560
5561 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5562 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5563 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5564
5565 out:
5566
5567 if (pbuf)
5568 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5569}
5570
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005572/**
5573 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 * @ioc: Pointer to MPT_ADAPTER structure
5575 * @EvSwitch: Event switch flags
5576 */
5577static int
5578SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5579{
5580 EventNotification_t *evnp;
5581
5582 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5583 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305584 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 ioc->name));
5586 return 0;
5587 }
5588 memset(evnp, 0, sizeof(*evnp));
5589
Prakash, Sathya436ace72007-07-24 15:42:08 +05305590 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591
5592 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5593 evnp->ChainOffset = 0;
5594 evnp->MsgFlags = 0;
5595 evnp->Switch = EvSwitch;
5596
5597 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5598
5599 return 0;
5600}
5601
5602/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5603/**
5604 * SendEventAck - Send EventAck request to MPT adapter.
5605 * @ioc: Pointer to MPT_ADAPTER structure
5606 * @evnp: Pointer to original EventNotification request
5607 */
5608static int
5609SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5610{
5611 EventAck_t *pAck;
5612
5613 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305614 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005615 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 return -1;
5617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
Prakash, Sathya436ace72007-07-24 15:42:08 +05305619 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620
5621 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5622 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005623 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005625 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 pAck->Event = evnp->Event;
5627 pAck->EventContext = evnp->EventContext;
5628
5629 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5630
5631 return 0;
5632}
5633
5634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5635/**
5636 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005637 * @ioc: Pointer to an adapter structure
5638 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 * action, page address, direction, physical address
5640 * and pointer to a configuration page header
5641 * Page header is updated.
5642 *
5643 * Returns 0 for success
5644 * -EPERM if not allowed due to ISR context
5645 * -EAGAIN if no msg frames currently available
5646 * -EFAULT for non-successful reply or no reply (timeout)
5647 */
5648int
5649mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5650{
5651 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005652 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 MPT_FRAME_HDR *mf;
5654 unsigned long flags;
5655 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005656 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 int in_isr;
5658
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005659 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 * to be in ISR context, because that is fatal!
5661 */
5662 in_isr = in_interrupt();
5663 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305664 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 ioc->name));
5666 return -EPERM;
5667 }
5668
5669 /* Get and Populate a free Frame
5670 */
5671 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305672 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 ioc->name));
5674 return -EAGAIN;
5675 }
5676 pReq = (Config_t *)mf;
5677 pReq->Action = pCfg->action;
5678 pReq->Reserved = 0;
5679 pReq->ChainOffset = 0;
5680 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005681
5682 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 pReq->ExtPageLength = 0;
5684 pReq->ExtPageType = 0;
5685 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005686
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 for (ii=0; ii < 8; ii++)
5688 pReq->Reserved2[ii] = 0;
5689
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005690 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5691 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5692 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5693 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5694
5695 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5696 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5697 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5698 pReq->ExtPageType = pExtHdr->ExtPageType;
5699 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5700
5701 /* Page Length must be treated as a reserved field for the extended header. */
5702 pReq->Header.PageLength = 0;
5703 }
5704
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5706
5707 /* Add a SGE to the config request.
5708 */
5709 if (pCfg->dir)
5710 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5711 else
5712 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5713
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005714 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5715 flagsLength |= pExtHdr->ExtPageLength * 4;
5716
Prakash, Sathya436ace72007-07-24 15:42:08 +05305717 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 +02005718 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5719 }
5720 else {
5721 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5722
Prakash, Sathya436ace72007-07-24 15:42:08 +05305723 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 +02005724 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
5727 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5728
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 /* Append pCfg pointer to end of mf
5730 */
5731 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5732
5733 /* Initalize the timer
5734 */
5735 init_timer(&pCfg->timer);
5736 pCfg->timer.data = (unsigned long) ioc;
5737 pCfg->timer.function = mpt_timer_expired;
5738 pCfg->wait_done = 0;
5739
5740 /* Set the timer; ensure 10 second minimum */
5741 if (pCfg->timeout < 10)
5742 pCfg->timer.expires = jiffies + HZ*10;
5743 else
5744 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5745
5746 /* Add to end of Q, set timer and then issue this command */
5747 spin_lock_irqsave(&ioc->FreeQlock, flags);
5748 list_add_tail(&pCfg->linkage, &ioc->configQ);
5749 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5750
5751 add_timer(&pCfg->timer);
5752 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5753 wait_event(mpt_waitq, pCfg->wait_done);
5754
5755 /* mf has been freed - do not access */
5756
5757 rc = pCfg->status;
5758
5759 return rc;
5760}
5761
5762/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005763/**
5764 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 * Used only internal config functionality.
5766 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5767 */
5768static void
5769mpt_timer_expired(unsigned long data)
5770{
5771 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5772
Prakash, Sathya436ace72007-07-24 15:42:08 +05305773 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
5775 /* Perform a FW reload */
5776 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5777 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5778
5779 /* No more processing.
5780 * Hard reset clean-up will wake up
5781 * process and free all resources.
5782 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305783 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
5785 return;
5786}
5787
5788/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005789/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 * mpt_ioc_reset - Base cleanup for hard reset
5791 * @ioc: Pointer to the adapter structure
5792 * @reset_phase: Indicates pre- or post-reset functionality
5793 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005794 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 */
5796static int
5797mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5798{
5799 CONFIGPARMS *pCfg;
5800 unsigned long flags;
5801
Eric Moore29dd3602007-09-14 18:46:51 -06005802 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5803 ": IOC %s_reset routed to MPT base driver!\n",
5804 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5805 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
5807 if (reset_phase == MPT_IOC_SETUP_RESET) {
5808 ;
5809 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5810 /* If the internal config Q is not empty -
5811 * delete timer. MF resources will be freed when
5812 * the FIFO's are primed.
5813 */
5814 spin_lock_irqsave(&ioc->FreeQlock, flags);
5815 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5816 del_timer(&pCfg->timer);
5817 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5818
5819 } else {
5820 CONFIGPARMS *pNext;
5821
5822 /* Search the configQ for internal commands.
5823 * Flush the Q, and wake up all suspended threads.
5824 */
5825 spin_lock_irqsave(&ioc->FreeQlock, flags);
5826 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5827 list_del(&pCfg->linkage);
5828
5829 pCfg->status = MPT_CONFIG_ERROR;
5830 pCfg->wait_done = 1;
5831 wake_up(&mpt_waitq);
5832 }
5833 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5834 }
5835
5836 return 1; /* currently means nothing really */
5837}
5838
5839
5840#ifdef CONFIG_PROC_FS /* { */
5841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5842/*
5843 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5844 */
5845/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005846/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5848 *
5849 * Returns 0 for success, non-zero for failure.
5850 */
5851static int
5852procmpt_create(void)
5853{
5854 struct proc_dir_entry *ent;
5855
5856 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5857 if (mpt_proc_root_dir == NULL)
5858 return -ENOTDIR;
5859
5860 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5861 if (ent)
5862 ent->read_proc = procmpt_summary_read;
5863
5864 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5865 if (ent)
5866 ent->read_proc = procmpt_version_read;
5867
5868 return 0;
5869}
5870
5871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005872/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5874 *
5875 * Returns 0 for success, non-zero for failure.
5876 */
5877static void
5878procmpt_destroy(void)
5879{
5880 remove_proc_entry("version", mpt_proc_root_dir);
5881 remove_proc_entry("summary", mpt_proc_root_dir);
5882 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5883}
5884
5885/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005886/**
5887 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 * @buf: Pointer to area to write information
5889 * @start: Pointer to start pointer
5890 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005891 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 * @eof: Pointer to EOF integer
5893 * @data: Pointer
5894 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005895 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 * Returns number of characters written to process performing the read.
5897 */
5898static int
5899procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5900{
5901 MPT_ADAPTER *ioc;
5902 char *out = buf;
5903 int len;
5904
5905 if (data) {
5906 int more = 0;
5907
5908 ioc = data;
5909 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5910
5911 out += more;
5912 } else {
5913 list_for_each_entry(ioc, &ioc_list, list) {
5914 int more = 0;
5915
5916 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5917
5918 out += more;
5919 if ((out-buf) >= request)
5920 break;
5921 }
5922 }
5923
5924 len = out - buf;
5925
5926 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5927}
5928
5929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005930/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 * procmpt_version_read - Handle read request from /proc/mpt/version.
5932 * @buf: Pointer to area to write information
5933 * @start: Pointer to start pointer
5934 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005935 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 * @eof: Pointer to EOF integer
5937 * @data: Pointer
5938 *
5939 * Returns number of characters written to process performing the read.
5940 */
5941static int
5942procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5943{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305944 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005945 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 char *drvname;
5947 int len;
5948
5949 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5950 len += sprintf(buf+len, " Fusion MPT base driver\n");
5951
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005952 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06005953 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305955 if (MptCallbacks[cb_idx]) {
5956 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005957 case MPTSPI_DRIVER:
5958 if (!scsi++) drvname = "SPI host";
5959 break;
5960 case MPTFC_DRIVER:
5961 if (!fc++) drvname = "FC host";
5962 break;
5963 case MPTSAS_DRIVER:
5964 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 break;
5966 case MPTLAN_DRIVER:
5967 if (!lan++) drvname = "LAN";
5968 break;
5969 case MPTSTM_DRIVER:
5970 if (!targ++) drvname = "SCSI target";
5971 break;
5972 case MPTCTL_DRIVER:
5973 if (!ctl++) drvname = "ioctl";
5974 break;
5975 }
5976
5977 if (drvname)
5978 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5979 }
5980 }
5981
5982 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5983}
5984
5985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005986/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5988 * @buf: Pointer to area to write information
5989 * @start: Pointer to start pointer
5990 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005991 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 * @eof: Pointer to EOF integer
5993 * @data: Pointer
5994 *
5995 * Returns number of characters written to process performing the read.
5996 */
5997static int
5998procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5999{
6000 MPT_ADAPTER *ioc = data;
6001 int len;
6002 char expVer[32];
6003 int sz;
6004 int p;
6005
6006 mpt_get_fw_exp_ver(expVer, ioc);
6007
6008 len = sprintf(buf, "%s:", ioc->name);
6009 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6010 len += sprintf(buf+len, " (f/w download boot flag set)");
6011// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6012// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6013
6014 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6015 ioc->facts.ProductID,
6016 ioc->prod_name);
6017 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6018 if (ioc->facts.FWImageSize)
6019 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6020 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6021 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6022 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6023
6024 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6025 ioc->facts.CurrentHostMfaHighAddr);
6026 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6027 ioc->facts.CurrentSenseBufferHighAddr);
6028
6029 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6030 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6031
6032 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6033 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6034 /*
6035 * Rounding UP to nearest 4-kB boundary here...
6036 */
6037 sz = (ioc->req_sz * ioc->req_depth) + 128;
6038 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6039 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6040 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6041 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6042 4*ioc->facts.RequestFrameSize,
6043 ioc->facts.GlobalCredits);
6044
6045 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6046 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6047 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6048 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6049 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6050 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6051 ioc->facts.CurReplyFrameSize,
6052 ioc->facts.ReplyQueueDepth);
6053
6054 len += sprintf(buf+len, " MaxDevices = %d\n",
6055 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6056 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6057
6058 /* per-port info */
6059 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6060 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6061 p+1,
6062 ioc->facts.NumberOfPorts);
6063 if (ioc->bus_type == FC) {
6064 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6065 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6066 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6067 a[5], a[4], a[3], a[2], a[1], a[0]);
6068 }
6069 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6070 ioc->fc_port_page0[p].WWNN.High,
6071 ioc->fc_port_page0[p].WWNN.Low,
6072 ioc->fc_port_page0[p].WWPN.High,
6073 ioc->fc_port_page0[p].WWPN.Low);
6074 }
6075 }
6076
6077 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6078}
6079
6080#endif /* CONFIG_PROC_FS } */
6081
6082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6083static void
6084mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6085{
6086 buf[0] ='\0';
6087 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6088 sprintf(buf, " (Exp %02d%02d)",
6089 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6090 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6091
6092 /* insider hack! */
6093 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6094 strcat(buf, " [MDBG]");
6095 }
6096}
6097
6098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6099/**
6100 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6101 * @ioc: Pointer to MPT_ADAPTER structure
6102 * @buffer: Pointer to buffer where IOC summary info should be written
6103 * @size: Pointer to number of bytes we wrote (set by this routine)
6104 * @len: Offset at which to start writing in buffer
6105 * @showlan: Display LAN stuff?
6106 *
6107 * This routine writes (english readable) ASCII text, which represents
6108 * a summary of IOC information, to a buffer.
6109 */
6110void
6111mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6112{
6113 char expVer[32];
6114 int y;
6115
6116 mpt_get_fw_exp_ver(expVer, ioc);
6117
6118 /*
6119 * Shorter summary of attached ioc's...
6120 */
6121 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6122 ioc->name,
6123 ioc->prod_name,
6124 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6125 ioc->facts.FWVersion.Word,
6126 expVer,
6127 ioc->facts.NumberOfPorts,
6128 ioc->req_depth);
6129
6130 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6131 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6132 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6133 a[5], a[4], a[3], a[2], a[1], a[0]);
6134 }
6135
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137
6138 if (!ioc->active)
6139 y += sprintf(buffer+len+y, " (disabled)");
6140
6141 y += sprintf(buffer+len+y, "\n");
6142
6143 *size = y;
6144}
6145
6146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6147/*
6148 * Reset Handling
6149 */
6150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6151/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006152 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 * @ioc: Pointer to MPT_ADAPTER structure
6154 * @sleepFlag: Indicates if sleep or schedule must be called.
6155 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006156 * Issues SCSI Task Management call based on input arg values.
6157 * If TaskMgmt fails, returns associated SCSI request.
6158 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6160 * or a non-interrupt thread. In the former, must not call schedule().
6161 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006162 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 * FW reload/initialization failed.
6164 *
6165 * Returns 0 for SUCCESS or -1 if FAILED.
6166 */
6167int
6168mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6169{
6170 int rc;
6171 unsigned long flags;
6172
Prakash, Sathya436ace72007-07-24 15:42:08 +05306173 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174#ifdef MFCNT
6175 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6176 printk("MF count 0x%x !\n", ioc->mfcnt);
6177#endif
6178
6179 /* Reset the adapter. Prevent more than 1 call to
6180 * mpt_do_ioc_recovery at any instant in time.
6181 */
6182 spin_lock_irqsave(&ioc->diagLock, flags);
6183 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6184 spin_unlock_irqrestore(&ioc->diagLock, flags);
6185 return 0;
6186 } else {
6187 ioc->diagPending = 1;
6188 }
6189 spin_unlock_irqrestore(&ioc->diagLock, flags);
6190
6191 /* FIXME: If do_ioc_recovery fails, repeat....
6192 */
6193
6194 /* The SCSI driver needs to adjust timeouts on all current
6195 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006196 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 * For all other protocol drivers, this is a no-op.
6198 */
6199 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306200 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 int r = 0;
6202
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306203 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6204 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306205 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306206 ioc->name, cb_idx));
6207 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306209 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306210 ioc->name, ioc->alt_ioc->name, cb_idx));
6211 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 }
6213 }
6214 }
6215 }
6216
6217 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006218 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 }
6220 ioc->reload_fw = 0;
6221 if (ioc->alt_ioc)
6222 ioc->alt_ioc->reload_fw = 0;
6223
6224 spin_lock_irqsave(&ioc->diagLock, flags);
6225 ioc->diagPending = 0;
6226 if (ioc->alt_ioc)
6227 ioc->alt_ioc->diagPending = 0;
6228 spin_unlock_irqrestore(&ioc->diagLock, flags);
6229
Prakash, Sathya436ace72007-07-24 15:42:08 +05306230 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
6232 return rc;
6233}
6234
6235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006236static void
6237EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238{
Eric Moore509e5e52006-04-26 13:22:37 -06006239 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240
6241 switch(event) {
6242 case MPI_EVENT_NONE:
6243 ds = "None";
6244 break;
6245 case MPI_EVENT_LOG_DATA:
6246 ds = "Log Data";
6247 break;
6248 case MPI_EVENT_STATE_CHANGE:
6249 ds = "State Change";
6250 break;
6251 case MPI_EVENT_UNIT_ATTENTION:
6252 ds = "Unit Attention";
6253 break;
6254 case MPI_EVENT_IOC_BUS_RESET:
6255 ds = "IOC Bus Reset";
6256 break;
6257 case MPI_EVENT_EXT_BUS_RESET:
6258 ds = "External Bus Reset";
6259 break;
6260 case MPI_EVENT_RESCAN:
6261 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 break;
6263 case MPI_EVENT_LINK_STATUS_CHANGE:
6264 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6265 ds = "Link Status(FAILURE) Change";
6266 else
6267 ds = "Link Status(ACTIVE) Change";
6268 break;
6269 case MPI_EVENT_LOOP_STATE_CHANGE:
6270 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6271 ds = "Loop State(LIP) Change";
6272 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006273 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 else
Eric Moore509e5e52006-04-26 13:22:37 -06006275 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 break;
6277 case MPI_EVENT_LOGOUT:
6278 ds = "Logout";
6279 break;
6280 case MPI_EVENT_EVENT_CHANGE:
6281 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006282 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006284 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 break;
6286 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006287 {
6288 u8 ReasonCode = (u8)(evData0 >> 16);
6289 switch (ReasonCode) {
6290 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6291 ds = "Integrated Raid: Volume Created";
6292 break;
6293 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6294 ds = "Integrated Raid: Volume Deleted";
6295 break;
6296 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6297 ds = "Integrated Raid: Volume Settings Changed";
6298 break;
6299 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6300 ds = "Integrated Raid: Volume Status Changed";
6301 break;
6302 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6303 ds = "Integrated Raid: Volume Physdisk Changed";
6304 break;
6305 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6306 ds = "Integrated Raid: Physdisk Created";
6307 break;
6308 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6309 ds = "Integrated Raid: Physdisk Deleted";
6310 break;
6311 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6312 ds = "Integrated Raid: Physdisk Settings Changed";
6313 break;
6314 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6315 ds = "Integrated Raid: Physdisk Status Changed";
6316 break;
6317 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6318 ds = "Integrated Raid: Domain Validation Needed";
6319 break;
6320 case MPI_EVENT_RAID_RC_SMART_DATA :
6321 ds = "Integrated Raid; Smart Data";
6322 break;
6323 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6324 ds = "Integrated Raid: Replace Action Started";
6325 break;
6326 default:
6327 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006329 }
6330 break;
6331 }
6332 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6333 ds = "SCSI Device Status Change";
6334 break;
6335 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6336 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006337 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006338 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006339 u8 ReasonCode = (u8)(evData0 >> 16);
6340 switch (ReasonCode) {
6341 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006342 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006343 "SAS Device Status Change: Added: "
6344 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006345 break;
6346 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006347 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006348 "SAS Device Status Change: Deleted: "
6349 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006350 break;
6351 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006352 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006353 "SAS Device Status Change: SMART Data: "
6354 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006355 break;
6356 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006357 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006358 "SAS Device Status Change: No Persistancy: "
6359 "id=%d channel=%d", id, channel);
6360 break;
6361 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6362 snprintf(evStr, EVENT_DESCR_STR_SZ,
6363 "SAS Device Status Change: Unsupported Device "
6364 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006365 break;
6366 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6367 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006368 "SAS Device Status Change: Internal Device "
6369 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006370 break;
6371 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6372 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006373 "SAS Device Status Change: Internal Task "
6374 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006375 break;
6376 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6377 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006378 "SAS Device Status Change: Internal Abort "
6379 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006380 break;
6381 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6382 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006383 "SAS Device Status Change: Internal Clear "
6384 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006385 break;
6386 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6387 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006388 "SAS Device Status Change: Internal Query "
6389 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006390 break;
6391 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006392 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006393 "SAS Device Status Change: Unknown: "
6394 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006395 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006396 }
6397 break;
6398 }
6399 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6400 ds = "Bus Timer Expired";
6401 break;
6402 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006403 {
6404 u16 curr_depth = (u16)(evData0 >> 16);
6405 u8 channel = (u8)(evData0 >> 8);
6406 u8 id = (u8)(evData0);
6407
6408 snprintf(evStr, EVENT_DESCR_STR_SZ,
6409 "Queue Full: channel=%d id=%d depth=%d",
6410 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006411 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006412 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006413 case MPI_EVENT_SAS_SES:
6414 ds = "SAS SES Event";
6415 break;
6416 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6417 ds = "Persistent Table Full";
6418 break;
6419 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006420 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006421 u8 LinkRates = (u8)(evData0 >> 8);
6422 u8 PhyNumber = (u8)(evData0);
6423 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6424 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6425 switch (LinkRates) {
6426 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006427 snprintf(evStr, EVENT_DESCR_STR_SZ,
6428 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006429 " Rate Unknown",PhyNumber);
6430 break;
6431 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006432 snprintf(evStr, EVENT_DESCR_STR_SZ,
6433 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006434 " Phy Disabled",PhyNumber);
6435 break;
6436 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006437 snprintf(evStr, EVENT_DESCR_STR_SZ,
6438 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006439 " Failed Speed Nego",PhyNumber);
6440 break;
6441 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006442 snprintf(evStr, EVENT_DESCR_STR_SZ,
6443 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006444 " Sata OOB Completed",PhyNumber);
6445 break;
6446 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006447 snprintf(evStr, EVENT_DESCR_STR_SZ,
6448 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006449 " Rate 1.5 Gbps",PhyNumber);
6450 break;
6451 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006452 snprintf(evStr, EVENT_DESCR_STR_SZ,
6453 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006454 " Rate 3.0 Gpbs",PhyNumber);
6455 break;
6456 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006457 snprintf(evStr, EVENT_DESCR_STR_SZ,
6458 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006459 break;
6460 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006461 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006462 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006463 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6464 ds = "SAS Discovery Error";
6465 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006466 case MPI_EVENT_IR_RESYNC_UPDATE:
6467 {
6468 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006469 snprintf(evStr, EVENT_DESCR_STR_SZ,
6470 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006471 break;
6472 }
6473 case MPI_EVENT_IR2:
6474 {
6475 u8 ReasonCode = (u8)(evData0 >> 16);
6476 switch (ReasonCode) {
6477 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6478 ds = "IR2: LD State Changed";
6479 break;
6480 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6481 ds = "IR2: PD State Changed";
6482 break;
6483 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6484 ds = "IR2: Bad Block Table Full";
6485 break;
6486 case MPI_EVENT_IR2_RC_PD_INSERTED:
6487 ds = "IR2: PD Inserted";
6488 break;
6489 case MPI_EVENT_IR2_RC_PD_REMOVED:
6490 ds = "IR2: PD Removed";
6491 break;
6492 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6493 ds = "IR2: Foreign CFG Detected";
6494 break;
6495 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6496 ds = "IR2: Rebuild Medium Error";
6497 break;
6498 default:
6499 ds = "IR2";
6500 break;
6501 }
6502 break;
6503 }
6504 case MPI_EVENT_SAS_DISCOVERY:
6505 {
6506 if (evData0)
6507 ds = "SAS Discovery: Start";
6508 else
6509 ds = "SAS Discovery: Stop";
6510 break;
6511 }
6512 case MPI_EVENT_LOG_ENTRY_ADDED:
6513 ds = "SAS Log Entry Added";
6514 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006515
Eric Moorec6c727a2007-01-29 09:44:54 -07006516 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6517 {
6518 u8 phy_num = (u8)(evData0);
6519 u8 port_num = (u8)(evData0 >> 8);
6520 u8 port_width = (u8)(evData0 >> 16);
6521 u8 primative = (u8)(evData0 >> 24);
6522 snprintf(evStr, EVENT_DESCR_STR_SZ,
6523 "SAS Broadcase Primative: phy=%d port=%d "
6524 "width=%d primative=0x%02x",
6525 phy_num, port_num, port_width, primative);
6526 break;
6527 }
6528
6529 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6530 {
6531 u8 reason = (u8)(evData0);
6532 u8 port_num = (u8)(evData0 >> 8);
6533 u16 handle = le16_to_cpu(evData0 >> 16);
6534
6535 snprintf(evStr, EVENT_DESCR_STR_SZ,
6536 "SAS Initiator Device Status Change: reason=0x%02x "
6537 "port=%d handle=0x%04x",
6538 reason, port_num, handle);
6539 break;
6540 }
6541
6542 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6543 {
6544 u8 max_init = (u8)(evData0);
6545 u8 current_init = (u8)(evData0 >> 8);
6546
6547 snprintf(evStr, EVENT_DESCR_STR_SZ,
6548 "SAS Initiator Device Table Overflow: max initiators=%02d "
6549 "current initators=%02d",
6550 max_init, current_init);
6551 break;
6552 }
6553 case MPI_EVENT_SAS_SMP_ERROR:
6554 {
6555 u8 status = (u8)(evData0);
6556 u8 port_num = (u8)(evData0 >> 8);
6557 u8 result = (u8)(evData0 >> 16);
6558
6559 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6560 snprintf(evStr, EVENT_DESCR_STR_SZ,
6561 "SAS SMP Error: port=%d result=0x%02x",
6562 port_num, result);
6563 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6564 snprintf(evStr, EVENT_DESCR_STR_SZ,
6565 "SAS SMP Error: port=%d : CRC Error",
6566 port_num);
6567 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6568 snprintf(evStr, EVENT_DESCR_STR_SZ,
6569 "SAS SMP Error: port=%d : Timeout",
6570 port_num);
6571 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6572 snprintf(evStr, EVENT_DESCR_STR_SZ,
6573 "SAS SMP Error: port=%d : No Destination",
6574 port_num);
6575 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6576 snprintf(evStr, EVENT_DESCR_STR_SZ,
6577 "SAS SMP Error: port=%d : Bad Destination",
6578 port_num);
6579 else
6580 snprintf(evStr, EVENT_DESCR_STR_SZ,
6581 "SAS SMP Error: port=%d : status=0x%02x",
6582 port_num, status);
6583 break;
6584 }
6585
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586 /*
6587 * MPT base "custom" events may be added here...
6588 */
6589 default:
6590 ds = "Unknown";
6591 break;
6592 }
Eric Moore509e5e52006-04-26 13:22:37 -06006593 if (ds)
6594 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595}
6596
6597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006598/**
6599 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600 * @ioc: Pointer to MPT_ADAPTER structure
6601 * @pEventReply: Pointer to EventNotification reply frame
6602 * @evHandlers: Pointer to integer, number of event handlers
6603 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006604 * Routes a received EventNotificationReply to all currently registered
6605 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 * Returns sum of event handlers return values.
6607 */
6608static int
6609ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6610{
6611 u16 evDataLen;
6612 u32 evData0 = 0;
6613// u32 evCtx;
6614 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306615 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 int r = 0;
6617 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006618 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619 u8 event;
6620
6621 /*
6622 * Do platform normalization of values
6623 */
6624 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6625// evCtx = le32_to_cpu(pEventReply->EventContext);
6626 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6627 if (evDataLen) {
6628 evData0 = le32_to_cpu(pEventReply->Data[0]);
6629 }
6630
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006631 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306632 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006634 event,
6635 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636
Prakash, Sathya436ace72007-07-24 15:42:08 +05306637#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006638 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6639 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306641 devtverboseprintk(ioc, printk(" %08x",
6642 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006643 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644#endif
6645
6646 /*
6647 * Do general / base driver event processing
6648 */
6649 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006650 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6651 if (evDataLen) {
6652 u8 evState = evData0 & 0xFF;
6653
6654 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6655
6656 /* Update EventState field in cached IocFacts */
6657 if (ioc->facts.Function) {
6658 ioc->facts.EventState = evState;
6659 }
6660 }
6661 break;
Moore, Ericece50912006-01-16 18:53:19 -07006662 case MPI_EVENT_INTEGRATED_RAID:
6663 mptbase_raid_process_event_data(ioc,
6664 (MpiEventDataRaid_t *)pEventReply->Data);
6665 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006666 default:
6667 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668 }
6669
6670 /*
6671 * Should this event be logged? Events are written sequentially.
6672 * When buffer is full, start again at the top.
6673 */
6674 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6675 int idx;
6676
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006677 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678
6679 ioc->events[idx].event = event;
6680 ioc->events[idx].eventContext = ioc->eventContext;
6681
6682 for (ii = 0; ii < 2; ii++) {
6683 if (ii < evDataLen)
6684 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6685 else
6686 ioc->events[idx].data[ii] = 0;
6687 }
6688
6689 ioc->eventContext++;
6690 }
6691
6692
6693 /*
6694 * Call each currently registered protocol event handler.
6695 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006696 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306697 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306698 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306699 ioc->name, cb_idx));
6700 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 handlers++;
6702 }
6703 }
6704 /* FIXME? Examine results here? */
6705
6706 /*
6707 * If needed, send (a single) EventAck.
6708 */
6709 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306710 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006711 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306713 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714 ioc->name, ii));
6715 }
6716 }
6717
6718 *evHandlers = handlers;
6719 return r;
6720}
6721
6722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006723/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6725 * @ioc: Pointer to MPT_ADAPTER structure
6726 * @log_info: U32 LogInfo reply word from the IOC
6727 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006728 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729 */
6730static void
6731mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6732{
Eric Moore7c431e52007-06-13 16:34:36 -06006733 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734
Eric Moore7c431e52007-06-13 16:34:36 -06006735 switch (log_info & 0xFF000000) {
6736 case MPI_IOCLOGINFO_FC_INIT_BASE:
6737 desc = "FCP Initiator";
6738 break;
6739 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6740 desc = "FCP Target";
6741 break;
6742 case MPI_IOCLOGINFO_FC_LAN_BASE:
6743 desc = "LAN";
6744 break;
6745 case MPI_IOCLOGINFO_FC_MSG_BASE:
6746 desc = "MPI Message Layer";
6747 break;
6748 case MPI_IOCLOGINFO_FC_LINK_BASE:
6749 desc = "FC Link";
6750 break;
6751 case MPI_IOCLOGINFO_FC_CTX_BASE:
6752 desc = "Context Manager";
6753 break;
6754 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6755 desc = "Invalid Field Offset";
6756 break;
6757 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6758 desc = "State Change Info";
6759 break;
6760 }
6761
6762 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6763 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764}
6765
6766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006767/**
Moore, Eric335a9412006-01-17 17:06:23 -07006768 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769 * @ioc: Pointer to MPT_ADAPTER structure
6770 * @mr: Pointer to MPT reply frame
6771 * @log_info: U32 LogInfo word from the IOC
6772 *
6773 * Refer to lsi/sp_log.h.
6774 */
6775static void
Moore, Eric335a9412006-01-17 17:06:23 -07006776mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777{
6778 u32 info = log_info & 0x00FF0000;
6779 char *desc = "unknown";
6780
6781 switch (info) {
6782 case 0x00010000:
6783 desc = "bug! MID not found";
6784 if (ioc->reload_fw == 0)
6785 ioc->reload_fw++;
6786 break;
6787
6788 case 0x00020000:
6789 desc = "Parity Error";
6790 break;
6791
6792 case 0x00030000:
6793 desc = "ASYNC Outbound Overrun";
6794 break;
6795
6796 case 0x00040000:
6797 desc = "SYNC Offset Error";
6798 break;
6799
6800 case 0x00050000:
6801 desc = "BM Change";
6802 break;
6803
6804 case 0x00060000:
6805 desc = "Msg In Overflow";
6806 break;
6807
6808 case 0x00070000:
6809 desc = "DMA Error";
6810 break;
6811
6812 case 0x00080000:
6813 desc = "Outbound DMA Overrun";
6814 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006815
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 case 0x00090000:
6817 desc = "Task Management";
6818 break;
6819
6820 case 0x000A0000:
6821 desc = "Device Problem";
6822 break;
6823
6824 case 0x000B0000:
6825 desc = "Invalid Phase Change";
6826 break;
6827
6828 case 0x000C0000:
6829 desc = "Untagged Table Size";
6830 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006831
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832 }
6833
6834 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6835}
6836
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006837/* strings for sas loginfo */
6838 static char *originator_str[] = {
6839 "IOP", /* 00h */
6840 "PL", /* 01h */
6841 "IR" /* 02h */
6842 };
6843 static char *iop_code_str[] = {
6844 NULL, /* 00h */
6845 "Invalid SAS Address", /* 01h */
6846 NULL, /* 02h */
6847 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006848 "Diag Message Error", /* 04h */
6849 "Task Terminated", /* 05h */
6850 "Enclosure Management", /* 06h */
6851 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006852 };
6853 static char *pl_code_str[] = {
6854 NULL, /* 00h */
6855 "Open Failure", /* 01h */
6856 "Invalid Scatter Gather List", /* 02h */
6857 "Wrong Relative Offset or Frame Length", /* 03h */
6858 "Frame Transfer Error", /* 04h */
6859 "Transmit Frame Connected Low", /* 05h */
6860 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6861 "SATA Read Log Receive Data Error", /* 07h */
6862 "SATA NCQ Fail All Commands After Error", /* 08h */
6863 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6864 "Receive Frame Invalid Message", /* 0Ah */
6865 "Receive Context Message Valid Error", /* 0Bh */
6866 "Receive Frame Current Frame Error", /* 0Ch */
6867 "SATA Link Down", /* 0Dh */
6868 "Discovery SATA Init W IOS", /* 0Eh */
6869 "Config Invalid Page", /* 0Fh */
6870 "Discovery SATA Init Timeout", /* 10h */
6871 "Reset", /* 11h */
6872 "Abort", /* 12h */
6873 "IO Not Yet Executed", /* 13h */
6874 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006875 "Persistent Reservation Out Not Affiliation "
6876 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006877 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006878 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006879 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006880 NULL, /* 19h */
6881 NULL, /* 1Ah */
6882 NULL, /* 1Bh */
6883 NULL, /* 1Ch */
6884 NULL, /* 1Dh */
6885 NULL, /* 1Eh */
6886 NULL, /* 1Fh */
6887 "Enclosure Management" /* 20h */
6888 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006889 static char *ir_code_str[] = {
6890 "Raid Action Error", /* 00h */
6891 NULL, /* 00h */
6892 NULL, /* 01h */
6893 NULL, /* 02h */
6894 NULL, /* 03h */
6895 NULL, /* 04h */
6896 NULL, /* 05h */
6897 NULL, /* 06h */
6898 NULL /* 07h */
6899 };
6900 static char *raid_sub_code_str[] = {
6901 NULL, /* 00h */
6902 "Volume Creation Failed: Data Passed too "
6903 "Large", /* 01h */
6904 "Volume Creation Failed: Duplicate Volumes "
6905 "Attempted", /* 02h */
6906 "Volume Creation Failed: Max Number "
6907 "Supported Volumes Exceeded", /* 03h */
6908 "Volume Creation Failed: DMA Error", /* 04h */
6909 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6910 "Volume Creation Failed: Error Reading "
6911 "MFG Page 4", /* 06h */
6912 "Volume Creation Failed: Creating Internal "
6913 "Structures", /* 07h */
6914 NULL, /* 08h */
6915 NULL, /* 09h */
6916 NULL, /* 0Ah */
6917 NULL, /* 0Bh */
6918 NULL, /* 0Ch */
6919 NULL, /* 0Dh */
6920 NULL, /* 0Eh */
6921 NULL, /* 0Fh */
6922 "Activation failed: Already Active Volume", /* 10h */
6923 "Activation failed: Unsupported Volume Type", /* 11h */
6924 "Activation failed: Too Many Active Volumes", /* 12h */
6925 "Activation failed: Volume ID in Use", /* 13h */
6926 "Activation failed: Reported Failure", /* 14h */
6927 "Activation failed: Importing a Volume", /* 15h */
6928 NULL, /* 16h */
6929 NULL, /* 17h */
6930 NULL, /* 18h */
6931 NULL, /* 19h */
6932 NULL, /* 1Ah */
6933 NULL, /* 1Bh */
6934 NULL, /* 1Ch */
6935 NULL, /* 1Dh */
6936 NULL, /* 1Eh */
6937 NULL, /* 1Fh */
6938 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6939 "Phys Disk failed: Data Passed too Large", /* 21h */
6940 "Phys Disk failed: DMA Error", /* 22h */
6941 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6942 "Phys Disk failed: Creating Phys Disk Config "
6943 "Page", /* 24h */
6944 NULL, /* 25h */
6945 NULL, /* 26h */
6946 NULL, /* 27h */
6947 NULL, /* 28h */
6948 NULL, /* 29h */
6949 NULL, /* 2Ah */
6950 NULL, /* 2Bh */
6951 NULL, /* 2Ch */
6952 NULL, /* 2Dh */
6953 NULL, /* 2Eh */
6954 NULL, /* 2Fh */
6955 "Compatibility Error: IR Disabled", /* 30h */
6956 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6957 "Compatibility Error: Device not Direct Access "
6958 "Device ", /* 32h */
6959 "Compatibility Error: Removable Device Found", /* 33h */
6960 "Compatibility Error: Device SCSI Version not "
6961 "2 or Higher", /* 34h */
6962 "Compatibility Error: SATA Device, 48 BIT LBA "
6963 "not Supported", /* 35h */
6964 "Compatibility Error: Device doesn't have "
6965 "512 Byte Block Sizes", /* 36h */
6966 "Compatibility Error: Volume Type Check Failed", /* 37h */
6967 "Compatibility Error: Volume Type is "
6968 "Unsupported by FW", /* 38h */
6969 "Compatibility Error: Disk Drive too Small for "
6970 "use in Volume", /* 39h */
6971 "Compatibility Error: Phys Disk for Create "
6972 "Volume not Found", /* 3Ah */
6973 "Compatibility Error: Too Many or too Few "
6974 "Disks for Volume Type", /* 3Bh */
6975 "Compatibility Error: Disk stripe Sizes "
6976 "Must be 64KB", /* 3Ch */
6977 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6978 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006979
6980/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006981/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006982 * mpt_sas_log_info - Log information returned from SAS IOC.
6983 * @ioc: Pointer to MPT_ADAPTER structure
6984 * @log_info: U32 LogInfo reply word from the IOC
6985 *
6986 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006987 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006988static void
6989mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6990{
6991union loginfo_type {
6992 u32 loginfo;
6993 struct {
6994 u32 subcode:16;
6995 u32 code:8;
6996 u32 originator:4;
6997 u32 bus_type:4;
6998 }dw;
6999};
7000 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007001 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007002 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007003 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007004
7005 sas_loginfo.loginfo = log_info;
7006 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7007 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7008 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007009
7010 originator_desc = originator_str[sas_loginfo.dw.originator];
7011
7012 switch (sas_loginfo.dw.originator) {
7013
7014 case 0: /* IOP */
7015 if (sas_loginfo.dw.code <
7016 sizeof(iop_code_str)/sizeof(char*))
7017 code_desc = iop_code_str[sas_loginfo.dw.code];
7018 break;
7019 case 1: /* PL */
7020 if (sas_loginfo.dw.code <
7021 sizeof(pl_code_str)/sizeof(char*))
7022 code_desc = pl_code_str[sas_loginfo.dw.code];
7023 break;
7024 case 2: /* IR */
7025 if (sas_loginfo.dw.code >=
7026 sizeof(ir_code_str)/sizeof(char*))
7027 break;
7028 code_desc = ir_code_str[sas_loginfo.dw.code];
7029 if (sas_loginfo.dw.subcode >=
7030 sizeof(raid_sub_code_str)/sizeof(char*))
7031 break;
7032 if (sas_loginfo.dw.code == 0)
7033 sub_code_desc =
7034 raid_sub_code_str[sas_loginfo.dw.subcode];
7035 break;
7036 default:
7037 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007038 }
7039
Eric Moorec6c727a2007-01-29 09:44:54 -07007040 if (sub_code_desc != NULL)
7041 printk(MYIOC_s_INFO_FMT
7042 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7043 " SubCode={%s}\n",
7044 ioc->name, log_info, originator_desc, code_desc,
7045 sub_code_desc);
7046 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007047 printk(MYIOC_s_INFO_FMT
7048 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7049 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007050 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007051 sas_loginfo.dw.subcode);
7052 else
7053 printk(MYIOC_s_INFO_FMT
7054 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7055 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007056 ioc->name, log_info, originator_desc,
7057 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007058}
7059
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007061/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007062 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7063 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007064 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007065 * @mf: Pointer to MPT request frame
7066 *
7067 * Refer to lsi/mpi.h.
7068 **/
7069static void
7070mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7071{
7072 Config_t *pReq = (Config_t *)mf;
7073 char extend_desc[EVENT_DESCR_STR_SZ];
7074 char *desc = NULL;
7075 u32 form;
7076 u8 page_type;
7077
7078 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7079 page_type = pReq->ExtPageType;
7080 else
7081 page_type = pReq->Header.PageType;
7082
7083 /*
7084 * ignore invalid page messages for GET_NEXT_HANDLE
7085 */
7086 form = le32_to_cpu(pReq->PageAddress);
7087 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7088 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7089 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7090 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7091 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7092 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7093 return;
7094 }
7095 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7096 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7097 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7098 return;
7099 }
7100
7101 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7102 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7103 page_type, pReq->Header.PageNumber, pReq->Action, form);
7104
7105 switch (ioc_status) {
7106
7107 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7108 desc = "Config Page Invalid Action";
7109 break;
7110
7111 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7112 desc = "Config Page Invalid Type";
7113 break;
7114
7115 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7116 desc = "Config Page Invalid Page";
7117 break;
7118
7119 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7120 desc = "Config Page Invalid Data";
7121 break;
7122
7123 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7124 desc = "Config Page No Defaults";
7125 break;
7126
7127 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7128 desc = "Config Page Can't Commit";
7129 break;
7130 }
7131
7132 if (!desc)
7133 return;
7134
Eric Moore29dd3602007-09-14 18:46:51 -06007135 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7136 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007137}
7138
7139/**
7140 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007141 * @ioc: Pointer to MPT_ADAPTER structure
7142 * @ioc_status: U32 IOCStatus word from IOC
7143 * @mf: Pointer to MPT request frame
7144 *
7145 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007146 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007148mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149{
7150 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007151 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152
7153 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007154
7155/****************************************************************************/
7156/* Common IOCStatus values for all replies */
7157/****************************************************************************/
7158
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7160 desc = "Invalid Function";
7161 break;
7162
7163 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7164 desc = "Busy";
7165 break;
7166
7167 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7168 desc = "Invalid SGL";
7169 break;
7170
7171 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7172 desc = "Internal Error";
7173 break;
7174
7175 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7176 desc = "Reserved";
7177 break;
7178
7179 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7180 desc = "Insufficient Resources";
7181 break;
7182
7183 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7184 desc = "Invalid Field";
7185 break;
7186
7187 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7188 desc = "Invalid State";
7189 break;
7190
Eric Moorec6c727a2007-01-29 09:44:54 -07007191/****************************************************************************/
7192/* Config IOCStatus values */
7193/****************************************************************************/
7194
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7196 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7197 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7198 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7199 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7200 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007201 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202 break;
7203
Eric Moorec6c727a2007-01-29 09:44:54 -07007204/****************************************************************************/
7205/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7206/* */
7207/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7208/* */
7209/****************************************************************************/
7210
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007213 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7214 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7215 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7216 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007223 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007224 break;
7225
Eric Moorec6c727a2007-01-29 09:44:54 -07007226/****************************************************************************/
7227/* SCSI Target values */
7228/****************************************************************************/
7229
7230 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7231 desc = "Target: Priority IO";
7232 break;
7233
7234 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7235 desc = "Target: Invalid Port";
7236 break;
7237
7238 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7239 desc = "Target Invalid IO Index:";
7240 break;
7241
7242 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7243 desc = "Target: Aborted";
7244 break;
7245
7246 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7247 desc = "Target: No Conn Retryable";
7248 break;
7249
7250 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7251 desc = "Target: No Connection";
7252 break;
7253
7254 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7255 desc = "Target: Transfer Count Mismatch";
7256 break;
7257
7258 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7259 desc = "Target: STS Data not Sent";
7260 break;
7261
7262 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7263 desc = "Target: Data Offset Error";
7264 break;
7265
7266 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7267 desc = "Target: Too Much Write Data";
7268 break;
7269
7270 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7271 desc = "Target: IU Too Short";
7272 break;
7273
7274 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7275 desc = "Target: ACK NAK Timeout";
7276 break;
7277
7278 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7279 desc = "Target: Nak Received";
7280 break;
7281
7282/****************************************************************************/
7283/* Fibre Channel Direct Access values */
7284/****************************************************************************/
7285
7286 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7287 desc = "FC: Aborted";
7288 break;
7289
7290 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7291 desc = "FC: RX ID Invalid";
7292 break;
7293
7294 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7295 desc = "FC: DID Invalid";
7296 break;
7297
7298 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7299 desc = "FC: Node Logged Out";
7300 break;
7301
7302 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7303 desc = "FC: Exchange Canceled";
7304 break;
7305
7306/****************************************************************************/
7307/* LAN values */
7308/****************************************************************************/
7309
7310 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7311 desc = "LAN: Device not Found";
7312 break;
7313
7314 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7315 desc = "LAN: Device Failure";
7316 break;
7317
7318 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7319 desc = "LAN: Transmit Error";
7320 break;
7321
7322 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7323 desc = "LAN: Transmit Aborted";
7324 break;
7325
7326 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7327 desc = "LAN: Receive Error";
7328 break;
7329
7330 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7331 desc = "LAN: Receive Aborted";
7332 break;
7333
7334 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7335 desc = "LAN: Partial Packet";
7336 break;
7337
7338 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7339 desc = "LAN: Canceled";
7340 break;
7341
7342/****************************************************************************/
7343/* Serial Attached SCSI values */
7344/****************************************************************************/
7345
7346 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7347 desc = "SAS: SMP Request Failed";
7348 break;
7349
7350 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7351 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352 break;
7353
7354 default:
7355 desc = "Others";
7356 break;
7357 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007358
7359 if (!desc)
7360 return;
7361
Eric Moore29dd3602007-09-14 18:46:51 -06007362 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7363 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364}
7365
7366/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007367EXPORT_SYMBOL(mpt_attach);
7368EXPORT_SYMBOL(mpt_detach);
7369#ifdef CONFIG_PM
7370EXPORT_SYMBOL(mpt_resume);
7371EXPORT_SYMBOL(mpt_suspend);
7372#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007374EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375EXPORT_SYMBOL(mpt_register);
7376EXPORT_SYMBOL(mpt_deregister);
7377EXPORT_SYMBOL(mpt_event_register);
7378EXPORT_SYMBOL(mpt_event_deregister);
7379EXPORT_SYMBOL(mpt_reset_register);
7380EXPORT_SYMBOL(mpt_reset_deregister);
7381EXPORT_SYMBOL(mpt_device_driver_register);
7382EXPORT_SYMBOL(mpt_device_driver_deregister);
7383EXPORT_SYMBOL(mpt_get_msg_frame);
7384EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307385EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386EXPORT_SYMBOL(mpt_free_msg_frame);
7387EXPORT_SYMBOL(mpt_add_sge);
7388EXPORT_SYMBOL(mpt_send_handshake_request);
7389EXPORT_SYMBOL(mpt_verify_adapter);
7390EXPORT_SYMBOL(mpt_GetIocState);
7391EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392EXPORT_SYMBOL(mpt_HardResetHandler);
7393EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007395EXPORT_SYMBOL(mpt_alloc_fw_memory);
7396EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007397EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007398EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007401/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402 * fusion_init - Fusion MPT base driver initialization routine.
7403 *
7404 * Returns 0 for success, non-zero for failure.
7405 */
7406static int __init
7407fusion_init(void)
7408{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307409 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410
7411 show_mptmod_ver(my_NAME, my_VERSION);
7412 printk(KERN_INFO COPYRIGHT "\n");
7413
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307414 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7415 MptCallbacks[cb_idx] = NULL;
7416 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7417 MptEvHandlers[cb_idx] = NULL;
7418 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007419 }
7420
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007421 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007422 * EventNotification handling.
7423 */
7424 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7425
7426 /* Register for hard reset handling callbacks.
7427 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307428 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429
7430#ifdef CONFIG_PROC_FS
7431 (void) procmpt_create();
7432#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007433 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007434}
7435
7436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007437/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007438 * fusion_exit - Perform driver unload cleanup.
7439 *
7440 * This routine frees all resources associated with each MPT adapter
7441 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7442 */
7443static void __exit
7444fusion_exit(void)
7445{
7446
Linus Torvalds1da177e2005-04-16 15:20:36 -07007447 mpt_reset_deregister(mpt_base_index);
7448
7449#ifdef CONFIG_PROC_FS
7450 procmpt_destroy();
7451#endif
7452}
7453
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454module_init(fusion_init);
7455module_exit(fusion_exit);