blob: c6be6eba7dc360d82c63e0892d5da4008742f906 [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/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800635 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 * @cb_idx: previously registered (via mpt_register) callback handle
637 * @ev_cbfunc: callback function
638 *
639 * This routine can be called by one or more protocol-specific drivers
640 * if/when they choose to be notified of MPT events.
641 *
642 * Returns 0 for success.
643 */
644int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530645mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600647 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return -1;
649
650 MptEvHandlers[cb_idx] = ev_cbfunc;
651 return 0;
652}
653
654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
655/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800656 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 * @cb_idx: previously registered callback handle
658 *
659 * Each protocol-specific driver should call this routine
660 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800661 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 */
663void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530664mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600666 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return;
668
669 MptEvHandlers[cb_idx] = NULL;
670}
671
672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
673/**
674 * mpt_reset_register - Register protocol-specific IOC reset handler.
675 * @cb_idx: previously registered (via mpt_register) callback handle
676 * @reset_func: reset function
677 *
678 * This routine can be called by one or more protocol-specific drivers
679 * if/when they choose to be notified of IOC resets.
680 *
681 * Returns 0 for success.
682 */
683int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530684mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return -1;
688
689 MptResetHandlers[cb_idx] = reset_func;
690 return 0;
691}
692
693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
694/**
695 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
696 * @cb_idx: previously registered callback handle
697 *
698 * Each protocol-specific driver should call this routine
699 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800700 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 */
702void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530703mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530705 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
708 MptResetHandlers[cb_idx] = NULL;
709}
710
711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
712/**
713 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800714 * @dd_cbfunc: driver callbacks struct
715 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 */
717int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530718mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600721 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Eric Moore8d6d83e2007-09-14 18:47:40 -0600723 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400724 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
727
728 /* call per pci device probe entry point */
729 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600730 id = ioc->pcidev->driver ?
731 ioc->pcidev->driver->id_table : NULL;
732 if (dd_cbfunc->probe)
733 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
740/**
741 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800742 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 */
744void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530745mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 struct mpt_pci_driver *dd_cbfunc;
748 MPT_ADAPTER *ioc;
749
Eric Moore8d6d83e2007-09-14 18:47:40 -0600750 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return;
752
753 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
754
755 list_for_each_entry(ioc, &ioc_list, list) {
756 if (dd_cbfunc->remove)
757 dd_cbfunc->remove(ioc->pcidev);
758 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 MptDeviceDriverHandlers[cb_idx] = NULL;
761}
762
763
764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
765/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800766 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530767 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 * @ioc: Pointer to MPT adapter structure
769 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800770 * Obtain an MPT request frame from the pool (of 1024) that are
771 * allocated per MPT adapter.
772 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 * 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/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800837 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530838 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 * @ioc: Pointer to MPT adapter structure
840 * @mf: Pointer to MPT request frame
841 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800842 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 * specific MPT adapter.
844 */
845void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530846mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 u32 mf_dma_addr;
849 int req_offset;
850 u16 req_idx; /* Request index */
851
852 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530853 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
855 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500856 req_idx = req_offset / ioc->req_sz;
857 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
859
Prakash, Sathya436ace72007-07-24 15:42:08 +0530860 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200862 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600863 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
864 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
865 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
867}
868
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530869/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800870 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530871 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530872 * @ioc: Pointer to MPT adapter structure
873 * @mf: Pointer to MPT request frame
874 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800875 * Send a protocol-specific MPT request frame to an IOC using
876 * hi-priority request queue.
877 *
878 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530879 * specific MPT adapter.
880 **/
881void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530882mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530883{
884 u32 mf_dma_addr;
885 int req_offset;
886 u16 req_idx; /* Request index */
887
888 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530889 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530890 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
891 req_idx = req_offset / ioc->req_sz;
892 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
893 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
894
895 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
896
897 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
898 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
899 ioc->name, mf_dma_addr, req_idx));
900 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
901}
902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
904/**
905 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
906 * @handle: Handle of registered MPT protocol driver
907 * @ioc: Pointer to MPT adapter structure
908 * @mf: Pointer to MPT request frame
909 *
910 * This routine places a MPT request frame back on the MPT adapter's
911 * FreeQ.
912 */
913void
914mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
915{
916 unsigned long flags;
917
918 /* Put Request back on FreeQ! */
919 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200920 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
922#ifdef MFCNT
923 ioc->mfcnt--;
924#endif
925 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
926}
927
928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
929/**
930 * mpt_add_sge - Place a simple SGE at address pAddr.
931 * @pAddr: virtual address for SGE
932 * @flagslength: SGE flags and data transfer length
933 * @dma_addr: Physical address
934 *
935 * This routine places a MPT request frame back on the MPT adapter's
936 * FreeQ.
937 */
938void
939mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
940{
941 if (sizeof(dma_addr_t) == sizeof(u64)) {
942 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
943 u32 tmp = dma_addr & 0xFFFFFFFF;
944
945 pSge->FlagsLength = cpu_to_le32(flagslength);
946 pSge->Address.Low = cpu_to_le32(tmp);
947 tmp = (u32) ((u64)dma_addr >> 32);
948 pSge->Address.High = cpu_to_le32(tmp);
949
950 } else {
951 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
952 pSge->FlagsLength = cpu_to_le32(flagslength);
953 pSge->Address = cpu_to_le32(dma_addr);
954 }
955}
956
957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
958/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800959 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530960 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * @ioc: Pointer to MPT adapter structure
962 * @reqBytes: Size of the request in bytes
963 * @req: Pointer to MPT request frame
964 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
965 *
966 * This routine is used exclusively to send MptScsiTaskMgmt
967 * requests since they are required to be sent via doorbell handshake.
968 *
969 * NOTE: It is the callers responsibility to byte-swap fields in the
970 * request which are greater than 1 byte in size.
971 *
972 * Returns 0 for success, non-zero for failure.
973 */
974int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530975mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Eric Moorecd2c6192007-01-29 09:47:47 -0700977 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 u8 *req_as_bytes;
979 int ii;
980
981 /* State is known to be good upon entering
982 * this function so issue the bus reset
983 * request.
984 */
985
986 /*
987 * Emulate what mpt_put_msg_frame() does /wrt to sanity
988 * setting cb_idx/req_idx. But ONLY if this request
989 * is in proper (pre-alloc'd) request buffer range...
990 */
991 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
992 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
993 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
994 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530995 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997
998 /* Make sure there are no doorbells */
999 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1002 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1003 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1004
1005 /* Wait for IOC doorbell int */
1006 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1007 return ii;
1008 }
1009
1010 /* Read doorbell and check for active bit */
1011 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1012 return -5;
1013
Eric Moore29dd3602007-09-14 18:46:51 -06001014 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001015 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1018
1019 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1020 return -2;
1021 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* Send request via doorbell handshake */
1024 req_as_bytes = (u8 *) req;
1025 for (ii = 0; ii < reqBytes/4; ii++) {
1026 u32 word;
1027
1028 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1029 (req_as_bytes[(ii*4) + 1] << 8) |
1030 (req_as_bytes[(ii*4) + 2] << 16) |
1031 (req_as_bytes[(ii*4) + 3] << 24));
1032 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1033 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1034 r = -3;
1035 break;
1036 }
1037 }
1038
1039 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1040 r = 0;
1041 else
1042 r = -4;
1043
1044 /* Make sure there are no doorbells */
1045 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return r;
1048}
1049
1050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1051/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001052 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001053 * @ioc: Pointer to MPT adapter structure
1054 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001055 * @sleepFlag: Specifies whether the process can sleep
1056 *
1057 * Provides mechanism for the host driver to control the IOC's
1058 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001059 *
1060 * Access Control Value - bits[15:12]
1061 * 0h Reserved
1062 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1063 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1064 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1065 *
1066 * Returns 0 for success, non-zero for failure.
1067 */
1068
1069static int
1070mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1071{
1072 int r = 0;
1073
1074 /* return if in use */
1075 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1076 & MPI_DOORBELL_ACTIVE)
1077 return -1;
1078
1079 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1080
1081 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1082 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1083 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1084 (access_control_value<<12)));
1085
1086 /* Wait for IOC to clear Doorbell Status bit */
1087 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1088 return -2;
1089 }else
1090 return 0;
1091}
1092
1093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1094/**
1095 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001096 * @ioc: Pointer to pointer to IOC adapter
1097 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001098 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001099 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001100 * Returns 0 for success, non-zero for failure.
1101 */
1102static int
1103mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1104{
1105 char *psge;
1106 int flags_length;
1107 u32 host_page_buffer_sz=0;
1108
1109 if(!ioc->HostPageBuffer) {
1110
1111 host_page_buffer_sz =
1112 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1113
1114 if(!host_page_buffer_sz)
1115 return 0; /* fw doesn't need any host buffers */
1116
1117 /* spin till we get enough memory */
1118 while(host_page_buffer_sz > 0) {
1119
1120 if((ioc->HostPageBuffer = pci_alloc_consistent(
1121 ioc->pcidev,
1122 host_page_buffer_sz,
1123 &ioc->HostPageBuffer_dma)) != NULL) {
1124
Prakash, Sathya436ace72007-07-24 15:42:08 +05301125 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001126 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001127 ioc->name, ioc->HostPageBuffer,
1128 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001129 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001130 ioc->alloc_total += host_page_buffer_sz;
1131 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1132 break;
1133 }
1134
1135 host_page_buffer_sz -= (4*1024);
1136 }
1137 }
1138
1139 if(!ioc->HostPageBuffer) {
1140 printk(MYIOC_s_ERR_FMT
1141 "Failed to alloc memory for host_page_buffer!\n",
1142 ioc->name);
1143 return -999;
1144 }
1145
1146 psge = (char *)&ioc_init->HostPageBufferSGE;
1147 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1148 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1149 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1150 MPI_SGE_FLAGS_HOST_TO_IOC |
1151 MPI_SGE_FLAGS_END_OF_BUFFER;
1152 if (sizeof(dma_addr_t) == sizeof(u64)) {
1153 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1154 }
1155 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1156 flags_length |= ioc->HostPageBuffer_sz;
1157 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1158 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1159
1160return 0;
1161}
1162
1163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1164/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001165 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 * @iocid: IOC unique identifier (integer)
1167 * @iocpp: Pointer to pointer to IOC adapter
1168 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001169 * Given a unique IOC identifier, set pointer to the associated MPT
1170 * adapter structure.
1171 *
1172 * Returns iocid and sets iocpp if iocid is found.
1173 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 */
1175int
1176mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1177{
1178 MPT_ADAPTER *ioc;
1179
1180 list_for_each_entry(ioc,&ioc_list,list) {
1181 if (ioc->id == iocid) {
1182 *iocpp =ioc;
1183 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 *iocpp = NULL;
1188 return -1;
1189}
1190
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301191/**
1192 * mpt_get_product_name - returns product string
1193 * @vendor: pci vendor id
1194 * @device: pci device id
1195 * @revision: pci revision id
1196 * @prod_name: string returned
1197 *
1198 * Returns product string displayed when driver loads,
1199 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1200 *
1201 **/
1202static void
1203mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1204{
1205 char *product_str = NULL;
1206
1207 if (vendor == PCI_VENDOR_ID_BROCADE) {
1208 switch (device)
1209 {
1210 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1211 switch (revision)
1212 {
1213 case 0x00:
1214 product_str = "BRE040 A0";
1215 break;
1216 case 0x01:
1217 product_str = "BRE040 A1";
1218 break;
1219 default:
1220 product_str = "BRE040";
1221 break;
1222 }
1223 break;
1224 }
1225 goto out;
1226 }
1227
1228 switch (device)
1229 {
1230 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1231 product_str = "LSIFC909 B1";
1232 break;
1233 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1234 product_str = "LSIFC919 B0";
1235 break;
1236 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1237 product_str = "LSIFC929 B0";
1238 break;
1239 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1240 if (revision < 0x80)
1241 product_str = "LSIFC919X A0";
1242 else
1243 product_str = "LSIFC919XL A1";
1244 break;
1245 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1246 if (revision < 0x80)
1247 product_str = "LSIFC929X A0";
1248 else
1249 product_str = "LSIFC929XL A1";
1250 break;
1251 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1252 product_str = "LSIFC939X A1";
1253 break;
1254 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1255 product_str = "LSIFC949X A1";
1256 break;
1257 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1258 switch (revision)
1259 {
1260 case 0x00:
1261 product_str = "LSIFC949E A0";
1262 break;
1263 case 0x01:
1264 product_str = "LSIFC949E A1";
1265 break;
1266 default:
1267 product_str = "LSIFC949E";
1268 break;
1269 }
1270 break;
1271 case MPI_MANUFACTPAGE_DEVID_53C1030:
1272 switch (revision)
1273 {
1274 case 0x00:
1275 product_str = "LSI53C1030 A0";
1276 break;
1277 case 0x01:
1278 product_str = "LSI53C1030 B0";
1279 break;
1280 case 0x03:
1281 product_str = "LSI53C1030 B1";
1282 break;
1283 case 0x07:
1284 product_str = "LSI53C1030 B2";
1285 break;
1286 case 0x08:
1287 product_str = "LSI53C1030 C0";
1288 break;
1289 case 0x80:
1290 product_str = "LSI53C1030T A0";
1291 break;
1292 case 0x83:
1293 product_str = "LSI53C1030T A2";
1294 break;
1295 case 0x87:
1296 product_str = "LSI53C1030T A3";
1297 break;
1298 case 0xc1:
1299 product_str = "LSI53C1020A A1";
1300 break;
1301 default:
1302 product_str = "LSI53C1030";
1303 break;
1304 }
1305 break;
1306 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1307 switch (revision)
1308 {
1309 case 0x03:
1310 product_str = "LSI53C1035 A2";
1311 break;
1312 case 0x04:
1313 product_str = "LSI53C1035 B0";
1314 break;
1315 default:
1316 product_str = "LSI53C1035";
1317 break;
1318 }
1319 break;
1320 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1321 switch (revision)
1322 {
1323 case 0x00:
1324 product_str = "LSISAS1064 A1";
1325 break;
1326 case 0x01:
1327 product_str = "LSISAS1064 A2";
1328 break;
1329 case 0x02:
1330 product_str = "LSISAS1064 A3";
1331 break;
1332 case 0x03:
1333 product_str = "LSISAS1064 A4";
1334 break;
1335 default:
1336 product_str = "LSISAS1064";
1337 break;
1338 }
1339 break;
1340 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1341 switch (revision)
1342 {
1343 case 0x00:
1344 product_str = "LSISAS1064E A0";
1345 break;
1346 case 0x01:
1347 product_str = "LSISAS1064E B0";
1348 break;
1349 case 0x02:
1350 product_str = "LSISAS1064E B1";
1351 break;
1352 case 0x04:
1353 product_str = "LSISAS1064E B2";
1354 break;
1355 case 0x08:
1356 product_str = "LSISAS1064E B3";
1357 break;
1358 default:
1359 product_str = "LSISAS1064E";
1360 break;
1361 }
1362 break;
1363 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1364 switch (revision)
1365 {
1366 case 0x00:
1367 product_str = "LSISAS1068 A0";
1368 break;
1369 case 0x01:
1370 product_str = "LSISAS1068 B0";
1371 break;
1372 case 0x02:
1373 product_str = "LSISAS1068 B1";
1374 break;
1375 default:
1376 product_str = "LSISAS1068";
1377 break;
1378 }
1379 break;
1380 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1381 switch (revision)
1382 {
1383 case 0x00:
1384 product_str = "LSISAS1068E A0";
1385 break;
1386 case 0x01:
1387 product_str = "LSISAS1068E B0";
1388 break;
1389 case 0x02:
1390 product_str = "LSISAS1068E B1";
1391 break;
1392 case 0x04:
1393 product_str = "LSISAS1068E B2";
1394 break;
1395 case 0x08:
1396 product_str = "LSISAS1068E B3";
1397 break;
1398 default:
1399 product_str = "LSISAS1068E";
1400 break;
1401 }
1402 break;
1403 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1404 switch (revision)
1405 {
1406 case 0x00:
1407 product_str = "LSISAS1078 A0";
1408 break;
1409 case 0x01:
1410 product_str = "LSISAS1078 B0";
1411 break;
1412 case 0x02:
1413 product_str = "LSISAS1078 C0";
1414 break;
1415 case 0x03:
1416 product_str = "LSISAS1078 C1";
1417 break;
1418 case 0x04:
1419 product_str = "LSISAS1078 C2";
1420 break;
1421 default:
1422 product_str = "LSISAS1078";
1423 break;
1424 }
1425 break;
1426 }
1427
1428 out:
1429 if (product_str)
1430 sprintf(prod_name, "%s", product_str);
1431}
1432
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301433/**
1434 * mpt_mapresources - map in memory mapped io
1435 * @ioc: Pointer to pointer to IOC adapter
1436 *
1437 **/
1438static int
1439mpt_mapresources(MPT_ADAPTER *ioc)
1440{
1441 u8 __iomem *mem;
1442 int ii;
1443 unsigned long mem_phys;
1444 unsigned long port;
1445 u32 msize;
1446 u32 psize;
1447 u8 revision;
1448 int r = -ENODEV;
1449 struct pci_dev *pdev;
1450
1451 pdev = ioc->pcidev;
1452 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1453 if (pci_enable_device_mem(pdev)) {
1454 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1455 "failed\n", ioc->name);
1456 return r;
1457 }
1458 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1459 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1460 "MEM failed\n", ioc->name);
1461 return r;
1462 }
1463
1464 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1465
1466 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
1467 && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1468 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1469 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1470 ioc->name));
1471 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1472 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1473 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1474 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1475 ioc->name));
1476 } else {
1477 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1478 ioc->name, pci_name(pdev));
1479 pci_release_selected_regions(pdev, ioc->bars);
1480 return r;
1481 }
1482
1483 mem_phys = msize = 0;
1484 port = psize = 0;
1485 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1486 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1487 if (psize)
1488 continue;
1489 /* Get I/O space! */
1490 port = pci_resource_start(pdev, ii);
1491 psize = pci_resource_len(pdev, ii);
1492 } else {
1493 if (msize)
1494 continue;
1495 /* Get memmap */
1496 mem_phys = pci_resource_start(pdev, ii);
1497 msize = pci_resource_len(pdev, ii);
1498 }
1499 }
1500 ioc->mem_size = msize;
1501
1502 mem = NULL;
1503 /* Get logical ptr for PciMem0 space */
1504 /*mem = ioremap(mem_phys, msize);*/
1505 mem = ioremap(mem_phys, msize);
1506 if (mem == NULL) {
1507 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1508 " memory!\n", ioc->name);
1509 return -EINVAL;
1510 }
1511 ioc->memmap = mem;
1512 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1513 ioc->name, mem, mem_phys));
1514
1515 ioc->mem_phys = mem_phys;
1516 ioc->chip = (SYSIF_REGS __iomem *)mem;
1517
1518 /* Save Port IO values in case we need to do downloadboot */
1519 ioc->pio_mem_phys = port;
1520 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1521
1522 return 0;
1523}
1524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001526/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001527 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001529 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 *
1531 * This routine performs all the steps necessary to bring the IOC of
1532 * a MPT adapter to a OPERATIONAL state. This includes registering
1533 * memory regions, registering the interrupt, and allocating request
1534 * and reply memory pools.
1535 *
1536 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1537 * MPT adapter.
1538 *
1539 * Returns 0 for success, non-zero for failure.
1540 *
1541 * TODO: Add support for polled controllers
1542 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001543int
1544mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301547 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 u8 revision;
1550 u8 pcixcmd;
1551 static int mpt_ids = 0;
1552#ifdef CONFIG_PROC_FS
1553 struct proc_dir_entry *dent, *ent;
1554#endif
1555
Jesper Juhl56876192007-08-10 14:50:51 -07001556 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1557 if (ioc == NULL) {
1558 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1559 return -ENOMEM;
1560 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301561
Eric Moore29dd3602007-09-14 18:46:51 -06001562 ioc->id = mpt_ids++;
1563 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001564
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301565 /*
1566 * set initial debug level
1567 * (refer to mptdebug.h)
1568 *
1569 */
1570 ioc->debug_level = mpt_debug_level;
1571 if (mpt_debug_level)
1572 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301573
Eric Moore29dd3602007-09-14 18:46:51 -06001574 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001575
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301576 ioc->pcidev = pdev;
1577 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001578 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return r;
1580 }
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 ioc->alloc_total = sizeof(MPT_ADAPTER);
1583 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1584 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 ioc->pcidev = pdev;
1587 ioc->diagPending = 0;
1588 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001589 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 /* Initialize the event logging.
1592 */
1593 ioc->eventTypes = 0; /* None */
1594 ioc->eventContext = 0;
1595 ioc->eventLogSize = 0;
1596 ioc->events = NULL;
1597
1598#ifdef MFCNT
1599 ioc->mfcnt = 0;
1600#endif
1601
1602 ioc->cached_fw = NULL;
1603
1604 /* Initilize SCSI Config Data structure
1605 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001606 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 /* Initialize the running configQ head.
1609 */
1610 INIT_LIST_HEAD(&ioc->configQ);
1611
Michael Reed05e8ec12006-01-13 14:31:54 -06001612 /* Initialize the fc rport list head.
1613 */
1614 INIT_LIST_HEAD(&ioc->fc_rports);
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* Find lookup slot. */
1617 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001618
Eric Moore29dd3602007-09-14 18:46:51 -06001619 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1620 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301622 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1623 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1624
1625 switch (pdev->device)
1626 {
1627 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1628 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1629 ioc->errata_flag_1064 = 1;
1630 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1631 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1632 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1633 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301635 break;
1636
1637 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 /* 929X Chip Fix. Set Split transactions level
1640 * for PCIX. Set MOST bits to zero.
1641 */
1642 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1643 pcixcmd &= 0x8F;
1644 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1645 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 /* 929XL Chip Fix. Set MMRBC to 0x08.
1647 */
1648 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1649 pcixcmd |= 0x08;
1650 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301653 break;
1654
1655 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 /* 919X Chip Fix. Set Split transactions level
1657 * for PCIX. Set MOST bits to zero.
1658 */
1659 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1660 pcixcmd &= 0x8F;
1661 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001662 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301663 break;
1664
1665 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 /* 1030 Chip Fix. Disable Split transactions
1667 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1668 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (revision < C0_1030) {
1670 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1671 pcixcmd &= 0x8F;
1672 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1673 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301674
1675 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001676 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301677 break;
1678
1679 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1680 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001681 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301682
1683 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1684 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1685 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001686 ioc->bus_type = SAS;
1687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001689 if (ioc->errata_flag_1064)
1690 pci_disable_io_access(pdev);
1691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 spin_lock_init(&ioc->FreeQlock);
1693
1694 /* Disable all! */
1695 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1696 ioc->active = 0;
1697 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1698
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301699 /* Set IOC ptr in the pcidev's driver data. */
1700 pci_set_drvdata(ioc->pcidev, ioc);
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 /* Set lookup ptr. */
1703 list_add_tail(&ioc->list, &ioc_list);
1704
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001705 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 */
1707 mpt_detect_bound_ports(ioc, pdev);
1708
James Bottomleyc92f2222006-03-01 09:02:49 -06001709 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1710 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001711 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1712 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001715 if (ioc->alt_ioc)
1716 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301717 iounmap(ioc->memmap);
1718 if (r != -5)
1719 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 kfree(ioc);
1721 pci_set_drvdata(pdev, NULL);
1722 return r;
1723 }
1724
1725 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001726 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301727 if(MptDeviceDriverHandlers[cb_idx] &&
1728 MptDeviceDriverHandlers[cb_idx]->probe) {
1729 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
1731 }
1732
1733#ifdef CONFIG_PROC_FS
1734 /*
1735 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1736 */
1737 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1738 if (dent) {
1739 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1740 if (ent) {
1741 ent->read_proc = procmpt_iocinfo_read;
1742 ent->data = ioc;
1743 }
1744 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1745 if (ent) {
1746 ent->read_proc = procmpt_summary_read;
1747 ent->data = ioc;
1748 }
1749 }
1750#endif
1751
1752 return 0;
1753}
1754
1755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001756/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001757 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 */
1760
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001761void
1762mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
1764 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1765 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301766 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1769 remove_proc_entry(pname, NULL);
1770 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1771 remove_proc_entry(pname, NULL);
1772 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1773 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001776 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301777 if(MptDeviceDriverHandlers[cb_idx] &&
1778 MptDeviceDriverHandlers[cb_idx]->remove) {
1779 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 }
1781 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* Disable interrupts! */
1784 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1785
1786 ioc->active = 0;
1787 synchronize_irq(pdev->irq);
1788
1789 /* Clear any lingering interrupt */
1790 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1791
1792 CHIPREG_READ32(&ioc->chip->IntStatus);
1793
1794 mpt_adapter_dispose(ioc);
1795
1796 pci_set_drvdata(pdev, NULL);
1797}
1798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799/**************************************************************************
1800 * Power Management
1801 */
1802#ifdef CONFIG_PM
1803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001804/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001805 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001806 * @pdev: Pointer to pci_dev structure
1807 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001809int
1810mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
1812 u32 device_state;
1813 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301815 device_state = pci_choose_state(pdev, state);
1816 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1817 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1818 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820 /* put ioc into READY_STATE */
1821 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1822 printk(MYIOC_s_ERR_FMT
1823 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1824 }
1825
1826 /* disable interrupts */
1827 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1828 ioc->active = 0;
1829
1830 /* Clear any lingering interrupt */
1831 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1832
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301833 free_irq(ioc->pci_irq, ioc);
1834 if (mpt_msi_enable)
1835 pci_disable_msi(ioc->pcidev);
1836 ioc->pci_irq = -1;
1837 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301839 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return 0;
1842}
1843
1844/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001845/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001846 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001847 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001849int
1850mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
1852 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1853 u32 device_state = pdev->current_state;
1854 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301855 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001856
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301857 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1858 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1859 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301861 pci_set_power_state(pdev, PCI_D0);
1862 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301864 ioc->pcidev = pdev;
1865 err = mpt_mapresources(ioc);
1866 if (err)
1867 return err;
1868
1869 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1870 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1871 CHIPREG_READ32(&ioc->chip->Doorbell));
1872
1873 /*
1874 * Errata workaround for SAS pci express:
1875 * Upon returning to the D0 state, the contents of the doorbell will be
1876 * stale data, and this will incorrectly signal to the host driver that
1877 * the firmware is ready to process mpt commands. The workaround is
1878 * to issue a diagnostic reset.
1879 */
1880 if (ioc->bus_type == SAS && (pdev->device ==
1881 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1882 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1883 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1884 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1885 ioc->name);
1886 goto out;
1887 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301891 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1892 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1893 CAN_SLEEP);
1894 if (recovery_state != 0)
1895 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1896 "error:[%x]\n", ioc->name, recovery_state);
1897 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301899 "pci-resume: success\n", ioc->name);
1900 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904#endif
1905
James Bottomley4ff42a62006-05-17 18:06:52 -05001906static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301907mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001908{
1909 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1910 ioc->bus_type != SPI) ||
1911 (MptDriverClass[index] == MPTFC_DRIVER &&
1912 ioc->bus_type != FC) ||
1913 (MptDriverClass[index] == MPTSAS_DRIVER &&
1914 ioc->bus_type != SAS))
1915 /* make sure we only call the relevant reset handler
1916 * for the bus */
1917 return 0;
1918 return (MptResetHandlers[index])(ioc, reset_phase);
1919}
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001922/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1924 * @ioc: Pointer to MPT adapter structure
1925 * @reason: Event word / reason
1926 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1927 *
1928 * This routine performs all the steps necessary to bring the IOC
1929 * to a OPERATIONAL state.
1930 *
1931 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1932 * MPT adapter.
1933 *
1934 * Returns:
1935 * 0 for success
1936 * -1 if failed to get board READY
1937 * -2 if READY but IOCFacts Failed
1938 * -3 if READY but PrimeIOCFifos Failed
1939 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301940 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301941 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 */
1943static int
1944mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1945{
1946 int hard_reset_done = 0;
1947 int alt_ioc_ready = 0;
1948 int hard;
1949 int rc=0;
1950 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301951 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 int handlers;
1953 int ret = 0;
1954 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001955 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301956 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Eric Moore29dd3602007-09-14 18:46:51 -06001958 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1959 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
1961 /* Disable reply interrupts (also blocks FreeQ) */
1962 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1963 ioc->active = 0;
1964
1965 if (ioc->alt_ioc) {
1966 if (ioc->alt_ioc->active)
1967 reset_alt_ioc_active = 1;
1968
1969 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1970 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1971 ioc->alt_ioc->active = 0;
1972 }
1973
1974 hard = 1;
1975 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1976 hard = 0;
1977
1978 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1979 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001980 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1981 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
1983 if (reset_alt_ioc_active && ioc->alt_ioc) {
1984 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001985 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1986 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001987 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 ioc->alt_ioc->active = 1;
1989 }
1990
1991 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001992 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 }
1994 return -1;
1995 }
1996
1997 /* hard_reset_done = 0 if a soft reset was performed
1998 * and 1 if a hard reset was performed.
1999 */
2000 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2001 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2002 alt_ioc_ready = 1;
2003 else
Eric Moore29dd3602007-09-14 18:46:51 -06002004 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 }
2006
2007 for (ii=0; ii<5; ii++) {
2008 /* Get IOC facts! Allow 5 retries */
2009 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2010 break;
2011 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002012
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002015 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2016 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 ret = -2;
2018 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2019 MptDisplayIocCapabilities(ioc);
2020 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002021
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 if (alt_ioc_ready) {
2023 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302024 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002025 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 /* Retry - alt IOC was initialized once
2027 */
2028 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2029 }
2030 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302031 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002032 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 alt_ioc_ready = 0;
2034 reset_alt_ioc_active = 0;
2035 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2036 MptDisplayIocCapabilities(ioc->alt_ioc);
2037 }
2038 }
2039
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302040 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2041 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2042 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2043 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2044 IORESOURCE_IO);
2045 if (pci_enable_device(ioc->pcidev))
2046 return -5;
2047 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2048 "mpt"))
2049 return -5;
2050 }
2051
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002052 /*
2053 * Device is reset now. It must have de-asserted the interrupt line
2054 * (if it was asserted) and it should be safe to register for the
2055 * interrupt now.
2056 */
2057 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2058 ioc->pci_irq = -1;
2059 if (ioc->pcidev->irq) {
2060 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
2061 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002062 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002063 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002064 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002065 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002066 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002067 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002068 if (mpt_msi_enable)
2069 pci_disable_msi(ioc->pcidev);
2070 return -EBUSY;
2071 }
2072 irq_allocated = 1;
2073 ioc->pci_irq = ioc->pcidev->irq;
2074 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002075 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2076 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002077 }
2078 }
2079
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 /* Prime reply & request queues!
2081 * (mucho alloc's) Must be done prior to
2082 * init as upper addresses are needed for init.
2083 * If fails, continue with alt-ioc processing
2084 */
2085 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2086 ret = -3;
2087
2088 /* May need to check/upload firmware & data here!
2089 * If fails, continue with alt-ioc processing
2090 */
2091 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2092 ret = -4;
2093// NEW!
2094 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002095 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2096 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 alt_ioc_ready = 0;
2098 reset_alt_ioc_active = 0;
2099 }
2100
2101 if (alt_ioc_ready) {
2102 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2103 alt_ioc_ready = 0;
2104 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002105 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2106 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 }
2108 }
2109
2110 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2111 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302112 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002113 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115 /* Controller is not operational, cannot do upload
2116 */
2117 if (ret == 0) {
2118 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002119 if (rc == 0) {
2120 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2121 /*
2122 * Maintain only one pointer to FW memory
2123 * so there will not be two attempt to
2124 * downloadboot onboard dual function
2125 * chips (mpt_adapter_disable,
2126 * mpt_diag_reset)
2127 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302128 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002129 "mpt_upload: alt_%s has cached_fw=%p \n",
2130 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302131 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002132 }
2133 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002134 printk(MYIOC_s_WARN_FMT
2135 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302136 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 }
2139 }
2140 }
2141
2142 if (ret == 0) {
2143 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002144 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 ioc->active = 1;
2146 }
2147
2148 if (reset_alt_ioc_active && ioc->alt_ioc) {
2149 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002150 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2151 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002152 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 ioc->alt_ioc->active = 1;
2154 }
2155
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002156 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 * and EventAck handling.
2158 */
2159 if ((ret == 0) && (!ioc->facts.EventState))
2160 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2161
2162 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2163 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2164
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002165 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2167 * recursive scenario; GetLanConfigPages times out, timer expired
2168 * routine calls HardResetHandler, which calls into here again,
2169 * and we try GetLanConfigPages again...
2170 */
2171 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002172
2173 /*
2174 * Initalize link list for inactive raid volumes.
2175 */
2176 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2177 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2178
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002179 if (ioc->bus_type == SAS) {
2180
2181 /* clear persistency table */
2182 if(ioc->facts.IOCExceptions &
2183 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2184 ret = mptbase_sas_persist_operation(ioc,
2185 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2186 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002187 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002188 }
2189
2190 /* Find IM volumes
2191 */
2192 mpt_findImVolumes(ioc);
2193
2194 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2196 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2197 /*
2198 * Pre-fetch the ports LAN MAC address!
2199 * (LANPage1_t stuff)
2200 */
2201 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302202 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2203 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002204 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2205 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302206
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 }
2208 } else {
2209 /* Get NVRAM and adapter maximums from SPP 0 and 2
2210 */
2211 mpt_GetScsiPortSettings(ioc, 0);
2212
2213 /* Get version and length of SDP 1
2214 */
2215 mpt_readScsiDevicePageHeaders(ioc, 0);
2216
2217 /* Find IM volumes
2218 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002219 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 mpt_findImVolumes(ioc);
2221
2222 /* Check, and possibly reset, the coalescing value
2223 */
2224 mpt_read_ioc_pg_1(ioc);
2225
2226 mpt_read_ioc_pg_4(ioc);
2227 }
2228
2229 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302230 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 }
2232
2233 /*
2234 * Call each currently registered protocol IOC reset handler
2235 * with post-reset indication.
2236 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2237 * MptResetHandlers[] registered yet.
2238 */
2239 if (hard_reset_done) {
2240 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302241 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2242 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302243 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002244 "Calling IOC post_reset handler #%d\n",
2245 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302246 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 handlers++;
2248 }
2249
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302250 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302251 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002252 "Calling IOC post_reset handler #%d\n",
2253 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302254 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 handlers++;
2256 }
2257 }
2258 /* FIXME? Examine results here? */
2259 }
2260
Eric Moore0ccdb002006-07-11 17:33:13 -06002261 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002262 if ((ret != 0) && irq_allocated) {
2263 free_irq(ioc->pci_irq, ioc);
2264 if (mpt_msi_enable)
2265 pci_disable_msi(ioc->pcidev);
2266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 return ret;
2268}
2269
2270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002271/**
2272 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 * @ioc: Pointer to MPT adapter structure
2274 * @pdev: Pointer to (struct pci_dev) structure
2275 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002276 * Search for PCI bus/dev_function which matches
2277 * PCI bus/dev_function (+/-1) for newly discovered 929,
2278 * 929X, 1030 or 1035.
2279 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2281 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2282 */
2283static void
2284mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2285{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002286 struct pci_dev *peer=NULL;
2287 unsigned int slot = PCI_SLOT(pdev->devfn);
2288 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 MPT_ADAPTER *ioc_srch;
2290
Prakash, Sathya436ace72007-07-24 15:42:08 +05302291 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002292 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002293 ioc->name, pci_name(pdev), pdev->bus->number,
2294 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002295
2296 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2297 if (!peer) {
2298 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2299 if (!peer)
2300 return;
2301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
2303 list_for_each_entry(ioc_srch, &ioc_list, list) {
2304 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002305 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* Paranoia checks */
2307 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002308 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002309 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 break;
2311 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002312 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002313 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 break;
2315 }
Eric Moore29dd3602007-09-14 18:46:51 -06002316 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002317 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 ioc_srch->alt_ioc = ioc;
2319 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 }
2321 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002322 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323}
2324
2325/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002326/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002328 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 */
2330static void
2331mpt_adapter_disable(MPT_ADAPTER *ioc)
2332{
2333 int sz;
2334 int ret;
2335
2336 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302337 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2338 "adapter\n", __FUNCTION__, ioc->name));
2339 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2340 ioc->cached_fw, CAN_SLEEP)) < 0) {
2341 printk(MYIOC_s_WARN_FMT
2342 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002343 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 }
2345 }
2346
2347 /* Disable adapter interrupts! */
2348 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2349 ioc->active = 0;
2350 /* Clear any lingering interrupt */
2351 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2352
2353 if (ioc->alloc != NULL) {
2354 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002355 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2356 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 pci_free_consistent(ioc->pcidev, sz,
2358 ioc->alloc, ioc->alloc_dma);
2359 ioc->reply_frames = NULL;
2360 ioc->req_frames = NULL;
2361 ioc->alloc = NULL;
2362 ioc->alloc_total -= sz;
2363 }
2364
2365 if (ioc->sense_buf_pool != NULL) {
2366 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2367 pci_free_consistent(ioc->pcidev, sz,
2368 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2369 ioc->sense_buf_pool = NULL;
2370 ioc->alloc_total -= sz;
2371 }
2372
2373 if (ioc->events != NULL){
2374 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2375 kfree(ioc->events);
2376 ioc->events = NULL;
2377 ioc->alloc_total -= sz;
2378 }
2379
Prakash, Sathya984621b2008-01-11 14:42:17 +05302380 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002382 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002383 mpt_inactive_raid_list_free(ioc);
2384 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002385 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002386 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002387 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
2389 if (ioc->spi_data.pIocPg4 != NULL) {
2390 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302391 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 ioc->spi_data.pIocPg4,
2393 ioc->spi_data.IocPg4_dma);
2394 ioc->spi_data.pIocPg4 = NULL;
2395 ioc->alloc_total -= sz;
2396 }
2397
2398 if (ioc->ReqToChain != NULL) {
2399 kfree(ioc->ReqToChain);
2400 kfree(ioc->RequestNB);
2401 ioc->ReqToChain = NULL;
2402 }
2403
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002404 kfree(ioc->ChainToChain);
2405 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002406
2407 if (ioc->HostPageBuffer != NULL) {
2408 if((ret = mpt_host_page_access_control(ioc,
2409 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002410 printk(MYIOC_s_ERR_FMT
2411 "host page buffers free failed (%d)!\n",
2412 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002413 }
Eric Moore29dd3602007-09-14 18:46:51 -06002414 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002415 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2416 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002417 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002418 ioc->HostPageBuffer = NULL;
2419 ioc->HostPageBuffer_sz = 0;
2420 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422}
2423
2424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002425/**
2426 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 * @ioc: Pointer to MPT adapter structure
2428 *
2429 * This routine unregisters h/w resources and frees all alloc'd memory
2430 * associated with a MPT adapter structure.
2431 */
2432static void
2433mpt_adapter_dispose(MPT_ADAPTER *ioc)
2434{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002435 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002437 if (ioc == NULL)
2438 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002440 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002442 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002444 if (ioc->pci_irq != -1) {
2445 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002446 if (mpt_msi_enable)
2447 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002448 ioc->pci_irq = -1;
2449 }
2450
2451 if (ioc->memmap != NULL) {
2452 iounmap(ioc->memmap);
2453 ioc->memmap = NULL;
2454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302456 pci_disable_device(ioc->pcidev);
2457 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002460 if (ioc->mtrr_reg > 0) {
2461 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002462 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464#endif
2465
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002466 /* Zap the adapter lookup ptr! */
2467 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002469 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002470 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2471 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002472
2473 if (ioc->alt_ioc)
2474 ioc->alt_ioc->alt_ioc = NULL;
2475
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002476 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477}
2478
2479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002480/**
2481 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 * @ioc: Pointer to MPT adapter structure
2483 */
2484static void
2485MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2486{
2487 int i = 0;
2488
2489 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302490 if (ioc->prod_name)
2491 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 printk("Capabilities={");
2493
2494 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2495 printk("Initiator");
2496 i++;
2497 }
2498
2499 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2500 printk("%sTarget", i ? "," : "");
2501 i++;
2502 }
2503
2504 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2505 printk("%sLAN", i ? "," : "");
2506 i++;
2507 }
2508
2509#if 0
2510 /*
2511 * This would probably evoke more questions than it's worth
2512 */
2513 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2514 printk("%sLogBusAddr", i ? "," : "");
2515 i++;
2516 }
2517#endif
2518
2519 printk("}\n");
2520}
2521
2522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002523/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2525 * @ioc: Pointer to MPT_ADAPTER structure
2526 * @force: Force hard KickStart of IOC
2527 * @sleepFlag: Specifies whether the process can sleep
2528 *
2529 * Returns:
2530 * 1 - DIAG reset and READY
2531 * 0 - READY initially OR soft reset and READY
2532 * -1 - Any failure on KickStart
2533 * -2 - Msg Unit Reset Failed
2534 * -3 - IO Unit Reset Failed
2535 * -4 - IOC owned by a PEER
2536 */
2537static int
2538MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2539{
2540 u32 ioc_state;
2541 int statefault = 0;
2542 int cntdn;
2543 int hard_reset_done = 0;
2544 int r;
2545 int ii;
2546 int whoinit;
2547
2548 /* Get current [raw] IOC state */
2549 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002550 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
2552 /*
2553 * Check to see if IOC got left/stuck in doorbell handshake
2554 * grip of death. If so, hard reset the IOC.
2555 */
2556 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2557 statefault = 1;
2558 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2559 ioc->name);
2560 }
2561
2562 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002563 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 return 0;
2565
2566 /*
2567 * Check to see if IOC is in FAULT state.
2568 */
2569 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2570 statefault = 2;
2571 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002572 ioc->name);
2573 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2574 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 }
2576
2577 /*
2578 * Hmmm... Did it get left operational?
2579 */
2580 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302581 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 ioc->name));
2583
2584 /* Check WhoInit.
2585 * If PCI Peer, exit.
2586 * Else, if no fault conditions are present, issue a MessageUnitReset
2587 * Else, fall through to KickStart case
2588 */
2589 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002590 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2591 "whoinit 0x%x statefault %d force %d\n",
2592 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 if (whoinit == MPI_WHOINIT_PCI_PEER)
2594 return -4;
2595 else {
2596 if ((statefault == 0 ) && (force == 0)) {
2597 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2598 return 0;
2599 }
2600 statefault = 3;
2601 }
2602 }
2603
2604 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2605 if (hard_reset_done < 0)
2606 return -1;
2607
2608 /*
2609 * Loop here waiting for IOC to come READY.
2610 */
2611 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002612 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
2614 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2615 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2616 /*
2617 * BIOS or previous driver load left IOC in OP state.
2618 * Reset messaging FIFOs.
2619 */
2620 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2621 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2622 return -2;
2623 }
2624 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2625 /*
2626 * Something is wrong. Try to get IOC back
2627 * to a known state.
2628 */
2629 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2630 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2631 return -3;
2632 }
2633 }
2634
2635 ii++; cntdn--;
2636 if (!cntdn) {
2637 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2638 ioc->name, (int)((ii+5)/HZ));
2639 return -ETIME;
2640 }
2641
2642 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002643 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 } else {
2645 mdelay (1); /* 1 msec delay */
2646 }
2647
2648 }
2649
2650 if (statefault < 3) {
2651 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2652 ioc->name,
2653 statefault==1 ? "stuck handshake" : "IOC FAULT");
2654 }
2655
2656 return hard_reset_done;
2657}
2658
2659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002660/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 * mpt_GetIocState - Get the current state of a MPT adapter.
2662 * @ioc: Pointer to MPT_ADAPTER structure
2663 * @cooked: Request raw or cooked IOC state
2664 *
2665 * Returns all IOC Doorbell register bits if cooked==0, else just the
2666 * Doorbell bits in MPI_IOC_STATE_MASK.
2667 */
2668u32
2669mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2670{
2671 u32 s, sc;
2672
2673 /* Get! */
2674 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 sc = s & MPI_IOC_STATE_MASK;
2676
2677 /* Save! */
2678 ioc->last_state = sc;
2679
2680 return cooked ? sc : s;
2681}
2682
2683/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002684/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 * GetIocFacts - Send IOCFacts request to MPT adapter.
2686 * @ioc: Pointer to MPT_ADAPTER structure
2687 * @sleepFlag: Specifies whether the process can sleep
2688 * @reason: If recovery, only update facts.
2689 *
2690 * Returns 0 for success, non-zero for failure.
2691 */
2692static int
2693GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2694{
2695 IOCFacts_t get_facts;
2696 IOCFactsReply_t *facts;
2697 int r;
2698 int req_sz;
2699 int reply_sz;
2700 int sz;
2701 u32 status, vv;
2702 u8 shiftFactor=1;
2703
2704 /* IOC *must* NOT be in RESET state! */
2705 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002706 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2707 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 return -44;
2709 }
2710
2711 facts = &ioc->facts;
2712
2713 /* Destination (reply area)... */
2714 reply_sz = sizeof(*facts);
2715 memset(facts, 0, reply_sz);
2716
2717 /* Request area (get_facts on the stack right now!) */
2718 req_sz = sizeof(get_facts);
2719 memset(&get_facts, 0, req_sz);
2720
2721 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2722 /* Assert: All other get_facts fields are zero! */
2723
Prakash, Sathya436ace72007-07-24 15:42:08 +05302724 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002725 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 ioc->name, req_sz, reply_sz));
2727
2728 /* No non-zero fields in the get_facts request are greater than
2729 * 1 byte in size, so we can just fire it off as is.
2730 */
2731 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2732 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2733 if (r != 0)
2734 return r;
2735
2736 /*
2737 * Now byte swap (GRRR) the necessary fields before any further
2738 * inspection of reply contents.
2739 *
2740 * But need to do some sanity checks on MsgLength (byte) field
2741 * to make sure we don't zero IOC's req_sz!
2742 */
2743 /* Did we get a valid reply? */
2744 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2745 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2746 /*
2747 * If not been here, done that, save off first WhoInit value
2748 */
2749 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2750 ioc->FirstWhoInit = facts->WhoInit;
2751 }
2752
2753 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2754 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2755 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2756 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2757 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002758 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* CHECKME! IOCStatus, IOCLogInfo */
2760
2761 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2762 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2763
2764 /*
2765 * FC f/w version changed between 1.1 and 1.2
2766 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2767 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2768 */
2769 if (facts->MsgVersion < 0x0102) {
2770 /*
2771 * Handle old FC f/w style, convert to new...
2772 */
2773 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2774 facts->FWVersion.Word =
2775 ((oldv<<12) & 0xFF000000) |
2776 ((oldv<<8) & 0x000FFF00);
2777 } else
2778 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2779
2780 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002781 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2782 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2783 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 facts->CurrentHostMfaHighAddr =
2785 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2786 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2787 facts->CurrentSenseBufferHighAddr =
2788 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2789 facts->CurReplyFrameSize =
2790 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002791 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 /*
2794 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2795 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2796 * to 14 in MPI-1.01.0x.
2797 */
2798 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2799 facts->MsgVersion > 0x0100) {
2800 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2801 }
2802
2803 sz = facts->FWImageSize;
2804 if ( sz & 0x01 )
2805 sz += 1;
2806 if ( sz & 0x02 )
2807 sz += 2;
2808 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002809
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 if (!facts->RequestFrameSize) {
2811 /* Something is wrong! */
2812 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2813 ioc->name);
2814 return -55;
2815 }
2816
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002817 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 vv = ((63 / (sz * 4)) + 1) & 0x03;
2819 ioc->NB_for_64_byte_frame = vv;
2820 while ( sz )
2821 {
2822 shiftFactor++;
2823 sz = sz >> 1;
2824 }
2825 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302826 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002827 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2828 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002829
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2831 /*
2832 * Set values for this IOC's request & reply frame sizes,
2833 * and request & reply queue depths...
2834 */
2835 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2836 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2837 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2838 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2839
Prakash, Sathya436ace72007-07-24 15:42:08 +05302840 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302842 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 ioc->name, ioc->req_sz, ioc->req_depth));
2844
2845 /* Get port facts! */
2846 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2847 return r;
2848 }
2849 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002850 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2852 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2853 RequestFrameSize)/sizeof(u32)));
2854 return -66;
2855 }
2856
2857 return 0;
2858}
2859
2860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002861/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 * GetPortFacts - Send PortFacts request to MPT adapter.
2863 * @ioc: Pointer to MPT_ADAPTER structure
2864 * @portnum: Port number
2865 * @sleepFlag: Specifies whether the process can sleep
2866 *
2867 * Returns 0 for success, non-zero for failure.
2868 */
2869static int
2870GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2871{
2872 PortFacts_t get_pfacts;
2873 PortFactsReply_t *pfacts;
2874 int ii;
2875 int req_sz;
2876 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002877 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
2879 /* IOC *must* NOT be in RESET state! */
2880 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002881 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2882 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 return -4;
2884 }
2885
2886 pfacts = &ioc->pfacts[portnum];
2887
2888 /* Destination (reply area)... */
2889 reply_sz = sizeof(*pfacts);
2890 memset(pfacts, 0, reply_sz);
2891
2892 /* Request area (get_pfacts on the stack right now!) */
2893 req_sz = sizeof(get_pfacts);
2894 memset(&get_pfacts, 0, req_sz);
2895
2896 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2897 get_pfacts.PortNumber = portnum;
2898 /* Assert: All other get_pfacts fields are zero! */
2899
Prakash, Sathya436ace72007-07-24 15:42:08 +05302900 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 ioc->name, portnum));
2902
2903 /* No non-zero fields in the get_pfacts request are greater than
2904 * 1 byte in size, so we can just fire it off as is.
2905 */
2906 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2907 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2908 if (ii != 0)
2909 return ii;
2910
2911 /* Did we get a valid reply? */
2912
2913 /* Now byte swap the necessary fields in the response. */
2914 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2915 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2916 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2917 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2918 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2919 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2920 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2921 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2922 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2923
Eric Moore793955f2007-01-29 09:42:20 -07002924 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2925 pfacts->MaxDevices;
2926 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2927 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2928
2929 /*
2930 * Place all the devices on channels
2931 *
2932 * (for debuging)
2933 */
2934 if (mpt_channel_mapping) {
2935 ioc->devices_per_bus = 1;
2936 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2937 }
2938
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 return 0;
2940}
2941
2942/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002943/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 * SendIocInit - Send IOCInit request to MPT adapter.
2945 * @ioc: Pointer to MPT_ADAPTER structure
2946 * @sleepFlag: Specifies whether the process can sleep
2947 *
2948 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2949 *
2950 * Returns 0 for success, non-zero for failure.
2951 */
2952static int
2953SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2954{
2955 IOCInit_t ioc_init;
2956 MPIDefaultReply_t init_reply;
2957 u32 state;
2958 int r;
2959 int count;
2960 int cntdn;
2961
2962 memset(&ioc_init, 0, sizeof(ioc_init));
2963 memset(&init_reply, 0, sizeof(init_reply));
2964
2965 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2966 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2967
2968 /* If we are in a recovery mode and we uploaded the FW image,
2969 * then this pointer is not NULL. Skip the upload a second time.
2970 * Set this flag if cached_fw set for either IOC.
2971 */
2972 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2973 ioc->upload_fw = 1;
2974 else
2975 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302976 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2978
Eric Moore793955f2007-01-29 09:42:20 -07002979 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2980 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302981 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002982 ioc->name, ioc->facts.MsgVersion));
2983 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2984 // set MsgVersion and HeaderVersion host driver was built with
2985 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2986 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002988 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2989 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2990 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2991 return -99;
2992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2994
2995 if (sizeof(dma_addr_t) == sizeof(u64)) {
2996 /* Save the upper 32-bits of the request
2997 * (reply) and sense buffers.
2998 */
2999 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3000 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3001 } else {
3002 /* Force 32-bit addressing */
3003 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3004 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3005 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3008 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003009 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3010 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Prakash, Sathya436ace72007-07-24 15:42:08 +05303012 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 ioc->name, &ioc_init));
3014
3015 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3016 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003017 if (r != 0) {
3018 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
3022 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003023 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 */
3025
Prakash, Sathya436ace72007-07-24 15:42:08 +05303026 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003028
3029 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3030 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 /* YIKES! SUPER IMPORTANT!!!
3035 * Poll IocState until _OPERATIONAL while IOC is doing
3036 * LoopInit and TargetDiscovery!
3037 */
3038 count = 0;
3039 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3040 state = mpt_GetIocState(ioc, 1);
3041 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3042 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003043 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 } else {
3045 mdelay(1);
3046 }
3047
3048 if (!cntdn) {
3049 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3050 ioc->name, (int)((count+5)/HZ));
3051 return -9;
3052 }
3053
3054 state = mpt_GetIocState(ioc, 1);
3055 count++;
3056 }
Eric Moore29dd3602007-09-14 18:46:51 -06003057 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 ioc->name, count));
3059
Eric Mooreba856d32006-07-11 17:34:01 -06003060 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 return r;
3062}
3063
3064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003065/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 * SendPortEnable - Send PortEnable request to MPT adapter port.
3067 * @ioc: Pointer to MPT_ADAPTER structure
3068 * @portnum: Port number to enable
3069 * @sleepFlag: Specifies whether the process can sleep
3070 *
3071 * Send PortEnable to bring IOC to OPERATIONAL state.
3072 *
3073 * Returns 0 for success, non-zero for failure.
3074 */
3075static int
3076SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3077{
3078 PortEnable_t port_enable;
3079 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003080 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 int req_sz;
3082 int reply_sz;
3083
3084 /* Destination... */
3085 reply_sz = sizeof(MPIDefaultReply_t);
3086 memset(&reply_buf, 0, reply_sz);
3087
3088 req_sz = sizeof(PortEnable_t);
3089 memset(&port_enable, 0, req_sz);
3090
3091 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3092 port_enable.PortNumber = portnum;
3093/* port_enable.ChainOffset = 0; */
3094/* port_enable.MsgFlags = 0; */
3095/* port_enable.MsgContext = 0; */
3096
Prakash, Sathya436ace72007-07-24 15:42:08 +05303097 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 ioc->name, portnum, &port_enable));
3099
3100 /* RAID FW may take a long time to enable
3101 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003102 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003103 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3104 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3105 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003106 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003107 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3108 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3109 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003111 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112}
3113
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003114/**
3115 * mpt_alloc_fw_memory - allocate firmware memory
3116 * @ioc: Pointer to MPT_ADAPTER structure
3117 * @size: total FW bytes
3118 *
3119 * If memory has already been allocated, the same (cached) value
3120 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303121 *
3122 * Return 0 if successfull, or non-zero for failure
3123 **/
3124int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3126{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303127 int rc;
3128
3129 if (ioc->cached_fw) {
3130 rc = 0; /* use already allocated memory */
3131 goto out;
3132 }
3133 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3135 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303136 rc = 0;
3137 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303139 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3140 if (!ioc->cached_fw) {
3141 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3142 ioc->name);
3143 rc = -1;
3144 } else {
3145 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3146 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3147 ioc->alloc_total += size;
3148 rc = 0;
3149 }
3150 out:
3151 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303153
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003154/**
3155 * mpt_free_fw_memory - free firmware memory
3156 * @ioc: Pointer to MPT_ADAPTER structure
3157 *
3158 * If alt_img is NULL, delete from ioc structure.
3159 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303160 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161void
3162mpt_free_fw_memory(MPT_ADAPTER *ioc)
3163{
3164 int sz;
3165
Prakash, Sathya984621b2008-01-11 14:42:17 +05303166 if (!ioc->cached_fw)
3167 return;
3168
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303170 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3171 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003172 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303173 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175}
3176
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003178/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3180 * @ioc: Pointer to MPT_ADAPTER structure
3181 * @sleepFlag: Specifies whether the process can sleep
3182 *
3183 * Returns 0 for success, >0 for handshake failure
3184 * <0 for fw upload failure.
3185 *
3186 * Remark: If bound IOC and a successful FWUpload was performed
3187 * on the bound IOC, the second image is discarded
3188 * and memory is free'd. Both channels must upload to prevent
3189 * IOC from running in degraded mode.
3190 */
3191static int
3192mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3193{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 u8 reply[sizeof(FWUploadReply_t)];
3195 FWUpload_t *prequest;
3196 FWUploadReply_t *preply;
3197 FWUploadTCSGE_t *ptcsge;
3198 int sgeoffset;
3199 u32 flagsLength;
3200 int ii, sz, reply_sz;
3201 int cmdStatus;
3202
3203 /* If the image size is 0, we are done.
3204 */
3205 if ((sz = ioc->facts.FWImageSize) == 0)
3206 return 0;
3207
Prakash, Sathya984621b2008-01-11 14:42:17 +05303208 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3209 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Eric Moore29dd3602007-09-14 18:46:51 -06003211 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3212 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003213
Eric Moorebc6e0892007-09-29 10:16:28 -06003214 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3215 kzalloc(ioc->req_sz, GFP_KERNEL);
3216 if (!prequest) {
3217 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3218 "while allocating memory \n", ioc->name));
3219 mpt_free_fw_memory(ioc);
3220 return -ENOMEM;
3221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
Eric Moorebc6e0892007-09-29 10:16:28 -06003223 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
3225 reply_sz = sizeof(reply);
3226 memset(preply, 0, reply_sz);
3227
3228 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3229 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3230
3231 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3232 ptcsge->DetailsLength = 12;
3233 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3234 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003235 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
3237 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3238
3239 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003240 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003243 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3244 ioc->name, prequest, sgeoffset));
3245 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
3247 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3248 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3249
Eric Moore29dd3602007-09-14 18:46:51 -06003250 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
3252 cmdStatus = -EFAULT;
3253 if (ii == 0) {
3254 /* Handshake transfer was complete and successful.
3255 * Check the Reply Frame.
3256 */
3257 int status, transfer_sz;
3258 status = le16_to_cpu(preply->IOCStatus);
3259 if (status == MPI_IOCSTATUS_SUCCESS) {
3260 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3261 if (transfer_sz == sz)
3262 cmdStatus = 0;
3263 }
3264 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303265 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 ioc->name, cmdStatus));
3267
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003268
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 if (cmdStatus) {
3270
Prakash, Sathya436ace72007-07-24 15:42:08 +05303271 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 ioc->name));
3273 mpt_free_fw_memory(ioc);
3274 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003275 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
3277 return cmdStatus;
3278}
3279
3280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003281/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 * mpt_downloadboot - DownloadBoot code
3283 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003284 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 * @sleepFlag: Specifies whether the process can sleep
3286 *
3287 * FwDownloadBoot requires Programmed IO access.
3288 *
3289 * Returns 0 for success
3290 * -1 FW Image size is 0
3291 * -2 No valid cached_fw Pointer
3292 * <0 for fw upload failure.
3293 */
3294static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003295mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 MpiExtImageHeader_t *pExtImage;
3298 u32 fwSize;
3299 u32 diag0val;
3300 int count;
3301 u32 *ptrFw;
3302 u32 diagRwData;
3303 u32 nextImage;
3304 u32 load_addr;
3305 u32 ioc_state=0;
3306
Prakash, Sathya436ace72007-07-24 15:42:08 +05303307 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003308 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003309
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3311 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3312 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3313 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3314 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3315 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3316
3317 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3318
3319 /* wait 1 msec */
3320 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003321 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 } else {
3323 mdelay (1);
3324 }
3325
3326 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3327 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3328
3329 for (count = 0; count < 30; count ++) {
3330 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3331 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303332 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 ioc->name, count));
3334 break;
3335 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003336 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003338 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003340 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 }
3342 }
3343
3344 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303345 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003346 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 ioc->name, diag0val));
3348 return -3;
3349 }
3350
3351 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3352 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3353 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3354 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3355 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3356 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3357
3358 /* Set the DiagRwEn and Disable ARM bits */
3359 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3360
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 fwSize = (pFwHeader->ImageSize + 3)/4;
3362 ptrFw = (u32 *) pFwHeader;
3363
3364 /* Write the LoadStartAddress to the DiagRw Address Register
3365 * using Programmed IO
3366 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003367 if (ioc->errata_flag_1064)
3368 pci_enable_io_access(ioc->pcidev);
3369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303371 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 ioc->name, pFwHeader->LoadStartAddress));
3373
Prakash, Sathya436ace72007-07-24 15:42:08 +05303374 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 ioc->name, fwSize*4, ptrFw));
3376 while (fwSize--) {
3377 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3378 }
3379
3380 nextImage = pFwHeader->NextImageHeaderOffset;
3381 while (nextImage) {
3382 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3383
3384 load_addr = pExtImage->LoadStartAddress;
3385
3386 fwSize = (pExtImage->ImageSize + 3) >> 2;
3387 ptrFw = (u32 *)pExtImage;
3388
Prakash, Sathya436ace72007-07-24 15:42:08 +05303389 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 +02003390 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3392
3393 while (fwSize--) {
3394 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3395 }
3396 nextImage = pExtImage->NextImageHeaderOffset;
3397 }
3398
3399 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303400 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3402
3403 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303404 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3406
3407 /* Clear the internal flash bad bit - autoincrementing register,
3408 * so must do two writes.
3409 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003410 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003411 /*
3412 * 1030 and 1035 H/W errata, workaround to access
3413 * the ClearFlashBadSignatureBit
3414 */
3415 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3416 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3417 diagRwData |= 0x40000000;
3418 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3419 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3420
3421 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3422 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3423 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3424 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3425
3426 /* wait 1 msec */
3427 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003428 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003429 } else {
3430 mdelay (1);
3431 }
3432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003434 if (ioc->errata_flag_1064)
3435 pci_disable_io_access(ioc->pcidev);
3436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303438 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003439 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003441 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303442 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 ioc->name, diag0val));
3444 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3445
3446 /* Write 0xFF to reset the sequencer */
3447 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3448
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003449 if (ioc->bus_type == SAS) {
3450 ioc_state = mpt_GetIocState(ioc, 0);
3451 if ( (GetIocFacts(ioc, sleepFlag,
3452 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303453 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003454 ioc->name, ioc_state));
3455 return -EFAULT;
3456 }
3457 }
3458
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 for (count=0; count<HZ*20; count++) {
3460 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303461 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3462 "downloadboot successful! (count=%d) IocState=%x\n",
3463 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003464 if (ioc->bus_type == SAS) {
3465 return 0;
3466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303468 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3469 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 ioc->name));
3471 return -EFAULT;
3472 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303473 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3474 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 ioc->name));
3476 return 0;
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 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303484 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3485 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 return -EFAULT;
3487}
3488
3489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003490/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 * KickStart - Perform hard reset of MPT adapter.
3492 * @ioc: Pointer to MPT_ADAPTER structure
3493 * @force: Force hard reset
3494 * @sleepFlag: Specifies whether the process can sleep
3495 *
3496 * This routine places MPT adapter in diagnostic mode via the
3497 * WriteSequence register, and then performs a hard reset of adapter
3498 * via the Diagnostic register.
3499 *
3500 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3501 * or NO_SLEEP (interrupt thread, use mdelay)
3502 * force - 1 if doorbell active, board fault state
3503 * board operational, IOC_RECOVERY or
3504 * IOC_BRINGUP and there is an alt_ioc.
3505 * 0 else
3506 *
3507 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003508 * 1 - hard reset, READY
3509 * 0 - no reset due to History bit, READY
3510 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 * OR reset but failed to come READY
3512 * -2 - no reset, could not enter DIAG mode
3513 * -3 - reset but bad FW bit
3514 */
3515static int
3516KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3517{
3518 int hard_reset_done = 0;
3519 u32 ioc_state=0;
3520 int cnt,cntdn;
3521
Eric Moore29dd3602007-09-14 18:46:51 -06003522 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003523 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 /* Always issue a Msg Unit Reset first. This will clear some
3525 * SCSI bus hang conditions.
3526 */
3527 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3528
3529 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003530 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 } else {
3532 mdelay (1000);
3533 }
3534 }
3535
3536 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3537 if (hard_reset_done < 0)
3538 return hard_reset_done;
3539
Prakash, Sathya436ace72007-07-24 15:42:08 +05303540 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003541 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
3543 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3544 for (cnt=0; cnt<cntdn; cnt++) {
3545 ioc_state = mpt_GetIocState(ioc, 1);
3546 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303547 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 ioc->name, cnt));
3549 return hard_reset_done;
3550 }
3551 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003552 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 } else {
3554 mdelay (10);
3555 }
3556 }
3557
Eric Moore29dd3602007-09-14 18:46:51 -06003558 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3559 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 return -1;
3561}
3562
3563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003564/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 * mpt_diag_reset - Perform hard reset of the adapter.
3566 * @ioc: Pointer to MPT_ADAPTER structure
3567 * @ignore: Set if to honor and clear to ignore
3568 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003569 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 * else set to NO_SLEEP (use mdelay instead)
3571 *
3572 * This routine places the adapter in diagnostic mode via the
3573 * WriteSequence register and then performs a hard reset of adapter
3574 * via the Diagnostic register. Adapter should be in ready state
3575 * upon successful completion.
3576 *
3577 * Returns: 1 hard reset successful
3578 * 0 no reset performed because reset history bit set
3579 * -2 enabling diagnostic mode failed
3580 * -3 diagnostic reset failed
3581 */
3582static int
3583mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3584{
3585 u32 diag0val;
3586 u32 doorbell;
3587 int hard_reset_done = 0;
3588 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303590 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
Eric Moorecd2c6192007-01-29 09:47:47 -07003592 /* Clear any existing interrupts */
3593 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3594
Eric Moore87cf8982006-06-27 16:09:26 -06003595 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303596 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003597 "address=%p\n", ioc->name, __FUNCTION__,
3598 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3599 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3600 if (sleepFlag == CAN_SLEEP)
3601 msleep(1);
3602 else
3603 mdelay(1);
3604
3605 for (count = 0; count < 60; count ++) {
3606 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3607 doorbell &= MPI_IOC_STATE_MASK;
3608
Prakash, Sathya436ace72007-07-24 15:42:08 +05303609 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003610 "looking for READY STATE: doorbell=%x"
3611 " count=%d\n",
3612 ioc->name, doorbell, count));
3613 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003614 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003615 }
3616
3617 /* wait 1 sec */
3618 if (sleepFlag == CAN_SLEEP)
3619 msleep(1000);
3620 else
3621 mdelay(1000);
3622 }
3623 return -1;
3624 }
3625
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 /* Use "Diagnostic reset" method! (only thing available!) */
3627 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3628
Prakash, Sathya436ace72007-07-24 15:42:08 +05303629 if (ioc->debug_level & MPT_DEBUG) {
3630 if (ioc->alt_ioc)
3631 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3632 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
3636 /* Do the reset if we are told to ignore the reset history
3637 * or if the reset history is 0
3638 */
3639 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3640 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3641 /* Write magic sequence to WriteSequence register
3642 * Loop until in diagnostic mode
3643 */
3644 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3645 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3646 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3647 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3648 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3649 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3650
3651 /* wait 100 msec */
3652 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003653 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 } else {
3655 mdelay (100);
3656 }
3657
3658 count++;
3659 if (count > 20) {
3660 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3661 ioc->name, diag0val);
3662 return -2;
3663
3664 }
3665
3666 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3667
Prakash, Sathya436ace72007-07-24 15:42:08 +05303668 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 ioc->name, diag0val));
3670 }
3671
Prakash, Sathya436ace72007-07-24 15:42:08 +05303672 if (ioc->debug_level & MPT_DEBUG) {
3673 if (ioc->alt_ioc)
3674 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3675 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 /*
3679 * Disable the ARM (Bug fix)
3680 *
3681 */
3682 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003683 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685 /*
3686 * Now hit the reset bit in the Diagnostic register
3687 * (THE BIG HAMMER!) (Clears DRWE bit).
3688 */
3689 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3690 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303691 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ioc->name));
3693
3694 /*
3695 * Call each currently registered protocol IOC reset handler
3696 * with pre-reset indication.
3697 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3698 * MptResetHandlers[] registered yet.
3699 */
3700 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303701 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 int r = 0;
3703
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303704 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3705 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303706 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3707 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303708 ioc->name, cb_idx));
3709 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303711 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3712 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303713 ioc->name, ioc->alt_ioc->name, cb_idx));
3714 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 }
3716 }
3717 }
3718 /* FIXME? Examine results here? */
3719 }
3720
Eric Moore0ccdb002006-07-11 17:33:13 -06003721 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303722 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003723 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303724 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3725 else
3726 cached_fw = NULL;
3727 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 /* If the DownloadBoot operation fails, the
3729 * IOC will be left unusable. This is a fatal error
3730 * case. _diag_reset will return < 0
3731 */
3732 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303733 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3735 break;
3736 }
3737
Prakash, Sathya436ace72007-07-24 15:42:08 +05303738 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303739 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 /* wait 1 sec */
3741 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003742 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 } else {
3744 mdelay (1000);
3745 }
3746 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303747 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003748 printk(MYIOC_s_WARN_FMT
3749 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 }
3751
3752 } else {
3753 /* Wait for FW to reload and for board
3754 * to go to the READY state.
3755 * Maximum wait is 60 seconds.
3756 * If fail, no error will check again
3757 * with calling program.
3758 */
3759 for (count = 0; count < 60; count ++) {
3760 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3761 doorbell &= MPI_IOC_STATE_MASK;
3762
3763 if (doorbell == MPI_IOC_STATE_READY) {
3764 break;
3765 }
3766
3767 /* wait 1 sec */
3768 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003769 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 } else {
3771 mdelay (1000);
3772 }
3773 }
3774 }
3775 }
3776
3777 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303778 if (ioc->debug_level & MPT_DEBUG) {
3779 if (ioc->alt_ioc)
3780 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3781 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3782 ioc->name, diag0val, diag1val));
3783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
3785 /* Clear RESET_HISTORY bit! Place board in the
3786 * diagnostic mode to update the diag register.
3787 */
3788 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3789 count = 0;
3790 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3791 /* Write magic sequence to WriteSequence register
3792 * Loop until in diagnostic mode
3793 */
3794 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3795 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3796 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3797 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3798 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3799 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3800
3801 /* wait 100 msec */
3802 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003803 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 } else {
3805 mdelay (100);
3806 }
3807
3808 count++;
3809 if (count > 20) {
3810 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3811 ioc->name, diag0val);
3812 break;
3813 }
3814 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3815 }
3816 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3817 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3818 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3819 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3820 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3821 ioc->name);
3822 }
3823
3824 /* Disable Diagnostic Mode
3825 */
3826 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3827
3828 /* Check FW reload status flags.
3829 */
3830 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3831 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3832 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3833 ioc->name, diag0val);
3834 return -3;
3835 }
3836
Prakash, Sathya436ace72007-07-24 15:42:08 +05303837 if (ioc->debug_level & MPT_DEBUG) {
3838 if (ioc->alt_ioc)
3839 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3840 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
3844 /*
3845 * Reset flag that says we've enabled event notification
3846 */
3847 ioc->facts.EventState = 0;
3848
3849 if (ioc->alt_ioc)
3850 ioc->alt_ioc->facts.EventState = 0;
3851
3852 return hard_reset_done;
3853}
3854
3855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003856/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 * SendIocReset - Send IOCReset request to MPT adapter.
3858 * @ioc: Pointer to MPT_ADAPTER structure
3859 * @reset_type: reset type, expected values are
3860 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003861 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 *
3863 * Send IOCReset request to the MPT adapter.
3864 *
3865 * Returns 0 for success, non-zero for failure.
3866 */
3867static int
3868SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3869{
3870 int r;
3871 u32 state;
3872 int cntdn, count;
3873
Prakash, Sathya436ace72007-07-24 15:42:08 +05303874 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 ioc->name, reset_type));
3876 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3877 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3878 return r;
3879
3880 /* FW ACK'd request, wait for READY state
3881 */
3882 count = 0;
3883 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3884
3885 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3886 cntdn--;
3887 count++;
3888 if (!cntdn) {
3889 if (sleepFlag != CAN_SLEEP)
3890 count *= 10;
3891
Eric Moore29dd3602007-09-14 18:46:51 -06003892 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3893 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 return -ETIME;
3895 }
3896
3897 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003898 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 } else {
3900 mdelay (1); /* 1 msec delay */
3901 }
3902 }
3903
3904 /* TODO!
3905 * Cleanup all event stuff for this IOC; re-issue EventNotification
3906 * request if needed.
3907 */
3908 if (ioc->facts.Function)
3909 ioc->facts.EventState = 0;
3910
3911 return 0;
3912}
3913
3914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003915/**
3916 * initChainBuffers - Allocate memory for and initialize chain buffers
3917 * @ioc: Pointer to MPT_ADAPTER structure
3918 *
3919 * Allocates memory for and initializes chain buffers,
3920 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 */
3922static int
3923initChainBuffers(MPT_ADAPTER *ioc)
3924{
3925 u8 *mem;
3926 int sz, ii, num_chain;
3927 int scale, num_sge, numSGE;
3928
3929 /* ReqToChain size must equal the req_depth
3930 * index = req_idx
3931 */
3932 if (ioc->ReqToChain == NULL) {
3933 sz = ioc->req_depth * sizeof(int);
3934 mem = kmalloc(sz, GFP_ATOMIC);
3935 if (mem == NULL)
3936 return -1;
3937
3938 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303939 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 ioc->name, mem, sz));
3941 mem = kmalloc(sz, GFP_ATOMIC);
3942 if (mem == NULL)
3943 return -1;
3944
3945 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303946 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 ioc->name, mem, sz));
3948 }
3949 for (ii = 0; ii < ioc->req_depth; ii++) {
3950 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3951 }
3952
3953 /* ChainToChain size must equal the total number
3954 * of chain buffers to be allocated.
3955 * index = chain_idx
3956 *
3957 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003958 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 *
3960 * num_sge = num sge in request frame + last chain buffer
3961 * scale = num sge per chain buffer if no chain element
3962 */
3963 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3964 if (sizeof(dma_addr_t) == sizeof(u64))
3965 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3966 else
3967 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3968
3969 if (sizeof(dma_addr_t) == sizeof(u64)) {
3970 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3971 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3972 } else {
3973 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3974 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3975 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303976 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 ioc->name, num_sge, numSGE));
3978
3979 if ( numSGE > MPT_SCSI_SG_DEPTH )
3980 numSGE = MPT_SCSI_SG_DEPTH;
3981
3982 num_chain = 1;
3983 while (numSGE - num_sge > 0) {
3984 num_chain++;
3985 num_sge += (scale - 1);
3986 }
3987 num_chain++;
3988
Prakash, Sathya436ace72007-07-24 15:42:08 +05303989 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 ioc->name, numSGE, num_sge, num_chain));
3991
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003992 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 num_chain *= MPT_SCSI_CAN_QUEUE;
3994 else
3995 num_chain *= MPT_FC_CAN_QUEUE;
3996
3997 ioc->num_chain = num_chain;
3998
3999 sz = num_chain * sizeof(int);
4000 if (ioc->ChainToChain == NULL) {
4001 mem = kmalloc(sz, GFP_ATOMIC);
4002 if (mem == NULL)
4003 return -1;
4004
4005 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 ioc->name, mem, sz));
4008 } else {
4009 mem = (u8 *) ioc->ChainToChain;
4010 }
4011 memset(mem, 0xFF, sz);
4012 return num_chain;
4013}
4014
4015/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004016/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4018 * @ioc: Pointer to MPT_ADAPTER structure
4019 *
4020 * This routine allocates memory for the MPT reply and request frame
4021 * pools (if necessary), and primes the IOC reply FIFO with
4022 * reply frames.
4023 *
4024 * Returns 0 for success, non-zero for failure.
4025 */
4026static int
4027PrimeIocFifos(MPT_ADAPTER *ioc)
4028{
4029 MPT_FRAME_HDR *mf;
4030 unsigned long flags;
4031 dma_addr_t alloc_dma;
4032 u8 *mem;
4033 int i, reply_sz, sz, total_size, num_chain;
4034
4035 /* Prime reply FIFO... */
4036
4037 if (ioc->reply_frames == NULL) {
4038 if ( (num_chain = initChainBuffers(ioc)) < 0)
4039 return -1;
4040
4041 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304042 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304044 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 ioc->name, reply_sz, reply_sz));
4046
4047 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304048 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304050 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 ioc->name, sz, sz));
4052 total_size += sz;
4053
4054 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304055 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304057 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 ioc->name, sz, sz, num_chain));
4059
4060 total_size += sz;
4061 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4062 if (mem == NULL) {
4063 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4064 ioc->name);
4065 goto out_fail;
4066 }
4067
Prakash, Sathya436ace72007-07-24 15:42:08 +05304068 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4070
4071 memset(mem, 0, total_size);
4072 ioc->alloc_total += total_size;
4073 ioc->alloc = mem;
4074 ioc->alloc_dma = alloc_dma;
4075 ioc->alloc_sz = total_size;
4076 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4077 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4078
Prakash, Sathya436ace72007-07-24 15:42:08 +05304079 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004080 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4081
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 alloc_dma += reply_sz;
4083 mem += reply_sz;
4084
4085 /* Request FIFO - WE manage this! */
4086
4087 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4088 ioc->req_frames_dma = alloc_dma;
4089
Prakash, Sathya436ace72007-07-24 15:42:08 +05304090 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 ioc->name, mem, (void *)(ulong)alloc_dma));
4092
4093 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4094
4095#if defined(CONFIG_MTRR) && 0
4096 /*
4097 * Enable Write Combining MTRR for IOC's memory region.
4098 * (at least as much as we can; "size and base must be
4099 * multiples of 4 kiB"
4100 */
4101 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4102 sz,
4103 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304104 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 ioc->name, ioc->req_frames_dma, sz));
4106#endif
4107
4108 for (i = 0; i < ioc->req_depth; i++) {
4109 alloc_dma += ioc->req_sz;
4110 mem += ioc->req_sz;
4111 }
4112
4113 ioc->ChainBuffer = mem;
4114 ioc->ChainBufferDMA = alloc_dma;
4115
Prakash, Sathya436ace72007-07-24 15:42:08 +05304116 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4118
4119 /* Initialize the free chain Q.
4120 */
4121
4122 INIT_LIST_HEAD(&ioc->FreeChainQ);
4123
4124 /* Post the chain buffers to the FreeChainQ.
4125 */
4126 mem = (u8 *)ioc->ChainBuffer;
4127 for (i=0; i < num_chain; i++) {
4128 mf = (MPT_FRAME_HDR *) mem;
4129 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4130 mem += ioc->req_sz;
4131 }
4132
4133 /* Initialize Request frames linked list
4134 */
4135 alloc_dma = ioc->req_frames_dma;
4136 mem = (u8 *) ioc->req_frames;
4137
4138 spin_lock_irqsave(&ioc->FreeQlock, flags);
4139 INIT_LIST_HEAD(&ioc->FreeQ);
4140 for (i = 0; i < ioc->req_depth; i++) {
4141 mf = (MPT_FRAME_HDR *) mem;
4142
4143 /* Queue REQUESTs *internally*! */
4144 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4145
4146 mem += ioc->req_sz;
4147 }
4148 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4149
4150 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4151 ioc->sense_buf_pool =
4152 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4153 if (ioc->sense_buf_pool == NULL) {
4154 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4155 ioc->name);
4156 goto out_fail;
4157 }
4158
4159 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4160 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304161 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4163
4164 }
4165
4166 /* Post Reply frames to FIFO
4167 */
4168 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304169 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4171
4172 for (i = 0; i < ioc->reply_depth; i++) {
4173 /* Write each address to the IOC! */
4174 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4175 alloc_dma += ioc->reply_sz;
4176 }
4177
4178 return 0;
4179
4180out_fail:
4181 if (ioc->alloc != NULL) {
4182 sz = ioc->alloc_sz;
4183 pci_free_consistent(ioc->pcidev,
4184 sz,
4185 ioc->alloc, ioc->alloc_dma);
4186 ioc->reply_frames = NULL;
4187 ioc->req_frames = NULL;
4188 ioc->alloc_total -= sz;
4189 }
4190 if (ioc->sense_buf_pool != NULL) {
4191 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4192 pci_free_consistent(ioc->pcidev,
4193 sz,
4194 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4195 ioc->sense_buf_pool = NULL;
4196 }
4197 return -1;
4198}
4199
4200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4201/**
4202 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4203 * from IOC via doorbell handshake method.
4204 * @ioc: Pointer to MPT_ADAPTER structure
4205 * @reqBytes: Size of the request in bytes
4206 * @req: Pointer to MPT request frame
4207 * @replyBytes: Expected size of the reply in bytes
4208 * @u16reply: Pointer to area where reply should be written
4209 * @maxwait: Max wait time for a reply (in seconds)
4210 * @sleepFlag: Specifies whether the process can sleep
4211 *
4212 * NOTES: It is the callers responsibility to byte-swap fields in the
4213 * request which are greater than 1 byte in size. It is also the
4214 * callers responsibility to byte-swap response fields which are
4215 * greater than 1 byte in size.
4216 *
4217 * Returns 0 for success, non-zero for failure.
4218 */
4219static int
4220mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004221 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223 MPIDefaultReply_t *mptReply;
4224 int failcnt = 0;
4225 int t;
4226
4227 /*
4228 * Get ready to cache a handshake reply
4229 */
4230 ioc->hs_reply_idx = 0;
4231 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4232 mptReply->MsgLength = 0;
4233
4234 /*
4235 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4236 * then tell IOC that we want to handshake a request of N words.
4237 * (WRITE u32val to Doorbell reg).
4238 */
4239 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4240 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4241 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4242 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4243
4244 /*
4245 * Wait for IOC's doorbell handshake int
4246 */
4247 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4248 failcnt++;
4249
Prakash, Sathya436ace72007-07-24 15:42:08 +05304250 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4252
4253 /* Read doorbell and check for active bit */
4254 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4255 return -1;
4256
4257 /*
4258 * Clear doorbell int (WRITE 0 to IntStatus reg),
4259 * then wait for IOC to ACKnowledge that it's ready for
4260 * our handshake request.
4261 */
4262 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4263 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4264 failcnt++;
4265
4266 if (!failcnt) {
4267 int ii;
4268 u8 *req_as_bytes = (u8 *) req;
4269
4270 /*
4271 * Stuff request words via doorbell handshake,
4272 * with ACK from IOC for each.
4273 */
4274 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4275 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4276 (req_as_bytes[(ii*4) + 1] << 8) |
4277 (req_as_bytes[(ii*4) + 2] << 16) |
4278 (req_as_bytes[(ii*4) + 3] << 24));
4279
4280 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4281 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4282 failcnt++;
4283 }
4284
Prakash, Sathya436ace72007-07-24 15:42:08 +05304285 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004286 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Prakash, Sathya436ace72007-07-24 15:42:08 +05304288 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4290
4291 /*
4292 * Wait for completion of doorbell handshake reply from the IOC
4293 */
4294 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4295 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004296
Prakash, Sathya436ace72007-07-24 15:42:08 +05304297 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4299
4300 /*
4301 * Copy out the cached reply...
4302 */
4303 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4304 u16reply[ii] = ioc->hs_reply[ii];
4305 } else {
4306 return -99;
4307 }
4308
4309 return -failcnt;
4310}
4311
4312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004313/**
4314 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 * @ioc: Pointer to MPT_ADAPTER structure
4316 * @howlong: How long to wait (in seconds)
4317 * @sleepFlag: Specifies whether the process can sleep
4318 *
4319 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004320 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4321 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 *
4323 * Returns a negative value on failure, else wait loop count.
4324 */
4325static int
4326WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4327{
4328 int cntdn;
4329 int count = 0;
4330 u32 intstat=0;
4331
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004332 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
4334 if (sleepFlag == CAN_SLEEP) {
4335 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004336 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4338 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4339 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 count++;
4341 }
4342 } else {
4343 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004344 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4346 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4347 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 count++;
4349 }
4350 }
4351
4352 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304353 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 ioc->name, count));
4355 return count;
4356 }
4357
4358 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4359 ioc->name, count, intstat);
4360 return -1;
4361}
4362
4363/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004364/**
4365 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 * @ioc: Pointer to MPT_ADAPTER structure
4367 * @howlong: How long to wait (in seconds)
4368 * @sleepFlag: Specifies whether the process can sleep
4369 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004370 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4371 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 *
4373 * Returns a negative value on failure, else wait loop count.
4374 */
4375static int
4376WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4377{
4378 int cntdn;
4379 int count = 0;
4380 u32 intstat=0;
4381
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004382 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 if (sleepFlag == CAN_SLEEP) {
4384 while (--cntdn) {
4385 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4386 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4387 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004388 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 count++;
4390 }
4391 } else {
4392 while (--cntdn) {
4393 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4394 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4395 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004396 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 count++;
4398 }
4399 }
4400
4401 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304402 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 ioc->name, count, howlong));
4404 return count;
4405 }
4406
4407 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4408 ioc->name, count, intstat);
4409 return -1;
4410}
4411
4412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004413/**
4414 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 * @ioc: Pointer to MPT_ADAPTER structure
4416 * @howlong: How long to wait (in seconds)
4417 * @sleepFlag: Specifies whether the process can sleep
4418 *
4419 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4420 * Reply is cached to IOC private area large enough to hold a maximum
4421 * of 128 bytes of reply data.
4422 *
4423 * Returns a negative value on failure, else size of reply in WORDS.
4424 */
4425static int
4426WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4427{
4428 int u16cnt = 0;
4429 int failcnt = 0;
4430 int t;
4431 u16 *hs_reply = ioc->hs_reply;
4432 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4433 u16 hword;
4434
4435 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4436
4437 /*
4438 * Get first two u16's so we can look at IOC's intended reply MsgLength
4439 */
4440 u16cnt=0;
4441 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4442 failcnt++;
4443 } else {
4444 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4445 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4446 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4447 failcnt++;
4448 else {
4449 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4450 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4451 }
4452 }
4453
Prakash, Sathya436ace72007-07-24 15:42:08 +05304454 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004455 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4457
4458 /*
4459 * If no error (and IOC said MsgLength is > 0), piece together
4460 * reply 16 bits at a time.
4461 */
4462 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4463 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4464 failcnt++;
4465 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4466 /* don't overflow our IOC hs_reply[] buffer! */
4467 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4468 hs_reply[u16cnt] = hword;
4469 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4470 }
4471
4472 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4473 failcnt++;
4474 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4475
4476 if (failcnt) {
4477 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4478 ioc->name);
4479 return -failcnt;
4480 }
4481#if 0
4482 else if (u16cnt != (2 * mptReply->MsgLength)) {
4483 return -101;
4484 }
4485 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4486 return -102;
4487 }
4488#endif
4489
Prakash, Sathya436ace72007-07-24 15:42:08 +05304490 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004491 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492
Prakash, Sathya436ace72007-07-24 15:42:08 +05304493 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 ioc->name, t, u16cnt/2));
4495 return u16cnt/2;
4496}
4497
4498/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004499/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 * GetLanConfigPages - Fetch LANConfig pages.
4501 * @ioc: Pointer to MPT_ADAPTER structure
4502 *
4503 * Return: 0 for success
4504 * -ENOMEM if no memory available
4505 * -EPERM if not allowed due to ISR context
4506 * -EAGAIN if no msg frames currently available
4507 * -EFAULT for non-successful reply or no reply (timeout)
4508 */
4509static int
4510GetLanConfigPages(MPT_ADAPTER *ioc)
4511{
4512 ConfigPageHeader_t hdr;
4513 CONFIGPARMS cfg;
4514 LANPage0_t *ppage0_alloc;
4515 dma_addr_t page0_dma;
4516 LANPage1_t *ppage1_alloc;
4517 dma_addr_t page1_dma;
4518 int rc = 0;
4519 int data_sz;
4520 int copy_sz;
4521
4522 /* Get LAN Page 0 header */
4523 hdr.PageVersion = 0;
4524 hdr.PageLength = 0;
4525 hdr.PageNumber = 0;
4526 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004527 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 cfg.physAddr = -1;
4529 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4530 cfg.dir = 0;
4531 cfg.pageAddr = 0;
4532 cfg.timeout = 0;
4533
4534 if ((rc = mpt_config(ioc, &cfg)) != 0)
4535 return rc;
4536
4537 if (hdr.PageLength > 0) {
4538 data_sz = hdr.PageLength * 4;
4539 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4540 rc = -ENOMEM;
4541 if (ppage0_alloc) {
4542 memset((u8 *)ppage0_alloc, 0, data_sz);
4543 cfg.physAddr = page0_dma;
4544 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4545
4546 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4547 /* save the data */
4548 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4549 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4550
4551 }
4552
4553 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4554
4555 /* FIXME!
4556 * Normalize endianness of structure data,
4557 * by byte-swapping all > 1 byte fields!
4558 */
4559
4560 }
4561
4562 if (rc)
4563 return rc;
4564 }
4565
4566 /* Get LAN Page 1 header */
4567 hdr.PageVersion = 0;
4568 hdr.PageLength = 0;
4569 hdr.PageNumber = 1;
4570 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004571 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 cfg.physAddr = -1;
4573 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4574 cfg.dir = 0;
4575 cfg.pageAddr = 0;
4576
4577 if ((rc = mpt_config(ioc, &cfg)) != 0)
4578 return rc;
4579
4580 if (hdr.PageLength == 0)
4581 return 0;
4582
4583 data_sz = hdr.PageLength * 4;
4584 rc = -ENOMEM;
4585 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4586 if (ppage1_alloc) {
4587 memset((u8 *)ppage1_alloc, 0, data_sz);
4588 cfg.physAddr = page1_dma;
4589 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4590
4591 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4592 /* save the data */
4593 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4594 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4595 }
4596
4597 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4598
4599 /* FIXME!
4600 * Normalize endianness of structure data,
4601 * by byte-swapping all > 1 byte fields!
4602 */
4603
4604 }
4605
4606 return rc;
4607}
4608
4609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004610/**
4611 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004612 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004613 * @persist_opcode: see below
4614 *
4615 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4616 * devices not currently present.
4617 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4618 *
4619 * NOTE: Don't use not this function during interrupt time.
4620 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004621 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004622 */
4623
4624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4625int
4626mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4627{
4628 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4629 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4630 MPT_FRAME_HDR *mf = NULL;
4631 MPIHeader_t *mpi_hdr;
4632
4633
4634 /* insure garbage is not sent to fw */
4635 switch(persist_opcode) {
4636
4637 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4638 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4639 break;
4640
4641 default:
4642 return -1;
4643 break;
4644 }
4645
4646 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4647
4648 /* Get a MF for this command.
4649 */
4650 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4651 printk("%s: no msg frames!\n",__FUNCTION__);
4652 return -1;
4653 }
4654
4655 mpi_hdr = (MPIHeader_t *) mf;
4656 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4657 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4658 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4659 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4660 sasIoUnitCntrReq->Operation = persist_opcode;
4661
4662 init_timer(&ioc->persist_timer);
4663 ioc->persist_timer.data = (unsigned long) ioc;
4664 ioc->persist_timer.function = mpt_timer_expired;
4665 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4666 ioc->persist_wait_done=0;
4667 add_timer(&ioc->persist_timer);
4668 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4669 wait_event(mpt_waitq, ioc->persist_wait_done);
4670
4671 sasIoUnitCntrReply =
4672 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4673 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4674 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4675 __FUNCTION__,
4676 sasIoUnitCntrReply->IOCStatus,
4677 sasIoUnitCntrReply->IOCLogInfo);
4678 return -1;
4679 }
4680
4681 printk("%s: success\n",__FUNCTION__);
4682 return 0;
4683}
4684
4685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004686
4687static void
4688mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4689 MpiEventDataRaid_t * pRaidEventData)
4690{
4691 int volume;
4692 int reason;
4693 int disk;
4694 int status;
4695 int flags;
4696 int state;
4697
4698 volume = pRaidEventData->VolumeID;
4699 reason = pRaidEventData->ReasonCode;
4700 disk = pRaidEventData->PhysDiskNum;
4701 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4702 flags = (status >> 0) & 0xff;
4703 state = (status >> 8) & 0xff;
4704
4705 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4706 return;
4707 }
4708
4709 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4710 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4711 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004712 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4713 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004714 } else {
4715 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4716 ioc->name, volume);
4717 }
4718
4719 switch(reason) {
4720 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4721 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4722 ioc->name);
4723 break;
4724
4725 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4726
4727 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4728 ioc->name);
4729 break;
4730
4731 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4732 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4733 ioc->name);
4734 break;
4735
4736 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4737 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4738 ioc->name,
4739 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4740 ? "optimal"
4741 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4742 ? "degraded"
4743 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4744 ? "failed"
4745 : "state unknown",
4746 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4747 ? ", enabled" : "",
4748 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4749 ? ", quiesced" : "",
4750 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4751 ? ", resync in progress" : "" );
4752 break;
4753
4754 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4755 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4756 ioc->name, disk);
4757 break;
4758
4759 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4760 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4761 ioc->name);
4762 break;
4763
4764 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4765 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4766 ioc->name);
4767 break;
4768
4769 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4770 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4771 ioc->name);
4772 break;
4773
4774 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4775 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4776 ioc->name,
4777 state == MPI_PHYSDISK0_STATUS_ONLINE
4778 ? "online"
4779 : state == MPI_PHYSDISK0_STATUS_MISSING
4780 ? "missing"
4781 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4782 ? "not compatible"
4783 : state == MPI_PHYSDISK0_STATUS_FAILED
4784 ? "failed"
4785 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4786 ? "initializing"
4787 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4788 ? "offline requested"
4789 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4790 ? "failed requested"
4791 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4792 ? "offline"
4793 : "state unknown",
4794 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4795 ? ", out of sync" : "",
4796 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4797 ? ", quiesced" : "" );
4798 break;
4799
4800 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4801 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4802 ioc->name, disk);
4803 break;
4804
4805 case MPI_EVENT_RAID_RC_SMART_DATA:
4806 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4807 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4808 break;
4809
4810 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4811 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4812 ioc->name, disk);
4813 break;
4814 }
4815}
4816
4817/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004818/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4820 * @ioc: Pointer to MPT_ADAPTER structure
4821 *
4822 * Returns: 0 for success
4823 * -ENOMEM if no memory available
4824 * -EPERM if not allowed due to ISR context
4825 * -EAGAIN if no msg frames currently available
4826 * -EFAULT for non-successful reply or no reply (timeout)
4827 */
4828static int
4829GetIoUnitPage2(MPT_ADAPTER *ioc)
4830{
4831 ConfigPageHeader_t hdr;
4832 CONFIGPARMS cfg;
4833 IOUnitPage2_t *ppage_alloc;
4834 dma_addr_t page_dma;
4835 int data_sz;
4836 int rc;
4837
4838 /* Get the page header */
4839 hdr.PageVersion = 0;
4840 hdr.PageLength = 0;
4841 hdr.PageNumber = 2;
4842 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004843 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 cfg.physAddr = -1;
4845 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4846 cfg.dir = 0;
4847 cfg.pageAddr = 0;
4848 cfg.timeout = 0;
4849
4850 if ((rc = mpt_config(ioc, &cfg)) != 0)
4851 return rc;
4852
4853 if (hdr.PageLength == 0)
4854 return 0;
4855
4856 /* Read the config page */
4857 data_sz = hdr.PageLength * 4;
4858 rc = -ENOMEM;
4859 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4860 if (ppage_alloc) {
4861 memset((u8 *)ppage_alloc, 0, data_sz);
4862 cfg.physAddr = page_dma;
4863 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4864
4865 /* If Good, save data */
4866 if ((rc = mpt_config(ioc, &cfg)) == 0)
4867 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4868
4869 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4870 }
4871
4872 return rc;
4873}
4874
4875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004876/**
4877 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 * @ioc: Pointer to a Adapter Strucutre
4879 * @portnum: IOC port number
4880 *
4881 * Return: -EFAULT if read of config page header fails
4882 * or if no nvram
4883 * If read of SCSI Port Page 0 fails,
4884 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4885 * Adapter settings: async, narrow
4886 * Return 1
4887 * If read of SCSI Port Page 2 fails,
4888 * Adapter settings valid
4889 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4890 * Return 1
4891 * Else
4892 * Both valid
4893 * Return 0
4894 * CHECK - what type of locking mechanisms should be used????
4895 */
4896static int
4897mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4898{
4899 u8 *pbuf;
4900 dma_addr_t buf_dma;
4901 CONFIGPARMS cfg;
4902 ConfigPageHeader_t header;
4903 int ii;
4904 int data, rc = 0;
4905
4906 /* Allocate memory
4907 */
4908 if (!ioc->spi_data.nvram) {
4909 int sz;
4910 u8 *mem;
4911 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4912 mem = kmalloc(sz, GFP_ATOMIC);
4913 if (mem == NULL)
4914 return -EFAULT;
4915
4916 ioc->spi_data.nvram = (int *) mem;
4917
Prakash, Sathya436ace72007-07-24 15:42:08 +05304918 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 ioc->name, ioc->spi_data.nvram, sz));
4920 }
4921
4922 /* Invalidate NVRAM information
4923 */
4924 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4925 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4926 }
4927
4928 /* Read SPP0 header, allocate memory, then read page.
4929 */
4930 header.PageVersion = 0;
4931 header.PageLength = 0;
4932 header.PageNumber = 0;
4933 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004934 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 cfg.physAddr = -1;
4936 cfg.pageAddr = portnum;
4937 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4938 cfg.dir = 0;
4939 cfg.timeout = 0; /* use default */
4940 if (mpt_config(ioc, &cfg) != 0)
4941 return -EFAULT;
4942
4943 if (header.PageLength > 0) {
4944 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4945 if (pbuf) {
4946 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4947 cfg.physAddr = buf_dma;
4948 if (mpt_config(ioc, &cfg) != 0) {
4949 ioc->spi_data.maxBusWidth = MPT_NARROW;
4950 ioc->spi_data.maxSyncOffset = 0;
4951 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4952 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4953 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304954 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4955 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004956 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 } else {
4958 /* Save the Port Page 0 data
4959 */
4960 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4961 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4962 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4963
4964 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4965 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004966 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4967 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 ioc->name, pPP0->Capabilities));
4969 }
4970 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4971 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4972 if (data) {
4973 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4974 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4975 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304976 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4977 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004978 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 } else {
4980 ioc->spi_data.maxSyncOffset = 0;
4981 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4982 }
4983
4984 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4985
4986 /* Update the minSyncFactor based on bus type.
4987 */
4988 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4989 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4990
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004991 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304993 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4994 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004995 ioc->name, ioc->spi_data.minSyncFactor));
4996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 }
4998 }
4999 if (pbuf) {
5000 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5001 }
5002 }
5003 }
5004
5005 /* SCSI Port Page 2 - Read the header then the page.
5006 */
5007 header.PageVersion = 0;
5008 header.PageLength = 0;
5009 header.PageNumber = 2;
5010 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005011 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 cfg.physAddr = -1;
5013 cfg.pageAddr = portnum;
5014 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5015 cfg.dir = 0;
5016 if (mpt_config(ioc, &cfg) != 0)
5017 return -EFAULT;
5018
5019 if (header.PageLength > 0) {
5020 /* Allocate memory and read SCSI Port Page 2
5021 */
5022 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5023 if (pbuf) {
5024 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5025 cfg.physAddr = buf_dma;
5026 if (mpt_config(ioc, &cfg) != 0) {
5027 /* Nvram data is left with INVALID mark
5028 */
5029 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005030 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5031
5032 /* This is an ATTO adapter, read Page2 accordingly
5033 */
5034 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5035 ATTODeviceInfo_t *pdevice = NULL;
5036 u16 ATTOFlags;
5037
5038 /* Save the Port Page 2 data
5039 * (reformat into a 32bit quantity)
5040 */
5041 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5042 pdevice = &pPP2->DeviceSettings[ii];
5043 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5044 data = 0;
5045
5046 /* Translate ATTO device flags to LSI format
5047 */
5048 if (ATTOFlags & ATTOFLAG_DISC)
5049 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5050 if (ATTOFlags & ATTOFLAG_ID_ENB)
5051 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5052 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5053 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5054 if (ATTOFlags & ATTOFLAG_TAGGED)
5055 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5056 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5057 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5058
5059 data = (data << 16) | (pdevice->Period << 8) | 10;
5060 ioc->spi_data.nvram[ii] = data;
5061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 } else {
5063 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5064 MpiDeviceInfo_t *pdevice = NULL;
5065
Moore, Ericd8e925d2006-01-16 18:53:06 -07005066 /*
5067 * Save "Set to Avoid SCSI Bus Resets" flag
5068 */
5069 ioc->spi_data.bus_reset =
5070 (le32_to_cpu(pPP2->PortFlags) &
5071 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5072 0 : 1 ;
5073
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 /* Save the Port Page 2 data
5075 * (reformat into a 32bit quantity)
5076 */
5077 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5078 ioc->spi_data.PortFlags = data;
5079 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5080 pdevice = &pPP2->DeviceSettings[ii];
5081 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5082 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5083 ioc->spi_data.nvram[ii] = data;
5084 }
5085 }
5086
5087 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5088 }
5089 }
5090
5091 /* Update Adapter limits with those from NVRAM
5092 * Comment: Don't need to do this. Target performance
5093 * parameters will never exceed the adapters limits.
5094 */
5095
5096 return rc;
5097}
5098
5099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005100/**
5101 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 * @ioc: Pointer to a Adapter Strucutre
5103 * @portnum: IOC port number
5104 *
5105 * Return: -EFAULT if read of config page header fails
5106 * or 0 if success.
5107 */
5108static int
5109mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5110{
5111 CONFIGPARMS cfg;
5112 ConfigPageHeader_t header;
5113
5114 /* Read the SCSI Device Page 1 header
5115 */
5116 header.PageVersion = 0;
5117 header.PageLength = 0;
5118 header.PageNumber = 1;
5119 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005120 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 cfg.physAddr = -1;
5122 cfg.pageAddr = portnum;
5123 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5124 cfg.dir = 0;
5125 cfg.timeout = 0;
5126 if (mpt_config(ioc, &cfg) != 0)
5127 return -EFAULT;
5128
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005129 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5130 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131
5132 header.PageVersion = 0;
5133 header.PageLength = 0;
5134 header.PageNumber = 0;
5135 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5136 if (mpt_config(ioc, &cfg) != 0)
5137 return -EFAULT;
5138
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005139 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5140 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
Prakash, Sathya436ace72007-07-24 15:42:08 +05305142 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5144
Prakash, Sathya436ace72007-07-24 15:42:08 +05305145 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5147 return 0;
5148}
5149
Eric Mooreb506ade2007-01-29 09:45:37 -07005150/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005151 * mpt_inactive_raid_list_free - This clears this link list.
5152 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005153 **/
5154static void
5155mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5156{
5157 struct inactive_raid_component_info *component_info, *pNext;
5158
5159 if (list_empty(&ioc->raid_data.inactive_list))
5160 return;
5161
5162 down(&ioc->raid_data.inactive_list_mutex);
5163 list_for_each_entry_safe(component_info, pNext,
5164 &ioc->raid_data.inactive_list, list) {
5165 list_del(&component_info->list);
5166 kfree(component_info);
5167 }
5168 up(&ioc->raid_data.inactive_list_mutex);
5169}
5170
5171/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005172 * 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 -07005173 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005174 * @ioc : pointer to per adapter structure
5175 * @channel : volume channel
5176 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005177 **/
5178static void
5179mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5180{
5181 CONFIGPARMS cfg;
5182 ConfigPageHeader_t hdr;
5183 dma_addr_t dma_handle;
5184 pRaidVolumePage0_t buffer = NULL;
5185 int i;
5186 RaidPhysDiskPage0_t phys_disk;
5187 struct inactive_raid_component_info *component_info;
5188 int handle_inactive_volumes;
5189
5190 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5191 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5192 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5193 cfg.pageAddr = (channel << 8) + id;
5194 cfg.cfghdr.hdr = &hdr;
5195 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5196
5197 if (mpt_config(ioc, &cfg) != 0)
5198 goto out;
5199
5200 if (!hdr.PageLength)
5201 goto out;
5202
5203 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5204 &dma_handle);
5205
5206 if (!buffer)
5207 goto out;
5208
5209 cfg.physAddr = dma_handle;
5210 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5211
5212 if (mpt_config(ioc, &cfg) != 0)
5213 goto out;
5214
5215 if (!buffer->NumPhysDisks)
5216 goto out;
5217
5218 handle_inactive_volumes =
5219 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5220 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5221 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5222 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5223
5224 if (!handle_inactive_volumes)
5225 goto out;
5226
5227 down(&ioc->raid_data.inactive_list_mutex);
5228 for (i = 0; i < buffer->NumPhysDisks; i++) {
5229 if(mpt_raid_phys_disk_pg0(ioc,
5230 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5231 continue;
5232
5233 if ((component_info = kmalloc(sizeof (*component_info),
5234 GFP_KERNEL)) == NULL)
5235 continue;
5236
5237 component_info->volumeID = id;
5238 component_info->volumeBus = channel;
5239 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5240 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5241 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5242 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5243
5244 list_add_tail(&component_info->list,
5245 &ioc->raid_data.inactive_list);
5246 }
5247 up(&ioc->raid_data.inactive_list_mutex);
5248
5249 out:
5250 if (buffer)
5251 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5252 dma_handle);
5253}
5254
5255/**
5256 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5257 * @ioc: Pointer to a Adapter Structure
5258 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5259 * @phys_disk: requested payload data returned
5260 *
5261 * Return:
5262 * 0 on success
5263 * -EFAULT if read of config page header fails or data pointer not NULL
5264 * -ENOMEM if pci_alloc failed
5265 **/
5266int
5267mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5268{
5269 CONFIGPARMS cfg;
5270 ConfigPageHeader_t hdr;
5271 dma_addr_t dma_handle;
5272 pRaidPhysDiskPage0_t buffer = NULL;
5273 int rc;
5274
5275 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5276 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5277
5278 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5279 cfg.cfghdr.hdr = &hdr;
5280 cfg.physAddr = -1;
5281 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5282
5283 if (mpt_config(ioc, &cfg) != 0) {
5284 rc = -EFAULT;
5285 goto out;
5286 }
5287
5288 if (!hdr.PageLength) {
5289 rc = -EFAULT;
5290 goto out;
5291 }
5292
5293 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5294 &dma_handle);
5295
5296 if (!buffer) {
5297 rc = -ENOMEM;
5298 goto out;
5299 }
5300
5301 cfg.physAddr = dma_handle;
5302 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5303 cfg.pageAddr = phys_disk_num;
5304
5305 if (mpt_config(ioc, &cfg) != 0) {
5306 rc = -EFAULT;
5307 goto out;
5308 }
5309
5310 rc = 0;
5311 memcpy(phys_disk, buffer, sizeof(*buffer));
5312 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5313
5314 out:
5315
5316 if (buffer)
5317 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5318 dma_handle);
5319
5320 return rc;
5321}
5322
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323/**
5324 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5325 * @ioc: Pointer to a Adapter Strucutre
5326 * @portnum: IOC port number
5327 *
5328 * Return:
5329 * 0 on success
5330 * -EFAULT if read of config page header fails or data pointer not NULL
5331 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005332 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333int
5334mpt_findImVolumes(MPT_ADAPTER *ioc)
5335{
5336 IOCPage2_t *pIoc2;
5337 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 dma_addr_t ioc2_dma;
5339 CONFIGPARMS cfg;
5340 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 int rc = 0;
5342 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005343 int i;
5344
5345 if (!ioc->ir_firmware)
5346 return 0;
5347
5348 /* Free the old page
5349 */
5350 kfree(ioc->raid_data.pIocPg2);
5351 ioc->raid_data.pIocPg2 = NULL;
5352 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353
5354 /* Read IOCP2 header then the page.
5355 */
5356 header.PageVersion = 0;
5357 header.PageLength = 0;
5358 header.PageNumber = 2;
5359 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005360 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 cfg.physAddr = -1;
5362 cfg.pageAddr = 0;
5363 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5364 cfg.dir = 0;
5365 cfg.timeout = 0;
5366 if (mpt_config(ioc, &cfg) != 0)
5367 return -EFAULT;
5368
5369 if (header.PageLength == 0)
5370 return -EFAULT;
5371
5372 iocpage2sz = header.PageLength * 4;
5373 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5374 if (!pIoc2)
5375 return -ENOMEM;
5376
5377 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5378 cfg.physAddr = ioc2_dma;
5379 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005380 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
Eric Mooreb506ade2007-01-29 09:45:37 -07005382 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5383 if (!mem)
5384 goto out;
5385
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005387 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Eric Mooreb506ade2007-01-29 09:45:37 -07005389 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390
Eric Mooreb506ade2007-01-29 09:45:37 -07005391 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5392 mpt_inactive_raid_volumes(ioc,
5393 pIoc2->RaidVolume[i].VolumeBus,
5394 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Eric Mooreb506ade2007-01-29 09:45:37 -07005396 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5398
5399 return rc;
5400}
5401
Moore, Ericc972c702006-03-14 09:14:06 -07005402static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5404{
5405 IOCPage3_t *pIoc3;
5406 u8 *mem;
5407 CONFIGPARMS cfg;
5408 ConfigPageHeader_t header;
5409 dma_addr_t ioc3_dma;
5410 int iocpage3sz = 0;
5411
5412 /* Free the old page
5413 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005414 kfree(ioc->raid_data.pIocPg3);
5415 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416
5417 /* There is at least one physical disk.
5418 * Read and save IOC Page 3
5419 */
5420 header.PageVersion = 0;
5421 header.PageLength = 0;
5422 header.PageNumber = 3;
5423 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005424 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 cfg.physAddr = -1;
5426 cfg.pageAddr = 0;
5427 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5428 cfg.dir = 0;
5429 cfg.timeout = 0;
5430 if (mpt_config(ioc, &cfg) != 0)
5431 return 0;
5432
5433 if (header.PageLength == 0)
5434 return 0;
5435
5436 /* Read Header good, alloc memory
5437 */
5438 iocpage3sz = header.PageLength * 4;
5439 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5440 if (!pIoc3)
5441 return 0;
5442
5443 /* Read the Page and save the data
5444 * into malloc'd memory.
5445 */
5446 cfg.physAddr = ioc3_dma;
5447 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5448 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005449 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 if (mem) {
5451 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005452 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 }
5454 }
5455
5456 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5457
5458 return 0;
5459}
5460
5461static void
5462mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5463{
5464 IOCPage4_t *pIoc4;
5465 CONFIGPARMS cfg;
5466 ConfigPageHeader_t header;
5467 dma_addr_t ioc4_dma;
5468 int iocpage4sz;
5469
5470 /* Read and save IOC Page 4
5471 */
5472 header.PageVersion = 0;
5473 header.PageLength = 0;
5474 header.PageNumber = 4;
5475 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005476 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 cfg.physAddr = -1;
5478 cfg.pageAddr = 0;
5479 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5480 cfg.dir = 0;
5481 cfg.timeout = 0;
5482 if (mpt_config(ioc, &cfg) != 0)
5483 return;
5484
5485 if (header.PageLength == 0)
5486 return;
5487
5488 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5489 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5490 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5491 if (!pIoc4)
5492 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005493 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 } else {
5495 ioc4_dma = ioc->spi_data.IocPg4_dma;
5496 iocpage4sz = ioc->spi_data.IocPg4Sz;
5497 }
5498
5499 /* Read the Page into dma memory.
5500 */
5501 cfg.physAddr = ioc4_dma;
5502 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5503 if (mpt_config(ioc, &cfg) == 0) {
5504 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5505 ioc->spi_data.IocPg4_dma = ioc4_dma;
5506 ioc->spi_data.IocPg4Sz = iocpage4sz;
5507 } else {
5508 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5509 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005510 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 }
5512}
5513
5514static void
5515mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5516{
5517 IOCPage1_t *pIoc1;
5518 CONFIGPARMS cfg;
5519 ConfigPageHeader_t header;
5520 dma_addr_t ioc1_dma;
5521 int iocpage1sz = 0;
5522 u32 tmp;
5523
5524 /* Check the Coalescing Timeout in IOC Page 1
5525 */
5526 header.PageVersion = 0;
5527 header.PageLength = 0;
5528 header.PageNumber = 1;
5529 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005530 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 cfg.physAddr = -1;
5532 cfg.pageAddr = 0;
5533 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5534 cfg.dir = 0;
5535 cfg.timeout = 0;
5536 if (mpt_config(ioc, &cfg) != 0)
5537 return;
5538
5539 if (header.PageLength == 0)
5540 return;
5541
5542 /* Read Header good, alloc memory
5543 */
5544 iocpage1sz = header.PageLength * 4;
5545 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5546 if (!pIoc1)
5547 return;
5548
5549 /* Read the Page and check coalescing timeout
5550 */
5551 cfg.physAddr = ioc1_dma;
5552 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5553 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305554
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5556 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5557 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5558
Prakash, Sathya436ace72007-07-24 15:42:08 +05305559 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 ioc->name, tmp));
5561
5562 if (tmp > MPT_COALESCING_TIMEOUT) {
5563 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5564
5565 /* Write NVRAM and current
5566 */
5567 cfg.dir = 1;
5568 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5569 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305570 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 ioc->name, MPT_COALESCING_TIMEOUT));
5572
5573 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5574 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305575 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5576 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 ioc->name, MPT_COALESCING_TIMEOUT));
5578 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305579 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5580 "Reset NVRAM Coalescing Timeout Failed\n",
5581 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 }
5583
5584 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305585 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5586 "Reset of Current Coalescing Timeout Failed!\n",
5587 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 }
5589 }
5590
5591 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305592 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 }
5594 }
5595
5596 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5597
5598 return;
5599}
5600
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305601static void
5602mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5603{
5604 CONFIGPARMS cfg;
5605 ConfigPageHeader_t hdr;
5606 dma_addr_t buf_dma;
5607 ManufacturingPage0_t *pbuf = NULL;
5608
5609 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5610 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5611
5612 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5613 cfg.cfghdr.hdr = &hdr;
5614 cfg.physAddr = -1;
5615 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5616 cfg.timeout = 10;
5617
5618 if (mpt_config(ioc, &cfg) != 0)
5619 goto out;
5620
5621 if (!cfg.cfghdr.hdr->PageLength)
5622 goto out;
5623
5624 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5625 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5626 if (!pbuf)
5627 goto out;
5628
5629 cfg.physAddr = buf_dma;
5630
5631 if (mpt_config(ioc, &cfg) != 0)
5632 goto out;
5633
5634 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5635 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5636 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5637
5638 out:
5639
5640 if (pbuf)
5641 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5642}
5643
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005645/**
5646 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 * @ioc: Pointer to MPT_ADAPTER structure
5648 * @EvSwitch: Event switch flags
5649 */
5650static int
5651SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5652{
5653 EventNotification_t *evnp;
5654
5655 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5656 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305657 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 ioc->name));
5659 return 0;
5660 }
5661 memset(evnp, 0, sizeof(*evnp));
5662
Prakash, Sathya436ace72007-07-24 15:42:08 +05305663 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
5665 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5666 evnp->ChainOffset = 0;
5667 evnp->MsgFlags = 0;
5668 evnp->Switch = EvSwitch;
5669
5670 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5671
5672 return 0;
5673}
5674
5675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5676/**
5677 * SendEventAck - Send EventAck request to MPT adapter.
5678 * @ioc: Pointer to MPT_ADAPTER structure
5679 * @evnp: Pointer to original EventNotification request
5680 */
5681static int
5682SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5683{
5684 EventAck_t *pAck;
5685
5686 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305687 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005688 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 return -1;
5690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691
Prakash, Sathya436ace72007-07-24 15:42:08 +05305692 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693
5694 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5695 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005696 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005698 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 pAck->Event = evnp->Event;
5700 pAck->EventContext = evnp->EventContext;
5701
5702 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5703
5704 return 0;
5705}
5706
5707/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5708/**
5709 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005710 * @ioc: Pointer to an adapter structure
5711 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712 * action, page address, direction, physical address
5713 * and pointer to a configuration page header
5714 * Page header is updated.
5715 *
5716 * Returns 0 for success
5717 * -EPERM if not allowed due to ISR context
5718 * -EAGAIN if no msg frames currently available
5719 * -EFAULT for non-successful reply or no reply (timeout)
5720 */
5721int
5722mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5723{
5724 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005725 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726 MPT_FRAME_HDR *mf;
5727 unsigned long flags;
5728 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005729 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 int in_isr;
5731
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005732 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 * to be in ISR context, because that is fatal!
5734 */
5735 in_isr = in_interrupt();
5736 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305737 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 ioc->name));
5739 return -EPERM;
5740 }
5741
5742 /* Get and Populate a free Frame
5743 */
5744 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305745 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 ioc->name));
5747 return -EAGAIN;
5748 }
5749 pReq = (Config_t *)mf;
5750 pReq->Action = pCfg->action;
5751 pReq->Reserved = 0;
5752 pReq->ChainOffset = 0;
5753 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005754
5755 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 pReq->ExtPageLength = 0;
5757 pReq->ExtPageType = 0;
5758 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005759
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 for (ii=0; ii < 8; ii++)
5761 pReq->Reserved2[ii] = 0;
5762
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005763 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5764 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5765 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5766 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5767
5768 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5769 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5770 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5771 pReq->ExtPageType = pExtHdr->ExtPageType;
5772 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5773
5774 /* Page Length must be treated as a reserved field for the extended header. */
5775 pReq->Header.PageLength = 0;
5776 }
5777
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5779
5780 /* Add a SGE to the config request.
5781 */
5782 if (pCfg->dir)
5783 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5784 else
5785 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5786
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005787 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5788 flagsLength |= pExtHdr->ExtPageLength * 4;
5789
Prakash, Sathya436ace72007-07-24 15:42:08 +05305790 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 +02005791 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5792 }
5793 else {
5794 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5795
Prakash, Sathya436ace72007-07-24 15:42:08 +05305796 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 +02005797 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
5800 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5801
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 /* Append pCfg pointer to end of mf
5803 */
5804 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5805
5806 /* Initalize the timer
5807 */
5808 init_timer(&pCfg->timer);
5809 pCfg->timer.data = (unsigned long) ioc;
5810 pCfg->timer.function = mpt_timer_expired;
5811 pCfg->wait_done = 0;
5812
5813 /* Set the timer; ensure 10 second minimum */
5814 if (pCfg->timeout < 10)
5815 pCfg->timer.expires = jiffies + HZ*10;
5816 else
5817 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5818
5819 /* Add to end of Q, set timer and then issue this command */
5820 spin_lock_irqsave(&ioc->FreeQlock, flags);
5821 list_add_tail(&pCfg->linkage, &ioc->configQ);
5822 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5823
5824 add_timer(&pCfg->timer);
5825 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5826 wait_event(mpt_waitq, pCfg->wait_done);
5827
5828 /* mf has been freed - do not access */
5829
5830 rc = pCfg->status;
5831
5832 return rc;
5833}
5834
5835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005836/**
5837 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 * Used only internal config functionality.
5839 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5840 */
5841static void
5842mpt_timer_expired(unsigned long data)
5843{
5844 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5845
Prakash, Sathya436ace72007-07-24 15:42:08 +05305846 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 /* Perform a FW reload */
5849 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5850 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5851
5852 /* No more processing.
5853 * Hard reset clean-up will wake up
5854 * process and free all resources.
5855 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305856 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
5858 return;
5859}
5860
5861/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005862/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 * mpt_ioc_reset - Base cleanup for hard reset
5864 * @ioc: Pointer to the adapter structure
5865 * @reset_phase: Indicates pre- or post-reset functionality
5866 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005867 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 */
5869static int
5870mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5871{
5872 CONFIGPARMS *pCfg;
5873 unsigned long flags;
5874
Eric Moore29dd3602007-09-14 18:46:51 -06005875 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5876 ": IOC %s_reset routed to MPT base driver!\n",
5877 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5878 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879
5880 if (reset_phase == MPT_IOC_SETUP_RESET) {
5881 ;
5882 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5883 /* If the internal config Q is not empty -
5884 * delete timer. MF resources will be freed when
5885 * the FIFO's are primed.
5886 */
5887 spin_lock_irqsave(&ioc->FreeQlock, flags);
5888 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5889 del_timer(&pCfg->timer);
5890 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5891
5892 } else {
5893 CONFIGPARMS *pNext;
5894
5895 /* Search the configQ for internal commands.
5896 * Flush the Q, and wake up all suspended threads.
5897 */
5898 spin_lock_irqsave(&ioc->FreeQlock, flags);
5899 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5900 list_del(&pCfg->linkage);
5901
5902 pCfg->status = MPT_CONFIG_ERROR;
5903 pCfg->wait_done = 1;
5904 wake_up(&mpt_waitq);
5905 }
5906 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5907 }
5908
5909 return 1; /* currently means nothing really */
5910}
5911
5912
5913#ifdef CONFIG_PROC_FS /* { */
5914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5915/*
5916 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5917 */
5918/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005919/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5921 *
5922 * Returns 0 for success, non-zero for failure.
5923 */
5924static int
5925procmpt_create(void)
5926{
5927 struct proc_dir_entry *ent;
5928
5929 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5930 if (mpt_proc_root_dir == NULL)
5931 return -ENOTDIR;
5932
5933 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5934 if (ent)
5935 ent->read_proc = procmpt_summary_read;
5936
5937 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5938 if (ent)
5939 ent->read_proc = procmpt_version_read;
5940
5941 return 0;
5942}
5943
5944/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005945/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5947 *
5948 * Returns 0 for success, non-zero for failure.
5949 */
5950static void
5951procmpt_destroy(void)
5952{
5953 remove_proc_entry("version", mpt_proc_root_dir);
5954 remove_proc_entry("summary", mpt_proc_root_dir);
5955 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5956}
5957
5958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005959/**
5960 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 * @buf: Pointer to area to write information
5962 * @start: Pointer to start pointer
5963 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005964 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 * @eof: Pointer to EOF integer
5966 * @data: Pointer
5967 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005968 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969 * Returns number of characters written to process performing the read.
5970 */
5971static int
5972procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5973{
5974 MPT_ADAPTER *ioc;
5975 char *out = buf;
5976 int len;
5977
5978 if (data) {
5979 int more = 0;
5980
5981 ioc = data;
5982 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5983
5984 out += more;
5985 } else {
5986 list_for_each_entry(ioc, &ioc_list, list) {
5987 int more = 0;
5988
5989 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5990
5991 out += more;
5992 if ((out-buf) >= request)
5993 break;
5994 }
5995 }
5996
5997 len = out - buf;
5998
5999 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6000}
6001
6002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006003/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 * procmpt_version_read - Handle read request from /proc/mpt/version.
6005 * @buf: Pointer to area to write information
6006 * @start: Pointer to start pointer
6007 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006008 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 * @eof: Pointer to EOF integer
6010 * @data: Pointer
6011 *
6012 * Returns number of characters written to process performing the read.
6013 */
6014static int
6015procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6016{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306017 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006018 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 char *drvname;
6020 int len;
6021
6022 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6023 len += sprintf(buf+len, " Fusion MPT base driver\n");
6024
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006025 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006026 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306028 if (MptCallbacks[cb_idx]) {
6029 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006030 case MPTSPI_DRIVER:
6031 if (!scsi++) drvname = "SPI host";
6032 break;
6033 case MPTFC_DRIVER:
6034 if (!fc++) drvname = "FC host";
6035 break;
6036 case MPTSAS_DRIVER:
6037 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038 break;
6039 case MPTLAN_DRIVER:
6040 if (!lan++) drvname = "LAN";
6041 break;
6042 case MPTSTM_DRIVER:
6043 if (!targ++) drvname = "SCSI target";
6044 break;
6045 case MPTCTL_DRIVER:
6046 if (!ctl++) drvname = "ioctl";
6047 break;
6048 }
6049
6050 if (drvname)
6051 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6052 }
6053 }
6054
6055 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6056}
6057
6058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006059/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6061 * @buf: Pointer to area to write information
6062 * @start: Pointer to start pointer
6063 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006064 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065 * @eof: Pointer to EOF integer
6066 * @data: Pointer
6067 *
6068 * Returns number of characters written to process performing the read.
6069 */
6070static int
6071procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6072{
6073 MPT_ADAPTER *ioc = data;
6074 int len;
6075 char expVer[32];
6076 int sz;
6077 int p;
6078
6079 mpt_get_fw_exp_ver(expVer, ioc);
6080
6081 len = sprintf(buf, "%s:", ioc->name);
6082 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6083 len += sprintf(buf+len, " (f/w download boot flag set)");
6084// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6085// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6086
6087 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6088 ioc->facts.ProductID,
6089 ioc->prod_name);
6090 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6091 if (ioc->facts.FWImageSize)
6092 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6093 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6094 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6095 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6096
6097 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6098 ioc->facts.CurrentHostMfaHighAddr);
6099 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6100 ioc->facts.CurrentSenseBufferHighAddr);
6101
6102 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6103 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6104
6105 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6106 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6107 /*
6108 * Rounding UP to nearest 4-kB boundary here...
6109 */
6110 sz = (ioc->req_sz * ioc->req_depth) + 128;
6111 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6112 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6113 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6114 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6115 4*ioc->facts.RequestFrameSize,
6116 ioc->facts.GlobalCredits);
6117
6118 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6119 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6120 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6121 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6122 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6123 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6124 ioc->facts.CurReplyFrameSize,
6125 ioc->facts.ReplyQueueDepth);
6126
6127 len += sprintf(buf+len, " MaxDevices = %d\n",
6128 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6129 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6130
6131 /* per-port info */
6132 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6133 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6134 p+1,
6135 ioc->facts.NumberOfPorts);
6136 if (ioc->bus_type == FC) {
6137 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6138 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6139 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6140 a[5], a[4], a[3], a[2], a[1], a[0]);
6141 }
6142 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6143 ioc->fc_port_page0[p].WWNN.High,
6144 ioc->fc_port_page0[p].WWNN.Low,
6145 ioc->fc_port_page0[p].WWPN.High,
6146 ioc->fc_port_page0[p].WWPN.Low);
6147 }
6148 }
6149
6150 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6151}
6152
6153#endif /* CONFIG_PROC_FS } */
6154
6155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6156static void
6157mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6158{
6159 buf[0] ='\0';
6160 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6161 sprintf(buf, " (Exp %02d%02d)",
6162 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6163 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6164
6165 /* insider hack! */
6166 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6167 strcat(buf, " [MDBG]");
6168 }
6169}
6170
6171/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6172/**
6173 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6174 * @ioc: Pointer to MPT_ADAPTER structure
6175 * @buffer: Pointer to buffer where IOC summary info should be written
6176 * @size: Pointer to number of bytes we wrote (set by this routine)
6177 * @len: Offset at which to start writing in buffer
6178 * @showlan: Display LAN stuff?
6179 *
6180 * This routine writes (english readable) ASCII text, which represents
6181 * a summary of IOC information, to a buffer.
6182 */
6183void
6184mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6185{
6186 char expVer[32];
6187 int y;
6188
6189 mpt_get_fw_exp_ver(expVer, ioc);
6190
6191 /*
6192 * Shorter summary of attached ioc's...
6193 */
6194 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6195 ioc->name,
6196 ioc->prod_name,
6197 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6198 ioc->facts.FWVersion.Word,
6199 expVer,
6200 ioc->facts.NumberOfPorts,
6201 ioc->req_depth);
6202
6203 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6204 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6205 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6206 a[5], a[4], a[3], a[2], a[1], a[0]);
6207 }
6208
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210
6211 if (!ioc->active)
6212 y += sprintf(buffer+len+y, " (disabled)");
6213
6214 y += sprintf(buffer+len+y, "\n");
6215
6216 *size = y;
6217}
6218
6219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6220/*
6221 * Reset Handling
6222 */
6223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6224/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006225 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 * @ioc: Pointer to MPT_ADAPTER structure
6227 * @sleepFlag: Indicates if sleep or schedule must be called.
6228 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006229 * Issues SCSI Task Management call based on input arg values.
6230 * If TaskMgmt fails, returns associated SCSI request.
6231 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6233 * or a non-interrupt thread. In the former, must not call schedule().
6234 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006235 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236 * FW reload/initialization failed.
6237 *
6238 * Returns 0 for SUCCESS or -1 if FAILED.
6239 */
6240int
6241mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6242{
6243 int rc;
6244 unsigned long flags;
6245
Prakash, Sathya436ace72007-07-24 15:42:08 +05306246 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247#ifdef MFCNT
6248 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6249 printk("MF count 0x%x !\n", ioc->mfcnt);
6250#endif
6251
6252 /* Reset the adapter. Prevent more than 1 call to
6253 * mpt_do_ioc_recovery at any instant in time.
6254 */
6255 spin_lock_irqsave(&ioc->diagLock, flags);
6256 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6257 spin_unlock_irqrestore(&ioc->diagLock, flags);
6258 return 0;
6259 } else {
6260 ioc->diagPending = 1;
6261 }
6262 spin_unlock_irqrestore(&ioc->diagLock, flags);
6263
6264 /* FIXME: If do_ioc_recovery fails, repeat....
6265 */
6266
6267 /* The SCSI driver needs to adjust timeouts on all current
6268 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006269 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 * For all other protocol drivers, this is a no-op.
6271 */
6272 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306273 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 int r = 0;
6275
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306276 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6277 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306278 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306279 ioc->name, cb_idx));
6280 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306282 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306283 ioc->name, ioc->alt_ioc->name, cb_idx));
6284 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 }
6286 }
6287 }
6288 }
6289
6290 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006291 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 }
6293 ioc->reload_fw = 0;
6294 if (ioc->alt_ioc)
6295 ioc->alt_ioc->reload_fw = 0;
6296
6297 spin_lock_irqsave(&ioc->diagLock, flags);
6298 ioc->diagPending = 0;
6299 if (ioc->alt_ioc)
6300 ioc->alt_ioc->diagPending = 0;
6301 spin_unlock_irqrestore(&ioc->diagLock, flags);
6302
Prakash, Sathya436ace72007-07-24 15:42:08 +05306303 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304
6305 return rc;
6306}
6307
6308/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006309static void
6310EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311{
Eric Moore509e5e52006-04-26 13:22:37 -06006312 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313
6314 switch(event) {
6315 case MPI_EVENT_NONE:
6316 ds = "None";
6317 break;
6318 case MPI_EVENT_LOG_DATA:
6319 ds = "Log Data";
6320 break;
6321 case MPI_EVENT_STATE_CHANGE:
6322 ds = "State Change";
6323 break;
6324 case MPI_EVENT_UNIT_ATTENTION:
6325 ds = "Unit Attention";
6326 break;
6327 case MPI_EVENT_IOC_BUS_RESET:
6328 ds = "IOC Bus Reset";
6329 break;
6330 case MPI_EVENT_EXT_BUS_RESET:
6331 ds = "External Bus Reset";
6332 break;
6333 case MPI_EVENT_RESCAN:
6334 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 break;
6336 case MPI_EVENT_LINK_STATUS_CHANGE:
6337 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6338 ds = "Link Status(FAILURE) Change";
6339 else
6340 ds = "Link Status(ACTIVE) Change";
6341 break;
6342 case MPI_EVENT_LOOP_STATE_CHANGE:
6343 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6344 ds = "Loop State(LIP) Change";
6345 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006346 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 else
Eric Moore509e5e52006-04-26 13:22:37 -06006348 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 break;
6350 case MPI_EVENT_LOGOUT:
6351 ds = "Logout";
6352 break;
6353 case MPI_EVENT_EVENT_CHANGE:
6354 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006355 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006357 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 break;
6359 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006360 {
6361 u8 ReasonCode = (u8)(evData0 >> 16);
6362 switch (ReasonCode) {
6363 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6364 ds = "Integrated Raid: Volume Created";
6365 break;
6366 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6367 ds = "Integrated Raid: Volume Deleted";
6368 break;
6369 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6370 ds = "Integrated Raid: Volume Settings Changed";
6371 break;
6372 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6373 ds = "Integrated Raid: Volume Status Changed";
6374 break;
6375 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6376 ds = "Integrated Raid: Volume Physdisk Changed";
6377 break;
6378 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6379 ds = "Integrated Raid: Physdisk Created";
6380 break;
6381 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6382 ds = "Integrated Raid: Physdisk Deleted";
6383 break;
6384 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6385 ds = "Integrated Raid: Physdisk Settings Changed";
6386 break;
6387 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6388 ds = "Integrated Raid: Physdisk Status Changed";
6389 break;
6390 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6391 ds = "Integrated Raid: Domain Validation Needed";
6392 break;
6393 case MPI_EVENT_RAID_RC_SMART_DATA :
6394 ds = "Integrated Raid; Smart Data";
6395 break;
6396 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6397 ds = "Integrated Raid: Replace Action Started";
6398 break;
6399 default:
6400 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006402 }
6403 break;
6404 }
6405 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6406 ds = "SCSI Device Status Change";
6407 break;
6408 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6409 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006410 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006411 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006412 u8 ReasonCode = (u8)(evData0 >> 16);
6413 switch (ReasonCode) {
6414 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006415 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006416 "SAS Device Status Change: Added: "
6417 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006418 break;
6419 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006420 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006421 "SAS Device Status Change: Deleted: "
6422 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006423 break;
6424 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006425 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006426 "SAS Device Status Change: SMART Data: "
6427 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006428 break;
6429 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006430 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006431 "SAS Device Status Change: No Persistancy: "
6432 "id=%d channel=%d", id, channel);
6433 break;
6434 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6435 snprintf(evStr, EVENT_DESCR_STR_SZ,
6436 "SAS Device Status Change: Unsupported Device "
6437 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006438 break;
6439 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6440 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006441 "SAS Device Status Change: Internal Device "
6442 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006443 break;
6444 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6445 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006446 "SAS Device Status Change: Internal Task "
6447 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006448 break;
6449 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6450 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006451 "SAS Device Status Change: Internal Abort "
6452 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006453 break;
6454 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6455 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006456 "SAS Device Status Change: Internal Clear "
6457 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006458 break;
6459 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6460 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006461 "SAS Device Status Change: Internal Query "
6462 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006463 break;
6464 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006465 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006466 "SAS Device Status Change: Unknown: "
6467 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006468 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006469 }
6470 break;
6471 }
6472 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6473 ds = "Bus Timer Expired";
6474 break;
6475 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006476 {
6477 u16 curr_depth = (u16)(evData0 >> 16);
6478 u8 channel = (u8)(evData0 >> 8);
6479 u8 id = (u8)(evData0);
6480
6481 snprintf(evStr, EVENT_DESCR_STR_SZ,
6482 "Queue Full: channel=%d id=%d depth=%d",
6483 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006484 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006485 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006486 case MPI_EVENT_SAS_SES:
6487 ds = "SAS SES Event";
6488 break;
6489 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6490 ds = "Persistent Table Full";
6491 break;
6492 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006493 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006494 u8 LinkRates = (u8)(evData0 >> 8);
6495 u8 PhyNumber = (u8)(evData0);
6496 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6497 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6498 switch (LinkRates) {
6499 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006500 snprintf(evStr, EVENT_DESCR_STR_SZ,
6501 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006502 " Rate Unknown",PhyNumber);
6503 break;
6504 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006505 snprintf(evStr, EVENT_DESCR_STR_SZ,
6506 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006507 " Phy Disabled",PhyNumber);
6508 break;
6509 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006510 snprintf(evStr, EVENT_DESCR_STR_SZ,
6511 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006512 " Failed Speed Nego",PhyNumber);
6513 break;
6514 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006515 snprintf(evStr, EVENT_DESCR_STR_SZ,
6516 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006517 " Sata OOB Completed",PhyNumber);
6518 break;
6519 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006520 snprintf(evStr, EVENT_DESCR_STR_SZ,
6521 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006522 " Rate 1.5 Gbps",PhyNumber);
6523 break;
6524 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006525 snprintf(evStr, EVENT_DESCR_STR_SZ,
6526 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006527 " Rate 3.0 Gpbs",PhyNumber);
6528 break;
6529 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006530 snprintf(evStr, EVENT_DESCR_STR_SZ,
6531 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006532 break;
6533 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006534 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006535 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006536 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6537 ds = "SAS Discovery Error";
6538 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006539 case MPI_EVENT_IR_RESYNC_UPDATE:
6540 {
6541 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006542 snprintf(evStr, EVENT_DESCR_STR_SZ,
6543 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006544 break;
6545 }
6546 case MPI_EVENT_IR2:
6547 {
6548 u8 ReasonCode = (u8)(evData0 >> 16);
6549 switch (ReasonCode) {
6550 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6551 ds = "IR2: LD State Changed";
6552 break;
6553 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6554 ds = "IR2: PD State Changed";
6555 break;
6556 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6557 ds = "IR2: Bad Block Table Full";
6558 break;
6559 case MPI_EVENT_IR2_RC_PD_INSERTED:
6560 ds = "IR2: PD Inserted";
6561 break;
6562 case MPI_EVENT_IR2_RC_PD_REMOVED:
6563 ds = "IR2: PD Removed";
6564 break;
6565 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6566 ds = "IR2: Foreign CFG Detected";
6567 break;
6568 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6569 ds = "IR2: Rebuild Medium Error";
6570 break;
6571 default:
6572 ds = "IR2";
6573 break;
6574 }
6575 break;
6576 }
6577 case MPI_EVENT_SAS_DISCOVERY:
6578 {
6579 if (evData0)
6580 ds = "SAS Discovery: Start";
6581 else
6582 ds = "SAS Discovery: Stop";
6583 break;
6584 }
6585 case MPI_EVENT_LOG_ENTRY_ADDED:
6586 ds = "SAS Log Entry Added";
6587 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006588
Eric Moorec6c727a2007-01-29 09:44:54 -07006589 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6590 {
6591 u8 phy_num = (u8)(evData0);
6592 u8 port_num = (u8)(evData0 >> 8);
6593 u8 port_width = (u8)(evData0 >> 16);
6594 u8 primative = (u8)(evData0 >> 24);
6595 snprintf(evStr, EVENT_DESCR_STR_SZ,
6596 "SAS Broadcase Primative: phy=%d port=%d "
6597 "width=%d primative=0x%02x",
6598 phy_num, port_num, port_width, primative);
6599 break;
6600 }
6601
6602 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6603 {
6604 u8 reason = (u8)(evData0);
6605 u8 port_num = (u8)(evData0 >> 8);
6606 u16 handle = le16_to_cpu(evData0 >> 16);
6607
6608 snprintf(evStr, EVENT_DESCR_STR_SZ,
6609 "SAS Initiator Device Status Change: reason=0x%02x "
6610 "port=%d handle=0x%04x",
6611 reason, port_num, handle);
6612 break;
6613 }
6614
6615 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6616 {
6617 u8 max_init = (u8)(evData0);
6618 u8 current_init = (u8)(evData0 >> 8);
6619
6620 snprintf(evStr, EVENT_DESCR_STR_SZ,
6621 "SAS Initiator Device Table Overflow: max initiators=%02d "
6622 "current initators=%02d",
6623 max_init, current_init);
6624 break;
6625 }
6626 case MPI_EVENT_SAS_SMP_ERROR:
6627 {
6628 u8 status = (u8)(evData0);
6629 u8 port_num = (u8)(evData0 >> 8);
6630 u8 result = (u8)(evData0 >> 16);
6631
6632 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6633 snprintf(evStr, EVENT_DESCR_STR_SZ,
6634 "SAS SMP Error: port=%d result=0x%02x",
6635 port_num, result);
6636 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6637 snprintf(evStr, EVENT_DESCR_STR_SZ,
6638 "SAS SMP Error: port=%d : CRC Error",
6639 port_num);
6640 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6641 snprintf(evStr, EVENT_DESCR_STR_SZ,
6642 "SAS SMP Error: port=%d : Timeout",
6643 port_num);
6644 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6645 snprintf(evStr, EVENT_DESCR_STR_SZ,
6646 "SAS SMP Error: port=%d : No Destination",
6647 port_num);
6648 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6649 snprintf(evStr, EVENT_DESCR_STR_SZ,
6650 "SAS SMP Error: port=%d : Bad Destination",
6651 port_num);
6652 else
6653 snprintf(evStr, EVENT_DESCR_STR_SZ,
6654 "SAS SMP Error: port=%d : status=0x%02x",
6655 port_num, status);
6656 break;
6657 }
6658
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659 /*
6660 * MPT base "custom" events may be added here...
6661 */
6662 default:
6663 ds = "Unknown";
6664 break;
6665 }
Eric Moore509e5e52006-04-26 13:22:37 -06006666 if (ds)
6667 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668}
6669
6670/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006671/**
6672 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673 * @ioc: Pointer to MPT_ADAPTER structure
6674 * @pEventReply: Pointer to EventNotification reply frame
6675 * @evHandlers: Pointer to integer, number of event handlers
6676 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006677 * Routes a received EventNotificationReply to all currently registered
6678 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679 * Returns sum of event handlers return values.
6680 */
6681static int
6682ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6683{
6684 u16 evDataLen;
6685 u32 evData0 = 0;
6686// u32 evCtx;
6687 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306688 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689 int r = 0;
6690 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006691 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692 u8 event;
6693
6694 /*
6695 * Do platform normalization of values
6696 */
6697 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6698// evCtx = le32_to_cpu(pEventReply->EventContext);
6699 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6700 if (evDataLen) {
6701 evData0 = le32_to_cpu(pEventReply->Data[0]);
6702 }
6703
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006704 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306705 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006707 event,
6708 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006709
Prakash, Sathya436ace72007-07-24 15:42:08 +05306710#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006711 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6712 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306714 devtverboseprintk(ioc, printk(" %08x",
6715 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006716 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717#endif
6718
6719 /*
6720 * Do general / base driver event processing
6721 */
6722 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6724 if (evDataLen) {
6725 u8 evState = evData0 & 0xFF;
6726
6727 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6728
6729 /* Update EventState field in cached IocFacts */
6730 if (ioc->facts.Function) {
6731 ioc->facts.EventState = evState;
6732 }
6733 }
6734 break;
Moore, Ericece50912006-01-16 18:53:19 -07006735 case MPI_EVENT_INTEGRATED_RAID:
6736 mptbase_raid_process_event_data(ioc,
6737 (MpiEventDataRaid_t *)pEventReply->Data);
6738 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006739 default:
6740 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006741 }
6742
6743 /*
6744 * Should this event be logged? Events are written sequentially.
6745 * When buffer is full, start again at the top.
6746 */
6747 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6748 int idx;
6749
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006750 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
6752 ioc->events[idx].event = event;
6753 ioc->events[idx].eventContext = ioc->eventContext;
6754
6755 for (ii = 0; ii < 2; ii++) {
6756 if (ii < evDataLen)
6757 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6758 else
6759 ioc->events[idx].data[ii] = 0;
6760 }
6761
6762 ioc->eventContext++;
6763 }
6764
6765
6766 /*
6767 * Call each currently registered protocol event handler.
6768 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006769 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306770 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306771 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306772 ioc->name, cb_idx));
6773 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006774 handlers++;
6775 }
6776 }
6777 /* FIXME? Examine results here? */
6778
6779 /*
6780 * If needed, send (a single) EventAck.
6781 */
6782 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306783 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006784 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306786 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787 ioc->name, ii));
6788 }
6789 }
6790
6791 *evHandlers = handlers;
6792 return r;
6793}
6794
6795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006796/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6798 * @ioc: Pointer to MPT_ADAPTER structure
6799 * @log_info: U32 LogInfo reply word from the IOC
6800 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006801 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006802 */
6803static void
6804mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6805{
Eric Moore7c431e52007-06-13 16:34:36 -06006806 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807
Eric Moore7c431e52007-06-13 16:34:36 -06006808 switch (log_info & 0xFF000000) {
6809 case MPI_IOCLOGINFO_FC_INIT_BASE:
6810 desc = "FCP Initiator";
6811 break;
6812 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6813 desc = "FCP Target";
6814 break;
6815 case MPI_IOCLOGINFO_FC_LAN_BASE:
6816 desc = "LAN";
6817 break;
6818 case MPI_IOCLOGINFO_FC_MSG_BASE:
6819 desc = "MPI Message Layer";
6820 break;
6821 case MPI_IOCLOGINFO_FC_LINK_BASE:
6822 desc = "FC Link";
6823 break;
6824 case MPI_IOCLOGINFO_FC_CTX_BASE:
6825 desc = "Context Manager";
6826 break;
6827 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6828 desc = "Invalid Field Offset";
6829 break;
6830 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6831 desc = "State Change Info";
6832 break;
6833 }
6834
6835 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6836 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837}
6838
6839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006840/**
Moore, Eric335a9412006-01-17 17:06:23 -07006841 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006842 * @ioc: Pointer to MPT_ADAPTER structure
6843 * @mr: Pointer to MPT reply frame
6844 * @log_info: U32 LogInfo word from the IOC
6845 *
6846 * Refer to lsi/sp_log.h.
6847 */
6848static void
Moore, Eric335a9412006-01-17 17:06:23 -07006849mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850{
6851 u32 info = log_info & 0x00FF0000;
6852 char *desc = "unknown";
6853
6854 switch (info) {
6855 case 0x00010000:
6856 desc = "bug! MID not found";
6857 if (ioc->reload_fw == 0)
6858 ioc->reload_fw++;
6859 break;
6860
6861 case 0x00020000:
6862 desc = "Parity Error";
6863 break;
6864
6865 case 0x00030000:
6866 desc = "ASYNC Outbound Overrun";
6867 break;
6868
6869 case 0x00040000:
6870 desc = "SYNC Offset Error";
6871 break;
6872
6873 case 0x00050000:
6874 desc = "BM Change";
6875 break;
6876
6877 case 0x00060000:
6878 desc = "Msg In Overflow";
6879 break;
6880
6881 case 0x00070000:
6882 desc = "DMA Error";
6883 break;
6884
6885 case 0x00080000:
6886 desc = "Outbound DMA Overrun";
6887 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006888
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889 case 0x00090000:
6890 desc = "Task Management";
6891 break;
6892
6893 case 0x000A0000:
6894 desc = "Device Problem";
6895 break;
6896
6897 case 0x000B0000:
6898 desc = "Invalid Phase Change";
6899 break;
6900
6901 case 0x000C0000:
6902 desc = "Untagged Table Size";
6903 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006904
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905 }
6906
6907 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6908}
6909
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006910/* strings for sas loginfo */
6911 static char *originator_str[] = {
6912 "IOP", /* 00h */
6913 "PL", /* 01h */
6914 "IR" /* 02h */
6915 };
6916 static char *iop_code_str[] = {
6917 NULL, /* 00h */
6918 "Invalid SAS Address", /* 01h */
6919 NULL, /* 02h */
6920 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006921 "Diag Message Error", /* 04h */
6922 "Task Terminated", /* 05h */
6923 "Enclosure Management", /* 06h */
6924 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006925 };
6926 static char *pl_code_str[] = {
6927 NULL, /* 00h */
6928 "Open Failure", /* 01h */
6929 "Invalid Scatter Gather List", /* 02h */
6930 "Wrong Relative Offset or Frame Length", /* 03h */
6931 "Frame Transfer Error", /* 04h */
6932 "Transmit Frame Connected Low", /* 05h */
6933 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6934 "SATA Read Log Receive Data Error", /* 07h */
6935 "SATA NCQ Fail All Commands After Error", /* 08h */
6936 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6937 "Receive Frame Invalid Message", /* 0Ah */
6938 "Receive Context Message Valid Error", /* 0Bh */
6939 "Receive Frame Current Frame Error", /* 0Ch */
6940 "SATA Link Down", /* 0Dh */
6941 "Discovery SATA Init W IOS", /* 0Eh */
6942 "Config Invalid Page", /* 0Fh */
6943 "Discovery SATA Init Timeout", /* 10h */
6944 "Reset", /* 11h */
6945 "Abort", /* 12h */
6946 "IO Not Yet Executed", /* 13h */
6947 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006948 "Persistent Reservation Out Not Affiliation "
6949 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006950 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006951 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006952 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006953 NULL, /* 19h */
6954 NULL, /* 1Ah */
6955 NULL, /* 1Bh */
6956 NULL, /* 1Ch */
6957 NULL, /* 1Dh */
6958 NULL, /* 1Eh */
6959 NULL, /* 1Fh */
6960 "Enclosure Management" /* 20h */
6961 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006962 static char *ir_code_str[] = {
6963 "Raid Action Error", /* 00h */
6964 NULL, /* 00h */
6965 NULL, /* 01h */
6966 NULL, /* 02h */
6967 NULL, /* 03h */
6968 NULL, /* 04h */
6969 NULL, /* 05h */
6970 NULL, /* 06h */
6971 NULL /* 07h */
6972 };
6973 static char *raid_sub_code_str[] = {
6974 NULL, /* 00h */
6975 "Volume Creation Failed: Data Passed too "
6976 "Large", /* 01h */
6977 "Volume Creation Failed: Duplicate Volumes "
6978 "Attempted", /* 02h */
6979 "Volume Creation Failed: Max Number "
6980 "Supported Volumes Exceeded", /* 03h */
6981 "Volume Creation Failed: DMA Error", /* 04h */
6982 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6983 "Volume Creation Failed: Error Reading "
6984 "MFG Page 4", /* 06h */
6985 "Volume Creation Failed: Creating Internal "
6986 "Structures", /* 07h */
6987 NULL, /* 08h */
6988 NULL, /* 09h */
6989 NULL, /* 0Ah */
6990 NULL, /* 0Bh */
6991 NULL, /* 0Ch */
6992 NULL, /* 0Dh */
6993 NULL, /* 0Eh */
6994 NULL, /* 0Fh */
6995 "Activation failed: Already Active Volume", /* 10h */
6996 "Activation failed: Unsupported Volume Type", /* 11h */
6997 "Activation failed: Too Many Active Volumes", /* 12h */
6998 "Activation failed: Volume ID in Use", /* 13h */
6999 "Activation failed: Reported Failure", /* 14h */
7000 "Activation failed: Importing a Volume", /* 15h */
7001 NULL, /* 16h */
7002 NULL, /* 17h */
7003 NULL, /* 18h */
7004 NULL, /* 19h */
7005 NULL, /* 1Ah */
7006 NULL, /* 1Bh */
7007 NULL, /* 1Ch */
7008 NULL, /* 1Dh */
7009 NULL, /* 1Eh */
7010 NULL, /* 1Fh */
7011 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7012 "Phys Disk failed: Data Passed too Large", /* 21h */
7013 "Phys Disk failed: DMA Error", /* 22h */
7014 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7015 "Phys Disk failed: Creating Phys Disk Config "
7016 "Page", /* 24h */
7017 NULL, /* 25h */
7018 NULL, /* 26h */
7019 NULL, /* 27h */
7020 NULL, /* 28h */
7021 NULL, /* 29h */
7022 NULL, /* 2Ah */
7023 NULL, /* 2Bh */
7024 NULL, /* 2Ch */
7025 NULL, /* 2Dh */
7026 NULL, /* 2Eh */
7027 NULL, /* 2Fh */
7028 "Compatibility Error: IR Disabled", /* 30h */
7029 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7030 "Compatibility Error: Device not Direct Access "
7031 "Device ", /* 32h */
7032 "Compatibility Error: Removable Device Found", /* 33h */
7033 "Compatibility Error: Device SCSI Version not "
7034 "2 or Higher", /* 34h */
7035 "Compatibility Error: SATA Device, 48 BIT LBA "
7036 "not Supported", /* 35h */
7037 "Compatibility Error: Device doesn't have "
7038 "512 Byte Block Sizes", /* 36h */
7039 "Compatibility Error: Volume Type Check Failed", /* 37h */
7040 "Compatibility Error: Volume Type is "
7041 "Unsupported by FW", /* 38h */
7042 "Compatibility Error: Disk Drive too Small for "
7043 "use in Volume", /* 39h */
7044 "Compatibility Error: Phys Disk for Create "
7045 "Volume not Found", /* 3Ah */
7046 "Compatibility Error: Too Many or too Few "
7047 "Disks for Volume Type", /* 3Bh */
7048 "Compatibility Error: Disk stripe Sizes "
7049 "Must be 64KB", /* 3Ch */
7050 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7051 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007052
7053/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007054/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007055 * mpt_sas_log_info - Log information returned from SAS IOC.
7056 * @ioc: Pointer to MPT_ADAPTER structure
7057 * @log_info: U32 LogInfo reply word from the IOC
7058 *
7059 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007060 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007061static void
7062mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7063{
7064union loginfo_type {
7065 u32 loginfo;
7066 struct {
7067 u32 subcode:16;
7068 u32 code:8;
7069 u32 originator:4;
7070 u32 bus_type:4;
7071 }dw;
7072};
7073 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007074 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007075 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007076 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007077
7078 sas_loginfo.loginfo = log_info;
7079 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7080 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7081 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007082
7083 originator_desc = originator_str[sas_loginfo.dw.originator];
7084
7085 switch (sas_loginfo.dw.originator) {
7086
7087 case 0: /* IOP */
7088 if (sas_loginfo.dw.code <
7089 sizeof(iop_code_str)/sizeof(char*))
7090 code_desc = iop_code_str[sas_loginfo.dw.code];
7091 break;
7092 case 1: /* PL */
7093 if (sas_loginfo.dw.code <
7094 sizeof(pl_code_str)/sizeof(char*))
7095 code_desc = pl_code_str[sas_loginfo.dw.code];
7096 break;
7097 case 2: /* IR */
7098 if (sas_loginfo.dw.code >=
7099 sizeof(ir_code_str)/sizeof(char*))
7100 break;
7101 code_desc = ir_code_str[sas_loginfo.dw.code];
7102 if (sas_loginfo.dw.subcode >=
7103 sizeof(raid_sub_code_str)/sizeof(char*))
7104 break;
7105 if (sas_loginfo.dw.code == 0)
7106 sub_code_desc =
7107 raid_sub_code_str[sas_loginfo.dw.subcode];
7108 break;
7109 default:
7110 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007111 }
7112
Eric Moorec6c727a2007-01-29 09:44:54 -07007113 if (sub_code_desc != NULL)
7114 printk(MYIOC_s_INFO_FMT
7115 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7116 " SubCode={%s}\n",
7117 ioc->name, log_info, originator_desc, code_desc,
7118 sub_code_desc);
7119 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007120 printk(MYIOC_s_INFO_FMT
7121 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7122 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007123 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007124 sas_loginfo.dw.subcode);
7125 else
7126 printk(MYIOC_s_INFO_FMT
7127 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7128 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007129 ioc->name, log_info, originator_desc,
7130 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007131}
7132
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007134/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007135 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7136 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007137 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007138 * @mf: Pointer to MPT request frame
7139 *
7140 * Refer to lsi/mpi.h.
7141 **/
7142static void
7143mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7144{
7145 Config_t *pReq = (Config_t *)mf;
7146 char extend_desc[EVENT_DESCR_STR_SZ];
7147 char *desc = NULL;
7148 u32 form;
7149 u8 page_type;
7150
7151 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7152 page_type = pReq->ExtPageType;
7153 else
7154 page_type = pReq->Header.PageType;
7155
7156 /*
7157 * ignore invalid page messages for GET_NEXT_HANDLE
7158 */
7159 form = le32_to_cpu(pReq->PageAddress);
7160 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7161 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7162 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7163 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7164 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7165 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7166 return;
7167 }
7168 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7169 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7170 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7171 return;
7172 }
7173
7174 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7175 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7176 page_type, pReq->Header.PageNumber, pReq->Action, form);
7177
7178 switch (ioc_status) {
7179
7180 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7181 desc = "Config Page Invalid Action";
7182 break;
7183
7184 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7185 desc = "Config Page Invalid Type";
7186 break;
7187
7188 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7189 desc = "Config Page Invalid Page";
7190 break;
7191
7192 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7193 desc = "Config Page Invalid Data";
7194 break;
7195
7196 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7197 desc = "Config Page No Defaults";
7198 break;
7199
7200 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7201 desc = "Config Page Can't Commit";
7202 break;
7203 }
7204
7205 if (!desc)
7206 return;
7207
Eric Moore29dd3602007-09-14 18:46:51 -06007208 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7209 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007210}
7211
7212/**
7213 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214 * @ioc: Pointer to MPT_ADAPTER structure
7215 * @ioc_status: U32 IOCStatus word from IOC
7216 * @mf: Pointer to MPT request frame
7217 *
7218 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007219 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007221mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222{
7223 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007224 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007225
7226 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007227
7228/****************************************************************************/
7229/* Common IOCStatus values for all replies */
7230/****************************************************************************/
7231
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7233 desc = "Invalid Function";
7234 break;
7235
7236 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7237 desc = "Busy";
7238 break;
7239
7240 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7241 desc = "Invalid SGL";
7242 break;
7243
7244 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7245 desc = "Internal Error";
7246 break;
7247
7248 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7249 desc = "Reserved";
7250 break;
7251
7252 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7253 desc = "Insufficient Resources";
7254 break;
7255
7256 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7257 desc = "Invalid Field";
7258 break;
7259
7260 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7261 desc = "Invalid State";
7262 break;
7263
Eric Moorec6c727a2007-01-29 09:44:54 -07007264/****************************************************************************/
7265/* Config IOCStatus values */
7266/****************************************************************************/
7267
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7269 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7270 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7271 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7272 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7273 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007274 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007275 break;
7276
Eric Moorec6c727a2007-01-29 09:44:54 -07007277/****************************************************************************/
7278/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7279/* */
7280/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7281/* */
7282/****************************************************************************/
7283
Linus Torvalds1da177e2005-04-16 15:20:36 -07007284 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007285 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007286 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7287 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7288 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7289 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007291 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007295 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007296 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297 break;
7298
Eric Moorec6c727a2007-01-29 09:44:54 -07007299/****************************************************************************/
7300/* SCSI Target values */
7301/****************************************************************************/
7302
7303 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7304 desc = "Target: Priority IO";
7305 break;
7306
7307 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7308 desc = "Target: Invalid Port";
7309 break;
7310
7311 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7312 desc = "Target Invalid IO Index:";
7313 break;
7314
7315 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7316 desc = "Target: Aborted";
7317 break;
7318
7319 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7320 desc = "Target: No Conn Retryable";
7321 break;
7322
7323 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7324 desc = "Target: No Connection";
7325 break;
7326
7327 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7328 desc = "Target: Transfer Count Mismatch";
7329 break;
7330
7331 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7332 desc = "Target: STS Data not Sent";
7333 break;
7334
7335 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7336 desc = "Target: Data Offset Error";
7337 break;
7338
7339 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7340 desc = "Target: Too Much Write Data";
7341 break;
7342
7343 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7344 desc = "Target: IU Too Short";
7345 break;
7346
7347 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7348 desc = "Target: ACK NAK Timeout";
7349 break;
7350
7351 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7352 desc = "Target: Nak Received";
7353 break;
7354
7355/****************************************************************************/
7356/* Fibre Channel Direct Access values */
7357/****************************************************************************/
7358
7359 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7360 desc = "FC: Aborted";
7361 break;
7362
7363 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7364 desc = "FC: RX ID Invalid";
7365 break;
7366
7367 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7368 desc = "FC: DID Invalid";
7369 break;
7370
7371 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7372 desc = "FC: Node Logged Out";
7373 break;
7374
7375 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7376 desc = "FC: Exchange Canceled";
7377 break;
7378
7379/****************************************************************************/
7380/* LAN values */
7381/****************************************************************************/
7382
7383 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7384 desc = "LAN: Device not Found";
7385 break;
7386
7387 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7388 desc = "LAN: Device Failure";
7389 break;
7390
7391 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7392 desc = "LAN: Transmit Error";
7393 break;
7394
7395 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7396 desc = "LAN: Transmit Aborted";
7397 break;
7398
7399 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7400 desc = "LAN: Receive Error";
7401 break;
7402
7403 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7404 desc = "LAN: Receive Aborted";
7405 break;
7406
7407 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7408 desc = "LAN: Partial Packet";
7409 break;
7410
7411 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7412 desc = "LAN: Canceled";
7413 break;
7414
7415/****************************************************************************/
7416/* Serial Attached SCSI values */
7417/****************************************************************************/
7418
7419 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7420 desc = "SAS: SMP Request Failed";
7421 break;
7422
7423 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7424 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425 break;
7426
7427 default:
7428 desc = "Others";
7429 break;
7430 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007431
7432 if (!desc)
7433 return;
7434
Eric Moore29dd3602007-09-14 18:46:51 -06007435 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7436 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437}
7438
7439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007440EXPORT_SYMBOL(mpt_attach);
7441EXPORT_SYMBOL(mpt_detach);
7442#ifdef CONFIG_PM
7443EXPORT_SYMBOL(mpt_resume);
7444EXPORT_SYMBOL(mpt_suspend);
7445#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007447EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448EXPORT_SYMBOL(mpt_register);
7449EXPORT_SYMBOL(mpt_deregister);
7450EXPORT_SYMBOL(mpt_event_register);
7451EXPORT_SYMBOL(mpt_event_deregister);
7452EXPORT_SYMBOL(mpt_reset_register);
7453EXPORT_SYMBOL(mpt_reset_deregister);
7454EXPORT_SYMBOL(mpt_device_driver_register);
7455EXPORT_SYMBOL(mpt_device_driver_deregister);
7456EXPORT_SYMBOL(mpt_get_msg_frame);
7457EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307458EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007459EXPORT_SYMBOL(mpt_free_msg_frame);
7460EXPORT_SYMBOL(mpt_add_sge);
7461EXPORT_SYMBOL(mpt_send_handshake_request);
7462EXPORT_SYMBOL(mpt_verify_adapter);
7463EXPORT_SYMBOL(mpt_GetIocState);
7464EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465EXPORT_SYMBOL(mpt_HardResetHandler);
7466EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468EXPORT_SYMBOL(mpt_alloc_fw_memory);
7469EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007470EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007471EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007472
Linus Torvalds1da177e2005-04-16 15:20:36 -07007473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007474/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475 * fusion_init - Fusion MPT base driver initialization routine.
7476 *
7477 * Returns 0 for success, non-zero for failure.
7478 */
7479static int __init
7480fusion_init(void)
7481{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307482 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483
7484 show_mptmod_ver(my_NAME, my_VERSION);
7485 printk(KERN_INFO COPYRIGHT "\n");
7486
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307487 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7488 MptCallbacks[cb_idx] = NULL;
7489 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7490 MptEvHandlers[cb_idx] = NULL;
7491 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492 }
7493
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007494 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495 * EventNotification handling.
7496 */
7497 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7498
7499 /* Register for hard reset handling callbacks.
7500 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307501 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502
7503#ifdef CONFIG_PROC_FS
7504 (void) procmpt_create();
7505#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007506 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007507}
7508
7509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007510/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511 * fusion_exit - Perform driver unload cleanup.
7512 *
7513 * This routine frees all resources associated with each MPT adapter
7514 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7515 */
7516static void __exit
7517fusion_exit(void)
7518{
7519
Linus Torvalds1da177e2005-04-16 15:20:36 -07007520 mpt_reset_deregister(mpt_base_index);
7521
7522#ifdef CONFIG_PROC_FS
7523 procmpt_destroy();
7524#endif
7525}
7526
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527module_init(fusion_init);
7528module_exit(fusion_exit);