blob: db3c892f87fb50aafc6f53ac5aaaaf016ee2860f [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 */
Prakash, Sathya23a274c2008-03-07 15:53:21 +053082static int mpt_msi_enable = -1;
Christoph Hellwig4ddce142006-01-17 13:44:29 +000083module_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
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301689 if (ioc->bus_type == SAS && mpt_msi_enable == -1)
1690 ioc->msi_enable = 1;
1691 else
1692 ioc->msi_enable = mpt_msi_enable;
1693
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001694 if (ioc->errata_flag_1064)
1695 pci_disable_io_access(pdev);
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 spin_lock_init(&ioc->FreeQlock);
1698
1699 /* Disable all! */
1700 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1701 ioc->active = 0;
1702 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1703
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301704 /* Set IOC ptr in the pcidev's driver data. */
1705 pci_set_drvdata(ioc->pcidev, ioc);
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 /* Set lookup ptr. */
1708 list_add_tail(&ioc->list, &ioc_list);
1709
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001710 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 */
1712 mpt_detect_bound_ports(ioc, pdev);
1713
James Bottomleyc92f2222006-03-01 09:02:49 -06001714 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1715 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001716 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1717 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001720 if (ioc->alt_ioc)
1721 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301722 iounmap(ioc->memmap);
1723 if (r != -5)
1724 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 kfree(ioc);
1726 pci_set_drvdata(pdev, NULL);
1727 return r;
1728 }
1729
1730 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001731 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301732 if(MptDeviceDriverHandlers[cb_idx] &&
1733 MptDeviceDriverHandlers[cb_idx]->probe) {
1734 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 }
1737
1738#ifdef CONFIG_PROC_FS
1739 /*
1740 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1741 */
1742 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1743 if (dent) {
1744 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1745 if (ent) {
1746 ent->read_proc = procmpt_iocinfo_read;
1747 ent->data = ioc;
1748 }
1749 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1750 if (ent) {
1751 ent->read_proc = procmpt_summary_read;
1752 ent->data = ioc;
1753 }
1754 }
1755#endif
1756
1757 return 0;
1758}
1759
1760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001761/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001762 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 */
1765
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001766void
1767mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1770 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301771 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1774 remove_proc_entry(pname, NULL);
1775 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1776 remove_proc_entry(pname, NULL);
1777 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1778 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001781 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301782 if(MptDeviceDriverHandlers[cb_idx] &&
1783 MptDeviceDriverHandlers[cb_idx]->remove) {
1784 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 /* Disable interrupts! */
1789 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1790
1791 ioc->active = 0;
1792 synchronize_irq(pdev->irq);
1793
1794 /* Clear any lingering interrupt */
1795 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1796
1797 CHIPREG_READ32(&ioc->chip->IntStatus);
1798
1799 mpt_adapter_dispose(ioc);
1800
1801 pci_set_drvdata(pdev, NULL);
1802}
1803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804/**************************************************************************
1805 * Power Management
1806 */
1807#ifdef CONFIG_PM
1808/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001809/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001810 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001811 * @pdev: Pointer to pci_dev structure
1812 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001814int
1815mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816{
1817 u32 device_state;
1818 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301820 device_state = pci_choose_state(pdev, state);
1821 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1822 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1823 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
1825 /* put ioc into READY_STATE */
1826 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1827 printk(MYIOC_s_ERR_FMT
1828 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1829 }
1830
1831 /* disable interrupts */
1832 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1833 ioc->active = 0;
1834
1835 /* Clear any lingering interrupt */
1836 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1837
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301838 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001839 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301840 pci_disable_msi(ioc->pcidev);
1841 ioc->pci_irq = -1;
1842 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301844 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 return 0;
1847}
1848
1849/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001850/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001851 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001852 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001854int
1855mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856{
1857 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1858 u32 device_state = pdev->current_state;
1859 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301860 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001861
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301862 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1863 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1864 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301866 pci_set_power_state(pdev, PCI_D0);
1867 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301869 ioc->pcidev = pdev;
1870 err = mpt_mapresources(ioc);
1871 if (err)
1872 return err;
1873
1874 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1875 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1876 CHIPREG_READ32(&ioc->chip->Doorbell));
1877
1878 /*
1879 * Errata workaround for SAS pci express:
1880 * Upon returning to the D0 state, the contents of the doorbell will be
1881 * stale data, and this will incorrectly signal to the host driver that
1882 * the firmware is ready to process mpt commands. The workaround is
1883 * to issue a diagnostic reset.
1884 */
1885 if (ioc->bus_type == SAS && (pdev->device ==
1886 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1887 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1888 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1889 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1890 ioc->name);
1891 goto out;
1892 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301896 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1897 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1898 CAN_SLEEP);
1899 if (recovery_state != 0)
1900 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1901 "error:[%x]\n", ioc->name, recovery_state);
1902 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301904 "pci-resume: success\n", ioc->name);
1905 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301907
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908}
1909#endif
1910
James Bottomley4ff42a62006-05-17 18:06:52 -05001911static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301912mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001913{
1914 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1915 ioc->bus_type != SPI) ||
1916 (MptDriverClass[index] == MPTFC_DRIVER &&
1917 ioc->bus_type != FC) ||
1918 (MptDriverClass[index] == MPTSAS_DRIVER &&
1919 ioc->bus_type != SAS))
1920 /* make sure we only call the relevant reset handler
1921 * for the bus */
1922 return 0;
1923 return (MptResetHandlers[index])(ioc, reset_phase);
1924}
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001927/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1929 * @ioc: Pointer to MPT adapter structure
1930 * @reason: Event word / reason
1931 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1932 *
1933 * This routine performs all the steps necessary to bring the IOC
1934 * to a OPERATIONAL state.
1935 *
1936 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1937 * MPT adapter.
1938 *
1939 * Returns:
1940 * 0 for success
1941 * -1 if failed to get board READY
1942 * -2 if READY but IOCFacts Failed
1943 * -3 if READY but PrimeIOCFifos Failed
1944 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301945 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301946 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 */
1948static int
1949mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1950{
1951 int hard_reset_done = 0;
1952 int alt_ioc_ready = 0;
1953 int hard;
1954 int rc=0;
1955 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301956 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 int handlers;
1958 int ret = 0;
1959 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001960 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301961 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
Eric Moore29dd3602007-09-14 18:46:51 -06001963 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1964 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966 /* Disable reply interrupts (also blocks FreeQ) */
1967 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1968 ioc->active = 0;
1969
1970 if (ioc->alt_ioc) {
1971 if (ioc->alt_ioc->active)
1972 reset_alt_ioc_active = 1;
1973
1974 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1975 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1976 ioc->alt_ioc->active = 0;
1977 }
1978
1979 hard = 1;
1980 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1981 hard = 0;
1982
1983 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1984 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001985 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1986 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
1988 if (reset_alt_ioc_active && ioc->alt_ioc) {
1989 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001990 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1991 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001992 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 ioc->alt_ioc->active = 1;
1994 }
1995
1996 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001997 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 }
1999 return -1;
2000 }
2001
2002 /* hard_reset_done = 0 if a soft reset was performed
2003 * and 1 if a hard reset was performed.
2004 */
2005 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2006 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2007 alt_ioc_ready = 1;
2008 else
Eric Moore29dd3602007-09-14 18:46:51 -06002009 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 }
2011
2012 for (ii=0; ii<5; ii++) {
2013 /* Get IOC facts! Allow 5 retries */
2014 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2015 break;
2016 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002017
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
2019 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002020 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2021 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 ret = -2;
2023 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2024 MptDisplayIocCapabilities(ioc);
2025 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 if (alt_ioc_ready) {
2028 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302029 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002030 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 /* Retry - alt IOC was initialized once
2032 */
2033 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2034 }
2035 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302036 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002037 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 alt_ioc_ready = 0;
2039 reset_alt_ioc_active = 0;
2040 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2041 MptDisplayIocCapabilities(ioc->alt_ioc);
2042 }
2043 }
2044
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302045 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2046 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2047 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2048 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2049 IORESOURCE_IO);
2050 if (pci_enable_device(ioc->pcidev))
2051 return -5;
2052 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2053 "mpt"))
2054 return -5;
2055 }
2056
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002057 /*
2058 * Device is reset now. It must have de-asserted the interrupt line
2059 * (if it was asserted) and it should be safe to register for the
2060 * interrupt now.
2061 */
2062 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2063 ioc->pci_irq = -1;
2064 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302065 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002066 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002067 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302068 else
2069 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002070 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002071 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002072 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002073 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002074 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302075 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002076 pci_disable_msi(ioc->pcidev);
2077 return -EBUSY;
2078 }
2079 irq_allocated = 1;
2080 ioc->pci_irq = ioc->pcidev->irq;
2081 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002082 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2083 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002084 }
2085 }
2086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 /* Prime reply & request queues!
2088 * (mucho alloc's) Must be done prior to
2089 * init as upper addresses are needed for init.
2090 * If fails, continue with alt-ioc processing
2091 */
2092 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2093 ret = -3;
2094
2095 /* May need to check/upload firmware & data here!
2096 * If fails, continue with alt-ioc processing
2097 */
2098 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2099 ret = -4;
2100// NEW!
2101 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002102 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2103 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 alt_ioc_ready = 0;
2105 reset_alt_ioc_active = 0;
2106 }
2107
2108 if (alt_ioc_ready) {
2109 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2110 alt_ioc_ready = 0;
2111 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002112 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2113 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 }
2115 }
2116
2117 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2118 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302119 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002120 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
2122 /* Controller is not operational, cannot do upload
2123 */
2124 if (ret == 0) {
2125 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002126 if (rc == 0) {
2127 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2128 /*
2129 * Maintain only one pointer to FW memory
2130 * so there will not be two attempt to
2131 * downloadboot onboard dual function
2132 * chips (mpt_adapter_disable,
2133 * mpt_diag_reset)
2134 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302135 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002136 "mpt_upload: alt_%s has cached_fw=%p \n",
2137 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302138 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002139 }
2140 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002141 printk(MYIOC_s_WARN_FMT
2142 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302143 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 }
2146 }
2147 }
2148
2149 if (ret == 0) {
2150 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002151 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 ioc->active = 1;
2153 }
2154
2155 if (reset_alt_ioc_active && ioc->alt_ioc) {
2156 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002157 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2158 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002159 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 ioc->alt_ioc->active = 1;
2161 }
2162
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002163 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 * and EventAck handling.
2165 */
2166 if ((ret == 0) && (!ioc->facts.EventState))
2167 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2168
2169 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2170 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2171
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002172 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2174 * recursive scenario; GetLanConfigPages times out, timer expired
2175 * routine calls HardResetHandler, which calls into here again,
2176 * and we try GetLanConfigPages again...
2177 */
2178 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002179
2180 /*
2181 * Initalize link list for inactive raid volumes.
2182 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002183 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002184 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2185
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002186 if (ioc->bus_type == SAS) {
2187
2188 /* clear persistency table */
2189 if(ioc->facts.IOCExceptions &
2190 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2191 ret = mptbase_sas_persist_operation(ioc,
2192 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2193 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002194 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002195 }
2196
2197 /* Find IM volumes
2198 */
2199 mpt_findImVolumes(ioc);
2200
2201 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2203 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2204 /*
2205 * Pre-fetch the ports LAN MAC address!
2206 * (LANPage1_t stuff)
2207 */
2208 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302209 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2210 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002211 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2212 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 }
2215 } else {
2216 /* Get NVRAM and adapter maximums from SPP 0 and 2
2217 */
2218 mpt_GetScsiPortSettings(ioc, 0);
2219
2220 /* Get version and length of SDP 1
2221 */
2222 mpt_readScsiDevicePageHeaders(ioc, 0);
2223
2224 /* Find IM volumes
2225 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002226 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 mpt_findImVolumes(ioc);
2228
2229 /* Check, and possibly reset, the coalescing value
2230 */
2231 mpt_read_ioc_pg_1(ioc);
2232
2233 mpt_read_ioc_pg_4(ioc);
2234 }
2235
2236 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302237 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 }
2239
2240 /*
2241 * Call each currently registered protocol IOC reset handler
2242 * with post-reset indication.
2243 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2244 * MptResetHandlers[] registered yet.
2245 */
2246 if (hard_reset_done) {
2247 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302248 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2249 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302250 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002251 "Calling IOC post_reset handler #%d\n",
2252 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302253 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 handlers++;
2255 }
2256
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302257 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302258 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002259 "Calling IOC post_reset handler #%d\n",
2260 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302261 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 handlers++;
2263 }
2264 }
2265 /* FIXME? Examine results here? */
2266 }
2267
Eric Moore0ccdb002006-07-11 17:33:13 -06002268 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002269 if ((ret != 0) && irq_allocated) {
2270 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302271 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002272 pci_disable_msi(ioc->pcidev);
2273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 return ret;
2275}
2276
2277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002278/**
2279 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 * @ioc: Pointer to MPT adapter structure
2281 * @pdev: Pointer to (struct pci_dev) structure
2282 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002283 * Search for PCI bus/dev_function which matches
2284 * PCI bus/dev_function (+/-1) for newly discovered 929,
2285 * 929X, 1030 or 1035.
2286 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2288 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2289 */
2290static void
2291mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2292{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002293 struct pci_dev *peer=NULL;
2294 unsigned int slot = PCI_SLOT(pdev->devfn);
2295 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 MPT_ADAPTER *ioc_srch;
2297
Prakash, Sathya436ace72007-07-24 15:42:08 +05302298 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002299 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002300 ioc->name, pci_name(pdev), pdev->bus->number,
2301 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002302
2303 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2304 if (!peer) {
2305 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2306 if (!peer)
2307 return;
2308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 list_for_each_entry(ioc_srch, &ioc_list, list) {
2311 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002312 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 /* Paranoia checks */
2314 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002315 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002316 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 break;
2318 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002319 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002320 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 break;
2322 }
Eric Moore29dd3602007-09-14 18:46:51 -06002323 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002324 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 ioc_srch->alt_ioc = ioc;
2326 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 }
2328 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002329 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330}
2331
2332/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002333/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002335 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 */
2337static void
2338mpt_adapter_disable(MPT_ADAPTER *ioc)
2339{
2340 int sz;
2341 int ret;
2342
2343 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302344 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2345 "adapter\n", __FUNCTION__, ioc->name));
2346 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2347 ioc->cached_fw, CAN_SLEEP)) < 0) {
2348 printk(MYIOC_s_WARN_FMT
2349 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002350 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 }
2352 }
2353
2354 /* Disable adapter interrupts! */
2355 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2356 ioc->active = 0;
2357 /* Clear any lingering interrupt */
2358 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2359
2360 if (ioc->alloc != NULL) {
2361 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002362 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2363 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 pci_free_consistent(ioc->pcidev, sz,
2365 ioc->alloc, ioc->alloc_dma);
2366 ioc->reply_frames = NULL;
2367 ioc->req_frames = NULL;
2368 ioc->alloc = NULL;
2369 ioc->alloc_total -= sz;
2370 }
2371
2372 if (ioc->sense_buf_pool != NULL) {
2373 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2374 pci_free_consistent(ioc->pcidev, sz,
2375 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2376 ioc->sense_buf_pool = NULL;
2377 ioc->alloc_total -= sz;
2378 }
2379
2380 if (ioc->events != NULL){
2381 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2382 kfree(ioc->events);
2383 ioc->events = NULL;
2384 ioc->alloc_total -= sz;
2385 }
2386
Prakash, Sathya984621b2008-01-11 14:42:17 +05302387 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002389 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002390 mpt_inactive_raid_list_free(ioc);
2391 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002392 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002393 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002394 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
2396 if (ioc->spi_data.pIocPg4 != NULL) {
2397 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302398 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 ioc->spi_data.pIocPg4,
2400 ioc->spi_data.IocPg4_dma);
2401 ioc->spi_data.pIocPg4 = NULL;
2402 ioc->alloc_total -= sz;
2403 }
2404
2405 if (ioc->ReqToChain != NULL) {
2406 kfree(ioc->ReqToChain);
2407 kfree(ioc->RequestNB);
2408 ioc->ReqToChain = NULL;
2409 }
2410
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002411 kfree(ioc->ChainToChain);
2412 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002413
2414 if (ioc->HostPageBuffer != NULL) {
2415 if((ret = mpt_host_page_access_control(ioc,
2416 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002417 printk(MYIOC_s_ERR_FMT
2418 "host page buffers free failed (%d)!\n",
2419 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002420 }
Eric Moore29dd3602007-09-14 18:46:51 -06002421 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002422 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2423 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002424 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002425 ioc->HostPageBuffer = NULL;
2426 ioc->HostPageBuffer_sz = 0;
2427 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429}
2430
2431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002432/**
2433 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 * @ioc: Pointer to MPT adapter structure
2435 *
2436 * This routine unregisters h/w resources and frees all alloc'd memory
2437 * associated with a MPT adapter structure.
2438 */
2439static void
2440mpt_adapter_dispose(MPT_ADAPTER *ioc)
2441{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002442 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002444 if (ioc == NULL)
2445 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002447 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002449 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002451 if (ioc->pci_irq != -1) {
2452 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302453 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002454 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002455 ioc->pci_irq = -1;
2456 }
2457
2458 if (ioc->memmap != NULL) {
2459 iounmap(ioc->memmap);
2460 ioc->memmap = NULL;
2461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302463 pci_disable_device(ioc->pcidev);
2464 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002467 if (ioc->mtrr_reg > 0) {
2468 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002469 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471#endif
2472
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002473 /* Zap the adapter lookup ptr! */
2474 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002476 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002477 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2478 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002479
2480 if (ioc->alt_ioc)
2481 ioc->alt_ioc->alt_ioc = NULL;
2482
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002483 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484}
2485
2486/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002487/**
2488 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 * @ioc: Pointer to MPT adapter structure
2490 */
2491static void
2492MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2493{
2494 int i = 0;
2495
2496 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302497 if (ioc->prod_name)
2498 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 printk("Capabilities={");
2500
2501 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2502 printk("Initiator");
2503 i++;
2504 }
2505
2506 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2507 printk("%sTarget", i ? "," : "");
2508 i++;
2509 }
2510
2511 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2512 printk("%sLAN", i ? "," : "");
2513 i++;
2514 }
2515
2516#if 0
2517 /*
2518 * This would probably evoke more questions than it's worth
2519 */
2520 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2521 printk("%sLogBusAddr", i ? "," : "");
2522 i++;
2523 }
2524#endif
2525
2526 printk("}\n");
2527}
2528
2529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002530/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2532 * @ioc: Pointer to MPT_ADAPTER structure
2533 * @force: Force hard KickStart of IOC
2534 * @sleepFlag: Specifies whether the process can sleep
2535 *
2536 * Returns:
2537 * 1 - DIAG reset and READY
2538 * 0 - READY initially OR soft reset and READY
2539 * -1 - Any failure on KickStart
2540 * -2 - Msg Unit Reset Failed
2541 * -3 - IO Unit Reset Failed
2542 * -4 - IOC owned by a PEER
2543 */
2544static int
2545MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2546{
2547 u32 ioc_state;
2548 int statefault = 0;
2549 int cntdn;
2550 int hard_reset_done = 0;
2551 int r;
2552 int ii;
2553 int whoinit;
2554
2555 /* Get current [raw] IOC state */
2556 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002557 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
2559 /*
2560 * Check to see if IOC got left/stuck in doorbell handshake
2561 * grip of death. If so, hard reset the IOC.
2562 */
2563 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2564 statefault = 1;
2565 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2566 ioc->name);
2567 }
2568
2569 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002570 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 return 0;
2572
2573 /*
2574 * Check to see if IOC is in FAULT state.
2575 */
2576 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2577 statefault = 2;
2578 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002579 ioc->name);
2580 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2581 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 }
2583
2584 /*
2585 * Hmmm... Did it get left operational?
2586 */
2587 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302588 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 ioc->name));
2590
2591 /* Check WhoInit.
2592 * If PCI Peer, exit.
2593 * Else, if no fault conditions are present, issue a MessageUnitReset
2594 * Else, fall through to KickStart case
2595 */
2596 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002597 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2598 "whoinit 0x%x statefault %d force %d\n",
2599 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 if (whoinit == MPI_WHOINIT_PCI_PEER)
2601 return -4;
2602 else {
2603 if ((statefault == 0 ) && (force == 0)) {
2604 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2605 return 0;
2606 }
2607 statefault = 3;
2608 }
2609 }
2610
2611 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2612 if (hard_reset_done < 0)
2613 return -1;
2614
2615 /*
2616 * Loop here waiting for IOC to come READY.
2617 */
2618 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002619 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2622 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2623 /*
2624 * BIOS or previous driver load left IOC in OP state.
2625 * Reset messaging FIFOs.
2626 */
2627 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2628 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2629 return -2;
2630 }
2631 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2632 /*
2633 * Something is wrong. Try to get IOC back
2634 * to a known state.
2635 */
2636 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2637 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2638 return -3;
2639 }
2640 }
2641
2642 ii++; cntdn--;
2643 if (!cntdn) {
2644 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2645 ioc->name, (int)((ii+5)/HZ));
2646 return -ETIME;
2647 }
2648
2649 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002650 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 } else {
2652 mdelay (1); /* 1 msec delay */
2653 }
2654
2655 }
2656
2657 if (statefault < 3) {
2658 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2659 ioc->name,
2660 statefault==1 ? "stuck handshake" : "IOC FAULT");
2661 }
2662
2663 return hard_reset_done;
2664}
2665
2666/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002667/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 * mpt_GetIocState - Get the current state of a MPT adapter.
2669 * @ioc: Pointer to MPT_ADAPTER structure
2670 * @cooked: Request raw or cooked IOC state
2671 *
2672 * Returns all IOC Doorbell register bits if cooked==0, else just the
2673 * Doorbell bits in MPI_IOC_STATE_MASK.
2674 */
2675u32
2676mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2677{
2678 u32 s, sc;
2679
2680 /* Get! */
2681 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 sc = s & MPI_IOC_STATE_MASK;
2683
2684 /* Save! */
2685 ioc->last_state = sc;
2686
2687 return cooked ? sc : s;
2688}
2689
2690/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002691/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 * GetIocFacts - Send IOCFacts request to MPT adapter.
2693 * @ioc: Pointer to MPT_ADAPTER structure
2694 * @sleepFlag: Specifies whether the process can sleep
2695 * @reason: If recovery, only update facts.
2696 *
2697 * Returns 0 for success, non-zero for failure.
2698 */
2699static int
2700GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2701{
2702 IOCFacts_t get_facts;
2703 IOCFactsReply_t *facts;
2704 int r;
2705 int req_sz;
2706 int reply_sz;
2707 int sz;
2708 u32 status, vv;
2709 u8 shiftFactor=1;
2710
2711 /* IOC *must* NOT be in RESET state! */
2712 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002713 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2714 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 return -44;
2716 }
2717
2718 facts = &ioc->facts;
2719
2720 /* Destination (reply area)... */
2721 reply_sz = sizeof(*facts);
2722 memset(facts, 0, reply_sz);
2723
2724 /* Request area (get_facts on the stack right now!) */
2725 req_sz = sizeof(get_facts);
2726 memset(&get_facts, 0, req_sz);
2727
2728 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2729 /* Assert: All other get_facts fields are zero! */
2730
Prakash, Sathya436ace72007-07-24 15:42:08 +05302731 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002732 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 ioc->name, req_sz, reply_sz));
2734
2735 /* No non-zero fields in the get_facts request are greater than
2736 * 1 byte in size, so we can just fire it off as is.
2737 */
2738 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2739 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2740 if (r != 0)
2741 return r;
2742
2743 /*
2744 * Now byte swap (GRRR) the necessary fields before any further
2745 * inspection of reply contents.
2746 *
2747 * But need to do some sanity checks on MsgLength (byte) field
2748 * to make sure we don't zero IOC's req_sz!
2749 */
2750 /* Did we get a valid reply? */
2751 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2752 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2753 /*
2754 * If not been here, done that, save off first WhoInit value
2755 */
2756 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2757 ioc->FirstWhoInit = facts->WhoInit;
2758 }
2759
2760 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2761 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2762 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2763 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2764 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002765 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 /* CHECKME! IOCStatus, IOCLogInfo */
2767
2768 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2769 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2770
2771 /*
2772 * FC f/w version changed between 1.1 and 1.2
2773 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2774 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2775 */
2776 if (facts->MsgVersion < 0x0102) {
2777 /*
2778 * Handle old FC f/w style, convert to new...
2779 */
2780 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2781 facts->FWVersion.Word =
2782 ((oldv<<12) & 0xFF000000) |
2783 ((oldv<<8) & 0x000FFF00);
2784 } else
2785 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2786
2787 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002788 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2789 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2790 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 facts->CurrentHostMfaHighAddr =
2792 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2793 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2794 facts->CurrentSenseBufferHighAddr =
2795 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2796 facts->CurReplyFrameSize =
2797 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002798 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
2800 /*
2801 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2802 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2803 * to 14 in MPI-1.01.0x.
2804 */
2805 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2806 facts->MsgVersion > 0x0100) {
2807 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2808 }
2809
2810 sz = facts->FWImageSize;
2811 if ( sz & 0x01 )
2812 sz += 1;
2813 if ( sz & 0x02 )
2814 sz += 2;
2815 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 if (!facts->RequestFrameSize) {
2818 /* Something is wrong! */
2819 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2820 ioc->name);
2821 return -55;
2822 }
2823
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002824 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 vv = ((63 / (sz * 4)) + 1) & 0x03;
2826 ioc->NB_for_64_byte_frame = vv;
2827 while ( sz )
2828 {
2829 shiftFactor++;
2830 sz = sz >> 1;
2831 }
2832 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302833 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002834 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2835 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2838 /*
2839 * Set values for this IOC's request & reply frame sizes,
2840 * and request & reply queue depths...
2841 */
2842 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2843 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2844 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2845 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2846
Prakash, Sathya436ace72007-07-24 15:42:08 +05302847 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302849 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 ioc->name, ioc->req_sz, ioc->req_depth));
2851
2852 /* Get port facts! */
2853 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2854 return r;
2855 }
2856 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002857 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2859 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2860 RequestFrameSize)/sizeof(u32)));
2861 return -66;
2862 }
2863
2864 return 0;
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002868/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 * GetPortFacts - Send PortFacts request to MPT adapter.
2870 * @ioc: Pointer to MPT_ADAPTER structure
2871 * @portnum: Port number
2872 * @sleepFlag: Specifies whether the process can sleep
2873 *
2874 * Returns 0 for success, non-zero for failure.
2875 */
2876static int
2877GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2878{
2879 PortFacts_t get_pfacts;
2880 PortFactsReply_t *pfacts;
2881 int ii;
2882 int req_sz;
2883 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002884 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
2886 /* IOC *must* NOT be in RESET state! */
2887 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002888 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2889 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 return -4;
2891 }
2892
2893 pfacts = &ioc->pfacts[portnum];
2894
2895 /* Destination (reply area)... */
2896 reply_sz = sizeof(*pfacts);
2897 memset(pfacts, 0, reply_sz);
2898
2899 /* Request area (get_pfacts on the stack right now!) */
2900 req_sz = sizeof(get_pfacts);
2901 memset(&get_pfacts, 0, req_sz);
2902
2903 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2904 get_pfacts.PortNumber = portnum;
2905 /* Assert: All other get_pfacts fields are zero! */
2906
Prakash, Sathya436ace72007-07-24 15:42:08 +05302907 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 ioc->name, portnum));
2909
2910 /* No non-zero fields in the get_pfacts request are greater than
2911 * 1 byte in size, so we can just fire it off as is.
2912 */
2913 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2914 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2915 if (ii != 0)
2916 return ii;
2917
2918 /* Did we get a valid reply? */
2919
2920 /* Now byte swap the necessary fields in the response. */
2921 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2922 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2923 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2924 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2925 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2926 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2927 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2928 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2929 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2930
Eric Moore793955f2007-01-29 09:42:20 -07002931 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2932 pfacts->MaxDevices;
2933 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2934 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2935
2936 /*
2937 * Place all the devices on channels
2938 *
2939 * (for debuging)
2940 */
2941 if (mpt_channel_mapping) {
2942 ioc->devices_per_bus = 1;
2943 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2944 }
2945
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 return 0;
2947}
2948
2949/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002950/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 * SendIocInit - Send IOCInit request to MPT adapter.
2952 * @ioc: Pointer to MPT_ADAPTER structure
2953 * @sleepFlag: Specifies whether the process can sleep
2954 *
2955 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2956 *
2957 * Returns 0 for success, non-zero for failure.
2958 */
2959static int
2960SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2961{
2962 IOCInit_t ioc_init;
2963 MPIDefaultReply_t init_reply;
2964 u32 state;
2965 int r;
2966 int count;
2967 int cntdn;
2968
2969 memset(&ioc_init, 0, sizeof(ioc_init));
2970 memset(&init_reply, 0, sizeof(init_reply));
2971
2972 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2973 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2974
2975 /* If we are in a recovery mode and we uploaded the FW image,
2976 * then this pointer is not NULL. Skip the upload a second time.
2977 * Set this flag if cached_fw set for either IOC.
2978 */
2979 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2980 ioc->upload_fw = 1;
2981 else
2982 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302983 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2985
Eric Moore793955f2007-01-29 09:42:20 -07002986 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2987 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302988 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002989 ioc->name, ioc->facts.MsgVersion));
2990 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2991 // set MsgVersion and HeaderVersion host driver was built with
2992 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2993 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002995 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2996 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2997 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2998 return -99;
2999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3001
3002 if (sizeof(dma_addr_t) == sizeof(u64)) {
3003 /* Save the upper 32-bits of the request
3004 * (reply) and sense buffers.
3005 */
3006 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3007 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3008 } else {
3009 /* Force 32-bit addressing */
3010 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3011 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3012 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3015 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003016 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3017 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Prakash, Sathya436ace72007-07-24 15:42:08 +05303019 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 ioc->name, &ioc_init));
3021
3022 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3023 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003024 if (r != 0) {
3025 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
3029 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003030 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 */
3032
Prakash, Sathya436ace72007-07-24 15:42:08 +05303033 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003035
3036 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3037 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
3041 /* YIKES! SUPER IMPORTANT!!!
3042 * Poll IocState until _OPERATIONAL while IOC is doing
3043 * LoopInit and TargetDiscovery!
3044 */
3045 count = 0;
3046 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3047 state = mpt_GetIocState(ioc, 1);
3048 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3049 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003050 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 } else {
3052 mdelay(1);
3053 }
3054
3055 if (!cntdn) {
3056 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3057 ioc->name, (int)((count+5)/HZ));
3058 return -9;
3059 }
3060
3061 state = mpt_GetIocState(ioc, 1);
3062 count++;
3063 }
Eric Moore29dd3602007-09-14 18:46:51 -06003064 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 ioc->name, count));
3066
Eric Mooreba856d32006-07-11 17:34:01 -06003067 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 return r;
3069}
3070
3071/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003072/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 * SendPortEnable - Send PortEnable request to MPT adapter port.
3074 * @ioc: Pointer to MPT_ADAPTER structure
3075 * @portnum: Port number to enable
3076 * @sleepFlag: Specifies whether the process can sleep
3077 *
3078 * Send PortEnable to bring IOC to OPERATIONAL state.
3079 *
3080 * Returns 0 for success, non-zero for failure.
3081 */
3082static int
3083SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3084{
3085 PortEnable_t port_enable;
3086 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003087 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 int req_sz;
3089 int reply_sz;
3090
3091 /* Destination... */
3092 reply_sz = sizeof(MPIDefaultReply_t);
3093 memset(&reply_buf, 0, reply_sz);
3094
3095 req_sz = sizeof(PortEnable_t);
3096 memset(&port_enable, 0, req_sz);
3097
3098 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3099 port_enable.PortNumber = portnum;
3100/* port_enable.ChainOffset = 0; */
3101/* port_enable.MsgFlags = 0; */
3102/* port_enable.MsgContext = 0; */
3103
Prakash, Sathya436ace72007-07-24 15:42:08 +05303104 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 ioc->name, portnum, &port_enable));
3106
3107 /* RAID FW may take a long time to enable
3108 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003109 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003110 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3111 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3112 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003113 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003114 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3115 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3116 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003118 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119}
3120
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003121/**
3122 * mpt_alloc_fw_memory - allocate firmware memory
3123 * @ioc: Pointer to MPT_ADAPTER structure
3124 * @size: total FW bytes
3125 *
3126 * If memory has already been allocated, the same (cached) value
3127 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303128 *
3129 * Return 0 if successfull, or non-zero for failure
3130 **/
3131int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3133{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303134 int rc;
3135
3136 if (ioc->cached_fw) {
3137 rc = 0; /* use already allocated memory */
3138 goto out;
3139 }
3140 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3142 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303143 rc = 0;
3144 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303146 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3147 if (!ioc->cached_fw) {
3148 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3149 ioc->name);
3150 rc = -1;
3151 } else {
3152 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3153 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3154 ioc->alloc_total += size;
3155 rc = 0;
3156 }
3157 out:
3158 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303160
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003161/**
3162 * mpt_free_fw_memory - free firmware memory
3163 * @ioc: Pointer to MPT_ADAPTER structure
3164 *
3165 * If alt_img is NULL, delete from ioc structure.
3166 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303167 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168void
3169mpt_free_fw_memory(MPT_ADAPTER *ioc)
3170{
3171 int sz;
3172
Prakash, Sathya984621b2008-01-11 14:42:17 +05303173 if (!ioc->cached_fw)
3174 return;
3175
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3178 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003179 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303180 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182}
3183
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003185/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3187 * @ioc: Pointer to MPT_ADAPTER structure
3188 * @sleepFlag: Specifies whether the process can sleep
3189 *
3190 * Returns 0 for success, >0 for handshake failure
3191 * <0 for fw upload failure.
3192 *
3193 * Remark: If bound IOC and a successful FWUpload was performed
3194 * on the bound IOC, the second image is discarded
3195 * and memory is free'd. Both channels must upload to prevent
3196 * IOC from running in degraded mode.
3197 */
3198static int
3199mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3200{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 u8 reply[sizeof(FWUploadReply_t)];
3202 FWUpload_t *prequest;
3203 FWUploadReply_t *preply;
3204 FWUploadTCSGE_t *ptcsge;
3205 int sgeoffset;
3206 u32 flagsLength;
3207 int ii, sz, reply_sz;
3208 int cmdStatus;
3209
3210 /* If the image size is 0, we are done.
3211 */
3212 if ((sz = ioc->facts.FWImageSize) == 0)
3213 return 0;
3214
Prakash, Sathya984621b2008-01-11 14:42:17 +05303215 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3216 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Eric Moore29dd3602007-09-14 18:46:51 -06003218 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3219 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003220
Eric Moorebc6e0892007-09-29 10:16:28 -06003221 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3222 kzalloc(ioc->req_sz, GFP_KERNEL);
3223 if (!prequest) {
3224 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3225 "while allocating memory \n", ioc->name));
3226 mpt_free_fw_memory(ioc);
3227 return -ENOMEM;
3228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Eric Moorebc6e0892007-09-29 10:16:28 -06003230 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 reply_sz = sizeof(reply);
3233 memset(preply, 0, reply_sz);
3234
3235 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3236 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3237
3238 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3239 ptcsge->DetailsLength = 12;
3240 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3241 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003242 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
3244 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3245
3246 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003247 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
3249 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003250 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3251 ioc->name, prequest, sgeoffset));
3252 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
3254 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3255 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3256
Eric Moore29dd3602007-09-14 18:46:51 -06003257 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259 cmdStatus = -EFAULT;
3260 if (ii == 0) {
3261 /* Handshake transfer was complete and successful.
3262 * Check the Reply Frame.
3263 */
3264 int status, transfer_sz;
3265 status = le16_to_cpu(preply->IOCStatus);
3266 if (status == MPI_IOCSTATUS_SUCCESS) {
3267 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3268 if (transfer_sz == sz)
3269 cmdStatus = 0;
3270 }
3271 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303272 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 ioc->name, cmdStatus));
3274
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003275
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 if (cmdStatus) {
3277
Prakash, Sathya436ace72007-07-24 15:42:08 +05303278 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 ioc->name));
3280 mpt_free_fw_memory(ioc);
3281 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003282 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
3284 return cmdStatus;
3285}
3286
3287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003288/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 * mpt_downloadboot - DownloadBoot code
3290 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003291 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 * @sleepFlag: Specifies whether the process can sleep
3293 *
3294 * FwDownloadBoot requires Programmed IO access.
3295 *
3296 * Returns 0 for success
3297 * -1 FW Image size is 0
3298 * -2 No valid cached_fw Pointer
3299 * <0 for fw upload failure.
3300 */
3301static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003302mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 MpiExtImageHeader_t *pExtImage;
3305 u32 fwSize;
3306 u32 diag0val;
3307 int count;
3308 u32 *ptrFw;
3309 u32 diagRwData;
3310 u32 nextImage;
3311 u32 load_addr;
3312 u32 ioc_state=0;
3313
Prakash, Sathya436ace72007-07-24 15:42:08 +05303314 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003315 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003316
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3318 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3319 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3320 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3321 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3322 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3323
3324 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3325
3326 /* wait 1 msec */
3327 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003328 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 } else {
3330 mdelay (1);
3331 }
3332
3333 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3334 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3335
3336 for (count = 0; count < 30; count ++) {
3337 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3338 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303339 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 ioc->name, count));
3341 break;
3342 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003343 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003345 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003347 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 }
3349 }
3350
3351 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303352 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003353 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 ioc->name, diag0val));
3355 return -3;
3356 }
3357
3358 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3359 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3360 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3361 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3362 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3363 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3364
3365 /* Set the DiagRwEn and Disable ARM bits */
3366 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3367
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 fwSize = (pFwHeader->ImageSize + 3)/4;
3369 ptrFw = (u32 *) pFwHeader;
3370
3371 /* Write the LoadStartAddress to the DiagRw Address Register
3372 * using Programmed IO
3373 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003374 if (ioc->errata_flag_1064)
3375 pci_enable_io_access(ioc->pcidev);
3376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303378 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 ioc->name, pFwHeader->LoadStartAddress));
3380
Prakash, Sathya436ace72007-07-24 15:42:08 +05303381 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 ioc->name, fwSize*4, ptrFw));
3383 while (fwSize--) {
3384 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3385 }
3386
3387 nextImage = pFwHeader->NextImageHeaderOffset;
3388 while (nextImage) {
3389 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3390
3391 load_addr = pExtImage->LoadStartAddress;
3392
3393 fwSize = (pExtImage->ImageSize + 3) >> 2;
3394 ptrFw = (u32 *)pExtImage;
3395
Prakash, Sathya436ace72007-07-24 15:42:08 +05303396 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 +02003397 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3399
3400 while (fwSize--) {
3401 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3402 }
3403 nextImage = pExtImage->NextImageHeaderOffset;
3404 }
3405
3406 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303407 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3409
3410 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303411 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3413
3414 /* Clear the internal flash bad bit - autoincrementing register,
3415 * so must do two writes.
3416 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003417 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003418 /*
3419 * 1030 and 1035 H/W errata, workaround to access
3420 * the ClearFlashBadSignatureBit
3421 */
3422 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3423 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3424 diagRwData |= 0x40000000;
3425 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3426 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3427
3428 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3429 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3430 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3431 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3432
3433 /* wait 1 msec */
3434 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003435 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003436 } else {
3437 mdelay (1);
3438 }
3439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003441 if (ioc->errata_flag_1064)
3442 pci_disable_io_access(ioc->pcidev);
3443
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303445 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003446 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003448 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303449 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 ioc->name, diag0val));
3451 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3452
3453 /* Write 0xFF to reset the sequencer */
3454 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3455
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003456 if (ioc->bus_type == SAS) {
3457 ioc_state = mpt_GetIocState(ioc, 0);
3458 if ( (GetIocFacts(ioc, sleepFlag,
3459 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303460 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003461 ioc->name, ioc_state));
3462 return -EFAULT;
3463 }
3464 }
3465
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 for (count=0; count<HZ*20; count++) {
3467 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303468 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3469 "downloadboot successful! (count=%d) IocState=%x\n",
3470 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003471 if (ioc->bus_type == SAS) {
3472 return 0;
3473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303475 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3476 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 ioc->name));
3478 return -EFAULT;
3479 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303480 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3481 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 ioc->name));
3483 return 0;
3484 }
3485 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003486 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 } else {
3488 mdelay (10);
3489 }
3490 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303491 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3492 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 return -EFAULT;
3494}
3495
3496/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003497/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 * KickStart - Perform hard reset of MPT adapter.
3499 * @ioc: Pointer to MPT_ADAPTER structure
3500 * @force: Force hard reset
3501 * @sleepFlag: Specifies whether the process can sleep
3502 *
3503 * This routine places MPT adapter in diagnostic mode via the
3504 * WriteSequence register, and then performs a hard reset of adapter
3505 * via the Diagnostic register.
3506 *
3507 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3508 * or NO_SLEEP (interrupt thread, use mdelay)
3509 * force - 1 if doorbell active, board fault state
3510 * board operational, IOC_RECOVERY or
3511 * IOC_BRINGUP and there is an alt_ioc.
3512 * 0 else
3513 *
3514 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003515 * 1 - hard reset, READY
3516 * 0 - no reset due to History bit, READY
3517 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 * OR reset but failed to come READY
3519 * -2 - no reset, could not enter DIAG mode
3520 * -3 - reset but bad FW bit
3521 */
3522static int
3523KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3524{
3525 int hard_reset_done = 0;
3526 u32 ioc_state=0;
3527 int cnt,cntdn;
3528
Eric Moore29dd3602007-09-14 18:46:51 -06003529 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003530 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 /* Always issue a Msg Unit Reset first. This will clear some
3532 * SCSI bus hang conditions.
3533 */
3534 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3535
3536 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003537 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 } else {
3539 mdelay (1000);
3540 }
3541 }
3542
3543 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3544 if (hard_reset_done < 0)
3545 return hard_reset_done;
3546
Prakash, Sathya436ace72007-07-24 15:42:08 +05303547 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003548 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3551 for (cnt=0; cnt<cntdn; cnt++) {
3552 ioc_state = mpt_GetIocState(ioc, 1);
3553 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303554 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 ioc->name, cnt));
3556 return hard_reset_done;
3557 }
3558 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003559 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 } else {
3561 mdelay (10);
3562 }
3563 }
3564
Eric Moore29dd3602007-09-14 18:46:51 -06003565 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3566 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 return -1;
3568}
3569
3570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003571/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 * mpt_diag_reset - Perform hard reset of the adapter.
3573 * @ioc: Pointer to MPT_ADAPTER structure
3574 * @ignore: Set if to honor and clear to ignore
3575 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003576 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 * else set to NO_SLEEP (use mdelay instead)
3578 *
3579 * This routine places the adapter in diagnostic mode via the
3580 * WriteSequence register and then performs a hard reset of adapter
3581 * via the Diagnostic register. Adapter should be in ready state
3582 * upon successful completion.
3583 *
3584 * Returns: 1 hard reset successful
3585 * 0 no reset performed because reset history bit set
3586 * -2 enabling diagnostic mode failed
3587 * -3 diagnostic reset failed
3588 */
3589static int
3590mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3591{
3592 u32 diag0val;
3593 u32 doorbell;
3594 int hard_reset_done = 0;
3595 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303597 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
Eric Moorecd2c6192007-01-29 09:47:47 -07003599 /* Clear any existing interrupts */
3600 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3601
Eric Moore87cf8982006-06-27 16:09:26 -06003602 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303603 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003604 "address=%p\n", ioc->name, __FUNCTION__,
3605 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3606 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3607 if (sleepFlag == CAN_SLEEP)
3608 msleep(1);
3609 else
3610 mdelay(1);
3611
3612 for (count = 0; count < 60; count ++) {
3613 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3614 doorbell &= MPI_IOC_STATE_MASK;
3615
Prakash, Sathya436ace72007-07-24 15:42:08 +05303616 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003617 "looking for READY STATE: doorbell=%x"
3618 " count=%d\n",
3619 ioc->name, doorbell, count));
3620 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003621 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003622 }
3623
3624 /* wait 1 sec */
3625 if (sleepFlag == CAN_SLEEP)
3626 msleep(1000);
3627 else
3628 mdelay(1000);
3629 }
3630 return -1;
3631 }
3632
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 /* Use "Diagnostic reset" method! (only thing available!) */
3634 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3635
Prakash, Sathya436ace72007-07-24 15:42:08 +05303636 if (ioc->debug_level & MPT_DEBUG) {
3637 if (ioc->alt_ioc)
3638 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3639 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643 /* Do the reset if we are told to ignore the reset history
3644 * or if the reset history is 0
3645 */
3646 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3647 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3648 /* Write magic sequence to WriteSequence register
3649 * Loop until in diagnostic mode
3650 */
3651 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3652 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3653 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3654 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3655 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3656 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3657
3658 /* wait 100 msec */
3659 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003660 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 } else {
3662 mdelay (100);
3663 }
3664
3665 count++;
3666 if (count > 20) {
3667 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3668 ioc->name, diag0val);
3669 return -2;
3670
3671 }
3672
3673 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3674
Prakash, Sathya436ace72007-07-24 15:42:08 +05303675 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 ioc->name, diag0val));
3677 }
3678
Prakash, Sathya436ace72007-07-24 15:42:08 +05303679 if (ioc->debug_level & MPT_DEBUG) {
3680 if (ioc->alt_ioc)
3681 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3682 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 /*
3686 * Disable the ARM (Bug fix)
3687 *
3688 */
3689 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003690 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691
3692 /*
3693 * Now hit the reset bit in the Diagnostic register
3694 * (THE BIG HAMMER!) (Clears DRWE bit).
3695 */
3696 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3697 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303698 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 ioc->name));
3700
3701 /*
3702 * Call each currently registered protocol IOC reset handler
3703 * with pre-reset indication.
3704 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3705 * MptResetHandlers[] registered yet.
3706 */
3707 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303708 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 int r = 0;
3710
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303711 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3712 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303713 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3714 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303715 ioc->name, cb_idx));
3716 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303718 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3719 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303720 ioc->name, ioc->alt_ioc->name, cb_idx));
3721 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 }
3723 }
3724 }
3725 /* FIXME? Examine results here? */
3726 }
3727
Eric Moore0ccdb002006-07-11 17:33:13 -06003728 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303729 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003730 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303731 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3732 else
3733 cached_fw = NULL;
3734 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 /* If the DownloadBoot operation fails, the
3736 * IOC will be left unusable. This is a fatal error
3737 * case. _diag_reset will return < 0
3738 */
3739 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303740 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3742 break;
3743 }
3744
Prakash, Sathya436ace72007-07-24 15:42:08 +05303745 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303746 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 /* wait 1 sec */
3748 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003749 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 } else {
3751 mdelay (1000);
3752 }
3753 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303754 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003755 printk(MYIOC_s_WARN_FMT
3756 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 }
3758
3759 } else {
3760 /* Wait for FW to reload and for board
3761 * to go to the READY state.
3762 * Maximum wait is 60 seconds.
3763 * If fail, no error will check again
3764 * with calling program.
3765 */
3766 for (count = 0; count < 60; count ++) {
3767 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3768 doorbell &= MPI_IOC_STATE_MASK;
3769
3770 if (doorbell == MPI_IOC_STATE_READY) {
3771 break;
3772 }
3773
3774 /* wait 1 sec */
3775 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003776 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 } else {
3778 mdelay (1000);
3779 }
3780 }
3781 }
3782 }
3783
3784 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303785 if (ioc->debug_level & MPT_DEBUG) {
3786 if (ioc->alt_ioc)
3787 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3788 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3789 ioc->name, diag0val, diag1val));
3790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
3792 /* Clear RESET_HISTORY bit! Place board in the
3793 * diagnostic mode to update the diag register.
3794 */
3795 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3796 count = 0;
3797 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3798 /* Write magic sequence to WriteSequence register
3799 * Loop until in diagnostic mode
3800 */
3801 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3802 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3803 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3804 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3805 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3806 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3807
3808 /* wait 100 msec */
3809 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003810 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 } else {
3812 mdelay (100);
3813 }
3814
3815 count++;
3816 if (count > 20) {
3817 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3818 ioc->name, diag0val);
3819 break;
3820 }
3821 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3822 }
3823 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3824 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3825 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3826 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3827 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3828 ioc->name);
3829 }
3830
3831 /* Disable Diagnostic Mode
3832 */
3833 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3834
3835 /* Check FW reload status flags.
3836 */
3837 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3838 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3839 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3840 ioc->name, diag0val);
3841 return -3;
3842 }
3843
Prakash, Sathya436ace72007-07-24 15:42:08 +05303844 if (ioc->debug_level & MPT_DEBUG) {
3845 if (ioc->alt_ioc)
3846 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3847 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850
3851 /*
3852 * Reset flag that says we've enabled event notification
3853 */
3854 ioc->facts.EventState = 0;
3855
3856 if (ioc->alt_ioc)
3857 ioc->alt_ioc->facts.EventState = 0;
3858
3859 return hard_reset_done;
3860}
3861
3862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003863/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 * SendIocReset - Send IOCReset request to MPT adapter.
3865 * @ioc: Pointer to MPT_ADAPTER structure
3866 * @reset_type: reset type, expected values are
3867 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003868 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 *
3870 * Send IOCReset request to the MPT adapter.
3871 *
3872 * Returns 0 for success, non-zero for failure.
3873 */
3874static int
3875SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3876{
3877 int r;
3878 u32 state;
3879 int cntdn, count;
3880
Prakash, Sathya436ace72007-07-24 15:42:08 +05303881 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 ioc->name, reset_type));
3883 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3884 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3885 return r;
3886
3887 /* FW ACK'd request, wait for READY state
3888 */
3889 count = 0;
3890 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3891
3892 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3893 cntdn--;
3894 count++;
3895 if (!cntdn) {
3896 if (sleepFlag != CAN_SLEEP)
3897 count *= 10;
3898
Eric Moore29dd3602007-09-14 18:46:51 -06003899 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3900 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 return -ETIME;
3902 }
3903
3904 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003905 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 } else {
3907 mdelay (1); /* 1 msec delay */
3908 }
3909 }
3910
3911 /* TODO!
3912 * Cleanup all event stuff for this IOC; re-issue EventNotification
3913 * request if needed.
3914 */
3915 if (ioc->facts.Function)
3916 ioc->facts.EventState = 0;
3917
3918 return 0;
3919}
3920
3921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003922/**
3923 * initChainBuffers - Allocate memory for and initialize chain buffers
3924 * @ioc: Pointer to MPT_ADAPTER structure
3925 *
3926 * Allocates memory for and initializes chain buffers,
3927 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 */
3929static int
3930initChainBuffers(MPT_ADAPTER *ioc)
3931{
3932 u8 *mem;
3933 int sz, ii, num_chain;
3934 int scale, num_sge, numSGE;
3935
3936 /* ReqToChain size must equal the req_depth
3937 * index = req_idx
3938 */
3939 if (ioc->ReqToChain == NULL) {
3940 sz = ioc->req_depth * sizeof(int);
3941 mem = kmalloc(sz, GFP_ATOMIC);
3942 if (mem == NULL)
3943 return -1;
3944
3945 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303946 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 ioc->name, mem, sz));
3948 mem = kmalloc(sz, GFP_ATOMIC);
3949 if (mem == NULL)
3950 return -1;
3951
3952 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303953 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 ioc->name, mem, sz));
3955 }
3956 for (ii = 0; ii < ioc->req_depth; ii++) {
3957 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3958 }
3959
3960 /* ChainToChain size must equal the total number
3961 * of chain buffers to be allocated.
3962 * index = chain_idx
3963 *
3964 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003965 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 *
3967 * num_sge = num sge in request frame + last chain buffer
3968 * scale = num sge per chain buffer if no chain element
3969 */
3970 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3971 if (sizeof(dma_addr_t) == sizeof(u64))
3972 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3973 else
3974 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3975
3976 if (sizeof(dma_addr_t) == sizeof(u64)) {
3977 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3978 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3979 } else {
3980 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3981 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3982 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303983 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 ioc->name, num_sge, numSGE));
3985
3986 if ( numSGE > MPT_SCSI_SG_DEPTH )
3987 numSGE = MPT_SCSI_SG_DEPTH;
3988
3989 num_chain = 1;
3990 while (numSGE - num_sge > 0) {
3991 num_chain++;
3992 num_sge += (scale - 1);
3993 }
3994 num_chain++;
3995
Prakash, Sathya436ace72007-07-24 15:42:08 +05303996 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 ioc->name, numSGE, num_sge, num_chain));
3998
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003999 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 num_chain *= MPT_SCSI_CAN_QUEUE;
4001 else
4002 num_chain *= MPT_FC_CAN_QUEUE;
4003
4004 ioc->num_chain = num_chain;
4005
4006 sz = num_chain * sizeof(int);
4007 if (ioc->ChainToChain == NULL) {
4008 mem = kmalloc(sz, GFP_ATOMIC);
4009 if (mem == NULL)
4010 return -1;
4011
4012 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 ioc->name, mem, sz));
4015 } else {
4016 mem = (u8 *) ioc->ChainToChain;
4017 }
4018 memset(mem, 0xFF, sz);
4019 return num_chain;
4020}
4021
4022/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004023/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4025 * @ioc: Pointer to MPT_ADAPTER structure
4026 *
4027 * This routine allocates memory for the MPT reply and request frame
4028 * pools (if necessary), and primes the IOC reply FIFO with
4029 * reply frames.
4030 *
4031 * Returns 0 for success, non-zero for failure.
4032 */
4033static int
4034PrimeIocFifos(MPT_ADAPTER *ioc)
4035{
4036 MPT_FRAME_HDR *mf;
4037 unsigned long flags;
4038 dma_addr_t alloc_dma;
4039 u8 *mem;
4040 int i, reply_sz, sz, total_size, num_chain;
4041
4042 /* Prime reply FIFO... */
4043
4044 if (ioc->reply_frames == NULL) {
4045 if ( (num_chain = initChainBuffers(ioc)) < 0)
4046 return -1;
4047
4048 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304049 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304051 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 ioc->name, reply_sz, reply_sz));
4053
4054 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304055 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304057 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 ioc->name, sz, sz));
4059 total_size += sz;
4060
4061 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304064 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 ioc->name, sz, sz, num_chain));
4066
4067 total_size += sz;
4068 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4069 if (mem == NULL) {
4070 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4071 ioc->name);
4072 goto out_fail;
4073 }
4074
Prakash, Sathya436ace72007-07-24 15:42:08 +05304075 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4077
4078 memset(mem, 0, total_size);
4079 ioc->alloc_total += total_size;
4080 ioc->alloc = mem;
4081 ioc->alloc_dma = alloc_dma;
4082 ioc->alloc_sz = total_size;
4083 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4084 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4085
Prakash, Sathya436ace72007-07-24 15:42:08 +05304086 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004087 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4088
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 alloc_dma += reply_sz;
4090 mem += reply_sz;
4091
4092 /* Request FIFO - WE manage this! */
4093
4094 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4095 ioc->req_frames_dma = alloc_dma;
4096
Prakash, Sathya436ace72007-07-24 15:42:08 +05304097 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 ioc->name, mem, (void *)(ulong)alloc_dma));
4099
4100 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4101
4102#if defined(CONFIG_MTRR) && 0
4103 /*
4104 * Enable Write Combining MTRR for IOC's memory region.
4105 * (at least as much as we can; "size and base must be
4106 * multiples of 4 kiB"
4107 */
4108 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4109 sz,
4110 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304111 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 ioc->name, ioc->req_frames_dma, sz));
4113#endif
4114
4115 for (i = 0; i < ioc->req_depth; i++) {
4116 alloc_dma += ioc->req_sz;
4117 mem += ioc->req_sz;
4118 }
4119
4120 ioc->ChainBuffer = mem;
4121 ioc->ChainBufferDMA = alloc_dma;
4122
Prakash, Sathya436ace72007-07-24 15:42:08 +05304123 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4125
4126 /* Initialize the free chain Q.
4127 */
4128
4129 INIT_LIST_HEAD(&ioc->FreeChainQ);
4130
4131 /* Post the chain buffers to the FreeChainQ.
4132 */
4133 mem = (u8 *)ioc->ChainBuffer;
4134 for (i=0; i < num_chain; i++) {
4135 mf = (MPT_FRAME_HDR *) mem;
4136 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4137 mem += ioc->req_sz;
4138 }
4139
4140 /* Initialize Request frames linked list
4141 */
4142 alloc_dma = ioc->req_frames_dma;
4143 mem = (u8 *) ioc->req_frames;
4144
4145 spin_lock_irqsave(&ioc->FreeQlock, flags);
4146 INIT_LIST_HEAD(&ioc->FreeQ);
4147 for (i = 0; i < ioc->req_depth; i++) {
4148 mf = (MPT_FRAME_HDR *) mem;
4149
4150 /* Queue REQUESTs *internally*! */
4151 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4152
4153 mem += ioc->req_sz;
4154 }
4155 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4156
4157 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4158 ioc->sense_buf_pool =
4159 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4160 if (ioc->sense_buf_pool == NULL) {
4161 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4162 ioc->name);
4163 goto out_fail;
4164 }
4165
4166 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4167 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304168 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4170
4171 }
4172
4173 /* Post Reply frames to FIFO
4174 */
4175 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304176 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4178
4179 for (i = 0; i < ioc->reply_depth; i++) {
4180 /* Write each address to the IOC! */
4181 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4182 alloc_dma += ioc->reply_sz;
4183 }
4184
4185 return 0;
4186
4187out_fail:
4188 if (ioc->alloc != NULL) {
4189 sz = ioc->alloc_sz;
4190 pci_free_consistent(ioc->pcidev,
4191 sz,
4192 ioc->alloc, ioc->alloc_dma);
4193 ioc->reply_frames = NULL;
4194 ioc->req_frames = NULL;
4195 ioc->alloc_total -= sz;
4196 }
4197 if (ioc->sense_buf_pool != NULL) {
4198 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4199 pci_free_consistent(ioc->pcidev,
4200 sz,
4201 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4202 ioc->sense_buf_pool = NULL;
4203 }
4204 return -1;
4205}
4206
4207/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4208/**
4209 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4210 * from IOC via doorbell handshake method.
4211 * @ioc: Pointer to MPT_ADAPTER structure
4212 * @reqBytes: Size of the request in bytes
4213 * @req: Pointer to MPT request frame
4214 * @replyBytes: Expected size of the reply in bytes
4215 * @u16reply: Pointer to area where reply should be written
4216 * @maxwait: Max wait time for a reply (in seconds)
4217 * @sleepFlag: Specifies whether the process can sleep
4218 *
4219 * NOTES: It is the callers responsibility to byte-swap fields in the
4220 * request which are greater than 1 byte in size. It is also the
4221 * callers responsibility to byte-swap response fields which are
4222 * greater than 1 byte in size.
4223 *
4224 * Returns 0 for success, non-zero for failure.
4225 */
4226static int
4227mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004228 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229{
4230 MPIDefaultReply_t *mptReply;
4231 int failcnt = 0;
4232 int t;
4233
4234 /*
4235 * Get ready to cache a handshake reply
4236 */
4237 ioc->hs_reply_idx = 0;
4238 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4239 mptReply->MsgLength = 0;
4240
4241 /*
4242 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4243 * then tell IOC that we want to handshake a request of N words.
4244 * (WRITE u32val to Doorbell reg).
4245 */
4246 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4247 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4248 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4249 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4250
4251 /*
4252 * Wait for IOC's doorbell handshake int
4253 */
4254 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4255 failcnt++;
4256
Prakash, Sathya436ace72007-07-24 15:42:08 +05304257 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4259
4260 /* Read doorbell and check for active bit */
4261 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4262 return -1;
4263
4264 /*
4265 * Clear doorbell int (WRITE 0 to IntStatus reg),
4266 * then wait for IOC to ACKnowledge that it's ready for
4267 * our handshake request.
4268 */
4269 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4270 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4271 failcnt++;
4272
4273 if (!failcnt) {
4274 int ii;
4275 u8 *req_as_bytes = (u8 *) req;
4276
4277 /*
4278 * Stuff request words via doorbell handshake,
4279 * with ACK from IOC for each.
4280 */
4281 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4282 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4283 (req_as_bytes[(ii*4) + 1] << 8) |
4284 (req_as_bytes[(ii*4) + 2] << 16) |
4285 (req_as_bytes[(ii*4) + 3] << 24));
4286
4287 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4288 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4289 failcnt++;
4290 }
4291
Prakash, Sathya436ace72007-07-24 15:42:08 +05304292 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004293 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Prakash, Sathya436ace72007-07-24 15:42:08 +05304295 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4297
4298 /*
4299 * Wait for completion of doorbell handshake reply from the IOC
4300 */
4301 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4302 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004303
Prakash, Sathya436ace72007-07-24 15:42:08 +05304304 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4306
4307 /*
4308 * Copy out the cached reply...
4309 */
4310 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4311 u16reply[ii] = ioc->hs_reply[ii];
4312 } else {
4313 return -99;
4314 }
4315
4316 return -failcnt;
4317}
4318
4319/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004320/**
4321 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 * @ioc: Pointer to MPT_ADAPTER structure
4323 * @howlong: How long to wait (in seconds)
4324 * @sleepFlag: Specifies whether the process can sleep
4325 *
4326 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004327 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4328 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 *
4330 * Returns a negative value on failure, else wait loop count.
4331 */
4332static int
4333WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4334{
4335 int cntdn;
4336 int count = 0;
4337 u32 intstat=0;
4338
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004339 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
4341 if (sleepFlag == CAN_SLEEP) {
4342 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004343 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4345 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4346 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 count++;
4348 }
4349 } else {
4350 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004351 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4353 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4354 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 count++;
4356 }
4357 }
4358
4359 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304360 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 ioc->name, count));
4362 return count;
4363 }
4364
4365 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4366 ioc->name, count, intstat);
4367 return -1;
4368}
4369
4370/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004371/**
4372 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 * @ioc: Pointer to MPT_ADAPTER structure
4374 * @howlong: How long to wait (in seconds)
4375 * @sleepFlag: Specifies whether the process can sleep
4376 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004377 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4378 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 *
4380 * Returns a negative value on failure, else wait loop count.
4381 */
4382static int
4383WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4384{
4385 int cntdn;
4386 int count = 0;
4387 u32 intstat=0;
4388
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004389 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 if (sleepFlag == CAN_SLEEP) {
4391 while (--cntdn) {
4392 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4393 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4394 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004395 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 count++;
4397 }
4398 } else {
4399 while (--cntdn) {
4400 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4401 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4402 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004403 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 count++;
4405 }
4406 }
4407
4408 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304409 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 ioc->name, count, howlong));
4411 return count;
4412 }
4413
4414 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4415 ioc->name, count, intstat);
4416 return -1;
4417}
4418
4419/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004420/**
4421 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 * @ioc: Pointer to MPT_ADAPTER structure
4423 * @howlong: How long to wait (in seconds)
4424 * @sleepFlag: Specifies whether the process can sleep
4425 *
4426 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4427 * Reply is cached to IOC private area large enough to hold a maximum
4428 * of 128 bytes of reply data.
4429 *
4430 * Returns a negative value on failure, else size of reply in WORDS.
4431 */
4432static int
4433WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4434{
4435 int u16cnt = 0;
4436 int failcnt = 0;
4437 int t;
4438 u16 *hs_reply = ioc->hs_reply;
4439 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4440 u16 hword;
4441
4442 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4443
4444 /*
4445 * Get first two u16's so we can look at IOC's intended reply MsgLength
4446 */
4447 u16cnt=0;
4448 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4449 failcnt++;
4450 } else {
4451 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4452 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4453 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4454 failcnt++;
4455 else {
4456 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4457 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4458 }
4459 }
4460
Prakash, Sathya436ace72007-07-24 15:42:08 +05304461 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004462 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4464
4465 /*
4466 * If no error (and IOC said MsgLength is > 0), piece together
4467 * reply 16 bits at a time.
4468 */
4469 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4470 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4471 failcnt++;
4472 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4473 /* don't overflow our IOC hs_reply[] buffer! */
4474 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4475 hs_reply[u16cnt] = hword;
4476 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4477 }
4478
4479 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4480 failcnt++;
4481 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4482
4483 if (failcnt) {
4484 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4485 ioc->name);
4486 return -failcnt;
4487 }
4488#if 0
4489 else if (u16cnt != (2 * mptReply->MsgLength)) {
4490 return -101;
4491 }
4492 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4493 return -102;
4494 }
4495#endif
4496
Prakash, Sathya436ace72007-07-24 15:42:08 +05304497 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004498 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
Prakash, Sathya436ace72007-07-24 15:42:08 +05304500 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 ioc->name, t, u16cnt/2));
4502 return u16cnt/2;
4503}
4504
4505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004506/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 * GetLanConfigPages - Fetch LANConfig pages.
4508 * @ioc: Pointer to MPT_ADAPTER structure
4509 *
4510 * Return: 0 for success
4511 * -ENOMEM if no memory available
4512 * -EPERM if not allowed due to ISR context
4513 * -EAGAIN if no msg frames currently available
4514 * -EFAULT for non-successful reply or no reply (timeout)
4515 */
4516static int
4517GetLanConfigPages(MPT_ADAPTER *ioc)
4518{
4519 ConfigPageHeader_t hdr;
4520 CONFIGPARMS cfg;
4521 LANPage0_t *ppage0_alloc;
4522 dma_addr_t page0_dma;
4523 LANPage1_t *ppage1_alloc;
4524 dma_addr_t page1_dma;
4525 int rc = 0;
4526 int data_sz;
4527 int copy_sz;
4528
4529 /* Get LAN Page 0 header */
4530 hdr.PageVersion = 0;
4531 hdr.PageLength = 0;
4532 hdr.PageNumber = 0;
4533 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004534 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 cfg.physAddr = -1;
4536 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4537 cfg.dir = 0;
4538 cfg.pageAddr = 0;
4539 cfg.timeout = 0;
4540
4541 if ((rc = mpt_config(ioc, &cfg)) != 0)
4542 return rc;
4543
4544 if (hdr.PageLength > 0) {
4545 data_sz = hdr.PageLength * 4;
4546 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4547 rc = -ENOMEM;
4548 if (ppage0_alloc) {
4549 memset((u8 *)ppage0_alloc, 0, data_sz);
4550 cfg.physAddr = page0_dma;
4551 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4552
4553 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4554 /* save the data */
4555 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4556 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4557
4558 }
4559
4560 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4561
4562 /* FIXME!
4563 * Normalize endianness of structure data,
4564 * by byte-swapping all > 1 byte fields!
4565 */
4566
4567 }
4568
4569 if (rc)
4570 return rc;
4571 }
4572
4573 /* Get LAN Page 1 header */
4574 hdr.PageVersion = 0;
4575 hdr.PageLength = 0;
4576 hdr.PageNumber = 1;
4577 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004578 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 cfg.physAddr = -1;
4580 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4581 cfg.dir = 0;
4582 cfg.pageAddr = 0;
4583
4584 if ((rc = mpt_config(ioc, &cfg)) != 0)
4585 return rc;
4586
4587 if (hdr.PageLength == 0)
4588 return 0;
4589
4590 data_sz = hdr.PageLength * 4;
4591 rc = -ENOMEM;
4592 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4593 if (ppage1_alloc) {
4594 memset((u8 *)ppage1_alloc, 0, data_sz);
4595 cfg.physAddr = page1_dma;
4596 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4597
4598 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4599 /* save the data */
4600 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4601 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4602 }
4603
4604 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4605
4606 /* FIXME!
4607 * Normalize endianness of structure data,
4608 * by byte-swapping all > 1 byte fields!
4609 */
4610
4611 }
4612
4613 return rc;
4614}
4615
4616/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004617/**
4618 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004619 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004620 * @persist_opcode: see below
4621 *
4622 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4623 * devices not currently present.
4624 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4625 *
4626 * NOTE: Don't use not this function during interrupt time.
4627 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004628 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004629 */
4630
4631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4632int
4633mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4634{
4635 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4636 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4637 MPT_FRAME_HDR *mf = NULL;
4638 MPIHeader_t *mpi_hdr;
4639
4640
4641 /* insure garbage is not sent to fw */
4642 switch(persist_opcode) {
4643
4644 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4645 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4646 break;
4647
4648 default:
4649 return -1;
4650 break;
4651 }
4652
4653 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4654
4655 /* Get a MF for this command.
4656 */
4657 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4658 printk("%s: no msg frames!\n",__FUNCTION__);
4659 return -1;
4660 }
4661
4662 mpi_hdr = (MPIHeader_t *) mf;
4663 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4664 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4665 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4666 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4667 sasIoUnitCntrReq->Operation = persist_opcode;
4668
4669 init_timer(&ioc->persist_timer);
4670 ioc->persist_timer.data = (unsigned long) ioc;
4671 ioc->persist_timer.function = mpt_timer_expired;
4672 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4673 ioc->persist_wait_done=0;
4674 add_timer(&ioc->persist_timer);
4675 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4676 wait_event(mpt_waitq, ioc->persist_wait_done);
4677
4678 sasIoUnitCntrReply =
4679 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4680 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4681 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4682 __FUNCTION__,
4683 sasIoUnitCntrReply->IOCStatus,
4684 sasIoUnitCntrReply->IOCLogInfo);
4685 return -1;
4686 }
4687
4688 printk("%s: success\n",__FUNCTION__);
4689 return 0;
4690}
4691
4692/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004693
4694static void
4695mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4696 MpiEventDataRaid_t * pRaidEventData)
4697{
4698 int volume;
4699 int reason;
4700 int disk;
4701 int status;
4702 int flags;
4703 int state;
4704
4705 volume = pRaidEventData->VolumeID;
4706 reason = pRaidEventData->ReasonCode;
4707 disk = pRaidEventData->PhysDiskNum;
4708 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4709 flags = (status >> 0) & 0xff;
4710 state = (status >> 8) & 0xff;
4711
4712 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4713 return;
4714 }
4715
4716 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4717 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4718 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004719 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4720 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004721 } else {
4722 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4723 ioc->name, volume);
4724 }
4725
4726 switch(reason) {
4727 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4728 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4729 ioc->name);
4730 break;
4731
4732 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4733
4734 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4735 ioc->name);
4736 break;
4737
4738 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4739 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4740 ioc->name);
4741 break;
4742
4743 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4744 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4745 ioc->name,
4746 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4747 ? "optimal"
4748 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4749 ? "degraded"
4750 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4751 ? "failed"
4752 : "state unknown",
4753 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4754 ? ", enabled" : "",
4755 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4756 ? ", quiesced" : "",
4757 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4758 ? ", resync in progress" : "" );
4759 break;
4760
4761 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4762 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4763 ioc->name, disk);
4764 break;
4765
4766 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4767 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4768 ioc->name);
4769 break;
4770
4771 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4772 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4773 ioc->name);
4774 break;
4775
4776 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4777 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4778 ioc->name);
4779 break;
4780
4781 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4782 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4783 ioc->name,
4784 state == MPI_PHYSDISK0_STATUS_ONLINE
4785 ? "online"
4786 : state == MPI_PHYSDISK0_STATUS_MISSING
4787 ? "missing"
4788 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4789 ? "not compatible"
4790 : state == MPI_PHYSDISK0_STATUS_FAILED
4791 ? "failed"
4792 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4793 ? "initializing"
4794 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4795 ? "offline requested"
4796 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4797 ? "failed requested"
4798 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4799 ? "offline"
4800 : "state unknown",
4801 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4802 ? ", out of sync" : "",
4803 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4804 ? ", quiesced" : "" );
4805 break;
4806
4807 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4808 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4809 ioc->name, disk);
4810 break;
4811
4812 case MPI_EVENT_RAID_RC_SMART_DATA:
4813 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4814 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4815 break;
4816
4817 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4818 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4819 ioc->name, disk);
4820 break;
4821 }
4822}
4823
4824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004825/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4827 * @ioc: Pointer to MPT_ADAPTER structure
4828 *
4829 * Returns: 0 for success
4830 * -ENOMEM if no memory available
4831 * -EPERM if not allowed due to ISR context
4832 * -EAGAIN if no msg frames currently available
4833 * -EFAULT for non-successful reply or no reply (timeout)
4834 */
4835static int
4836GetIoUnitPage2(MPT_ADAPTER *ioc)
4837{
4838 ConfigPageHeader_t hdr;
4839 CONFIGPARMS cfg;
4840 IOUnitPage2_t *ppage_alloc;
4841 dma_addr_t page_dma;
4842 int data_sz;
4843 int rc;
4844
4845 /* Get the page header */
4846 hdr.PageVersion = 0;
4847 hdr.PageLength = 0;
4848 hdr.PageNumber = 2;
4849 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004850 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 cfg.physAddr = -1;
4852 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4853 cfg.dir = 0;
4854 cfg.pageAddr = 0;
4855 cfg.timeout = 0;
4856
4857 if ((rc = mpt_config(ioc, &cfg)) != 0)
4858 return rc;
4859
4860 if (hdr.PageLength == 0)
4861 return 0;
4862
4863 /* Read the config page */
4864 data_sz = hdr.PageLength * 4;
4865 rc = -ENOMEM;
4866 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4867 if (ppage_alloc) {
4868 memset((u8 *)ppage_alloc, 0, data_sz);
4869 cfg.physAddr = page_dma;
4870 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4871
4872 /* If Good, save data */
4873 if ((rc = mpt_config(ioc, &cfg)) == 0)
4874 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4875
4876 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4877 }
4878
4879 return rc;
4880}
4881
4882/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004883/**
4884 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 * @ioc: Pointer to a Adapter Strucutre
4886 * @portnum: IOC port number
4887 *
4888 * Return: -EFAULT if read of config page header fails
4889 * or if no nvram
4890 * If read of SCSI Port Page 0 fails,
4891 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4892 * Adapter settings: async, narrow
4893 * Return 1
4894 * If read of SCSI Port Page 2 fails,
4895 * Adapter settings valid
4896 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4897 * Return 1
4898 * Else
4899 * Both valid
4900 * Return 0
4901 * CHECK - what type of locking mechanisms should be used????
4902 */
4903static int
4904mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4905{
4906 u8 *pbuf;
4907 dma_addr_t buf_dma;
4908 CONFIGPARMS cfg;
4909 ConfigPageHeader_t header;
4910 int ii;
4911 int data, rc = 0;
4912
4913 /* Allocate memory
4914 */
4915 if (!ioc->spi_data.nvram) {
4916 int sz;
4917 u8 *mem;
4918 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4919 mem = kmalloc(sz, GFP_ATOMIC);
4920 if (mem == NULL)
4921 return -EFAULT;
4922
4923 ioc->spi_data.nvram = (int *) mem;
4924
Prakash, Sathya436ace72007-07-24 15:42:08 +05304925 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 ioc->name, ioc->spi_data.nvram, sz));
4927 }
4928
4929 /* Invalidate NVRAM information
4930 */
4931 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4932 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4933 }
4934
4935 /* Read SPP0 header, allocate memory, then read page.
4936 */
4937 header.PageVersion = 0;
4938 header.PageLength = 0;
4939 header.PageNumber = 0;
4940 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004941 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 cfg.physAddr = -1;
4943 cfg.pageAddr = portnum;
4944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4945 cfg.dir = 0;
4946 cfg.timeout = 0; /* use default */
4947 if (mpt_config(ioc, &cfg) != 0)
4948 return -EFAULT;
4949
4950 if (header.PageLength > 0) {
4951 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4952 if (pbuf) {
4953 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4954 cfg.physAddr = buf_dma;
4955 if (mpt_config(ioc, &cfg) != 0) {
4956 ioc->spi_data.maxBusWidth = MPT_NARROW;
4957 ioc->spi_data.maxSyncOffset = 0;
4958 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4959 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4960 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304961 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4962 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004963 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 } else {
4965 /* Save the Port Page 0 data
4966 */
4967 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4968 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4969 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4970
4971 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4972 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004973 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4974 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 ioc->name, pPP0->Capabilities));
4976 }
4977 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4978 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4979 if (data) {
4980 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4981 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4982 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304983 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4984 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004985 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 } else {
4987 ioc->spi_data.maxSyncOffset = 0;
4988 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4989 }
4990
4991 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4992
4993 /* Update the minSyncFactor based on bus type.
4994 */
4995 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4996 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4997
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004998 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305000 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5001 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005002 ioc->name, ioc->spi_data.minSyncFactor));
5003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 }
5005 }
5006 if (pbuf) {
5007 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5008 }
5009 }
5010 }
5011
5012 /* SCSI Port Page 2 - Read the header then the page.
5013 */
5014 header.PageVersion = 0;
5015 header.PageLength = 0;
5016 header.PageNumber = 2;
5017 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005018 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 cfg.physAddr = -1;
5020 cfg.pageAddr = portnum;
5021 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5022 cfg.dir = 0;
5023 if (mpt_config(ioc, &cfg) != 0)
5024 return -EFAULT;
5025
5026 if (header.PageLength > 0) {
5027 /* Allocate memory and read SCSI Port Page 2
5028 */
5029 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5030 if (pbuf) {
5031 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5032 cfg.physAddr = buf_dma;
5033 if (mpt_config(ioc, &cfg) != 0) {
5034 /* Nvram data is left with INVALID mark
5035 */
5036 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005037 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5038
5039 /* This is an ATTO adapter, read Page2 accordingly
5040 */
5041 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5042 ATTODeviceInfo_t *pdevice = NULL;
5043 u16 ATTOFlags;
5044
5045 /* Save the Port Page 2 data
5046 * (reformat into a 32bit quantity)
5047 */
5048 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5049 pdevice = &pPP2->DeviceSettings[ii];
5050 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5051 data = 0;
5052
5053 /* Translate ATTO device flags to LSI format
5054 */
5055 if (ATTOFlags & ATTOFLAG_DISC)
5056 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5057 if (ATTOFlags & ATTOFLAG_ID_ENB)
5058 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5059 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5060 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5061 if (ATTOFlags & ATTOFLAG_TAGGED)
5062 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5063 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5064 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5065
5066 data = (data << 16) | (pdevice->Period << 8) | 10;
5067 ioc->spi_data.nvram[ii] = data;
5068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 } else {
5070 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5071 MpiDeviceInfo_t *pdevice = NULL;
5072
Moore, Ericd8e925d2006-01-16 18:53:06 -07005073 /*
5074 * Save "Set to Avoid SCSI Bus Resets" flag
5075 */
5076 ioc->spi_data.bus_reset =
5077 (le32_to_cpu(pPP2->PortFlags) &
5078 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5079 0 : 1 ;
5080
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 /* Save the Port Page 2 data
5082 * (reformat into a 32bit quantity)
5083 */
5084 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5085 ioc->spi_data.PortFlags = data;
5086 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5087 pdevice = &pPP2->DeviceSettings[ii];
5088 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5089 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5090 ioc->spi_data.nvram[ii] = data;
5091 }
5092 }
5093
5094 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5095 }
5096 }
5097
5098 /* Update Adapter limits with those from NVRAM
5099 * Comment: Don't need to do this. Target performance
5100 * parameters will never exceed the adapters limits.
5101 */
5102
5103 return rc;
5104}
5105
5106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005107/**
5108 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 * @ioc: Pointer to a Adapter Strucutre
5110 * @portnum: IOC port number
5111 *
5112 * Return: -EFAULT if read of config page header fails
5113 * or 0 if success.
5114 */
5115static int
5116mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5117{
5118 CONFIGPARMS cfg;
5119 ConfigPageHeader_t header;
5120
5121 /* Read the SCSI Device Page 1 header
5122 */
5123 header.PageVersion = 0;
5124 header.PageLength = 0;
5125 header.PageNumber = 1;
5126 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005127 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 cfg.physAddr = -1;
5129 cfg.pageAddr = portnum;
5130 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5131 cfg.dir = 0;
5132 cfg.timeout = 0;
5133 if (mpt_config(ioc, &cfg) != 0)
5134 return -EFAULT;
5135
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005136 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5137 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138
5139 header.PageVersion = 0;
5140 header.PageLength = 0;
5141 header.PageNumber = 0;
5142 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5143 if (mpt_config(ioc, &cfg) != 0)
5144 return -EFAULT;
5145
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005146 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5147 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148
Prakash, Sathya436ace72007-07-24 15:42:08 +05305149 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5151
Prakash, Sathya436ace72007-07-24 15:42:08 +05305152 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5154 return 0;
5155}
5156
Eric Mooreb506ade2007-01-29 09:45:37 -07005157/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005158 * mpt_inactive_raid_list_free - This clears this link list.
5159 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005160 **/
5161static void
5162mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5163{
5164 struct inactive_raid_component_info *component_info, *pNext;
5165
5166 if (list_empty(&ioc->raid_data.inactive_list))
5167 return;
5168
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005169 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005170 list_for_each_entry_safe(component_info, pNext,
5171 &ioc->raid_data.inactive_list, list) {
5172 list_del(&component_info->list);
5173 kfree(component_info);
5174 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005175 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005176}
5177
5178/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005179 * 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 -07005180 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005181 * @ioc : pointer to per adapter structure
5182 * @channel : volume channel
5183 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005184 **/
5185static void
5186mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5187{
5188 CONFIGPARMS cfg;
5189 ConfigPageHeader_t hdr;
5190 dma_addr_t dma_handle;
5191 pRaidVolumePage0_t buffer = NULL;
5192 int i;
5193 RaidPhysDiskPage0_t phys_disk;
5194 struct inactive_raid_component_info *component_info;
5195 int handle_inactive_volumes;
5196
5197 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5198 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5199 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5200 cfg.pageAddr = (channel << 8) + id;
5201 cfg.cfghdr.hdr = &hdr;
5202 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5203
5204 if (mpt_config(ioc, &cfg) != 0)
5205 goto out;
5206
5207 if (!hdr.PageLength)
5208 goto out;
5209
5210 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5211 &dma_handle);
5212
5213 if (!buffer)
5214 goto out;
5215
5216 cfg.physAddr = dma_handle;
5217 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5218
5219 if (mpt_config(ioc, &cfg) != 0)
5220 goto out;
5221
5222 if (!buffer->NumPhysDisks)
5223 goto out;
5224
5225 handle_inactive_volumes =
5226 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5227 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5228 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5229 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5230
5231 if (!handle_inactive_volumes)
5232 goto out;
5233
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005234 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005235 for (i = 0; i < buffer->NumPhysDisks; i++) {
5236 if(mpt_raid_phys_disk_pg0(ioc,
5237 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5238 continue;
5239
5240 if ((component_info = kmalloc(sizeof (*component_info),
5241 GFP_KERNEL)) == NULL)
5242 continue;
5243
5244 component_info->volumeID = id;
5245 component_info->volumeBus = channel;
5246 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5247 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5248 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5249 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5250
5251 list_add_tail(&component_info->list,
5252 &ioc->raid_data.inactive_list);
5253 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005254 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005255
5256 out:
5257 if (buffer)
5258 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5259 dma_handle);
5260}
5261
5262/**
5263 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5264 * @ioc: Pointer to a Adapter Structure
5265 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5266 * @phys_disk: requested payload data returned
5267 *
5268 * Return:
5269 * 0 on success
5270 * -EFAULT if read of config page header fails or data pointer not NULL
5271 * -ENOMEM if pci_alloc failed
5272 **/
5273int
5274mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5275{
5276 CONFIGPARMS cfg;
5277 ConfigPageHeader_t hdr;
5278 dma_addr_t dma_handle;
5279 pRaidPhysDiskPage0_t buffer = NULL;
5280 int rc;
5281
5282 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5283 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5284
5285 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5286 cfg.cfghdr.hdr = &hdr;
5287 cfg.physAddr = -1;
5288 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5289
5290 if (mpt_config(ioc, &cfg) != 0) {
5291 rc = -EFAULT;
5292 goto out;
5293 }
5294
5295 if (!hdr.PageLength) {
5296 rc = -EFAULT;
5297 goto out;
5298 }
5299
5300 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5301 &dma_handle);
5302
5303 if (!buffer) {
5304 rc = -ENOMEM;
5305 goto out;
5306 }
5307
5308 cfg.physAddr = dma_handle;
5309 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5310 cfg.pageAddr = phys_disk_num;
5311
5312 if (mpt_config(ioc, &cfg) != 0) {
5313 rc = -EFAULT;
5314 goto out;
5315 }
5316
5317 rc = 0;
5318 memcpy(phys_disk, buffer, sizeof(*buffer));
5319 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5320
5321 out:
5322
5323 if (buffer)
5324 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5325 dma_handle);
5326
5327 return rc;
5328}
5329
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330/**
5331 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5332 * @ioc: Pointer to a Adapter Strucutre
5333 * @portnum: IOC port number
5334 *
5335 * Return:
5336 * 0 on success
5337 * -EFAULT if read of config page header fails or data pointer not NULL
5338 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005339 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340int
5341mpt_findImVolumes(MPT_ADAPTER *ioc)
5342{
5343 IOCPage2_t *pIoc2;
5344 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 dma_addr_t ioc2_dma;
5346 CONFIGPARMS cfg;
5347 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 int rc = 0;
5349 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005350 int i;
5351
5352 if (!ioc->ir_firmware)
5353 return 0;
5354
5355 /* Free the old page
5356 */
5357 kfree(ioc->raid_data.pIocPg2);
5358 ioc->raid_data.pIocPg2 = NULL;
5359 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360
5361 /* Read IOCP2 header then the page.
5362 */
5363 header.PageVersion = 0;
5364 header.PageLength = 0;
5365 header.PageNumber = 2;
5366 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005367 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 cfg.physAddr = -1;
5369 cfg.pageAddr = 0;
5370 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5371 cfg.dir = 0;
5372 cfg.timeout = 0;
5373 if (mpt_config(ioc, &cfg) != 0)
5374 return -EFAULT;
5375
5376 if (header.PageLength == 0)
5377 return -EFAULT;
5378
5379 iocpage2sz = header.PageLength * 4;
5380 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5381 if (!pIoc2)
5382 return -ENOMEM;
5383
5384 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5385 cfg.physAddr = ioc2_dma;
5386 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005387 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Eric Mooreb506ade2007-01-29 09:45:37 -07005389 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5390 if (!mem)
5391 goto out;
5392
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005394 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Eric Mooreb506ade2007-01-29 09:45:37 -07005396 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397
Eric Mooreb506ade2007-01-29 09:45:37 -07005398 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5399 mpt_inactive_raid_volumes(ioc,
5400 pIoc2->RaidVolume[i].VolumeBus,
5401 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
Eric Mooreb506ade2007-01-29 09:45:37 -07005403 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5405
5406 return rc;
5407}
5408
Moore, Ericc972c702006-03-14 09:14:06 -07005409static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5411{
5412 IOCPage3_t *pIoc3;
5413 u8 *mem;
5414 CONFIGPARMS cfg;
5415 ConfigPageHeader_t header;
5416 dma_addr_t ioc3_dma;
5417 int iocpage3sz = 0;
5418
5419 /* Free the old page
5420 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005421 kfree(ioc->raid_data.pIocPg3);
5422 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423
5424 /* There is at least one physical disk.
5425 * Read and save IOC Page 3
5426 */
5427 header.PageVersion = 0;
5428 header.PageLength = 0;
5429 header.PageNumber = 3;
5430 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005431 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 cfg.physAddr = -1;
5433 cfg.pageAddr = 0;
5434 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5435 cfg.dir = 0;
5436 cfg.timeout = 0;
5437 if (mpt_config(ioc, &cfg) != 0)
5438 return 0;
5439
5440 if (header.PageLength == 0)
5441 return 0;
5442
5443 /* Read Header good, alloc memory
5444 */
5445 iocpage3sz = header.PageLength * 4;
5446 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5447 if (!pIoc3)
5448 return 0;
5449
5450 /* Read the Page and save the data
5451 * into malloc'd memory.
5452 */
5453 cfg.physAddr = ioc3_dma;
5454 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5455 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005456 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 if (mem) {
5458 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005459 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 }
5461 }
5462
5463 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5464
5465 return 0;
5466}
5467
5468static void
5469mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5470{
5471 IOCPage4_t *pIoc4;
5472 CONFIGPARMS cfg;
5473 ConfigPageHeader_t header;
5474 dma_addr_t ioc4_dma;
5475 int iocpage4sz;
5476
5477 /* Read and save IOC Page 4
5478 */
5479 header.PageVersion = 0;
5480 header.PageLength = 0;
5481 header.PageNumber = 4;
5482 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005483 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 cfg.physAddr = -1;
5485 cfg.pageAddr = 0;
5486 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5487 cfg.dir = 0;
5488 cfg.timeout = 0;
5489 if (mpt_config(ioc, &cfg) != 0)
5490 return;
5491
5492 if (header.PageLength == 0)
5493 return;
5494
5495 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5496 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5497 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5498 if (!pIoc4)
5499 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005500 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 } else {
5502 ioc4_dma = ioc->spi_data.IocPg4_dma;
5503 iocpage4sz = ioc->spi_data.IocPg4Sz;
5504 }
5505
5506 /* Read the Page into dma memory.
5507 */
5508 cfg.physAddr = ioc4_dma;
5509 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5510 if (mpt_config(ioc, &cfg) == 0) {
5511 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5512 ioc->spi_data.IocPg4_dma = ioc4_dma;
5513 ioc->spi_data.IocPg4Sz = iocpage4sz;
5514 } else {
5515 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5516 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005517 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 }
5519}
5520
5521static void
5522mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5523{
5524 IOCPage1_t *pIoc1;
5525 CONFIGPARMS cfg;
5526 ConfigPageHeader_t header;
5527 dma_addr_t ioc1_dma;
5528 int iocpage1sz = 0;
5529 u32 tmp;
5530
5531 /* Check the Coalescing Timeout in IOC Page 1
5532 */
5533 header.PageVersion = 0;
5534 header.PageLength = 0;
5535 header.PageNumber = 1;
5536 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005537 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 cfg.physAddr = -1;
5539 cfg.pageAddr = 0;
5540 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5541 cfg.dir = 0;
5542 cfg.timeout = 0;
5543 if (mpt_config(ioc, &cfg) != 0)
5544 return;
5545
5546 if (header.PageLength == 0)
5547 return;
5548
5549 /* Read Header good, alloc memory
5550 */
5551 iocpage1sz = header.PageLength * 4;
5552 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5553 if (!pIoc1)
5554 return;
5555
5556 /* Read the Page and check coalescing timeout
5557 */
5558 cfg.physAddr = ioc1_dma;
5559 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5560 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305561
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5563 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5564 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5565
Prakash, Sathya436ace72007-07-24 15:42:08 +05305566 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 ioc->name, tmp));
5568
5569 if (tmp > MPT_COALESCING_TIMEOUT) {
5570 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5571
5572 /* Write NVRAM and current
5573 */
5574 cfg.dir = 1;
5575 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5576 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305577 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 ioc->name, MPT_COALESCING_TIMEOUT));
5579
5580 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5581 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305582 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5583 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 ioc->name, MPT_COALESCING_TIMEOUT));
5585 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305586 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5587 "Reset NVRAM Coalescing Timeout Failed\n",
5588 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 }
5590
5591 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305592 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5593 "Reset of Current Coalescing Timeout Failed!\n",
5594 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 }
5596 }
5597
5598 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305599 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 }
5601 }
5602
5603 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5604
5605 return;
5606}
5607
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305608static void
5609mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5610{
5611 CONFIGPARMS cfg;
5612 ConfigPageHeader_t hdr;
5613 dma_addr_t buf_dma;
5614 ManufacturingPage0_t *pbuf = NULL;
5615
5616 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5617 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5618
5619 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5620 cfg.cfghdr.hdr = &hdr;
5621 cfg.physAddr = -1;
5622 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5623 cfg.timeout = 10;
5624
5625 if (mpt_config(ioc, &cfg) != 0)
5626 goto out;
5627
5628 if (!cfg.cfghdr.hdr->PageLength)
5629 goto out;
5630
5631 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5632 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5633 if (!pbuf)
5634 goto out;
5635
5636 cfg.physAddr = buf_dma;
5637
5638 if (mpt_config(ioc, &cfg) != 0)
5639 goto out;
5640
5641 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5642 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5643 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5644
5645 out:
5646
5647 if (pbuf)
5648 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5649}
5650
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005652/**
5653 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 * @ioc: Pointer to MPT_ADAPTER structure
5655 * @EvSwitch: Event switch flags
5656 */
5657static int
5658SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5659{
5660 EventNotification_t *evnp;
5661
5662 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5663 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305664 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 ioc->name));
5666 return 0;
5667 }
5668 memset(evnp, 0, sizeof(*evnp));
5669
Prakash, Sathya436ace72007-07-24 15:42:08 +05305670 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671
5672 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5673 evnp->ChainOffset = 0;
5674 evnp->MsgFlags = 0;
5675 evnp->Switch = EvSwitch;
5676
5677 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5678
5679 return 0;
5680}
5681
5682/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5683/**
5684 * SendEventAck - Send EventAck request to MPT adapter.
5685 * @ioc: Pointer to MPT_ADAPTER structure
5686 * @evnp: Pointer to original EventNotification request
5687 */
5688static int
5689SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5690{
5691 EventAck_t *pAck;
5692
5693 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305694 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005695 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 return -1;
5697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Prakash, Sathya436ace72007-07-24 15:42:08 +05305699 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
5701 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5702 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005703 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005705 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 pAck->Event = evnp->Event;
5707 pAck->EventContext = evnp->EventContext;
5708
5709 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5710
5711 return 0;
5712}
5713
5714/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5715/**
5716 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005717 * @ioc: Pointer to an adapter structure
5718 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 * action, page address, direction, physical address
5720 * and pointer to a configuration page header
5721 * Page header is updated.
5722 *
5723 * Returns 0 for success
5724 * -EPERM if not allowed due to ISR context
5725 * -EAGAIN if no msg frames currently available
5726 * -EFAULT for non-successful reply or no reply (timeout)
5727 */
5728int
5729mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5730{
5731 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005732 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 MPT_FRAME_HDR *mf;
5734 unsigned long flags;
5735 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005736 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 int in_isr;
5738
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005739 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740 * to be in ISR context, because that is fatal!
5741 */
5742 in_isr = in_interrupt();
5743 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305744 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 ioc->name));
5746 return -EPERM;
5747 }
5748
5749 /* Get and Populate a free Frame
5750 */
5751 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305752 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 ioc->name));
5754 return -EAGAIN;
5755 }
5756 pReq = (Config_t *)mf;
5757 pReq->Action = pCfg->action;
5758 pReq->Reserved = 0;
5759 pReq->ChainOffset = 0;
5760 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005761
5762 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 pReq->ExtPageLength = 0;
5764 pReq->ExtPageType = 0;
5765 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005766
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 for (ii=0; ii < 8; ii++)
5768 pReq->Reserved2[ii] = 0;
5769
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005770 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5771 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5772 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5773 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5774
5775 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5776 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5777 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5778 pReq->ExtPageType = pExtHdr->ExtPageType;
5779 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5780
5781 /* Page Length must be treated as a reserved field for the extended header. */
5782 pReq->Header.PageLength = 0;
5783 }
5784
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5786
5787 /* Add a SGE to the config request.
5788 */
5789 if (pCfg->dir)
5790 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5791 else
5792 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5793
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005794 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5795 flagsLength |= pExtHdr->ExtPageLength * 4;
5796
Prakash, Sathya436ace72007-07-24 15:42:08 +05305797 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 +02005798 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5799 }
5800 else {
5801 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5802
Prakash, Sathya436ace72007-07-24 15:42:08 +05305803 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 +02005804 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
5807 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5808
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 /* Append pCfg pointer to end of mf
5810 */
5811 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5812
5813 /* Initalize the timer
5814 */
5815 init_timer(&pCfg->timer);
5816 pCfg->timer.data = (unsigned long) ioc;
5817 pCfg->timer.function = mpt_timer_expired;
5818 pCfg->wait_done = 0;
5819
5820 /* Set the timer; ensure 10 second minimum */
5821 if (pCfg->timeout < 10)
5822 pCfg->timer.expires = jiffies + HZ*10;
5823 else
5824 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5825
5826 /* Add to end of Q, set timer and then issue this command */
5827 spin_lock_irqsave(&ioc->FreeQlock, flags);
5828 list_add_tail(&pCfg->linkage, &ioc->configQ);
5829 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5830
5831 add_timer(&pCfg->timer);
5832 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5833 wait_event(mpt_waitq, pCfg->wait_done);
5834
5835 /* mf has been freed - do not access */
5836
5837 rc = pCfg->status;
5838
5839 return rc;
5840}
5841
5842/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005843/**
5844 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 * Used only internal config functionality.
5846 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5847 */
5848static void
5849mpt_timer_expired(unsigned long data)
5850{
5851 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5852
Prakash, Sathya436ace72007-07-24 15:42:08 +05305853 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854
5855 /* Perform a FW reload */
5856 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5857 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5858
5859 /* No more processing.
5860 * Hard reset clean-up will wake up
5861 * process and free all resources.
5862 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305863 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864
5865 return;
5866}
5867
5868/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005869/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 * mpt_ioc_reset - Base cleanup for hard reset
5871 * @ioc: Pointer to the adapter structure
5872 * @reset_phase: Indicates pre- or post-reset functionality
5873 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005874 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 */
5876static int
5877mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5878{
5879 CONFIGPARMS *pCfg;
5880 unsigned long flags;
5881
Eric Moore29dd3602007-09-14 18:46:51 -06005882 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5883 ": IOC %s_reset routed to MPT base driver!\n",
5884 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5885 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886
5887 if (reset_phase == MPT_IOC_SETUP_RESET) {
5888 ;
5889 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5890 /* If the internal config Q is not empty -
5891 * delete timer. MF resources will be freed when
5892 * the FIFO's are primed.
5893 */
5894 spin_lock_irqsave(&ioc->FreeQlock, flags);
5895 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5896 del_timer(&pCfg->timer);
5897 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5898
5899 } else {
5900 CONFIGPARMS *pNext;
5901
5902 /* Search the configQ for internal commands.
5903 * Flush the Q, and wake up all suspended threads.
5904 */
5905 spin_lock_irqsave(&ioc->FreeQlock, flags);
5906 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5907 list_del(&pCfg->linkage);
5908
5909 pCfg->status = MPT_CONFIG_ERROR;
5910 pCfg->wait_done = 1;
5911 wake_up(&mpt_waitq);
5912 }
5913 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5914 }
5915
5916 return 1; /* currently means nothing really */
5917}
5918
5919
5920#ifdef CONFIG_PROC_FS /* { */
5921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5922/*
5923 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5924 */
5925/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005926/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5928 *
5929 * Returns 0 for success, non-zero for failure.
5930 */
5931static int
5932procmpt_create(void)
5933{
5934 struct proc_dir_entry *ent;
5935
5936 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5937 if (mpt_proc_root_dir == NULL)
5938 return -ENOTDIR;
5939
5940 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5941 if (ent)
5942 ent->read_proc = procmpt_summary_read;
5943
5944 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5945 if (ent)
5946 ent->read_proc = procmpt_version_read;
5947
5948 return 0;
5949}
5950
5951/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005952/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5954 *
5955 * Returns 0 for success, non-zero for failure.
5956 */
5957static void
5958procmpt_destroy(void)
5959{
5960 remove_proc_entry("version", mpt_proc_root_dir);
5961 remove_proc_entry("summary", mpt_proc_root_dir);
5962 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5963}
5964
5965/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005966/**
5967 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 * @buf: Pointer to area to write information
5969 * @start: Pointer to start pointer
5970 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005971 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 * @eof: Pointer to EOF integer
5973 * @data: Pointer
5974 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005975 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 * Returns number of characters written to process performing the read.
5977 */
5978static int
5979procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5980{
5981 MPT_ADAPTER *ioc;
5982 char *out = buf;
5983 int len;
5984
5985 if (data) {
5986 int more = 0;
5987
5988 ioc = data;
5989 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5990
5991 out += more;
5992 } else {
5993 list_for_each_entry(ioc, &ioc_list, list) {
5994 int more = 0;
5995
5996 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5997
5998 out += more;
5999 if ((out-buf) >= request)
6000 break;
6001 }
6002 }
6003
6004 len = out - buf;
6005
6006 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6007}
6008
6009/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006010/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 * procmpt_version_read - Handle read request from /proc/mpt/version.
6012 * @buf: Pointer to area to write information
6013 * @start: Pointer to start pointer
6014 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006015 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 * @eof: Pointer to EOF integer
6017 * @data: Pointer
6018 *
6019 * Returns number of characters written to process performing the read.
6020 */
6021static int
6022procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6023{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306024 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006025 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026 char *drvname;
6027 int len;
6028
6029 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6030 len += sprintf(buf+len, " Fusion MPT base driver\n");
6031
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006032 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006033 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306035 if (MptCallbacks[cb_idx]) {
6036 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006037 case MPTSPI_DRIVER:
6038 if (!scsi++) drvname = "SPI host";
6039 break;
6040 case MPTFC_DRIVER:
6041 if (!fc++) drvname = "FC host";
6042 break;
6043 case MPTSAS_DRIVER:
6044 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 break;
6046 case MPTLAN_DRIVER:
6047 if (!lan++) drvname = "LAN";
6048 break;
6049 case MPTSTM_DRIVER:
6050 if (!targ++) drvname = "SCSI target";
6051 break;
6052 case MPTCTL_DRIVER:
6053 if (!ctl++) drvname = "ioctl";
6054 break;
6055 }
6056
6057 if (drvname)
6058 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6059 }
6060 }
6061
6062 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6063}
6064
6065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006066/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6068 * @buf: Pointer to area to write information
6069 * @start: Pointer to start pointer
6070 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006071 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 * @eof: Pointer to EOF integer
6073 * @data: Pointer
6074 *
6075 * Returns number of characters written to process performing the read.
6076 */
6077static int
6078procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6079{
6080 MPT_ADAPTER *ioc = data;
6081 int len;
6082 char expVer[32];
6083 int sz;
6084 int p;
6085
6086 mpt_get_fw_exp_ver(expVer, ioc);
6087
6088 len = sprintf(buf, "%s:", ioc->name);
6089 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6090 len += sprintf(buf+len, " (f/w download boot flag set)");
6091// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6092// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6093
6094 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6095 ioc->facts.ProductID,
6096 ioc->prod_name);
6097 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6098 if (ioc->facts.FWImageSize)
6099 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6100 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6101 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6102 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6103
6104 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6105 ioc->facts.CurrentHostMfaHighAddr);
6106 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6107 ioc->facts.CurrentSenseBufferHighAddr);
6108
6109 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6110 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6111
6112 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6113 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6114 /*
6115 * Rounding UP to nearest 4-kB boundary here...
6116 */
6117 sz = (ioc->req_sz * ioc->req_depth) + 128;
6118 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6119 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6120 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6121 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6122 4*ioc->facts.RequestFrameSize,
6123 ioc->facts.GlobalCredits);
6124
6125 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6126 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6127 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6128 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6129 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6130 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6131 ioc->facts.CurReplyFrameSize,
6132 ioc->facts.ReplyQueueDepth);
6133
6134 len += sprintf(buf+len, " MaxDevices = %d\n",
6135 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6136 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6137
6138 /* per-port info */
6139 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6140 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6141 p+1,
6142 ioc->facts.NumberOfPorts);
6143 if (ioc->bus_type == FC) {
6144 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6145 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6146 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6147 a[5], a[4], a[3], a[2], a[1], a[0]);
6148 }
6149 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6150 ioc->fc_port_page0[p].WWNN.High,
6151 ioc->fc_port_page0[p].WWNN.Low,
6152 ioc->fc_port_page0[p].WWPN.High,
6153 ioc->fc_port_page0[p].WWPN.Low);
6154 }
6155 }
6156
6157 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6158}
6159
6160#endif /* CONFIG_PROC_FS } */
6161
6162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6163static void
6164mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6165{
6166 buf[0] ='\0';
6167 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6168 sprintf(buf, " (Exp %02d%02d)",
6169 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6170 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6171
6172 /* insider hack! */
6173 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6174 strcat(buf, " [MDBG]");
6175 }
6176}
6177
6178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6179/**
6180 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6181 * @ioc: Pointer to MPT_ADAPTER structure
6182 * @buffer: Pointer to buffer where IOC summary info should be written
6183 * @size: Pointer to number of bytes we wrote (set by this routine)
6184 * @len: Offset at which to start writing in buffer
6185 * @showlan: Display LAN stuff?
6186 *
6187 * This routine writes (english readable) ASCII text, which represents
6188 * a summary of IOC information, to a buffer.
6189 */
6190void
6191mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6192{
6193 char expVer[32];
6194 int y;
6195
6196 mpt_get_fw_exp_ver(expVer, ioc);
6197
6198 /*
6199 * Shorter summary of attached ioc's...
6200 */
6201 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6202 ioc->name,
6203 ioc->prod_name,
6204 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6205 ioc->facts.FWVersion.Word,
6206 expVer,
6207 ioc->facts.NumberOfPorts,
6208 ioc->req_depth);
6209
6210 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6211 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6212 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6213 a[5], a[4], a[3], a[2], a[1], a[0]);
6214 }
6215
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217
6218 if (!ioc->active)
6219 y += sprintf(buffer+len+y, " (disabled)");
6220
6221 y += sprintf(buffer+len+y, "\n");
6222
6223 *size = y;
6224}
6225
6226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6227/*
6228 * Reset Handling
6229 */
6230/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6231/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006232 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 * @ioc: Pointer to MPT_ADAPTER structure
6234 * @sleepFlag: Indicates if sleep or schedule must be called.
6235 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006236 * Issues SCSI Task Management call based on input arg values.
6237 * If TaskMgmt fails, returns associated SCSI request.
6238 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6240 * or a non-interrupt thread. In the former, must not call schedule().
6241 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006242 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 * FW reload/initialization failed.
6244 *
6245 * Returns 0 for SUCCESS or -1 if FAILED.
6246 */
6247int
6248mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6249{
6250 int rc;
6251 unsigned long flags;
6252
Prakash, Sathya436ace72007-07-24 15:42:08 +05306253 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254#ifdef MFCNT
6255 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6256 printk("MF count 0x%x !\n", ioc->mfcnt);
6257#endif
6258
6259 /* Reset the adapter. Prevent more than 1 call to
6260 * mpt_do_ioc_recovery at any instant in time.
6261 */
6262 spin_lock_irqsave(&ioc->diagLock, flags);
6263 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6264 spin_unlock_irqrestore(&ioc->diagLock, flags);
6265 return 0;
6266 } else {
6267 ioc->diagPending = 1;
6268 }
6269 spin_unlock_irqrestore(&ioc->diagLock, flags);
6270
6271 /* FIXME: If do_ioc_recovery fails, repeat....
6272 */
6273
6274 /* The SCSI driver needs to adjust timeouts on all current
6275 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006276 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 * For all other protocol drivers, this is a no-op.
6278 */
6279 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306280 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 int r = 0;
6282
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306283 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6284 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306285 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306286 ioc->name, cb_idx));
6287 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306289 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306290 ioc->name, ioc->alt_ioc->name, cb_idx));
6291 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 }
6293 }
6294 }
6295 }
6296
6297 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006298 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299 }
6300 ioc->reload_fw = 0;
6301 if (ioc->alt_ioc)
6302 ioc->alt_ioc->reload_fw = 0;
6303
6304 spin_lock_irqsave(&ioc->diagLock, flags);
6305 ioc->diagPending = 0;
6306 if (ioc->alt_ioc)
6307 ioc->alt_ioc->diagPending = 0;
6308 spin_unlock_irqrestore(&ioc->diagLock, flags);
6309
Prakash, Sathya436ace72007-07-24 15:42:08 +05306310 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
6312 return rc;
6313}
6314
6315/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006316static void
6317EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318{
Eric Moore509e5e52006-04-26 13:22:37 -06006319 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320
6321 switch(event) {
6322 case MPI_EVENT_NONE:
6323 ds = "None";
6324 break;
6325 case MPI_EVENT_LOG_DATA:
6326 ds = "Log Data";
6327 break;
6328 case MPI_EVENT_STATE_CHANGE:
6329 ds = "State Change";
6330 break;
6331 case MPI_EVENT_UNIT_ATTENTION:
6332 ds = "Unit Attention";
6333 break;
6334 case MPI_EVENT_IOC_BUS_RESET:
6335 ds = "IOC Bus Reset";
6336 break;
6337 case MPI_EVENT_EXT_BUS_RESET:
6338 ds = "External Bus Reset";
6339 break;
6340 case MPI_EVENT_RESCAN:
6341 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 break;
6343 case MPI_EVENT_LINK_STATUS_CHANGE:
6344 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6345 ds = "Link Status(FAILURE) Change";
6346 else
6347 ds = "Link Status(ACTIVE) Change";
6348 break;
6349 case MPI_EVENT_LOOP_STATE_CHANGE:
6350 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6351 ds = "Loop State(LIP) Change";
6352 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006353 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 else
Eric Moore509e5e52006-04-26 13:22:37 -06006355 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 break;
6357 case MPI_EVENT_LOGOUT:
6358 ds = "Logout";
6359 break;
6360 case MPI_EVENT_EVENT_CHANGE:
6361 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006362 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006364 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365 break;
6366 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006367 {
6368 u8 ReasonCode = (u8)(evData0 >> 16);
6369 switch (ReasonCode) {
6370 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6371 ds = "Integrated Raid: Volume Created";
6372 break;
6373 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6374 ds = "Integrated Raid: Volume Deleted";
6375 break;
6376 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6377 ds = "Integrated Raid: Volume Settings Changed";
6378 break;
6379 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6380 ds = "Integrated Raid: Volume Status Changed";
6381 break;
6382 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6383 ds = "Integrated Raid: Volume Physdisk Changed";
6384 break;
6385 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6386 ds = "Integrated Raid: Physdisk Created";
6387 break;
6388 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6389 ds = "Integrated Raid: Physdisk Deleted";
6390 break;
6391 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6392 ds = "Integrated Raid: Physdisk Settings Changed";
6393 break;
6394 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6395 ds = "Integrated Raid: Physdisk Status Changed";
6396 break;
6397 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6398 ds = "Integrated Raid: Domain Validation Needed";
6399 break;
6400 case MPI_EVENT_RAID_RC_SMART_DATA :
6401 ds = "Integrated Raid; Smart Data";
6402 break;
6403 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6404 ds = "Integrated Raid: Replace Action Started";
6405 break;
6406 default:
6407 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006409 }
6410 break;
6411 }
6412 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6413 ds = "SCSI Device Status Change";
6414 break;
6415 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6416 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006417 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006418 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006419 u8 ReasonCode = (u8)(evData0 >> 16);
6420 switch (ReasonCode) {
6421 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006422 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006423 "SAS Device Status Change: Added: "
6424 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006425 break;
6426 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006427 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006428 "SAS Device Status Change: Deleted: "
6429 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006430 break;
6431 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006432 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006433 "SAS Device Status Change: SMART Data: "
6434 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006435 break;
6436 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006437 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006438 "SAS Device Status Change: No Persistancy: "
6439 "id=%d channel=%d", id, channel);
6440 break;
6441 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6442 snprintf(evStr, EVENT_DESCR_STR_SZ,
6443 "SAS Device Status Change: Unsupported Device "
6444 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006445 break;
6446 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6447 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006448 "SAS Device Status Change: Internal Device "
6449 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006450 break;
6451 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6452 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006453 "SAS Device Status Change: Internal Task "
6454 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006455 break;
6456 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6457 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006458 "SAS Device Status Change: Internal Abort "
6459 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006460 break;
6461 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6462 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006463 "SAS Device Status Change: Internal Clear "
6464 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006465 break;
6466 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6467 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006468 "SAS Device Status Change: Internal Query "
6469 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006470 break;
6471 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006472 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006473 "SAS Device Status Change: Unknown: "
6474 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006475 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006476 }
6477 break;
6478 }
6479 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6480 ds = "Bus Timer Expired";
6481 break;
6482 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006483 {
6484 u16 curr_depth = (u16)(evData0 >> 16);
6485 u8 channel = (u8)(evData0 >> 8);
6486 u8 id = (u8)(evData0);
6487
6488 snprintf(evStr, EVENT_DESCR_STR_SZ,
6489 "Queue Full: channel=%d id=%d depth=%d",
6490 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006491 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006492 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006493 case MPI_EVENT_SAS_SES:
6494 ds = "SAS SES Event";
6495 break;
6496 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6497 ds = "Persistent Table Full";
6498 break;
6499 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006500 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006501 u8 LinkRates = (u8)(evData0 >> 8);
6502 u8 PhyNumber = (u8)(evData0);
6503 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6504 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6505 switch (LinkRates) {
6506 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006507 snprintf(evStr, EVENT_DESCR_STR_SZ,
6508 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006509 " Rate Unknown",PhyNumber);
6510 break;
6511 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006512 snprintf(evStr, EVENT_DESCR_STR_SZ,
6513 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006514 " Phy Disabled",PhyNumber);
6515 break;
6516 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006517 snprintf(evStr, EVENT_DESCR_STR_SZ,
6518 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006519 " Failed Speed Nego",PhyNumber);
6520 break;
6521 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006522 snprintf(evStr, EVENT_DESCR_STR_SZ,
6523 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006524 " Sata OOB Completed",PhyNumber);
6525 break;
6526 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006527 snprintf(evStr, EVENT_DESCR_STR_SZ,
6528 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006529 " Rate 1.5 Gbps",PhyNumber);
6530 break;
6531 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006532 snprintf(evStr, EVENT_DESCR_STR_SZ,
6533 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006534 " Rate 3.0 Gpbs",PhyNumber);
6535 break;
6536 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006537 snprintf(evStr, EVENT_DESCR_STR_SZ,
6538 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006539 break;
6540 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006541 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006542 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006543 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6544 ds = "SAS Discovery Error";
6545 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006546 case MPI_EVENT_IR_RESYNC_UPDATE:
6547 {
6548 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006549 snprintf(evStr, EVENT_DESCR_STR_SZ,
6550 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006551 break;
6552 }
6553 case MPI_EVENT_IR2:
6554 {
6555 u8 ReasonCode = (u8)(evData0 >> 16);
6556 switch (ReasonCode) {
6557 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6558 ds = "IR2: LD State Changed";
6559 break;
6560 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6561 ds = "IR2: PD State Changed";
6562 break;
6563 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6564 ds = "IR2: Bad Block Table Full";
6565 break;
6566 case MPI_EVENT_IR2_RC_PD_INSERTED:
6567 ds = "IR2: PD Inserted";
6568 break;
6569 case MPI_EVENT_IR2_RC_PD_REMOVED:
6570 ds = "IR2: PD Removed";
6571 break;
6572 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6573 ds = "IR2: Foreign CFG Detected";
6574 break;
6575 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6576 ds = "IR2: Rebuild Medium Error";
6577 break;
6578 default:
6579 ds = "IR2";
6580 break;
6581 }
6582 break;
6583 }
6584 case MPI_EVENT_SAS_DISCOVERY:
6585 {
6586 if (evData0)
6587 ds = "SAS Discovery: Start";
6588 else
6589 ds = "SAS Discovery: Stop";
6590 break;
6591 }
6592 case MPI_EVENT_LOG_ENTRY_ADDED:
6593 ds = "SAS Log Entry Added";
6594 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006595
Eric Moorec6c727a2007-01-29 09:44:54 -07006596 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6597 {
6598 u8 phy_num = (u8)(evData0);
6599 u8 port_num = (u8)(evData0 >> 8);
6600 u8 port_width = (u8)(evData0 >> 16);
6601 u8 primative = (u8)(evData0 >> 24);
6602 snprintf(evStr, EVENT_DESCR_STR_SZ,
6603 "SAS Broadcase Primative: phy=%d port=%d "
6604 "width=%d primative=0x%02x",
6605 phy_num, port_num, port_width, primative);
6606 break;
6607 }
6608
6609 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6610 {
6611 u8 reason = (u8)(evData0);
6612 u8 port_num = (u8)(evData0 >> 8);
6613 u16 handle = le16_to_cpu(evData0 >> 16);
6614
6615 snprintf(evStr, EVENT_DESCR_STR_SZ,
6616 "SAS Initiator Device Status Change: reason=0x%02x "
6617 "port=%d handle=0x%04x",
6618 reason, port_num, handle);
6619 break;
6620 }
6621
6622 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6623 {
6624 u8 max_init = (u8)(evData0);
6625 u8 current_init = (u8)(evData0 >> 8);
6626
6627 snprintf(evStr, EVENT_DESCR_STR_SZ,
6628 "SAS Initiator Device Table Overflow: max initiators=%02d "
6629 "current initators=%02d",
6630 max_init, current_init);
6631 break;
6632 }
6633 case MPI_EVENT_SAS_SMP_ERROR:
6634 {
6635 u8 status = (u8)(evData0);
6636 u8 port_num = (u8)(evData0 >> 8);
6637 u8 result = (u8)(evData0 >> 16);
6638
6639 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6640 snprintf(evStr, EVENT_DESCR_STR_SZ,
6641 "SAS SMP Error: port=%d result=0x%02x",
6642 port_num, result);
6643 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6644 snprintf(evStr, EVENT_DESCR_STR_SZ,
6645 "SAS SMP Error: port=%d : CRC Error",
6646 port_num);
6647 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6648 snprintf(evStr, EVENT_DESCR_STR_SZ,
6649 "SAS SMP Error: port=%d : Timeout",
6650 port_num);
6651 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6652 snprintf(evStr, EVENT_DESCR_STR_SZ,
6653 "SAS SMP Error: port=%d : No Destination",
6654 port_num);
6655 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6656 snprintf(evStr, EVENT_DESCR_STR_SZ,
6657 "SAS SMP Error: port=%d : Bad Destination",
6658 port_num);
6659 else
6660 snprintf(evStr, EVENT_DESCR_STR_SZ,
6661 "SAS SMP Error: port=%d : status=0x%02x",
6662 port_num, status);
6663 break;
6664 }
6665
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666 /*
6667 * MPT base "custom" events may be added here...
6668 */
6669 default:
6670 ds = "Unknown";
6671 break;
6672 }
Eric Moore509e5e52006-04-26 13:22:37 -06006673 if (ds)
6674 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675}
6676
6677/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006678/**
6679 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680 * @ioc: Pointer to MPT_ADAPTER structure
6681 * @pEventReply: Pointer to EventNotification reply frame
6682 * @evHandlers: Pointer to integer, number of event handlers
6683 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006684 * Routes a received EventNotificationReply to all currently registered
6685 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686 * Returns sum of event handlers return values.
6687 */
6688static int
6689ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6690{
6691 u16 evDataLen;
6692 u32 evData0 = 0;
6693// u32 evCtx;
6694 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306695 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696 int r = 0;
6697 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006698 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699 u8 event;
6700
6701 /*
6702 * Do platform normalization of values
6703 */
6704 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6705// evCtx = le32_to_cpu(pEventReply->EventContext);
6706 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6707 if (evDataLen) {
6708 evData0 = le32_to_cpu(pEventReply->Data[0]);
6709 }
6710
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006711 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306712 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006714 event,
6715 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716
Prakash, Sathya436ace72007-07-24 15:42:08 +05306717#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006718 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6719 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306721 devtverboseprintk(ioc, printk(" %08x",
6722 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006723 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724#endif
6725
6726 /*
6727 * Do general / base driver event processing
6728 */
6729 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6731 if (evDataLen) {
6732 u8 evState = evData0 & 0xFF;
6733
6734 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6735
6736 /* Update EventState field in cached IocFacts */
6737 if (ioc->facts.Function) {
6738 ioc->facts.EventState = evState;
6739 }
6740 }
6741 break;
Moore, Ericece50912006-01-16 18:53:19 -07006742 case MPI_EVENT_INTEGRATED_RAID:
6743 mptbase_raid_process_event_data(ioc,
6744 (MpiEventDataRaid_t *)pEventReply->Data);
6745 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006746 default:
6747 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748 }
6749
6750 /*
6751 * Should this event be logged? Events are written sequentially.
6752 * When buffer is full, start again at the top.
6753 */
6754 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6755 int idx;
6756
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006757 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758
6759 ioc->events[idx].event = event;
6760 ioc->events[idx].eventContext = ioc->eventContext;
6761
6762 for (ii = 0; ii < 2; ii++) {
6763 if (ii < evDataLen)
6764 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6765 else
6766 ioc->events[idx].data[ii] = 0;
6767 }
6768
6769 ioc->eventContext++;
6770 }
6771
6772
6773 /*
6774 * Call each currently registered protocol event handler.
6775 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006776 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306777 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306778 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306779 ioc->name, cb_idx));
6780 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781 handlers++;
6782 }
6783 }
6784 /* FIXME? Examine results here? */
6785
6786 /*
6787 * If needed, send (a single) EventAck.
6788 */
6789 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306790 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006791 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306793 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794 ioc->name, ii));
6795 }
6796 }
6797
6798 *evHandlers = handlers;
6799 return r;
6800}
6801
6802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006803/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6805 * @ioc: Pointer to MPT_ADAPTER structure
6806 * @log_info: U32 LogInfo reply word from the IOC
6807 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006808 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809 */
6810static void
6811mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6812{
Eric Moore7c431e52007-06-13 16:34:36 -06006813 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814
Eric Moore7c431e52007-06-13 16:34:36 -06006815 switch (log_info & 0xFF000000) {
6816 case MPI_IOCLOGINFO_FC_INIT_BASE:
6817 desc = "FCP Initiator";
6818 break;
6819 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6820 desc = "FCP Target";
6821 break;
6822 case MPI_IOCLOGINFO_FC_LAN_BASE:
6823 desc = "LAN";
6824 break;
6825 case MPI_IOCLOGINFO_FC_MSG_BASE:
6826 desc = "MPI Message Layer";
6827 break;
6828 case MPI_IOCLOGINFO_FC_LINK_BASE:
6829 desc = "FC Link";
6830 break;
6831 case MPI_IOCLOGINFO_FC_CTX_BASE:
6832 desc = "Context Manager";
6833 break;
6834 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6835 desc = "Invalid Field Offset";
6836 break;
6837 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6838 desc = "State Change Info";
6839 break;
6840 }
6841
6842 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6843 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844}
6845
6846/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006847/**
Moore, Eric335a9412006-01-17 17:06:23 -07006848 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849 * @ioc: Pointer to MPT_ADAPTER structure
6850 * @mr: Pointer to MPT reply frame
6851 * @log_info: U32 LogInfo word from the IOC
6852 *
6853 * Refer to lsi/sp_log.h.
6854 */
6855static void
Moore, Eric335a9412006-01-17 17:06:23 -07006856mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857{
6858 u32 info = log_info & 0x00FF0000;
6859 char *desc = "unknown";
6860
6861 switch (info) {
6862 case 0x00010000:
6863 desc = "bug! MID not found";
6864 if (ioc->reload_fw == 0)
6865 ioc->reload_fw++;
6866 break;
6867
6868 case 0x00020000:
6869 desc = "Parity Error";
6870 break;
6871
6872 case 0x00030000:
6873 desc = "ASYNC Outbound Overrun";
6874 break;
6875
6876 case 0x00040000:
6877 desc = "SYNC Offset Error";
6878 break;
6879
6880 case 0x00050000:
6881 desc = "BM Change";
6882 break;
6883
6884 case 0x00060000:
6885 desc = "Msg In Overflow";
6886 break;
6887
6888 case 0x00070000:
6889 desc = "DMA Error";
6890 break;
6891
6892 case 0x00080000:
6893 desc = "Outbound DMA Overrun";
6894 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006895
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896 case 0x00090000:
6897 desc = "Task Management";
6898 break;
6899
6900 case 0x000A0000:
6901 desc = "Device Problem";
6902 break;
6903
6904 case 0x000B0000:
6905 desc = "Invalid Phase Change";
6906 break;
6907
6908 case 0x000C0000:
6909 desc = "Untagged Table Size";
6910 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006911
Linus Torvalds1da177e2005-04-16 15:20:36 -07006912 }
6913
6914 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6915}
6916
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006917/* strings for sas loginfo */
6918 static char *originator_str[] = {
6919 "IOP", /* 00h */
6920 "PL", /* 01h */
6921 "IR" /* 02h */
6922 };
6923 static char *iop_code_str[] = {
6924 NULL, /* 00h */
6925 "Invalid SAS Address", /* 01h */
6926 NULL, /* 02h */
6927 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006928 "Diag Message Error", /* 04h */
6929 "Task Terminated", /* 05h */
6930 "Enclosure Management", /* 06h */
6931 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006932 };
6933 static char *pl_code_str[] = {
6934 NULL, /* 00h */
6935 "Open Failure", /* 01h */
6936 "Invalid Scatter Gather List", /* 02h */
6937 "Wrong Relative Offset or Frame Length", /* 03h */
6938 "Frame Transfer Error", /* 04h */
6939 "Transmit Frame Connected Low", /* 05h */
6940 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6941 "SATA Read Log Receive Data Error", /* 07h */
6942 "SATA NCQ Fail All Commands After Error", /* 08h */
6943 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6944 "Receive Frame Invalid Message", /* 0Ah */
6945 "Receive Context Message Valid Error", /* 0Bh */
6946 "Receive Frame Current Frame Error", /* 0Ch */
6947 "SATA Link Down", /* 0Dh */
6948 "Discovery SATA Init W IOS", /* 0Eh */
6949 "Config Invalid Page", /* 0Fh */
6950 "Discovery SATA Init Timeout", /* 10h */
6951 "Reset", /* 11h */
6952 "Abort", /* 12h */
6953 "IO Not Yet Executed", /* 13h */
6954 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006955 "Persistent Reservation Out Not Affiliation "
6956 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006957 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006958 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006959 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006960 NULL, /* 19h */
6961 NULL, /* 1Ah */
6962 NULL, /* 1Bh */
6963 NULL, /* 1Ch */
6964 NULL, /* 1Dh */
6965 NULL, /* 1Eh */
6966 NULL, /* 1Fh */
6967 "Enclosure Management" /* 20h */
6968 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006969 static char *ir_code_str[] = {
6970 "Raid Action Error", /* 00h */
6971 NULL, /* 00h */
6972 NULL, /* 01h */
6973 NULL, /* 02h */
6974 NULL, /* 03h */
6975 NULL, /* 04h */
6976 NULL, /* 05h */
6977 NULL, /* 06h */
6978 NULL /* 07h */
6979 };
6980 static char *raid_sub_code_str[] = {
6981 NULL, /* 00h */
6982 "Volume Creation Failed: Data Passed too "
6983 "Large", /* 01h */
6984 "Volume Creation Failed: Duplicate Volumes "
6985 "Attempted", /* 02h */
6986 "Volume Creation Failed: Max Number "
6987 "Supported Volumes Exceeded", /* 03h */
6988 "Volume Creation Failed: DMA Error", /* 04h */
6989 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6990 "Volume Creation Failed: Error Reading "
6991 "MFG Page 4", /* 06h */
6992 "Volume Creation Failed: Creating Internal "
6993 "Structures", /* 07h */
6994 NULL, /* 08h */
6995 NULL, /* 09h */
6996 NULL, /* 0Ah */
6997 NULL, /* 0Bh */
6998 NULL, /* 0Ch */
6999 NULL, /* 0Dh */
7000 NULL, /* 0Eh */
7001 NULL, /* 0Fh */
7002 "Activation failed: Already Active Volume", /* 10h */
7003 "Activation failed: Unsupported Volume Type", /* 11h */
7004 "Activation failed: Too Many Active Volumes", /* 12h */
7005 "Activation failed: Volume ID in Use", /* 13h */
7006 "Activation failed: Reported Failure", /* 14h */
7007 "Activation failed: Importing a Volume", /* 15h */
7008 NULL, /* 16h */
7009 NULL, /* 17h */
7010 NULL, /* 18h */
7011 NULL, /* 19h */
7012 NULL, /* 1Ah */
7013 NULL, /* 1Bh */
7014 NULL, /* 1Ch */
7015 NULL, /* 1Dh */
7016 NULL, /* 1Eh */
7017 NULL, /* 1Fh */
7018 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7019 "Phys Disk failed: Data Passed too Large", /* 21h */
7020 "Phys Disk failed: DMA Error", /* 22h */
7021 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7022 "Phys Disk failed: Creating Phys Disk Config "
7023 "Page", /* 24h */
7024 NULL, /* 25h */
7025 NULL, /* 26h */
7026 NULL, /* 27h */
7027 NULL, /* 28h */
7028 NULL, /* 29h */
7029 NULL, /* 2Ah */
7030 NULL, /* 2Bh */
7031 NULL, /* 2Ch */
7032 NULL, /* 2Dh */
7033 NULL, /* 2Eh */
7034 NULL, /* 2Fh */
7035 "Compatibility Error: IR Disabled", /* 30h */
7036 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7037 "Compatibility Error: Device not Direct Access "
7038 "Device ", /* 32h */
7039 "Compatibility Error: Removable Device Found", /* 33h */
7040 "Compatibility Error: Device SCSI Version not "
7041 "2 or Higher", /* 34h */
7042 "Compatibility Error: SATA Device, 48 BIT LBA "
7043 "not Supported", /* 35h */
7044 "Compatibility Error: Device doesn't have "
7045 "512 Byte Block Sizes", /* 36h */
7046 "Compatibility Error: Volume Type Check Failed", /* 37h */
7047 "Compatibility Error: Volume Type is "
7048 "Unsupported by FW", /* 38h */
7049 "Compatibility Error: Disk Drive too Small for "
7050 "use in Volume", /* 39h */
7051 "Compatibility Error: Phys Disk for Create "
7052 "Volume not Found", /* 3Ah */
7053 "Compatibility Error: Too Many or too Few "
7054 "Disks for Volume Type", /* 3Bh */
7055 "Compatibility Error: Disk stripe Sizes "
7056 "Must be 64KB", /* 3Ch */
7057 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7058 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007059
7060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007061/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007062 * mpt_sas_log_info - Log information returned from SAS IOC.
7063 * @ioc: Pointer to MPT_ADAPTER structure
7064 * @log_info: U32 LogInfo reply word from the IOC
7065 *
7066 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007067 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007068static void
7069mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7070{
7071union loginfo_type {
7072 u32 loginfo;
7073 struct {
7074 u32 subcode:16;
7075 u32 code:8;
7076 u32 originator:4;
7077 u32 bus_type:4;
7078 }dw;
7079};
7080 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007081 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007082 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007083 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007084
7085 sas_loginfo.loginfo = log_info;
7086 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7087 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7088 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007089
7090 originator_desc = originator_str[sas_loginfo.dw.originator];
7091
7092 switch (sas_loginfo.dw.originator) {
7093
7094 case 0: /* IOP */
7095 if (sas_loginfo.dw.code <
7096 sizeof(iop_code_str)/sizeof(char*))
7097 code_desc = iop_code_str[sas_loginfo.dw.code];
7098 break;
7099 case 1: /* PL */
7100 if (sas_loginfo.dw.code <
7101 sizeof(pl_code_str)/sizeof(char*))
7102 code_desc = pl_code_str[sas_loginfo.dw.code];
7103 break;
7104 case 2: /* IR */
7105 if (sas_loginfo.dw.code >=
7106 sizeof(ir_code_str)/sizeof(char*))
7107 break;
7108 code_desc = ir_code_str[sas_loginfo.dw.code];
7109 if (sas_loginfo.dw.subcode >=
7110 sizeof(raid_sub_code_str)/sizeof(char*))
7111 break;
7112 if (sas_loginfo.dw.code == 0)
7113 sub_code_desc =
7114 raid_sub_code_str[sas_loginfo.dw.subcode];
7115 break;
7116 default:
7117 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007118 }
7119
Eric Moorec6c727a2007-01-29 09:44:54 -07007120 if (sub_code_desc != NULL)
7121 printk(MYIOC_s_INFO_FMT
7122 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7123 " SubCode={%s}\n",
7124 ioc->name, log_info, originator_desc, code_desc,
7125 sub_code_desc);
7126 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007127 printk(MYIOC_s_INFO_FMT
7128 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7129 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007130 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007131 sas_loginfo.dw.subcode);
7132 else
7133 printk(MYIOC_s_INFO_FMT
7134 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7135 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007136 ioc->name, log_info, originator_desc,
7137 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007138}
7139
Linus Torvalds1da177e2005-04-16 15:20:36 -07007140/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007141/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007142 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7143 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007144 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007145 * @mf: Pointer to MPT request frame
7146 *
7147 * Refer to lsi/mpi.h.
7148 **/
7149static void
7150mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7151{
7152 Config_t *pReq = (Config_t *)mf;
7153 char extend_desc[EVENT_DESCR_STR_SZ];
7154 char *desc = NULL;
7155 u32 form;
7156 u8 page_type;
7157
7158 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7159 page_type = pReq->ExtPageType;
7160 else
7161 page_type = pReq->Header.PageType;
7162
7163 /*
7164 * ignore invalid page messages for GET_NEXT_HANDLE
7165 */
7166 form = le32_to_cpu(pReq->PageAddress);
7167 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7168 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7169 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7170 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7171 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7172 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7173 return;
7174 }
7175 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7176 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7177 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7178 return;
7179 }
7180
7181 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7182 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7183 page_type, pReq->Header.PageNumber, pReq->Action, form);
7184
7185 switch (ioc_status) {
7186
7187 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7188 desc = "Config Page Invalid Action";
7189 break;
7190
7191 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7192 desc = "Config Page Invalid Type";
7193 break;
7194
7195 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7196 desc = "Config Page Invalid Page";
7197 break;
7198
7199 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7200 desc = "Config Page Invalid Data";
7201 break;
7202
7203 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7204 desc = "Config Page No Defaults";
7205 break;
7206
7207 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7208 desc = "Config Page Can't Commit";
7209 break;
7210 }
7211
7212 if (!desc)
7213 return;
7214
Eric Moore29dd3602007-09-14 18:46:51 -06007215 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7216 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007217}
7218
7219/**
7220 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221 * @ioc: Pointer to MPT_ADAPTER structure
7222 * @ioc_status: U32 IOCStatus word from IOC
7223 * @mf: Pointer to MPT request frame
7224 *
7225 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007226 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007228mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229{
7230 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007231 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232
7233 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007234
7235/****************************************************************************/
7236/* Common IOCStatus values for all replies */
7237/****************************************************************************/
7238
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7240 desc = "Invalid Function";
7241 break;
7242
7243 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7244 desc = "Busy";
7245 break;
7246
7247 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7248 desc = "Invalid SGL";
7249 break;
7250
7251 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7252 desc = "Internal Error";
7253 break;
7254
7255 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7256 desc = "Reserved";
7257 break;
7258
7259 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7260 desc = "Insufficient Resources";
7261 break;
7262
7263 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7264 desc = "Invalid Field";
7265 break;
7266
7267 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7268 desc = "Invalid State";
7269 break;
7270
Eric Moorec6c727a2007-01-29 09:44:54 -07007271/****************************************************************************/
7272/* Config IOCStatus values */
7273/****************************************************************************/
7274
Linus Torvalds1da177e2005-04-16 15:20:36 -07007275 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7276 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7277 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7278 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7279 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7280 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007281 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007282 break;
7283
Eric Moorec6c727a2007-01-29 09:44:54 -07007284/****************************************************************************/
7285/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7286/* */
7287/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7288/* */
7289/****************************************************************************/
7290
Linus Torvalds1da177e2005-04-16 15:20:36 -07007291 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007293 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7294 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7295 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7296 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007299 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007300 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007301 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007302 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007303 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304 break;
7305
Eric Moorec6c727a2007-01-29 09:44:54 -07007306/****************************************************************************/
7307/* SCSI Target values */
7308/****************************************************************************/
7309
7310 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7311 desc = "Target: Priority IO";
7312 break;
7313
7314 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7315 desc = "Target: Invalid Port";
7316 break;
7317
7318 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7319 desc = "Target Invalid IO Index:";
7320 break;
7321
7322 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7323 desc = "Target: Aborted";
7324 break;
7325
7326 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7327 desc = "Target: No Conn Retryable";
7328 break;
7329
7330 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7331 desc = "Target: No Connection";
7332 break;
7333
7334 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7335 desc = "Target: Transfer Count Mismatch";
7336 break;
7337
7338 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7339 desc = "Target: STS Data not Sent";
7340 break;
7341
7342 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7343 desc = "Target: Data Offset Error";
7344 break;
7345
7346 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7347 desc = "Target: Too Much Write Data";
7348 break;
7349
7350 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7351 desc = "Target: IU Too Short";
7352 break;
7353
7354 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7355 desc = "Target: ACK NAK Timeout";
7356 break;
7357
7358 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7359 desc = "Target: Nak Received";
7360 break;
7361
7362/****************************************************************************/
7363/* Fibre Channel Direct Access values */
7364/****************************************************************************/
7365
7366 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7367 desc = "FC: Aborted";
7368 break;
7369
7370 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7371 desc = "FC: RX ID Invalid";
7372 break;
7373
7374 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7375 desc = "FC: DID Invalid";
7376 break;
7377
7378 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7379 desc = "FC: Node Logged Out";
7380 break;
7381
7382 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7383 desc = "FC: Exchange Canceled";
7384 break;
7385
7386/****************************************************************************/
7387/* LAN values */
7388/****************************************************************************/
7389
7390 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7391 desc = "LAN: Device not Found";
7392 break;
7393
7394 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7395 desc = "LAN: Device Failure";
7396 break;
7397
7398 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7399 desc = "LAN: Transmit Error";
7400 break;
7401
7402 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7403 desc = "LAN: Transmit Aborted";
7404 break;
7405
7406 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7407 desc = "LAN: Receive Error";
7408 break;
7409
7410 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7411 desc = "LAN: Receive Aborted";
7412 break;
7413
7414 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7415 desc = "LAN: Partial Packet";
7416 break;
7417
7418 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7419 desc = "LAN: Canceled";
7420 break;
7421
7422/****************************************************************************/
7423/* Serial Attached SCSI values */
7424/****************************************************************************/
7425
7426 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7427 desc = "SAS: SMP Request Failed";
7428 break;
7429
7430 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7431 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432 break;
7433
7434 default:
7435 desc = "Others";
7436 break;
7437 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007438
7439 if (!desc)
7440 return;
7441
Eric Moore29dd3602007-09-14 18:46:51 -06007442 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7443 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007444}
7445
7446/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007447EXPORT_SYMBOL(mpt_attach);
7448EXPORT_SYMBOL(mpt_detach);
7449#ifdef CONFIG_PM
7450EXPORT_SYMBOL(mpt_resume);
7451EXPORT_SYMBOL(mpt_suspend);
7452#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007454EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455EXPORT_SYMBOL(mpt_register);
7456EXPORT_SYMBOL(mpt_deregister);
7457EXPORT_SYMBOL(mpt_event_register);
7458EXPORT_SYMBOL(mpt_event_deregister);
7459EXPORT_SYMBOL(mpt_reset_register);
7460EXPORT_SYMBOL(mpt_reset_deregister);
7461EXPORT_SYMBOL(mpt_device_driver_register);
7462EXPORT_SYMBOL(mpt_device_driver_deregister);
7463EXPORT_SYMBOL(mpt_get_msg_frame);
7464EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307465EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007466EXPORT_SYMBOL(mpt_free_msg_frame);
7467EXPORT_SYMBOL(mpt_add_sge);
7468EXPORT_SYMBOL(mpt_send_handshake_request);
7469EXPORT_SYMBOL(mpt_verify_adapter);
7470EXPORT_SYMBOL(mpt_GetIocState);
7471EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007472EXPORT_SYMBOL(mpt_HardResetHandler);
7473EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475EXPORT_SYMBOL(mpt_alloc_fw_memory);
7476EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007477EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007478EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007479
Linus Torvalds1da177e2005-04-16 15:20:36 -07007480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007481/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482 * fusion_init - Fusion MPT base driver initialization routine.
7483 *
7484 * Returns 0 for success, non-zero for failure.
7485 */
7486static int __init
7487fusion_init(void)
7488{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307489 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490
7491 show_mptmod_ver(my_NAME, my_VERSION);
7492 printk(KERN_INFO COPYRIGHT "\n");
7493
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307494 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7495 MptCallbacks[cb_idx] = NULL;
7496 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7497 MptEvHandlers[cb_idx] = NULL;
7498 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499 }
7500
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007501 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502 * EventNotification handling.
7503 */
7504 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7505
7506 /* Register for hard reset handling callbacks.
7507 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307508 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007509
7510#ifdef CONFIG_PROC_FS
7511 (void) procmpt_create();
7512#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007513 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514}
7515
7516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007517/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518 * fusion_exit - Perform driver unload cleanup.
7519 *
7520 * This routine frees all resources associated with each MPT adapter
7521 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7522 */
7523static void __exit
7524fusion_exit(void)
7525{
7526
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527 mpt_reset_deregister(mpt_base_index);
7528
7529#ifdef CONFIG_PROC_FS
7530 procmpt_destroy();
7531#endif
7532}
7533
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534module_init(fusion_init);
7535module_exit(fusion_exit);