blob: 22cb0f8b2bcd36866ee62673ecb62b8d8863df05 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05308 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600256/*
257 * Process turbo (context) reply...
258 */
259static void
260mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
261{
262 MPT_FRAME_HDR *mf = NULL;
263 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264 u16 req_idx = 0;
265 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600266
Prakash, Sathya436ace72007-07-24 15:42:08 +0530267 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600268 ioc->name, pa));
269
270 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
271 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
272 req_idx = pa & 0x0000FFFF;
273 cb_idx = (pa & 0x00FF0000) >> 16;
274 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
275 break;
276 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530277 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600278 /*
279 * Blind set of mf to NULL here was fatal
280 * after lan_reply says "freeme"
281 * Fix sort of combined with an optimization here;
282 * added explicit check for case where lan_reply
283 * was just returning 1 and doing nothing else.
284 * For this case skip the callback, but set up
285 * proper mf value first here:-)
286 */
287 if ((pa & 0x58000000) == 0x58000000) {
288 req_idx = pa & 0x0000FFFF;
289 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
290 mpt_free_msg_frame(ioc, mf);
291 mb();
292 return;
293 break;
294 }
295 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
296 break;
297 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530298 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600299 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
300 break;
301 default:
302 cb_idx = 0;
303 BUG();
304 }
305
306 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530307 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600308 MptCallbacks[cb_idx] == NULL) {
309 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));
Prakash, Sathya436ace72007-07-24 15:42:08 +0530352 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 ||
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600372 MptCallbacks[cb_idx] == NULL) {
373 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)) {
454 dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
455 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200457#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530460 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 ioc->name, func));
462
463 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
464 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
465 int evHandlers = 0;
466 int results;
467
468 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
469 if (results != evHandlers) {
470 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530471 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 ioc->name, evHandlers, results));
473 }
474
475 /*
476 * Hmmm... It seems that EventNotificationReply is an exception
477 * to the rule of one reply per request.
478 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200479 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200481 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530482 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200483 ioc->name, pEvReply));
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486#ifdef CONFIG_PROC_FS
487// LogEvent(ioc, pEvReply);
488#endif
489
490 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530491 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700493 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 CONFIGPARMS *pCfg;
495 unsigned long flags;
496
Prakash, Sathya436ace72007-07-24 15:42:08 +0530497 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 ioc->name, mf, reply));
499
500 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
501
502 if (pCfg) {
503 /* disable timer and remove from linked list */
504 del_timer(&pCfg->timer);
505
506 spin_lock_irqsave(&ioc->FreeQlock, flags);
507 list_del(&pCfg->linkage);
508 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
509
510 /*
511 * If IOC Status is SUCCESS, save the header
512 * and set the status code to GOOD.
513 */
514 pCfg->status = MPT_CONFIG_ERROR;
515 if (reply) {
516 ConfigReply_t *pReply = (ConfigReply_t *)reply;
517 u16 status;
518
519 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530520 dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 status, le32_to_cpu(pReply->IOCLogInfo)));
522
523 pCfg->status = status;
524 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200525 if ((pReply->Header.PageType &
526 MPI_CONFIG_PAGETYPE_MASK) ==
527 MPI_CONFIG_PAGETYPE_EXTENDED) {
528 pCfg->cfghdr.ehdr->ExtPageLength =
529 le16_to_cpu(pReply->ExtPageLength);
530 pCfg->cfghdr.ehdr->ExtPageType =
531 pReply->ExtPageType;
532 }
533 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
534
535 /* If this is a regular header, save PageLength. */
536 /* LMP Do this better so not using a reserved field! */
537 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
538 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
539 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
541 }
542
543 /*
544 * Wake up the original calling thread
545 */
546 pCfg->wait_done = 1;
547 wake_up(&mpt_waitq);
548 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200549 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
550 /* we should be always getting a reply frame */
551 memcpy(ioc->persist_reply_frame, reply,
552 min(MPT_DEFAULT_FRAME_SIZE,
553 4*reply->u.reply.MsgLength));
554 del_timer(&ioc->persist_timer);
555 ioc->persist_wait_done = 1;
556 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 } else {
558 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
559 ioc->name, func);
560 }
561
562 /*
563 * Conditionally tell caller to free the original
564 * EventNotification/EventAck/unexpected request frame!
565 */
566 return freereq;
567}
568
569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
570/**
571 * mpt_register - Register protocol-specific main callback handler.
572 * @cbfunc: callback function pointer
573 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
574 *
575 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800576 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 * protocol-specific driver must do this before it will be able to
578 * use any IOC resources, such as obtaining request frames.
579 *
580 * NOTES: The SCSI protocol driver currently calls this routine thrice
581 * in order to register separate callbacks; one for "normal" SCSI IO;
582 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
583 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530584 * Returns u8 valued "handle" in the range (and S.O.D. order)
585 * {N,...,7,6,5,...,1} if successful.
586 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
587 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530589u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
591{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530592 u8 cb_idx;
593 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 /*
596 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
597 * (slot/handle 0 is reserved!)
598 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530599 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
600 if (MptCallbacks[cb_idx] == NULL) {
601 MptCallbacks[cb_idx] = cbfunc;
602 MptDriverClass[cb_idx] = dclass;
603 MptEvHandlers[cb_idx] = NULL;
604 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 break;
606 }
607 }
608
609 return last_drv_idx;
610}
611
612/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
613/**
614 * mpt_deregister - Deregister a protocol drivers resources.
615 * @cb_idx: previously registered callback handle
616 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800617 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 * module is unloaded.
619 */
620void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530621mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530623 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 MptCallbacks[cb_idx] = NULL;
625 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
626 MptEvHandlers[cb_idx] = NULL;
627
628 last_drv_idx++;
629 }
630}
631
632/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
633/**
634 * mpt_event_register - Register protocol-specific event callback
635 * handler.
636 * @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{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530647 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/**
656 * mpt_event_deregister - Deregister protocol-specific event callback
657 * handler.
658 * @cb_idx: previously registered callback handle
659 *
660 * Each protocol-specific driver should call this routine
661 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800662 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 */
664void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530665mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530667 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return;
669
670 MptEvHandlers[cb_idx] = NULL;
671}
672
673/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
674/**
675 * mpt_reset_register - Register protocol-specific IOC reset handler.
676 * @cb_idx: previously registered (via mpt_register) callback handle
677 * @reset_func: reset function
678 *
679 * This routine can be called by one or more protocol-specific drivers
680 * if/when they choose to be notified of IOC resets.
681 *
682 * Returns 0 for success.
683 */
684int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530685mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530687 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return -1;
689
690 MptResetHandlers[cb_idx] = reset_func;
691 return 0;
692}
693
694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
695/**
696 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
697 * @cb_idx: previously registered callback handle
698 *
699 * Each protocol-specific driver should call this routine
700 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800701 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 */
703void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530704mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530706 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return;
708
709 MptResetHandlers[cb_idx] = NULL;
710}
711
712/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
713/**
714 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800715 * @dd_cbfunc: driver callbacks struct
716 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
718int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530719mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
721 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600722 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530724 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400725 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
728
729 /* call per pci device probe entry point */
730 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600731 id = ioc->pcidev->driver ?
732 ioc->pcidev->driver->id_table : NULL;
733 if (dd_cbfunc->probe)
734 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 }
736
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400737 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738}
739
740/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
741/**
742 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800743 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 */
745void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530746mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
748 struct mpt_pci_driver *dd_cbfunc;
749 MPT_ADAPTER *ioc;
750
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530751 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return;
753
754 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
755
756 list_for_each_entry(ioc, &ioc_list, list) {
757 if (dd_cbfunc->remove)
758 dd_cbfunc->remove(ioc->pcidev);
759 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 MptDeviceDriverHandlers[cb_idx] = NULL;
762}
763
764
765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
766/**
767 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
768 * allocated per MPT adapter.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530769 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 * @ioc: Pointer to MPT adapter structure
771 *
772 * Returns pointer to a MPT request frame or %NULL if none are available
773 * or IOC is not active.
774 */
775MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530776mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 MPT_FRAME_HDR *mf;
779 unsigned long flags;
780 u16 req_idx; /* Request index */
781
782 /* validate handle and ioc identifier */
783
784#ifdef MFCNT
785 if (!ioc->active)
786 printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
787#endif
788
789 /* If interrupts are not attached, do not return a request frame */
790 if (!ioc->active)
791 return NULL;
792
793 spin_lock_irqsave(&ioc->FreeQlock, flags);
794 if (!list_empty(&ioc->FreeQ)) {
795 int req_offset;
796
797 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
798 u.frame.linkage.list);
799 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200800 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
803 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500804 req_idx = req_offset / ioc->req_sz;
805 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
807 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
808#ifdef MFCNT
809 ioc->mfcnt++;
810#endif
811 }
812 else
813 mf = NULL;
814 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
815
816#ifdef MFCNT
817 if (mf == NULL)
818 printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
819 mfcounter++;
820 if (mfcounter == PRINT_MF_COUNT)
821 printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
822#endif
823
Prakash, Sathya436ace72007-07-24 15:42:08 +0530824 dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530825 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 return mf;
827}
828
829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
830/**
831 * mpt_put_msg_frame - Send a protocol specific MPT request frame
832 * to a IOC.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 * @ioc: Pointer to MPT adapter structure
835 * @mf: Pointer to MPT request frame
836 *
837 * This routine posts a MPT request frame to the request post FIFO of a
838 * specific MPT adapter.
839 */
840void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530841mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 u32 mf_dma_addr;
844 int req_offset;
845 u16 req_idx; /* Request index */
846
847 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530848 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
850 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500851 req_idx = req_offset / ioc->req_sz;
852 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
854
Prakash, Sathya436ace72007-07-24 15:42:08 +0530855 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200857 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530858 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
860}
861
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530862/**
863 * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
864 * to a IOC using hi priority request queue.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530865 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530866 * @ioc: Pointer to MPT adapter structure
867 * @mf: Pointer to MPT request frame
868 *
869 * This routine posts a MPT request frame to the request post FIFO of a
870 * specific MPT adapter.
871 **/
872void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530873mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530874{
875 u32 mf_dma_addr;
876 int req_offset;
877 u16 req_idx; /* Request index */
878
879 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530880 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530881 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
882 req_idx = req_offset / ioc->req_sz;
883 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
884 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
885
886 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
887
888 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
889 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
890 ioc->name, mf_dma_addr, req_idx));
891 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
892}
893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
896 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
897 * @handle: Handle of registered MPT protocol driver
898 * @ioc: Pointer to MPT adapter structure
899 * @mf: Pointer to MPT request frame
900 *
901 * This routine places a MPT request frame back on the MPT adapter's
902 * FreeQ.
903 */
904void
905mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
906{
907 unsigned long flags;
908
909 /* Put Request back on FreeQ! */
910 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200911 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
913#ifdef MFCNT
914 ioc->mfcnt--;
915#endif
916 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
917}
918
919/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
920/**
921 * mpt_add_sge - Place a simple SGE at address pAddr.
922 * @pAddr: virtual address for SGE
923 * @flagslength: SGE flags and data transfer length
924 * @dma_addr: Physical address
925 *
926 * This routine places a MPT request frame back on the MPT adapter's
927 * FreeQ.
928 */
929void
930mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
931{
932 if (sizeof(dma_addr_t) == sizeof(u64)) {
933 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
934 u32 tmp = dma_addr & 0xFFFFFFFF;
935
936 pSge->FlagsLength = cpu_to_le32(flagslength);
937 pSge->Address.Low = cpu_to_le32(tmp);
938 tmp = (u32) ((u64)dma_addr >> 32);
939 pSge->Address.High = cpu_to_le32(tmp);
940
941 } else {
942 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
943 pSge->FlagsLength = cpu_to_le32(flagslength);
944 pSge->Address = cpu_to_le32(dma_addr);
945 }
946}
947
948/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
949/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800950 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530951 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 * @ioc: Pointer to MPT adapter structure
953 * @reqBytes: Size of the request in bytes
954 * @req: Pointer to MPT request frame
955 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
956 *
957 * This routine is used exclusively to send MptScsiTaskMgmt
958 * requests since they are required to be sent via doorbell handshake.
959 *
960 * NOTE: It is the callers responsibility to byte-swap fields in the
961 * request which are greater than 1 byte in size.
962 *
963 * Returns 0 for success, non-zero for failure.
964 */
965int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530966mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Eric Moorecd2c6192007-01-29 09:47:47 -0700968 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 u8 *req_as_bytes;
970 int ii;
971
972 /* State is known to be good upon entering
973 * this function so issue the bus reset
974 * request.
975 */
976
977 /*
978 * Emulate what mpt_put_msg_frame() does /wrt to sanity
979 * setting cb_idx/req_idx. But ONLY if this request
980 * is in proper (pre-alloc'd) request buffer range...
981 */
982 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
983 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
984 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
985 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530986 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
988
989 /* Make sure there are no doorbells */
990 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 CHIPREG_WRITE32(&ioc->chip->Doorbell,
993 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
994 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
995
996 /* Wait for IOC doorbell int */
997 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
998 return ii;
999 }
1000
1001 /* Read doorbell and check for active bit */
1002 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1003 return -5;
1004
Prakash, Sathya436ace72007-07-24 15:42:08 +05301005 dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001006 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1009
1010 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1011 return -2;
1012 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* Send request via doorbell handshake */
1015 req_as_bytes = (u8 *) req;
1016 for (ii = 0; ii < reqBytes/4; ii++) {
1017 u32 word;
1018
1019 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1020 (req_as_bytes[(ii*4) + 1] << 8) |
1021 (req_as_bytes[(ii*4) + 2] << 16) |
1022 (req_as_bytes[(ii*4) + 3] << 24));
1023 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1024 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1025 r = -3;
1026 break;
1027 }
1028 }
1029
1030 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1031 r = 0;
1032 else
1033 r = -4;
1034
1035 /* Make sure there are no doorbells */
1036 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return r;
1039}
1040
1041/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1042/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001043 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001044 * @ioc: Pointer to MPT adapter structure
1045 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001046 * @sleepFlag: Specifies whether the process can sleep
1047 *
1048 * Provides mechanism for the host driver to control the IOC's
1049 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001050 *
1051 * Access Control Value - bits[15:12]
1052 * 0h Reserved
1053 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1054 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1055 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1056 *
1057 * Returns 0 for success, non-zero for failure.
1058 */
1059
1060static int
1061mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1062{
1063 int r = 0;
1064
1065 /* return if in use */
1066 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1067 & MPI_DOORBELL_ACTIVE)
1068 return -1;
1069
1070 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1071
1072 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1073 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1074 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1075 (access_control_value<<12)));
1076
1077 /* Wait for IOC to clear Doorbell Status bit */
1078 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1079 return -2;
1080 }else
1081 return 0;
1082}
1083
1084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1085/**
1086 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001087 * @ioc: Pointer to pointer to IOC adapter
1088 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001089 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001090 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001091 * Returns 0 for success, non-zero for failure.
1092 */
1093static int
1094mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1095{
1096 char *psge;
1097 int flags_length;
1098 u32 host_page_buffer_sz=0;
1099
1100 if(!ioc->HostPageBuffer) {
1101
1102 host_page_buffer_sz =
1103 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1104
1105 if(!host_page_buffer_sz)
1106 return 0; /* fw doesn't need any host buffers */
1107
1108 /* spin till we get enough memory */
1109 while(host_page_buffer_sz > 0) {
1110
1111 if((ioc->HostPageBuffer = pci_alloc_consistent(
1112 ioc->pcidev,
1113 host_page_buffer_sz,
1114 &ioc->HostPageBuffer_dma)) != NULL) {
1115
Prakash, Sathya436ace72007-07-24 15:42:08 +05301116 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001117 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001118 ioc->name, ioc->HostPageBuffer,
1119 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001120 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001121 ioc->alloc_total += host_page_buffer_sz;
1122 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1123 break;
1124 }
1125
1126 host_page_buffer_sz -= (4*1024);
1127 }
1128 }
1129
1130 if(!ioc->HostPageBuffer) {
1131 printk(MYIOC_s_ERR_FMT
1132 "Failed to alloc memory for host_page_buffer!\n",
1133 ioc->name);
1134 return -999;
1135 }
1136
1137 psge = (char *)&ioc_init->HostPageBufferSGE;
1138 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1139 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1140 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1141 MPI_SGE_FLAGS_HOST_TO_IOC |
1142 MPI_SGE_FLAGS_END_OF_BUFFER;
1143 if (sizeof(dma_addr_t) == sizeof(u64)) {
1144 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1145 }
1146 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1147 flags_length |= ioc->HostPageBuffer_sz;
1148 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1149 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1150
1151return 0;
1152}
1153
1154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1155/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001156 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 * @iocid: IOC unique identifier (integer)
1158 * @iocpp: Pointer to pointer to IOC adapter
1159 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001160 * Given a unique IOC identifier, set pointer to the associated MPT
1161 * adapter structure.
1162 *
1163 * Returns iocid and sets iocpp if iocid is found.
1164 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 */
1166int
1167mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1168{
1169 MPT_ADAPTER *ioc;
1170
1171 list_for_each_entry(ioc,&ioc_list,list) {
1172 if (ioc->id == iocid) {
1173 *iocpp =ioc;
1174 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 *iocpp = NULL;
1179 return -1;
1180}
1181
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301182/**
1183 * mpt_get_product_name - returns product string
1184 * @vendor: pci vendor id
1185 * @device: pci device id
1186 * @revision: pci revision id
1187 * @prod_name: string returned
1188 *
1189 * Returns product string displayed when driver loads,
1190 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1191 *
1192 **/
1193static void
1194mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1195{
1196 char *product_str = NULL;
1197
1198 if (vendor == PCI_VENDOR_ID_BROCADE) {
1199 switch (device)
1200 {
1201 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1202 switch (revision)
1203 {
1204 case 0x00:
1205 product_str = "BRE040 A0";
1206 break;
1207 case 0x01:
1208 product_str = "BRE040 A1";
1209 break;
1210 default:
1211 product_str = "BRE040";
1212 break;
1213 }
1214 break;
1215 }
1216 goto out;
1217 }
1218
1219 switch (device)
1220 {
1221 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1222 product_str = "LSIFC909 B1";
1223 break;
1224 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1225 product_str = "LSIFC919 B0";
1226 break;
1227 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1228 product_str = "LSIFC929 B0";
1229 break;
1230 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1231 if (revision < 0x80)
1232 product_str = "LSIFC919X A0";
1233 else
1234 product_str = "LSIFC919XL A1";
1235 break;
1236 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1237 if (revision < 0x80)
1238 product_str = "LSIFC929X A0";
1239 else
1240 product_str = "LSIFC929XL A1";
1241 break;
1242 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1243 product_str = "LSIFC939X A1";
1244 break;
1245 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1246 product_str = "LSIFC949X A1";
1247 break;
1248 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1249 switch (revision)
1250 {
1251 case 0x00:
1252 product_str = "LSIFC949E A0";
1253 break;
1254 case 0x01:
1255 product_str = "LSIFC949E A1";
1256 break;
1257 default:
1258 product_str = "LSIFC949E";
1259 break;
1260 }
1261 break;
1262 case MPI_MANUFACTPAGE_DEVID_53C1030:
1263 switch (revision)
1264 {
1265 case 0x00:
1266 product_str = "LSI53C1030 A0";
1267 break;
1268 case 0x01:
1269 product_str = "LSI53C1030 B0";
1270 break;
1271 case 0x03:
1272 product_str = "LSI53C1030 B1";
1273 break;
1274 case 0x07:
1275 product_str = "LSI53C1030 B2";
1276 break;
1277 case 0x08:
1278 product_str = "LSI53C1030 C0";
1279 break;
1280 case 0x80:
1281 product_str = "LSI53C1030T A0";
1282 break;
1283 case 0x83:
1284 product_str = "LSI53C1030T A2";
1285 break;
1286 case 0x87:
1287 product_str = "LSI53C1030T A3";
1288 break;
1289 case 0xc1:
1290 product_str = "LSI53C1020A A1";
1291 break;
1292 default:
1293 product_str = "LSI53C1030";
1294 break;
1295 }
1296 break;
1297 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1298 switch (revision)
1299 {
1300 case 0x03:
1301 product_str = "LSI53C1035 A2";
1302 break;
1303 case 0x04:
1304 product_str = "LSI53C1035 B0";
1305 break;
1306 default:
1307 product_str = "LSI53C1035";
1308 break;
1309 }
1310 break;
1311 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1312 switch (revision)
1313 {
1314 case 0x00:
1315 product_str = "LSISAS1064 A1";
1316 break;
1317 case 0x01:
1318 product_str = "LSISAS1064 A2";
1319 break;
1320 case 0x02:
1321 product_str = "LSISAS1064 A3";
1322 break;
1323 case 0x03:
1324 product_str = "LSISAS1064 A4";
1325 break;
1326 default:
1327 product_str = "LSISAS1064";
1328 break;
1329 }
1330 break;
1331 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1332 switch (revision)
1333 {
1334 case 0x00:
1335 product_str = "LSISAS1064E A0";
1336 break;
1337 case 0x01:
1338 product_str = "LSISAS1064E B0";
1339 break;
1340 case 0x02:
1341 product_str = "LSISAS1064E B1";
1342 break;
1343 case 0x04:
1344 product_str = "LSISAS1064E B2";
1345 break;
1346 case 0x08:
1347 product_str = "LSISAS1064E B3";
1348 break;
1349 default:
1350 product_str = "LSISAS1064E";
1351 break;
1352 }
1353 break;
1354 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1355 switch (revision)
1356 {
1357 case 0x00:
1358 product_str = "LSISAS1068 A0";
1359 break;
1360 case 0x01:
1361 product_str = "LSISAS1068 B0";
1362 break;
1363 case 0x02:
1364 product_str = "LSISAS1068 B1";
1365 break;
1366 default:
1367 product_str = "LSISAS1068";
1368 break;
1369 }
1370 break;
1371 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1372 switch (revision)
1373 {
1374 case 0x00:
1375 product_str = "LSISAS1068E A0";
1376 break;
1377 case 0x01:
1378 product_str = "LSISAS1068E B0";
1379 break;
1380 case 0x02:
1381 product_str = "LSISAS1068E B1";
1382 break;
1383 case 0x04:
1384 product_str = "LSISAS1068E B2";
1385 break;
1386 case 0x08:
1387 product_str = "LSISAS1068E B3";
1388 break;
1389 default:
1390 product_str = "LSISAS1068E";
1391 break;
1392 }
1393 break;
1394 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1395 switch (revision)
1396 {
1397 case 0x00:
1398 product_str = "LSISAS1078 A0";
1399 break;
1400 case 0x01:
1401 product_str = "LSISAS1078 B0";
1402 break;
1403 case 0x02:
1404 product_str = "LSISAS1078 C0";
1405 break;
1406 case 0x03:
1407 product_str = "LSISAS1078 C1";
1408 break;
1409 case 0x04:
1410 product_str = "LSISAS1078 C2";
1411 break;
1412 default:
1413 product_str = "LSISAS1078";
1414 break;
1415 }
1416 break;
1417 }
1418
1419 out:
1420 if (product_str)
1421 sprintf(prod_name, "%s", product_str);
1422}
1423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001425/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001426 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001428 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 *
1430 * This routine performs all the steps necessary to bring the IOC of
1431 * a MPT adapter to a OPERATIONAL state. This includes registering
1432 * memory regions, registering the interrupt, and allocating request
1433 * and reply memory pools.
1434 *
1435 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1436 * MPT adapter.
1437 *
1438 * Returns 0 for success, non-zero for failure.
1439 *
1440 * TODO: Add support for polled controllers
1441 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001442int
1443mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444{
1445 MPT_ADAPTER *ioc;
1446 u8 __iomem *mem;
1447 unsigned long mem_phys;
1448 unsigned long port;
1449 u32 msize;
1450 u32 psize;
1451 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301452 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 u8 revision;
1455 u8 pcixcmd;
1456 static int mpt_ids = 0;
1457#ifdef CONFIG_PROC_FS
1458 struct proc_dir_entry *dent, *ent;
1459#endif
1460
Prakash, Sathya436ace72007-07-24 15:42:08 +05301461 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1462 if (ioc == NULL) {
1463 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1464 return -ENOMEM;
1465 }
1466
1467 ioc->debug_level = mpt_debug_level;
1468 if (mpt_debug_level)
1469 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1470
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (pci_enable_device(pdev))
1472 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001473
Prakash, Sathya436ace72007-07-24 15:42:08 +05301474 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001475
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001476 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301477 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001479 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
1481 return r;
1482 }
1483
Prakash, Sathya436ace72007-07-24 15:42:08 +05301484 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1485 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 ": Using 64 bit consistent mask\n"));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301487 } else {
1488 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 ": Not using 64 bit consistent mask\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 ioc->alloc_total = sizeof(MPT_ADAPTER);
1493 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1494 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 ioc->pcidev = pdev;
1497 ioc->diagPending = 0;
1498 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001499 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 /* Initialize the event logging.
1502 */
1503 ioc->eventTypes = 0; /* None */
1504 ioc->eventContext = 0;
1505 ioc->eventLogSize = 0;
1506 ioc->events = NULL;
1507
1508#ifdef MFCNT
1509 ioc->mfcnt = 0;
1510#endif
1511
1512 ioc->cached_fw = NULL;
1513
1514 /* Initilize SCSI Config Data structure
1515 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001516 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518 /* Initialize the running configQ head.
1519 */
1520 INIT_LIST_HEAD(&ioc->configQ);
1521
Michael Reed05e8ec12006-01-13 14:31:54 -06001522 /* Initialize the fc rport list head.
1523 */
1524 INIT_LIST_HEAD(&ioc->fc_rports);
1525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 /* Find lookup slot. */
1527 INIT_LIST_HEAD(&ioc->list);
1528 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 mem_phys = msize = 0;
1531 port = psize = 0;
1532 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1533 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001534 if (psize)
1535 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 /* Get I/O space! */
1537 port = pci_resource_start(pdev, ii);
1538 psize = pci_resource_len(pdev,ii);
1539 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001540 if (msize)
1541 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 /* Get memmap */
1543 mem_phys = pci_resource_start(pdev, ii);
1544 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
1546 }
1547 ioc->mem_size = msize;
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 mem = NULL;
1550 /* Get logical ptr for PciMem0 space */
1551 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001552 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 if (mem == NULL) {
1554 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1555 kfree(ioc);
1556 return -EINVAL;
1557 }
1558 ioc->memmap = mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301559 dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Prakash, Sathya436ace72007-07-24 15:42:08 +05301561 dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 &ioc->facts, &ioc->pfacts[0]));
1563
1564 ioc->mem_phys = mem_phys;
1565 ioc->chip = (SYSIF_REGS __iomem *)mem;
1566
1567 /* Save Port IO values in case we need to do downloadboot */
1568 {
1569 u8 *pmem = (u8*)port;
1570 ioc->pio_mem_phys = port;
1571 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1572 }
1573
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301574 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1575 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1576
1577 switch (pdev->device)
1578 {
1579 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1580 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1581 ioc->errata_flag_1064 = 1;
1582 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1583 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1584 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1585 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301587 break;
1588
1589 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 /* 929X Chip Fix. Set Split transactions level
1592 * for PCIX. Set MOST bits to zero.
1593 */
1594 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1595 pcixcmd &= 0x8F;
1596 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1597 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 /* 929XL Chip Fix. Set MMRBC to 0x08.
1599 */
1600 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1601 pcixcmd |= 0x08;
1602 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301605 break;
1606
1607 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* 919X Chip Fix. Set Split transactions level
1609 * for PCIX. Set MOST bits to zero.
1610 */
1611 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1612 pcixcmd &= 0x8F;
1613 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001614 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301615 break;
1616
1617 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* 1030 Chip Fix. Disable Split transactions
1619 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1620 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (revision < C0_1030) {
1622 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1623 pcixcmd &= 0x8F;
1624 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1625 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301626
1627 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001628 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301629 break;
1630
1631 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1632 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001633 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301634
1635 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1636 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1637 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001638 ioc->bus_type = SAS;
1639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001641 if (ioc->errata_flag_1064)
1642 pci_disable_io_access(pdev);
1643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 sprintf(ioc->name, "ioc%d", ioc->id);
1645
1646 spin_lock_init(&ioc->FreeQlock);
1647
1648 /* Disable all! */
1649 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1650 ioc->active = 0;
1651 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1652
1653 /* Set lookup ptr. */
1654 list_add_tail(&ioc->list, &ioc_list);
1655
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001656 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 */
1658 mpt_detect_bound_ports(ioc, pdev);
1659
James Bottomleyc92f2222006-03-01 09:02:49 -06001660 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1661 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 printk(KERN_WARNING MYNAM
1663 ": WARNING - %s did not initialize properly! (%d)\n",
1664 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001665
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001667 if (ioc->alt_ioc)
1668 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 iounmap(mem);
1670 kfree(ioc);
1671 pci_set_drvdata(pdev, NULL);
1672 return r;
1673 }
1674
1675 /* call per device driver probe entry point */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301676 for(cb_idx=0; cb_idx<MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
1677 if(MptDeviceDriverHandlers[cb_idx] &&
1678 MptDeviceDriverHandlers[cb_idx]->probe) {
1679 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 }
1682
1683#ifdef CONFIG_PROC_FS
1684 /*
1685 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1686 */
1687 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1688 if (dent) {
1689 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1690 if (ent) {
1691 ent->read_proc = procmpt_iocinfo_read;
1692 ent->data = ioc;
1693 }
1694 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1695 if (ent) {
1696 ent->read_proc = procmpt_summary_read;
1697 ent->data = ioc;
1698 }
1699 }
1700#endif
1701
1702 return 0;
1703}
1704
1705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001706/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001707 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 */
1710
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001711void
1712mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1715 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301716 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1719 remove_proc_entry(pname, NULL);
1720 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1721 remove_proc_entry(pname, NULL);
1722 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1723 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 /* call per device driver remove entry point */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301726 for(cb_idx=0; cb_idx<MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
1727 if(MptDeviceDriverHandlers[cb_idx] &&
1728 MptDeviceDriverHandlers[cb_idx]->remove) {
1729 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
1731 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* Disable interrupts! */
1734 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1735
1736 ioc->active = 0;
1737 synchronize_irq(pdev->irq);
1738
1739 /* Clear any lingering interrupt */
1740 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1741
1742 CHIPREG_READ32(&ioc->chip->IntStatus);
1743
1744 mpt_adapter_dispose(ioc);
1745
1746 pci_set_drvdata(pdev, NULL);
1747}
1748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749/**************************************************************************
1750 * Power Management
1751 */
1752#ifdef CONFIG_PM
1753/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001754/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001755 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001756 * @pdev: Pointer to pci_dev structure
1757 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001759int
1760mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761{
1762 u32 device_state;
1763 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
Pavel Machek2a569572005-07-07 17:56:40 -07001765 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 printk(MYIOC_s_INFO_FMT
1768 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1769 ioc->name, pdev, pci_name(pdev), device_state);
1770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 pci_save_state(pdev);
1772
1773 /* put ioc into READY_STATE */
1774 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1775 printk(MYIOC_s_ERR_FMT
1776 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1777 }
1778
1779 /* disable interrupts */
1780 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1781 ioc->active = 0;
1782
1783 /* Clear any lingering interrupt */
1784 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1785
1786 pci_disable_device(pdev);
1787 pci_set_power_state(pdev, device_state);
1788
1789 return 0;
1790}
1791
1792/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001793/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001794 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001795 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001797int
1798mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799{
1800 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1801 u32 device_state = pdev->current_state;
1802 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001803 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 printk(MYIOC_s_INFO_FMT
1806 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1807 ioc->name, pdev, pci_name(pdev), device_state);
1808
1809 pci_set_power_state(pdev, 0);
1810 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001811 err = pci_enable_device(pdev);
1812 if (err)
1813 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
1815 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001816 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 ioc->active = 1;
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 printk(MYIOC_s_INFO_FMT
1820 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1821 ioc->name,
1822 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1823 CHIPREG_READ32(&ioc->chip->Doorbell));
1824
1825 /* bring ioc to operational state */
1826 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1827 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1828 printk(MYIOC_s_INFO_FMT
1829 "pci-resume: Cannot recover, error:[%x]\n",
1830 ioc->name, recovery_state);
1831 } else {
1832 printk(MYIOC_s_INFO_FMT
1833 "pci-resume: success\n", ioc->name);
1834 }
1835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 return 0;
1837}
1838#endif
1839
James Bottomley4ff42a62006-05-17 18:06:52 -05001840static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301841mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001842{
1843 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1844 ioc->bus_type != SPI) ||
1845 (MptDriverClass[index] == MPTFC_DRIVER &&
1846 ioc->bus_type != FC) ||
1847 (MptDriverClass[index] == MPTSAS_DRIVER &&
1848 ioc->bus_type != SAS))
1849 /* make sure we only call the relevant reset handler
1850 * for the bus */
1851 return 0;
1852 return (MptResetHandlers[index])(ioc, reset_phase);
1853}
1854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001856/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1858 * @ioc: Pointer to MPT adapter structure
1859 * @reason: Event word / reason
1860 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1861 *
1862 * This routine performs all the steps necessary to bring the IOC
1863 * to a OPERATIONAL state.
1864 *
1865 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1866 * MPT adapter.
1867 *
1868 * Returns:
1869 * 0 for success
1870 * -1 if failed to get board READY
1871 * -2 if READY but IOCFacts Failed
1872 * -3 if READY but PrimeIOCFifos Failed
1873 * -4 if READY but IOCInit Failed
1874 */
1875static int
1876mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1877{
1878 int hard_reset_done = 0;
1879 int alt_ioc_ready = 0;
1880 int hard;
1881 int rc=0;
1882 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301883 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 int handlers;
1885 int ret = 0;
1886 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001887 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301888 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1891 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1892
1893 /* Disable reply interrupts (also blocks FreeQ) */
1894 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1895 ioc->active = 0;
1896
1897 if (ioc->alt_ioc) {
1898 if (ioc->alt_ioc->active)
1899 reset_alt_ioc_active = 1;
1900
1901 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1902 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1903 ioc->alt_ioc->active = 0;
1904 }
1905
1906 hard = 1;
1907 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1908 hard = 0;
1909
1910 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1911 if (hard_reset_done == -4) {
1912 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1913 ioc->name);
1914
1915 if (reset_alt_ioc_active && ioc->alt_ioc) {
1916 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05301917 dprintk(ioc, printk(KERN_INFO MYNAM
1918 ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001920 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 ioc->alt_ioc->active = 1;
1922 }
1923
1924 } else {
1925 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1926 ioc->name);
1927 }
1928 return -1;
1929 }
1930
1931 /* hard_reset_done = 0 if a soft reset was performed
1932 * and 1 if a hard reset was performed.
1933 */
1934 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1935 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1936 alt_ioc_ready = 1;
1937 else
1938 printk(KERN_WARNING MYNAM
1939 ": alt-%s: Not ready WARNING!\n",
1940 ioc->alt_ioc->name);
1941 }
1942
1943 for (ii=0; ii<5; ii++) {
1944 /* Get IOC facts! Allow 5 retries */
1945 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1946 break;
1947 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
1950 if (ii == 5) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301951 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 ret = -2;
1953 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1954 MptDisplayIocCapabilities(ioc);
1955 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001956
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 if (alt_ioc_ready) {
1958 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301959 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1960 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 /* Retry - alt IOC was initialized once
1962 */
1963 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1964 }
1965 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301966 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1967 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 alt_ioc_ready = 0;
1969 reset_alt_ioc_active = 0;
1970 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1971 MptDisplayIocCapabilities(ioc->alt_ioc);
1972 }
1973 }
1974
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001975 /*
1976 * Device is reset now. It must have de-asserted the interrupt line
1977 * (if it was asserted) and it should be safe to register for the
1978 * interrupt now.
1979 */
1980 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1981 ioc->pci_irq = -1;
1982 if (ioc->pcidev->irq) {
1983 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1984 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1985 ioc->name);
1986 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001987 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001988 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001989 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1990 "interrupt %d!\n", ioc->name,
1991 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001992 if (mpt_msi_enable)
1993 pci_disable_msi(ioc->pcidev);
1994 return -EBUSY;
1995 }
1996 irq_allocated = 1;
1997 ioc->pci_irq = ioc->pcidev->irq;
1998 pci_set_master(ioc->pcidev); /* ?? */
1999 pci_set_drvdata(ioc->pcidev, ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302000 dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002001 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002002 }
2003 }
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /* Prime reply & request queues!
2006 * (mucho alloc's) Must be done prior to
2007 * init as upper addresses are needed for init.
2008 * If fails, continue with alt-ioc processing
2009 */
2010 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2011 ret = -3;
2012
2013 /* May need to check/upload firmware & data here!
2014 * If fails, continue with alt-ioc processing
2015 */
2016 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2017 ret = -4;
2018// NEW!
2019 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
2020 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
2021 ioc->alt_ioc->name, rc);
2022 alt_ioc_ready = 0;
2023 reset_alt_ioc_active = 0;
2024 }
2025
2026 if (alt_ioc_ready) {
2027 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2028 alt_ioc_ready = 0;
2029 reset_alt_ioc_active = 0;
2030 printk(KERN_WARNING MYNAM
2031 ": alt-%s: (%d) init failure WARNING!\n",
2032 ioc->alt_ioc->name, rc);
2033 }
2034 }
2035
2036 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2037 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302038 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 "firmware upload required!\n", ioc->name));
2040
2041 /* Controller is not operational, cannot do upload
2042 */
2043 if (ret == 0) {
2044 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002045 if (rc == 0) {
2046 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2047 /*
2048 * Maintain only one pointer to FW memory
2049 * so there will not be two attempt to
2050 * downloadboot onboard dual function
2051 * chips (mpt_adapter_disable,
2052 * mpt_diag_reset)
2053 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302054 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2055 ": mpt_upload: alt_%s has cached_fw=%p \n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002056 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002057 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002058 }
2059 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002061 ret = -5;
2062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 }
2064 }
2065 }
2066
2067 if (ret == 0) {
2068 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002069 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 ioc->active = 1;
2071 }
2072
2073 if (reset_alt_ioc_active && ioc->alt_ioc) {
2074 /* (re)Enable alt-IOC! (reply interrupt) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302075 dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002077 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 ioc->alt_ioc->active = 1;
2079 }
2080
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002081 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 * and EventAck handling.
2083 */
2084 if ((ret == 0) && (!ioc->facts.EventState))
2085 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2086
2087 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2088 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2089
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002090 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2092 * recursive scenario; GetLanConfigPages times out, timer expired
2093 * routine calls HardResetHandler, which calls into here again,
2094 * and we try GetLanConfigPages again...
2095 */
2096 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002097
2098 /*
2099 * Initalize link list for inactive raid volumes.
2100 */
2101 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2102 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2103
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002104 if (ioc->bus_type == SAS) {
2105
2106 /* clear persistency table */
2107 if(ioc->facts.IOCExceptions &
2108 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2109 ret = mptbase_sas_persist_operation(ioc,
2110 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2111 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002112 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002113 }
2114
2115 /* Find IM volumes
2116 */
2117 mpt_findImVolumes(ioc);
2118
2119 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2121 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2122 /*
2123 * Pre-fetch the ports LAN MAC address!
2124 * (LANPage1_t stuff)
2125 */
2126 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302127 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2128 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2129 "LanAddr = %02X:%02X:%02X:"
2130 "%02X:%02X:%02X\n",
2131 ioc->name, a[5], a[4],
2132 a[3], a[2], a[1], a[0] ));
2133
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 }
2135 } else {
2136 /* Get NVRAM and adapter maximums from SPP 0 and 2
2137 */
2138 mpt_GetScsiPortSettings(ioc, 0);
2139
2140 /* Get version and length of SDP 1
2141 */
2142 mpt_readScsiDevicePageHeaders(ioc, 0);
2143
2144 /* Find IM volumes
2145 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002146 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 mpt_findImVolumes(ioc);
2148
2149 /* Check, and possibly reset, the coalescing value
2150 */
2151 mpt_read_ioc_pg_1(ioc);
2152
2153 mpt_read_ioc_pg_4(ioc);
2154 }
2155
2156 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302157 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 }
2159
2160 /*
2161 * Call each currently registered protocol IOC reset handler
2162 * with post-reset indication.
2163 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2164 * MptResetHandlers[] registered yet.
2165 */
2166 if (hard_reset_done) {
2167 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302168 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2169 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302170 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2171 "Calling IOC post_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302172 ioc->name, cb_idx));
2173 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 handlers++;
2175 }
2176
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302177 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302178 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2179 "Calling alt-%s post_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302180 ioc->name, ioc->alt_ioc->name, cb_idx));
2181 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 handlers++;
2183 }
2184 }
2185 /* FIXME? Examine results here? */
2186 }
2187
Eric Moore0ccdb002006-07-11 17:33:13 -06002188 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002189 if ((ret != 0) && irq_allocated) {
2190 free_irq(ioc->pci_irq, ioc);
2191 if (mpt_msi_enable)
2192 pci_disable_msi(ioc->pcidev);
2193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 return ret;
2195}
2196
2197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002198/**
2199 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 * @ioc: Pointer to MPT adapter structure
2201 * @pdev: Pointer to (struct pci_dev) structure
2202 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002203 * Search for PCI bus/dev_function which matches
2204 * PCI bus/dev_function (+/-1) for newly discovered 929,
2205 * 929X, 1030 or 1035.
2206 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2208 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2209 */
2210static void
2211mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2212{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002213 struct pci_dev *peer=NULL;
2214 unsigned int slot = PCI_SLOT(pdev->devfn);
2215 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 MPT_ADAPTER *ioc_srch;
2217
Prakash, Sathya436ace72007-07-24 15:42:08 +05302218 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002219 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002220 ioc->name, pci_name(pdev), pdev->bus->number,
2221 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002222
2223 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2224 if (!peer) {
2225 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2226 if (!peer)
2227 return;
2228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
2230 list_for_each_entry(ioc_srch, &ioc_list, list) {
2231 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002232 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 /* Paranoia checks */
2234 if (ioc->alt_ioc != NULL) {
2235 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002236 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 break;
2238 } else if (ioc_srch->alt_ioc != NULL) {
2239 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002240 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 break;
2242 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302243 dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002244 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 ioc_srch->alt_ioc = ioc;
2246 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 }
2248 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002249 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250}
2251
2252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002253/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002255 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 */
2257static void
2258mpt_adapter_disable(MPT_ADAPTER *ioc)
2259{
2260 int sz;
2261 int ret;
2262
2263 if (ioc->cached_fw != NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302264 ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002265 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 printk(KERN_WARNING MYNAM
2267 ": firmware downloadboot failure (%d)!\n", ret);
2268 }
2269 }
2270
2271 /* Disable adapter interrupts! */
2272 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2273 ioc->active = 0;
2274 /* Clear any lingering interrupt */
2275 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2276
2277 if (ioc->alloc != NULL) {
2278 sz = ioc->alloc_sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302279 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 ioc->name, ioc->alloc, ioc->alloc_sz));
2281 pci_free_consistent(ioc->pcidev, sz,
2282 ioc->alloc, ioc->alloc_dma);
2283 ioc->reply_frames = NULL;
2284 ioc->req_frames = NULL;
2285 ioc->alloc = NULL;
2286 ioc->alloc_total -= sz;
2287 }
2288
2289 if (ioc->sense_buf_pool != NULL) {
2290 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2291 pci_free_consistent(ioc->pcidev, sz,
2292 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2293 ioc->sense_buf_pool = NULL;
2294 ioc->alloc_total -= sz;
2295 }
2296
2297 if (ioc->events != NULL){
2298 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2299 kfree(ioc->events);
2300 ioc->events = NULL;
2301 ioc->alloc_total -= sz;
2302 }
2303
2304 if (ioc->cached_fw != NULL) {
2305 sz = ioc->facts.FWImageSize;
2306 pci_free_consistent(ioc->pcidev, sz,
2307 ioc->cached_fw, ioc->cached_fw_dma);
2308 ioc->cached_fw = NULL;
2309 ioc->alloc_total -= sz;
2310 }
2311
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002312 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002313 mpt_inactive_raid_list_free(ioc);
2314 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002315 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002316 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002317 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 if (ioc->spi_data.pIocPg4 != NULL) {
2320 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302321 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 ioc->spi_data.pIocPg4,
2323 ioc->spi_data.IocPg4_dma);
2324 ioc->spi_data.pIocPg4 = NULL;
2325 ioc->alloc_total -= sz;
2326 }
2327
2328 if (ioc->ReqToChain != NULL) {
2329 kfree(ioc->ReqToChain);
2330 kfree(ioc->RequestNB);
2331 ioc->ReqToChain = NULL;
2332 }
2333
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002334 kfree(ioc->ChainToChain);
2335 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002336
2337 if (ioc->HostPageBuffer != NULL) {
2338 if((ret = mpt_host_page_access_control(ioc,
2339 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2340 printk(KERN_ERR MYNAM
2341 ": %s: host page buffers free failed (%d)!\n",
2342 __FUNCTION__, ret);
2343 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302344 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002345 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2346 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2347 ioc->HostPageBuffer,
2348 ioc->HostPageBuffer_dma);
2349 ioc->HostPageBuffer = NULL;
2350 ioc->HostPageBuffer_sz = 0;
2351 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353}
2354
2355/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002356/**
2357 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 * @ioc: Pointer to MPT adapter structure
2359 *
2360 * This routine unregisters h/w resources and frees all alloc'd memory
2361 * associated with a MPT adapter structure.
2362 */
2363static void
2364mpt_adapter_dispose(MPT_ADAPTER *ioc)
2365{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002366 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002368 if (ioc == NULL)
2369 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002371 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002373 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002375 if (ioc->pci_irq != -1) {
2376 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002377 if (mpt_msi_enable)
2378 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002379 ioc->pci_irq = -1;
2380 }
2381
2382 if (ioc->memmap != NULL) {
2383 iounmap(ioc->memmap);
2384 ioc->memmap = NULL;
2385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
2387#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002388 if (ioc->mtrr_reg > 0) {
2389 mtrr_del(ioc->mtrr_reg, 0, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302390 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392#endif
2393
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002394 /* Zap the adapter lookup ptr! */
2395 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002397 sz_last = ioc->alloc_total;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302398 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002399 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002400
2401 if (ioc->alt_ioc)
2402 ioc->alt_ioc->alt_ioc = NULL;
2403
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002404 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405}
2406
2407/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002408/**
2409 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 * @ioc: Pointer to MPT adapter structure
2411 */
2412static void
2413MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2414{
2415 int i = 0;
2416
2417 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302418 if (ioc->prod_name)
2419 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 printk("Capabilities={");
2421
2422 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2423 printk("Initiator");
2424 i++;
2425 }
2426
2427 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2428 printk("%sTarget", i ? "," : "");
2429 i++;
2430 }
2431
2432 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2433 printk("%sLAN", i ? "," : "");
2434 i++;
2435 }
2436
2437#if 0
2438 /*
2439 * This would probably evoke more questions than it's worth
2440 */
2441 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2442 printk("%sLogBusAddr", i ? "," : "");
2443 i++;
2444 }
2445#endif
2446
2447 printk("}\n");
2448}
2449
2450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002451/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2453 * @ioc: Pointer to MPT_ADAPTER structure
2454 * @force: Force hard KickStart of IOC
2455 * @sleepFlag: Specifies whether the process can sleep
2456 *
2457 * Returns:
2458 * 1 - DIAG reset and READY
2459 * 0 - READY initially OR soft reset and READY
2460 * -1 - Any failure on KickStart
2461 * -2 - Msg Unit Reset Failed
2462 * -3 - IO Unit Reset Failed
2463 * -4 - IOC owned by a PEER
2464 */
2465static int
2466MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2467{
2468 u32 ioc_state;
2469 int statefault = 0;
2470 int cntdn;
2471 int hard_reset_done = 0;
2472 int r;
2473 int ii;
2474 int whoinit;
2475
2476 /* Get current [raw] IOC state */
2477 ioc_state = mpt_GetIocState(ioc, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302478 dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 /*
2481 * Check to see if IOC got left/stuck in doorbell handshake
2482 * grip of death. If so, hard reset the IOC.
2483 */
2484 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2485 statefault = 1;
2486 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2487 ioc->name);
2488 }
2489
2490 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002491 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 return 0;
2493
2494 /*
2495 * Check to see if IOC is in FAULT state.
2496 */
2497 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2498 statefault = 2;
2499 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2500 ioc->name);
2501 printk(KERN_WARNING " FAULT code = %04xh\n",
2502 ioc_state & MPI_DOORBELL_DATA_MASK);
2503 }
2504
2505 /*
2506 * Hmmm... Did it get left operational?
2507 */
2508 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302509 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 ioc->name));
2511
2512 /* Check WhoInit.
2513 * If PCI Peer, exit.
2514 * Else, if no fault conditions are present, issue a MessageUnitReset
2515 * Else, fall through to KickStart case
2516 */
2517 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302518 dinitprintk(ioc, printk(KERN_INFO MYNAM
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002519 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 whoinit, statefault, force));
2521 if (whoinit == MPI_WHOINIT_PCI_PEER)
2522 return -4;
2523 else {
2524 if ((statefault == 0 ) && (force == 0)) {
2525 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2526 return 0;
2527 }
2528 statefault = 3;
2529 }
2530 }
2531
2532 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2533 if (hard_reset_done < 0)
2534 return -1;
2535
2536 /*
2537 * Loop here waiting for IOC to come READY.
2538 */
2539 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002540 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
2542 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2543 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2544 /*
2545 * BIOS or previous driver load left IOC in OP state.
2546 * Reset messaging FIFOs.
2547 */
2548 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2549 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2550 return -2;
2551 }
2552 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2553 /*
2554 * Something is wrong. Try to get IOC back
2555 * to a known state.
2556 */
2557 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2558 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2559 return -3;
2560 }
2561 }
2562
2563 ii++; cntdn--;
2564 if (!cntdn) {
2565 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2566 ioc->name, (int)((ii+5)/HZ));
2567 return -ETIME;
2568 }
2569
2570 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002571 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 } else {
2573 mdelay (1); /* 1 msec delay */
2574 }
2575
2576 }
2577
2578 if (statefault < 3) {
2579 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2580 ioc->name,
2581 statefault==1 ? "stuck handshake" : "IOC FAULT");
2582 }
2583
2584 return hard_reset_done;
2585}
2586
2587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002588/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 * mpt_GetIocState - Get the current state of a MPT adapter.
2590 * @ioc: Pointer to MPT_ADAPTER structure
2591 * @cooked: Request raw or cooked IOC state
2592 *
2593 * Returns all IOC Doorbell register bits if cooked==0, else just the
2594 * Doorbell bits in MPI_IOC_STATE_MASK.
2595 */
2596u32
2597mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2598{
2599 u32 s, sc;
2600
2601 /* Get! */
2602 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2603// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2604 sc = s & MPI_IOC_STATE_MASK;
2605
2606 /* Save! */
2607 ioc->last_state = sc;
2608
2609 return cooked ? sc : s;
2610}
2611
2612/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002613/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 * GetIocFacts - Send IOCFacts request to MPT adapter.
2615 * @ioc: Pointer to MPT_ADAPTER structure
2616 * @sleepFlag: Specifies whether the process can sleep
2617 * @reason: If recovery, only update facts.
2618 *
2619 * Returns 0 for success, non-zero for failure.
2620 */
2621static int
2622GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2623{
2624 IOCFacts_t get_facts;
2625 IOCFactsReply_t *facts;
2626 int r;
2627 int req_sz;
2628 int reply_sz;
2629 int sz;
2630 u32 status, vv;
2631 u8 shiftFactor=1;
2632
2633 /* IOC *must* NOT be in RESET state! */
2634 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2635 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2636 ioc->name,
2637 ioc->last_state );
2638 return -44;
2639 }
2640
2641 facts = &ioc->facts;
2642
2643 /* Destination (reply area)... */
2644 reply_sz = sizeof(*facts);
2645 memset(facts, 0, reply_sz);
2646
2647 /* Request area (get_facts on the stack right now!) */
2648 req_sz = sizeof(get_facts);
2649 memset(&get_facts, 0, req_sz);
2650
2651 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2652 /* Assert: All other get_facts fields are zero! */
2653
Prakash, Sathya436ace72007-07-24 15:42:08 +05302654 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002655 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ioc->name, req_sz, reply_sz));
2657
2658 /* No non-zero fields in the get_facts request are greater than
2659 * 1 byte in size, so we can just fire it off as is.
2660 */
2661 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2662 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2663 if (r != 0)
2664 return r;
2665
2666 /*
2667 * Now byte swap (GRRR) the necessary fields before any further
2668 * inspection of reply contents.
2669 *
2670 * But need to do some sanity checks on MsgLength (byte) field
2671 * to make sure we don't zero IOC's req_sz!
2672 */
2673 /* Did we get a valid reply? */
2674 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2675 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2676 /*
2677 * If not been here, done that, save off first WhoInit value
2678 */
2679 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2680 ioc->FirstWhoInit = facts->WhoInit;
2681 }
2682
2683 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2684 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2685 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2686 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2687 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002688 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* CHECKME! IOCStatus, IOCLogInfo */
2690
2691 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2692 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2693
2694 /*
2695 * FC f/w version changed between 1.1 and 1.2
2696 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2697 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2698 */
2699 if (facts->MsgVersion < 0x0102) {
2700 /*
2701 * Handle old FC f/w style, convert to new...
2702 */
2703 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2704 facts->FWVersion.Word =
2705 ((oldv<<12) & 0xFF000000) |
2706 ((oldv<<8) & 0x000FFF00);
2707 } else
2708 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2709
2710 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002711 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2712 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2713 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 facts->CurrentHostMfaHighAddr =
2715 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2716 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2717 facts->CurrentSenseBufferHighAddr =
2718 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2719 facts->CurReplyFrameSize =
2720 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 /*
2724 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2725 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2726 * to 14 in MPI-1.01.0x.
2727 */
2728 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2729 facts->MsgVersion > 0x0100) {
2730 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2731 }
2732
2733 sz = facts->FWImageSize;
2734 if ( sz & 0x01 )
2735 sz += 1;
2736 if ( sz & 0x02 )
2737 sz += 2;
2738 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002739
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 if (!facts->RequestFrameSize) {
2741 /* Something is wrong! */
2742 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2743 ioc->name);
2744 return -55;
2745 }
2746
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002747 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 vv = ((63 / (sz * 4)) + 1) & 0x03;
2749 ioc->NB_for_64_byte_frame = vv;
2750 while ( sz )
2751 {
2752 shiftFactor++;
2753 sz = sz >> 1;
2754 }
2755 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302756 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2757 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2758 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2761 /*
2762 * Set values for this IOC's request & reply frame sizes,
2763 * and request & reply queue depths...
2764 */
2765 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2766 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2767 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2768 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2769
Prakash, Sathya436ace72007-07-24 15:42:08 +05302770 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302772 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 ioc->name, ioc->req_sz, ioc->req_depth));
2774
2775 /* Get port facts! */
2776 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2777 return r;
2778 }
2779 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2782 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2783 RequestFrameSize)/sizeof(u32)));
2784 return -66;
2785 }
2786
2787 return 0;
2788}
2789
2790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002791/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 * GetPortFacts - Send PortFacts request to MPT adapter.
2793 * @ioc: Pointer to MPT_ADAPTER structure
2794 * @portnum: Port number
2795 * @sleepFlag: Specifies whether the process can sleep
2796 *
2797 * Returns 0 for success, non-zero for failure.
2798 */
2799static int
2800GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2801{
2802 PortFacts_t get_pfacts;
2803 PortFactsReply_t *pfacts;
2804 int ii;
2805 int req_sz;
2806 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002807 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 /* IOC *must* NOT be in RESET state! */
2810 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2811 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2812 ioc->name,
2813 ioc->last_state );
2814 return -4;
2815 }
2816
2817 pfacts = &ioc->pfacts[portnum];
2818
2819 /* Destination (reply area)... */
2820 reply_sz = sizeof(*pfacts);
2821 memset(pfacts, 0, reply_sz);
2822
2823 /* Request area (get_pfacts on the stack right now!) */
2824 req_sz = sizeof(get_pfacts);
2825 memset(&get_pfacts, 0, req_sz);
2826
2827 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2828 get_pfacts.PortNumber = portnum;
2829 /* Assert: All other get_pfacts fields are zero! */
2830
Prakash, Sathya436ace72007-07-24 15:42:08 +05302831 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 ioc->name, portnum));
2833
2834 /* No non-zero fields in the get_pfacts request are greater than
2835 * 1 byte in size, so we can just fire it off as is.
2836 */
2837 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2838 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2839 if (ii != 0)
2840 return ii;
2841
2842 /* Did we get a valid reply? */
2843
2844 /* Now byte swap the necessary fields in the response. */
2845 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2846 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2847 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2848 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2849 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2850 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2851 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2852 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2853 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2854
Eric Moore793955f2007-01-29 09:42:20 -07002855 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2856 pfacts->MaxDevices;
2857 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2858 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2859
2860 /*
2861 * Place all the devices on channels
2862 *
2863 * (for debuging)
2864 */
2865 if (mpt_channel_mapping) {
2866 ioc->devices_per_bus = 1;
2867 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2868 }
2869
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 return 0;
2871}
2872
2873/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002874/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 * SendIocInit - Send IOCInit request to MPT adapter.
2876 * @ioc: Pointer to MPT_ADAPTER structure
2877 * @sleepFlag: Specifies whether the process can sleep
2878 *
2879 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2880 *
2881 * Returns 0 for success, non-zero for failure.
2882 */
2883static int
2884SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2885{
2886 IOCInit_t ioc_init;
2887 MPIDefaultReply_t init_reply;
2888 u32 state;
2889 int r;
2890 int count;
2891 int cntdn;
2892
2893 memset(&ioc_init, 0, sizeof(ioc_init));
2894 memset(&init_reply, 0, sizeof(init_reply));
2895
2896 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2897 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2898
2899 /* If we are in a recovery mode and we uploaded the FW image,
2900 * then this pointer is not NULL. Skip the upload a second time.
2901 * Set this flag if cached_fw set for either IOC.
2902 */
2903 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2904 ioc->upload_fw = 1;
2905 else
2906 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302907 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2909
Eric Moore793955f2007-01-29 09:42:20 -07002910 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2911 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302912 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002913 ioc->name, ioc->facts.MsgVersion));
2914 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2915 // set MsgVersion and HeaderVersion host driver was built with
2916 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2917 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002919 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2920 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2921 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2922 return -99;
2923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2925
2926 if (sizeof(dma_addr_t) == sizeof(u64)) {
2927 /* Save the upper 32-bits of the request
2928 * (reply) and sense buffers.
2929 */
2930 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2931 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2932 } else {
2933 /* Force 32-bit addressing */
2934 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2935 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2936 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002937
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2939 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002940 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2941 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
Prakash, Sathya436ace72007-07-24 15:42:08 +05302943 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 ioc->name, &ioc_init));
2945
2946 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2947 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002948 if (r != 0) {
2949 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
2953 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002954 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 */
2956
Prakash, Sathya436ace72007-07-24 15:42:08 +05302957 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002959
2960 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2961 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
2965 /* YIKES! SUPER IMPORTANT!!!
2966 * Poll IocState until _OPERATIONAL while IOC is doing
2967 * LoopInit and TargetDiscovery!
2968 */
2969 count = 0;
2970 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2971 state = mpt_GetIocState(ioc, 1);
2972 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2973 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002974 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 } else {
2976 mdelay(1);
2977 }
2978
2979 if (!cntdn) {
2980 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2981 ioc->name, (int)((count+5)/HZ));
2982 return -9;
2983 }
2984
2985 state = mpt_GetIocState(ioc, 1);
2986 count++;
2987 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302988 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 ioc->name, count));
2990
Eric Mooreba856d32006-07-11 17:34:01 -06002991 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 return r;
2993}
2994
2995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002996/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 * SendPortEnable - Send PortEnable request to MPT adapter port.
2998 * @ioc: Pointer to MPT_ADAPTER structure
2999 * @portnum: Port number to enable
3000 * @sleepFlag: Specifies whether the process can sleep
3001 *
3002 * Send PortEnable to bring IOC to OPERATIONAL state.
3003 *
3004 * Returns 0 for success, non-zero for failure.
3005 */
3006static int
3007SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3008{
3009 PortEnable_t port_enable;
3010 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003011 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 int req_sz;
3013 int reply_sz;
3014
3015 /* Destination... */
3016 reply_sz = sizeof(MPIDefaultReply_t);
3017 memset(&reply_buf, 0, reply_sz);
3018
3019 req_sz = sizeof(PortEnable_t);
3020 memset(&port_enable, 0, req_sz);
3021
3022 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3023 port_enable.PortNumber = portnum;
3024/* port_enable.ChainOffset = 0; */
3025/* port_enable.MsgFlags = 0; */
3026/* port_enable.MsgContext = 0; */
3027
Prakash, Sathya436ace72007-07-24 15:42:08 +05303028 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 ioc->name, portnum, &port_enable));
3030
3031 /* RAID FW may take a long time to enable
3032 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003033 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003034 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3035 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3036 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003037 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003038 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3039 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3040 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003042 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043}
3044
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003045/**
3046 * mpt_alloc_fw_memory - allocate firmware memory
3047 * @ioc: Pointer to MPT_ADAPTER structure
3048 * @size: total FW bytes
3049 *
3050 * If memory has already been allocated, the same (cached) value
3051 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 */
3053void
3054mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3055{
3056 if (ioc->cached_fw)
3057 return; /* use already allocated memory */
3058 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3059 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3060 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003061 ioc->alloc_total += size;
3062 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 } else {
3064 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3065 ioc->alloc_total += size;
3066 }
3067}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003068/**
3069 * mpt_free_fw_memory - free firmware memory
3070 * @ioc: Pointer to MPT_ADAPTER structure
3071 *
3072 * If alt_img is NULL, delete from ioc structure.
3073 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 */
3075void
3076mpt_free_fw_memory(MPT_ADAPTER *ioc)
3077{
3078 int sz;
3079
3080 sz = ioc->facts.FWImageSize;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303081 dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3083 pci_free_consistent(ioc->pcidev, sz,
3084 ioc->cached_fw, ioc->cached_fw_dma);
3085 ioc->cached_fw = NULL;
3086
3087 return;
3088}
3089
3090
3091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003092/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3094 * @ioc: Pointer to MPT_ADAPTER structure
3095 * @sleepFlag: Specifies whether the process can sleep
3096 *
3097 * Returns 0 for success, >0 for handshake failure
3098 * <0 for fw upload failure.
3099 *
3100 * Remark: If bound IOC and a successful FWUpload was performed
3101 * on the bound IOC, the second image is discarded
3102 * and memory is free'd. Both channels must upload to prevent
3103 * IOC from running in degraded mode.
3104 */
3105static int
3106mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3107{
3108 u8 request[ioc->req_sz];
3109 u8 reply[sizeof(FWUploadReply_t)];
3110 FWUpload_t *prequest;
3111 FWUploadReply_t *preply;
3112 FWUploadTCSGE_t *ptcsge;
3113 int sgeoffset;
3114 u32 flagsLength;
3115 int ii, sz, reply_sz;
3116 int cmdStatus;
3117
3118 /* If the image size is 0, we are done.
3119 */
3120 if ((sz = ioc->facts.FWImageSize) == 0)
3121 return 0;
3122
3123 mpt_alloc_fw_memory(ioc, sz);
3124
Prakash, Sathya436ace72007-07-24 15:42:08 +05303125 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003127
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 if (ioc->cached_fw == NULL) {
3129 /* Major Failure.
3130 */
3131 return -ENOMEM;
3132 }
3133
3134 prequest = (FWUpload_t *)&request;
3135 preply = (FWUploadReply_t *)&reply;
3136
3137 /* Destination... */
3138 memset(prequest, 0, ioc->req_sz);
3139
3140 reply_sz = sizeof(reply);
3141 memset(preply, 0, reply_sz);
3142
3143 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3144 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3145
3146 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3147 ptcsge->DetailsLength = 12;
3148 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3149 ptcsge->ImageSize = cpu_to_le32(sz);
3150
3151 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3152
3153 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3154 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3155
3156 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303157 dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 prequest, sgeoffset));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303159 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3162 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3163
Prakash, Sathya436ace72007-07-24 15:42:08 +05303164 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
3166 cmdStatus = -EFAULT;
3167 if (ii == 0) {
3168 /* Handshake transfer was complete and successful.
3169 * Check the Reply Frame.
3170 */
3171 int status, transfer_sz;
3172 status = le16_to_cpu(preply->IOCStatus);
3173 if (status == MPI_IOCSTATUS_SUCCESS) {
3174 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3175 if (transfer_sz == sz)
3176 cmdStatus = 0;
3177 }
3178 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303179 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 ioc->name, cmdStatus));
3181
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003182
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 if (cmdStatus) {
3184
Prakash, Sathya436ace72007-07-24 15:42:08 +05303185 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 ioc->name));
3187 mpt_free_fw_memory(ioc);
3188 }
3189
3190 return cmdStatus;
3191}
3192
3193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003194/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 * mpt_downloadboot - DownloadBoot code
3196 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003197 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 * @sleepFlag: Specifies whether the process can sleep
3199 *
3200 * FwDownloadBoot requires Programmed IO access.
3201 *
3202 * Returns 0 for success
3203 * -1 FW Image size is 0
3204 * -2 No valid cached_fw Pointer
3205 * <0 for fw upload failure.
3206 */
3207static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003208mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 MpiExtImageHeader_t *pExtImage;
3211 u32 fwSize;
3212 u32 diag0val;
3213 int count;
3214 u32 *ptrFw;
3215 u32 diagRwData;
3216 u32 nextImage;
3217 u32 load_addr;
3218 u32 ioc_state=0;
3219
Prakash, Sathya436ace72007-07-24 15:42:08 +05303220 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003221 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3224 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3225 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3226 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3227 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3228 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3229
3230 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3231
3232 /* wait 1 msec */
3233 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003234 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 } else {
3236 mdelay (1);
3237 }
3238
3239 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3240 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3241
3242 for (count = 0; count < 30; count ++) {
3243 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3244 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303245 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 ioc->name, count));
3247 break;
3248 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003249 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003251 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003253 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
3255 }
3256
3257 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303258 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003259 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 ioc->name, diag0val));
3261 return -3;
3262 }
3263
3264 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3265 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3266 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3267 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3268 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3269 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3270
3271 /* Set the DiagRwEn and Disable ARM bits */
3272 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3273
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 fwSize = (pFwHeader->ImageSize + 3)/4;
3275 ptrFw = (u32 *) pFwHeader;
3276
3277 /* Write the LoadStartAddress to the DiagRw Address Register
3278 * using Programmed IO
3279 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003280 if (ioc->errata_flag_1064)
3281 pci_enable_io_access(ioc->pcidev);
3282
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303284 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 ioc->name, pFwHeader->LoadStartAddress));
3286
Prakash, Sathya436ace72007-07-24 15:42:08 +05303287 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 ioc->name, fwSize*4, ptrFw));
3289 while (fwSize--) {
3290 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3291 }
3292
3293 nextImage = pFwHeader->NextImageHeaderOffset;
3294 while (nextImage) {
3295 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3296
3297 load_addr = pExtImage->LoadStartAddress;
3298
3299 fwSize = (pExtImage->ImageSize + 3) >> 2;
3300 ptrFw = (u32 *)pExtImage;
3301
Prakash, Sathya436ace72007-07-24 15:42:08 +05303302 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 +02003303 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3305
3306 while (fwSize--) {
3307 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3308 }
3309 nextImage = pExtImage->NextImageHeaderOffset;
3310 }
3311
3312 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303313 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3315
3316 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303317 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3319
3320 /* Clear the internal flash bad bit - autoincrementing register,
3321 * so must do two writes.
3322 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003323 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003324 /*
3325 * 1030 and 1035 H/W errata, workaround to access
3326 * the ClearFlashBadSignatureBit
3327 */
3328 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3329 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3330 diagRwData |= 0x40000000;
3331 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3332 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3333
3334 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3335 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3336 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3337 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3338
3339 /* wait 1 msec */
3340 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003341 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003342 } else {
3343 mdelay (1);
3344 }
3345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003347 if (ioc->errata_flag_1064)
3348 pci_disable_io_access(ioc->pcidev);
3349
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303351 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003352 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003354 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303355 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 ioc->name, diag0val));
3357 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3358
3359 /* Write 0xFF to reset the sequencer */
3360 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3361
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003362 if (ioc->bus_type == SAS) {
3363 ioc_state = mpt_GetIocState(ioc, 0);
3364 if ( (GetIocFacts(ioc, sleepFlag,
3365 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303366 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003367 ioc->name, ioc_state));
3368 return -EFAULT;
3369 }
3370 }
3371
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 for (count=0; count<HZ*20; count++) {
3373 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303374 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3375 "downloadboot successful! (count=%d) IocState=%x\n",
3376 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003377 if (ioc->bus_type == SAS) {
3378 return 0;
3379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303381 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3382 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 ioc->name));
3384 return -EFAULT;
3385 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303386 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3387 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 ioc->name));
3389 return 0;
3390 }
3391 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003392 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 } else {
3394 mdelay (10);
3395 }
3396 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303397 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3398 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 return -EFAULT;
3400}
3401
3402/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003403/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 * KickStart - Perform hard reset of MPT adapter.
3405 * @ioc: Pointer to MPT_ADAPTER structure
3406 * @force: Force hard reset
3407 * @sleepFlag: Specifies whether the process can sleep
3408 *
3409 * This routine places MPT adapter in diagnostic mode via the
3410 * WriteSequence register, and then performs a hard reset of adapter
3411 * via the Diagnostic register.
3412 *
3413 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3414 * or NO_SLEEP (interrupt thread, use mdelay)
3415 * force - 1 if doorbell active, board fault state
3416 * board operational, IOC_RECOVERY or
3417 * IOC_BRINGUP and there is an alt_ioc.
3418 * 0 else
3419 *
3420 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003421 * 1 - hard reset, READY
3422 * 0 - no reset due to History bit, READY
3423 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 * OR reset but failed to come READY
3425 * -2 - no reset, could not enter DIAG mode
3426 * -3 - reset but bad FW bit
3427 */
3428static int
3429KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3430{
3431 int hard_reset_done = 0;
3432 u32 ioc_state=0;
3433 int cnt,cntdn;
3434
Prakash, Sathya436ace72007-07-24 15:42:08 +05303435 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003436 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 /* Always issue a Msg Unit Reset first. This will clear some
3438 * SCSI bus hang conditions.
3439 */
3440 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3441
3442 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003443 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 } else {
3445 mdelay (1000);
3446 }
3447 }
3448
3449 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3450 if (hard_reset_done < 0)
3451 return hard_reset_done;
3452
Prakash, Sathya436ace72007-07-24 15:42:08 +05303453 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 ioc->name));
3455
3456 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3457 for (cnt=0; cnt<cntdn; cnt++) {
3458 ioc_state = mpt_GetIocState(ioc, 1);
3459 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303460 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 ioc->name, cnt));
3462 return hard_reset_done;
3463 }
3464 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003465 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 } else {
3467 mdelay (10);
3468 }
3469 }
3470
3471 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3472 ioc->name, ioc_state);
3473 return -1;
3474}
3475
3476/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003477/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 * mpt_diag_reset - Perform hard reset of the adapter.
3479 * @ioc: Pointer to MPT_ADAPTER structure
3480 * @ignore: Set if to honor and clear to ignore
3481 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003482 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 * else set to NO_SLEEP (use mdelay instead)
3484 *
3485 * This routine places the adapter in diagnostic mode via the
3486 * WriteSequence register and then performs a hard reset of adapter
3487 * via the Diagnostic register. Adapter should be in ready state
3488 * upon successful completion.
3489 *
3490 * Returns: 1 hard reset successful
3491 * 0 no reset performed because reset history bit set
3492 * -2 enabling diagnostic mode failed
3493 * -3 diagnostic reset failed
3494 */
3495static int
3496mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3497{
Eric Moore0ccdb002006-07-11 17:33:13 -06003498 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 u32 diag0val;
3500 u32 doorbell;
3501 int hard_reset_done = 0;
3502 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
Eric Moorecd2c6192007-01-29 09:47:47 -07003505 /* Clear any existing interrupts */
3506 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3507
Eric Moore87cf8982006-06-27 16:09:26 -06003508 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303509 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003510 "address=%p\n", ioc->name, __FUNCTION__,
3511 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3512 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3513 if (sleepFlag == CAN_SLEEP)
3514 msleep(1);
3515 else
3516 mdelay(1);
3517
3518 for (count = 0; count < 60; count ++) {
3519 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3520 doorbell &= MPI_IOC_STATE_MASK;
3521
Prakash, Sathya436ace72007-07-24 15:42:08 +05303522 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003523 "looking for READY STATE: doorbell=%x"
3524 " count=%d\n",
3525 ioc->name, doorbell, count));
3526 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003527 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003528 }
3529
3530 /* wait 1 sec */
3531 if (sleepFlag == CAN_SLEEP)
3532 msleep(1000);
3533 else
3534 mdelay(1000);
3535 }
3536 return -1;
3537 }
3538
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 /* Use "Diagnostic reset" method! (only thing available!) */
3540 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3541
Prakash, Sathya436ace72007-07-24 15:42:08 +05303542 if (ioc->debug_level & MPT_DEBUG) {
3543 if (ioc->alt_ioc)
3544 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3545 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
3549 /* Do the reset if we are told to ignore the reset history
3550 * or if the reset history is 0
3551 */
3552 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3553 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3554 /* Write magic sequence to WriteSequence register
3555 * Loop until in diagnostic mode
3556 */
3557 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3558 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3559 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3560 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3561 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3562 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3563
3564 /* wait 100 msec */
3565 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003566 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 } else {
3568 mdelay (100);
3569 }
3570
3571 count++;
3572 if (count > 20) {
3573 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3574 ioc->name, diag0val);
3575 return -2;
3576
3577 }
3578
3579 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3580
Prakash, Sathya436ace72007-07-24 15:42:08 +05303581 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 ioc->name, diag0val));
3583 }
3584
Prakash, Sathya436ace72007-07-24 15:42:08 +05303585 if (ioc->debug_level & MPT_DEBUG) {
3586 if (ioc->alt_ioc)
3587 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3588 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 /*
3592 * Disable the ARM (Bug fix)
3593 *
3594 */
3595 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003596 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598 /*
3599 * Now hit the reset bit in the Diagnostic register
3600 * (THE BIG HAMMER!) (Clears DRWE bit).
3601 */
3602 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3603 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303604 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 ioc->name));
3606
3607 /*
3608 * Call each currently registered protocol IOC reset handler
3609 * with pre-reset indication.
3610 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3611 * MptResetHandlers[] registered yet.
3612 */
3613 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303614 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 int r = 0;
3616
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303617 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3618 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303619 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3620 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303621 ioc->name, cb_idx));
3622 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303624 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3625 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303626 ioc->name, ioc->alt_ioc->name, cb_idx));
3627 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 }
3629 }
3630 }
3631 /* FIXME? Examine results here? */
3632 }
3633
Eric Moore0ccdb002006-07-11 17:33:13 -06003634 if (ioc->cached_fw)
3635 iocp = ioc;
3636 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3637 iocp = ioc->alt_ioc;
3638 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 /* If the DownloadBoot operation fails, the
3640 * IOC will be left unusable. This is a fatal error
3641 * case. _diag_reset will return < 0
3642 */
3643 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003644 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3646 break;
3647 }
3648
Prakash, Sathya436ace72007-07-24 15:42:08 +05303649 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003650 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 /* wait 1 sec */
3652 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003653 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 } else {
3655 mdelay (1000);
3656 }
3657 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003658 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003659 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 printk(KERN_WARNING MYNAM
3661 ": firmware downloadboot failure (%d)!\n", count);
3662 }
3663
3664 } else {
3665 /* Wait for FW to reload and for board
3666 * to go to the READY state.
3667 * Maximum wait is 60 seconds.
3668 * If fail, no error will check again
3669 * with calling program.
3670 */
3671 for (count = 0; count < 60; count ++) {
3672 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3673 doorbell &= MPI_IOC_STATE_MASK;
3674
3675 if (doorbell == MPI_IOC_STATE_READY) {
3676 break;
3677 }
3678
3679 /* wait 1 sec */
3680 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003681 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 } else {
3683 mdelay (1000);
3684 }
3685 }
3686 }
3687 }
3688
3689 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303690 if (ioc->debug_level & MPT_DEBUG) {
3691 if (ioc->alt_ioc)
3692 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3693 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3694 ioc->name, diag0val, diag1val));
3695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
3697 /* Clear RESET_HISTORY bit! Place board in the
3698 * diagnostic mode to update the diag register.
3699 */
3700 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3701 count = 0;
3702 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3703 /* Write magic sequence to WriteSequence register
3704 * Loop until in diagnostic mode
3705 */
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3708 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3710 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3711 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3712
3713 /* wait 100 msec */
3714 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003715 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 } else {
3717 mdelay (100);
3718 }
3719
3720 count++;
3721 if (count > 20) {
3722 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3723 ioc->name, diag0val);
3724 break;
3725 }
3726 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3727 }
3728 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3729 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3730 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3731 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3732 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3733 ioc->name);
3734 }
3735
3736 /* Disable Diagnostic Mode
3737 */
3738 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3739
3740 /* Check FW reload status flags.
3741 */
3742 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3743 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3744 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3745 ioc->name, diag0val);
3746 return -3;
3747 }
3748
Prakash, Sathya436ace72007-07-24 15:42:08 +05303749 if (ioc->debug_level & MPT_DEBUG) {
3750 if (ioc->alt_ioc)
3751 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3752 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
3756 /*
3757 * Reset flag that says we've enabled event notification
3758 */
3759 ioc->facts.EventState = 0;
3760
3761 if (ioc->alt_ioc)
3762 ioc->alt_ioc->facts.EventState = 0;
3763
3764 return hard_reset_done;
3765}
3766
3767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003768/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 * SendIocReset - Send IOCReset request to MPT adapter.
3770 * @ioc: Pointer to MPT_ADAPTER structure
3771 * @reset_type: reset type, expected values are
3772 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003773 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 *
3775 * Send IOCReset request to the MPT adapter.
3776 *
3777 * Returns 0 for success, non-zero for failure.
3778 */
3779static int
3780SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3781{
3782 int r;
3783 u32 state;
3784 int cntdn, count;
3785
Prakash, Sathya436ace72007-07-24 15:42:08 +05303786 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 ioc->name, reset_type));
3788 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3789 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3790 return r;
3791
3792 /* FW ACK'd request, wait for READY state
3793 */
3794 count = 0;
3795 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3796
3797 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3798 cntdn--;
3799 count++;
3800 if (!cntdn) {
3801 if (sleepFlag != CAN_SLEEP)
3802 count *= 10;
3803
3804 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3805 ioc->name, (int)((count+5)/HZ));
3806 return -ETIME;
3807 }
3808
3809 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003810 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 } else {
3812 mdelay (1); /* 1 msec delay */
3813 }
3814 }
3815
3816 /* TODO!
3817 * Cleanup all event stuff for this IOC; re-issue EventNotification
3818 * request if needed.
3819 */
3820 if (ioc->facts.Function)
3821 ioc->facts.EventState = 0;
3822
3823 return 0;
3824}
3825
3826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003827/**
3828 * initChainBuffers - Allocate memory for and initialize chain buffers
3829 * @ioc: Pointer to MPT_ADAPTER structure
3830 *
3831 * Allocates memory for and initializes chain buffers,
3832 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 */
3834static int
3835initChainBuffers(MPT_ADAPTER *ioc)
3836{
3837 u8 *mem;
3838 int sz, ii, num_chain;
3839 int scale, num_sge, numSGE;
3840
3841 /* ReqToChain size must equal the req_depth
3842 * index = req_idx
3843 */
3844 if (ioc->ReqToChain == NULL) {
3845 sz = ioc->req_depth * sizeof(int);
3846 mem = kmalloc(sz, GFP_ATOMIC);
3847 if (mem == NULL)
3848 return -1;
3849
3850 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303851 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 ioc->name, mem, sz));
3853 mem = kmalloc(sz, GFP_ATOMIC);
3854 if (mem == NULL)
3855 return -1;
3856
3857 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303858 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 ioc->name, mem, sz));
3860 }
3861 for (ii = 0; ii < ioc->req_depth; ii++) {
3862 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3863 }
3864
3865 /* ChainToChain size must equal the total number
3866 * of chain buffers to be allocated.
3867 * index = chain_idx
3868 *
3869 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003870 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 *
3872 * num_sge = num sge in request frame + last chain buffer
3873 * scale = num sge per chain buffer if no chain element
3874 */
3875 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3876 if (sizeof(dma_addr_t) == sizeof(u64))
3877 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3878 else
3879 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3880
3881 if (sizeof(dma_addr_t) == sizeof(u64)) {
3882 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3883 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3884 } else {
3885 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3886 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3887 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303888 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 ioc->name, num_sge, numSGE));
3890
3891 if ( numSGE > MPT_SCSI_SG_DEPTH )
3892 numSGE = MPT_SCSI_SG_DEPTH;
3893
3894 num_chain = 1;
3895 while (numSGE - num_sge > 0) {
3896 num_chain++;
3897 num_sge += (scale - 1);
3898 }
3899 num_chain++;
3900
Prakash, Sathya436ace72007-07-24 15:42:08 +05303901 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 ioc->name, numSGE, num_sge, num_chain));
3903
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003904 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 num_chain *= MPT_SCSI_CAN_QUEUE;
3906 else
3907 num_chain *= MPT_FC_CAN_QUEUE;
3908
3909 ioc->num_chain = num_chain;
3910
3911 sz = num_chain * sizeof(int);
3912 if (ioc->ChainToChain == NULL) {
3913 mem = kmalloc(sz, GFP_ATOMIC);
3914 if (mem == NULL)
3915 return -1;
3916
3917 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303918 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 ioc->name, mem, sz));
3920 } else {
3921 mem = (u8 *) ioc->ChainToChain;
3922 }
3923 memset(mem, 0xFF, sz);
3924 return num_chain;
3925}
3926
3927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003928/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3930 * @ioc: Pointer to MPT_ADAPTER structure
3931 *
3932 * This routine allocates memory for the MPT reply and request frame
3933 * pools (if necessary), and primes the IOC reply FIFO with
3934 * reply frames.
3935 *
3936 * Returns 0 for success, non-zero for failure.
3937 */
3938static int
3939PrimeIocFifos(MPT_ADAPTER *ioc)
3940{
3941 MPT_FRAME_HDR *mf;
3942 unsigned long flags;
3943 dma_addr_t alloc_dma;
3944 u8 *mem;
3945 int i, reply_sz, sz, total_size, num_chain;
3946
3947 /* Prime reply FIFO... */
3948
3949 if (ioc->reply_frames == NULL) {
3950 if ( (num_chain = initChainBuffers(ioc)) < 0)
3951 return -1;
3952
3953 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303954 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303956 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 ioc->name, reply_sz, reply_sz));
3958
3959 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303960 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303962 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 ioc->name, sz, sz));
3964 total_size += sz;
3965
3966 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 ioc->name, sz, sz, num_chain));
3971
3972 total_size += sz;
3973 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3974 if (mem == NULL) {
3975 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3976 ioc->name);
3977 goto out_fail;
3978 }
3979
Prakash, Sathya436ace72007-07-24 15:42:08 +05303980 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3982
3983 memset(mem, 0, total_size);
3984 ioc->alloc_total += total_size;
3985 ioc->alloc = mem;
3986 ioc->alloc_dma = alloc_dma;
3987 ioc->alloc_sz = total_size;
3988 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3989 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3990
Prakash, Sathya436ace72007-07-24 15:42:08 +05303991 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003992 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3993
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 alloc_dma += reply_sz;
3995 mem += reply_sz;
3996
3997 /* Request FIFO - WE manage this! */
3998
3999 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4000 ioc->req_frames_dma = alloc_dma;
4001
Prakash, Sathya436ace72007-07-24 15:42:08 +05304002 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 ioc->name, mem, (void *)(ulong)alloc_dma));
4004
4005 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4006
4007#if defined(CONFIG_MTRR) && 0
4008 /*
4009 * Enable Write Combining MTRR for IOC's memory region.
4010 * (at least as much as we can; "size and base must be
4011 * multiples of 4 kiB"
4012 */
4013 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4014 sz,
4015 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 ioc->name, ioc->req_frames_dma, sz));
4018#endif
4019
4020 for (i = 0; i < ioc->req_depth; i++) {
4021 alloc_dma += ioc->req_sz;
4022 mem += ioc->req_sz;
4023 }
4024
4025 ioc->ChainBuffer = mem;
4026 ioc->ChainBufferDMA = alloc_dma;
4027
Prakash, Sathya436ace72007-07-24 15:42:08 +05304028 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4030
4031 /* Initialize the free chain Q.
4032 */
4033
4034 INIT_LIST_HEAD(&ioc->FreeChainQ);
4035
4036 /* Post the chain buffers to the FreeChainQ.
4037 */
4038 mem = (u8 *)ioc->ChainBuffer;
4039 for (i=0; i < num_chain; i++) {
4040 mf = (MPT_FRAME_HDR *) mem;
4041 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4042 mem += ioc->req_sz;
4043 }
4044
4045 /* Initialize Request frames linked list
4046 */
4047 alloc_dma = ioc->req_frames_dma;
4048 mem = (u8 *) ioc->req_frames;
4049
4050 spin_lock_irqsave(&ioc->FreeQlock, flags);
4051 INIT_LIST_HEAD(&ioc->FreeQ);
4052 for (i = 0; i < ioc->req_depth; i++) {
4053 mf = (MPT_FRAME_HDR *) mem;
4054
4055 /* Queue REQUESTs *internally*! */
4056 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4057
4058 mem += ioc->req_sz;
4059 }
4060 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4061
4062 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4063 ioc->sense_buf_pool =
4064 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4065 if (ioc->sense_buf_pool == NULL) {
4066 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4067 ioc->name);
4068 goto out_fail;
4069 }
4070
4071 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4072 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304073 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4075
4076 }
4077
4078 /* Post Reply frames to FIFO
4079 */
4080 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304081 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4083
4084 for (i = 0; i < ioc->reply_depth; i++) {
4085 /* Write each address to the IOC! */
4086 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4087 alloc_dma += ioc->reply_sz;
4088 }
4089
4090 return 0;
4091
4092out_fail:
4093 if (ioc->alloc != NULL) {
4094 sz = ioc->alloc_sz;
4095 pci_free_consistent(ioc->pcidev,
4096 sz,
4097 ioc->alloc, ioc->alloc_dma);
4098 ioc->reply_frames = NULL;
4099 ioc->req_frames = NULL;
4100 ioc->alloc_total -= sz;
4101 }
4102 if (ioc->sense_buf_pool != NULL) {
4103 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4104 pci_free_consistent(ioc->pcidev,
4105 sz,
4106 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4107 ioc->sense_buf_pool = NULL;
4108 }
4109 return -1;
4110}
4111
4112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4113/**
4114 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4115 * from IOC via doorbell handshake method.
4116 * @ioc: Pointer to MPT_ADAPTER structure
4117 * @reqBytes: Size of the request in bytes
4118 * @req: Pointer to MPT request frame
4119 * @replyBytes: Expected size of the reply in bytes
4120 * @u16reply: Pointer to area where reply should be written
4121 * @maxwait: Max wait time for a reply (in seconds)
4122 * @sleepFlag: Specifies whether the process can sleep
4123 *
4124 * NOTES: It is the callers responsibility to byte-swap fields in the
4125 * request which are greater than 1 byte in size. It is also the
4126 * callers responsibility to byte-swap response fields which are
4127 * greater than 1 byte in size.
4128 *
4129 * Returns 0 for success, non-zero for failure.
4130 */
4131static int
4132mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004133 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134{
4135 MPIDefaultReply_t *mptReply;
4136 int failcnt = 0;
4137 int t;
4138
4139 /*
4140 * Get ready to cache a handshake reply
4141 */
4142 ioc->hs_reply_idx = 0;
4143 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4144 mptReply->MsgLength = 0;
4145
4146 /*
4147 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4148 * then tell IOC that we want to handshake a request of N words.
4149 * (WRITE u32val to Doorbell reg).
4150 */
4151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4152 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4153 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4154 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4155
4156 /*
4157 * Wait for IOC's doorbell handshake int
4158 */
4159 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4160 failcnt++;
4161
Prakash, Sathya436ace72007-07-24 15:42:08 +05304162 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4164
4165 /* Read doorbell and check for active bit */
4166 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4167 return -1;
4168
4169 /*
4170 * Clear doorbell int (WRITE 0 to IntStatus reg),
4171 * then wait for IOC to ACKnowledge that it's ready for
4172 * our handshake request.
4173 */
4174 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4175 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4176 failcnt++;
4177
4178 if (!failcnt) {
4179 int ii;
4180 u8 *req_as_bytes = (u8 *) req;
4181
4182 /*
4183 * Stuff request words via doorbell handshake,
4184 * with ACK from IOC for each.
4185 */
4186 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4187 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4188 (req_as_bytes[(ii*4) + 1] << 8) |
4189 (req_as_bytes[(ii*4) + 2] << 16) |
4190 (req_as_bytes[(ii*4) + 3] << 24));
4191
4192 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4193 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4194 failcnt++;
4195 }
4196
Prakash, Sathya436ace72007-07-24 15:42:08 +05304197 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
4198 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
Prakash, Sathya436ace72007-07-24 15:42:08 +05304200 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4202
4203 /*
4204 * Wait for completion of doorbell handshake reply from the IOC
4205 */
4206 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4207 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004208
Prakash, Sathya436ace72007-07-24 15:42:08 +05304209 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4211
4212 /*
4213 * Copy out the cached reply...
4214 */
4215 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4216 u16reply[ii] = ioc->hs_reply[ii];
4217 } else {
4218 return -99;
4219 }
4220
4221 return -failcnt;
4222}
4223
4224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004225/**
4226 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 * @ioc: Pointer to MPT_ADAPTER structure
4228 * @howlong: How long to wait (in seconds)
4229 * @sleepFlag: Specifies whether the process can sleep
4230 *
4231 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004232 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4233 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 *
4235 * Returns a negative value on failure, else wait loop count.
4236 */
4237static int
4238WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4239{
4240 int cntdn;
4241 int count = 0;
4242 u32 intstat=0;
4243
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004244 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245
4246 if (sleepFlag == CAN_SLEEP) {
4247 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004248 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4250 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4251 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 count++;
4253 }
4254 } else {
4255 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004256 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4258 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4259 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 count++;
4261 }
4262 }
4263
4264 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304265 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 ioc->name, count));
4267 return count;
4268 }
4269
4270 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4271 ioc->name, count, intstat);
4272 return -1;
4273}
4274
4275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004276/**
4277 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 * @ioc: Pointer to MPT_ADAPTER structure
4279 * @howlong: How long to wait (in seconds)
4280 * @sleepFlag: Specifies whether the process can sleep
4281 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004282 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4283 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 *
4285 * Returns a negative value on failure, else wait loop count.
4286 */
4287static int
4288WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4289{
4290 int cntdn;
4291 int count = 0;
4292 u32 intstat=0;
4293
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004294 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 if (sleepFlag == CAN_SLEEP) {
4296 while (--cntdn) {
4297 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4298 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4299 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004300 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 count++;
4302 }
4303 } else {
4304 while (--cntdn) {
4305 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4306 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4307 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004308 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 count++;
4310 }
4311 }
4312
4313 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304314 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 ioc->name, count, howlong));
4316 return count;
4317 }
4318
4319 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4320 ioc->name, count, intstat);
4321 return -1;
4322}
4323
4324/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004325/**
4326 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 * @ioc: Pointer to MPT_ADAPTER structure
4328 * @howlong: How long to wait (in seconds)
4329 * @sleepFlag: Specifies whether the process can sleep
4330 *
4331 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4332 * Reply is cached to IOC private area large enough to hold a maximum
4333 * of 128 bytes of reply data.
4334 *
4335 * Returns a negative value on failure, else size of reply in WORDS.
4336 */
4337static int
4338WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4339{
4340 int u16cnt = 0;
4341 int failcnt = 0;
4342 int t;
4343 u16 *hs_reply = ioc->hs_reply;
4344 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4345 u16 hword;
4346
4347 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4348
4349 /*
4350 * Get first two u16's so we can look at IOC's intended reply MsgLength
4351 */
4352 u16cnt=0;
4353 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4354 failcnt++;
4355 } else {
4356 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4357 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4358 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4359 failcnt++;
4360 else {
4361 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4362 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4363 }
4364 }
4365
Prakash, Sathya436ace72007-07-24 15:42:08 +05304366 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004367 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4369
4370 /*
4371 * If no error (and IOC said MsgLength is > 0), piece together
4372 * reply 16 bits at a time.
4373 */
4374 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4375 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4376 failcnt++;
4377 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4378 /* don't overflow our IOC hs_reply[] buffer! */
4379 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4380 hs_reply[u16cnt] = hword;
4381 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4382 }
4383
4384 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4385 failcnt++;
4386 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4387
4388 if (failcnt) {
4389 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4390 ioc->name);
4391 return -failcnt;
4392 }
4393#if 0
4394 else if (u16cnt != (2 * mptReply->MsgLength)) {
4395 return -101;
4396 }
4397 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4398 return -102;
4399 }
4400#endif
4401
Prakash, Sathya436ace72007-07-24 15:42:08 +05304402 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
4403 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404
Prakash, Sathya436ace72007-07-24 15:42:08 +05304405 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 ioc->name, t, u16cnt/2));
4407 return u16cnt/2;
4408}
4409
4410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004411/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 * GetLanConfigPages - Fetch LANConfig pages.
4413 * @ioc: Pointer to MPT_ADAPTER structure
4414 *
4415 * Return: 0 for success
4416 * -ENOMEM if no memory available
4417 * -EPERM if not allowed due to ISR context
4418 * -EAGAIN if no msg frames currently available
4419 * -EFAULT for non-successful reply or no reply (timeout)
4420 */
4421static int
4422GetLanConfigPages(MPT_ADAPTER *ioc)
4423{
4424 ConfigPageHeader_t hdr;
4425 CONFIGPARMS cfg;
4426 LANPage0_t *ppage0_alloc;
4427 dma_addr_t page0_dma;
4428 LANPage1_t *ppage1_alloc;
4429 dma_addr_t page1_dma;
4430 int rc = 0;
4431 int data_sz;
4432 int copy_sz;
4433
4434 /* Get LAN Page 0 header */
4435 hdr.PageVersion = 0;
4436 hdr.PageLength = 0;
4437 hdr.PageNumber = 0;
4438 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004439 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 cfg.physAddr = -1;
4441 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4442 cfg.dir = 0;
4443 cfg.pageAddr = 0;
4444 cfg.timeout = 0;
4445
4446 if ((rc = mpt_config(ioc, &cfg)) != 0)
4447 return rc;
4448
4449 if (hdr.PageLength > 0) {
4450 data_sz = hdr.PageLength * 4;
4451 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4452 rc = -ENOMEM;
4453 if (ppage0_alloc) {
4454 memset((u8 *)ppage0_alloc, 0, data_sz);
4455 cfg.physAddr = page0_dma;
4456 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4457
4458 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4459 /* save the data */
4460 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4461 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4462
4463 }
4464
4465 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4466
4467 /* FIXME!
4468 * Normalize endianness of structure data,
4469 * by byte-swapping all > 1 byte fields!
4470 */
4471
4472 }
4473
4474 if (rc)
4475 return rc;
4476 }
4477
4478 /* Get LAN Page 1 header */
4479 hdr.PageVersion = 0;
4480 hdr.PageLength = 0;
4481 hdr.PageNumber = 1;
4482 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004483 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 cfg.physAddr = -1;
4485 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4486 cfg.dir = 0;
4487 cfg.pageAddr = 0;
4488
4489 if ((rc = mpt_config(ioc, &cfg)) != 0)
4490 return rc;
4491
4492 if (hdr.PageLength == 0)
4493 return 0;
4494
4495 data_sz = hdr.PageLength * 4;
4496 rc = -ENOMEM;
4497 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4498 if (ppage1_alloc) {
4499 memset((u8 *)ppage1_alloc, 0, data_sz);
4500 cfg.physAddr = page1_dma;
4501 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4502
4503 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4504 /* save the data */
4505 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4506 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4507 }
4508
4509 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4510
4511 /* FIXME!
4512 * Normalize endianness of structure data,
4513 * by byte-swapping all > 1 byte fields!
4514 */
4515
4516 }
4517
4518 return rc;
4519}
4520
4521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004522/**
4523 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004524 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004525 * @persist_opcode: see below
4526 *
4527 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4528 * devices not currently present.
4529 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4530 *
4531 * NOTE: Don't use not this function during interrupt time.
4532 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004533 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004534 */
4535
4536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4537int
4538mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4539{
4540 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4541 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4542 MPT_FRAME_HDR *mf = NULL;
4543 MPIHeader_t *mpi_hdr;
4544
4545
4546 /* insure garbage is not sent to fw */
4547 switch(persist_opcode) {
4548
4549 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4550 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4551 break;
4552
4553 default:
4554 return -1;
4555 break;
4556 }
4557
4558 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4559
4560 /* Get a MF for this command.
4561 */
4562 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4563 printk("%s: no msg frames!\n",__FUNCTION__);
4564 return -1;
4565 }
4566
4567 mpi_hdr = (MPIHeader_t *) mf;
4568 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4569 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4570 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4571 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4572 sasIoUnitCntrReq->Operation = persist_opcode;
4573
4574 init_timer(&ioc->persist_timer);
4575 ioc->persist_timer.data = (unsigned long) ioc;
4576 ioc->persist_timer.function = mpt_timer_expired;
4577 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4578 ioc->persist_wait_done=0;
4579 add_timer(&ioc->persist_timer);
4580 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4581 wait_event(mpt_waitq, ioc->persist_wait_done);
4582
4583 sasIoUnitCntrReply =
4584 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4585 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4586 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4587 __FUNCTION__,
4588 sasIoUnitCntrReply->IOCStatus,
4589 sasIoUnitCntrReply->IOCLogInfo);
4590 return -1;
4591 }
4592
4593 printk("%s: success\n",__FUNCTION__);
4594 return 0;
4595}
4596
4597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004598
4599static void
4600mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4601 MpiEventDataRaid_t * pRaidEventData)
4602{
4603 int volume;
4604 int reason;
4605 int disk;
4606 int status;
4607 int flags;
4608 int state;
4609
4610 volume = pRaidEventData->VolumeID;
4611 reason = pRaidEventData->ReasonCode;
4612 disk = pRaidEventData->PhysDiskNum;
4613 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4614 flags = (status >> 0) & 0xff;
4615 state = (status >> 8) & 0xff;
4616
4617 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4618 return;
4619 }
4620
4621 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4622 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4623 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004624 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4625 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004626 } else {
4627 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4628 ioc->name, volume);
4629 }
4630
4631 switch(reason) {
4632 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4633 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4634 ioc->name);
4635 break;
4636
4637 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4638
4639 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4640 ioc->name);
4641 break;
4642
4643 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4644 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4645 ioc->name);
4646 break;
4647
4648 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4649 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4650 ioc->name,
4651 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4652 ? "optimal"
4653 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4654 ? "degraded"
4655 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4656 ? "failed"
4657 : "state unknown",
4658 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4659 ? ", enabled" : "",
4660 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4661 ? ", quiesced" : "",
4662 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4663 ? ", resync in progress" : "" );
4664 break;
4665
4666 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4667 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4668 ioc->name, disk);
4669 break;
4670
4671 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4672 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4673 ioc->name);
4674 break;
4675
4676 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4677 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4678 ioc->name);
4679 break;
4680
4681 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4682 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4683 ioc->name);
4684 break;
4685
4686 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4687 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4688 ioc->name,
4689 state == MPI_PHYSDISK0_STATUS_ONLINE
4690 ? "online"
4691 : state == MPI_PHYSDISK0_STATUS_MISSING
4692 ? "missing"
4693 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4694 ? "not compatible"
4695 : state == MPI_PHYSDISK0_STATUS_FAILED
4696 ? "failed"
4697 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4698 ? "initializing"
4699 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4700 ? "offline requested"
4701 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4702 ? "failed requested"
4703 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4704 ? "offline"
4705 : "state unknown",
4706 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4707 ? ", out of sync" : "",
4708 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4709 ? ", quiesced" : "" );
4710 break;
4711
4712 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4713 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4714 ioc->name, disk);
4715 break;
4716
4717 case MPI_EVENT_RAID_RC_SMART_DATA:
4718 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4719 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4720 break;
4721
4722 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4723 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4724 ioc->name, disk);
4725 break;
4726 }
4727}
4728
4729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004730/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4732 * @ioc: Pointer to MPT_ADAPTER structure
4733 *
4734 * Returns: 0 for success
4735 * -ENOMEM if no memory available
4736 * -EPERM if not allowed due to ISR context
4737 * -EAGAIN if no msg frames currently available
4738 * -EFAULT for non-successful reply or no reply (timeout)
4739 */
4740static int
4741GetIoUnitPage2(MPT_ADAPTER *ioc)
4742{
4743 ConfigPageHeader_t hdr;
4744 CONFIGPARMS cfg;
4745 IOUnitPage2_t *ppage_alloc;
4746 dma_addr_t page_dma;
4747 int data_sz;
4748 int rc;
4749
4750 /* Get the page header */
4751 hdr.PageVersion = 0;
4752 hdr.PageLength = 0;
4753 hdr.PageNumber = 2;
4754 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004755 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 cfg.physAddr = -1;
4757 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4758 cfg.dir = 0;
4759 cfg.pageAddr = 0;
4760 cfg.timeout = 0;
4761
4762 if ((rc = mpt_config(ioc, &cfg)) != 0)
4763 return rc;
4764
4765 if (hdr.PageLength == 0)
4766 return 0;
4767
4768 /* Read the config page */
4769 data_sz = hdr.PageLength * 4;
4770 rc = -ENOMEM;
4771 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4772 if (ppage_alloc) {
4773 memset((u8 *)ppage_alloc, 0, data_sz);
4774 cfg.physAddr = page_dma;
4775 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4776
4777 /* If Good, save data */
4778 if ((rc = mpt_config(ioc, &cfg)) == 0)
4779 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4780
4781 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4782 }
4783
4784 return rc;
4785}
4786
4787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004788/**
4789 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 * @ioc: Pointer to a Adapter Strucutre
4791 * @portnum: IOC port number
4792 *
4793 * Return: -EFAULT if read of config page header fails
4794 * or if no nvram
4795 * If read of SCSI Port Page 0 fails,
4796 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4797 * Adapter settings: async, narrow
4798 * Return 1
4799 * If read of SCSI Port Page 2 fails,
4800 * Adapter settings valid
4801 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4802 * Return 1
4803 * Else
4804 * Both valid
4805 * Return 0
4806 * CHECK - what type of locking mechanisms should be used????
4807 */
4808static int
4809mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4810{
4811 u8 *pbuf;
4812 dma_addr_t buf_dma;
4813 CONFIGPARMS cfg;
4814 ConfigPageHeader_t header;
4815 int ii;
4816 int data, rc = 0;
4817
4818 /* Allocate memory
4819 */
4820 if (!ioc->spi_data.nvram) {
4821 int sz;
4822 u8 *mem;
4823 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4824 mem = kmalloc(sz, GFP_ATOMIC);
4825 if (mem == NULL)
4826 return -EFAULT;
4827
4828 ioc->spi_data.nvram = (int *) mem;
4829
Prakash, Sathya436ace72007-07-24 15:42:08 +05304830 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 ioc->name, ioc->spi_data.nvram, sz));
4832 }
4833
4834 /* Invalidate NVRAM information
4835 */
4836 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4837 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4838 }
4839
4840 /* Read SPP0 header, allocate memory, then read page.
4841 */
4842 header.PageVersion = 0;
4843 header.PageLength = 0;
4844 header.PageNumber = 0;
4845 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004846 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 cfg.physAddr = -1;
4848 cfg.pageAddr = portnum;
4849 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4850 cfg.dir = 0;
4851 cfg.timeout = 0; /* use default */
4852 if (mpt_config(ioc, &cfg) != 0)
4853 return -EFAULT;
4854
4855 if (header.PageLength > 0) {
4856 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4857 if (pbuf) {
4858 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4859 cfg.physAddr = buf_dma;
4860 if (mpt_config(ioc, &cfg) != 0) {
4861 ioc->spi_data.maxBusWidth = MPT_NARROW;
4862 ioc->spi_data.maxSyncOffset = 0;
4863 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4864 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4865 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304866 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4867 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004868 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 } else {
4870 /* Save the Port Page 0 data
4871 */
4872 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4873 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4874 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4875
4876 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4877 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304878 ddvprintk(ioc, printk(KERN_INFO MYNAM
4879 " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 ioc->name, pPP0->Capabilities));
4881 }
4882 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4883 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4884 if (data) {
4885 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4886 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4887 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304888 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4889 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004890 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 } else {
4892 ioc->spi_data.maxSyncOffset = 0;
4893 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4894 }
4895
4896 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4897
4898 /* Update the minSyncFactor based on bus type.
4899 */
4900 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4901 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4902
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004903 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304905 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4906 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004907 ioc->name, ioc->spi_data.minSyncFactor));
4908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 }
4910 }
4911 if (pbuf) {
4912 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4913 }
4914 }
4915 }
4916
4917 /* SCSI Port Page 2 - Read the header then the page.
4918 */
4919 header.PageVersion = 0;
4920 header.PageLength = 0;
4921 header.PageNumber = 2;
4922 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004923 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 cfg.physAddr = -1;
4925 cfg.pageAddr = portnum;
4926 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4927 cfg.dir = 0;
4928 if (mpt_config(ioc, &cfg) != 0)
4929 return -EFAULT;
4930
4931 if (header.PageLength > 0) {
4932 /* Allocate memory and read SCSI Port Page 2
4933 */
4934 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4935 if (pbuf) {
4936 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4937 cfg.physAddr = buf_dma;
4938 if (mpt_config(ioc, &cfg) != 0) {
4939 /* Nvram data is left with INVALID mark
4940 */
4941 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004942 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4943
4944 /* This is an ATTO adapter, read Page2 accordingly
4945 */
4946 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4947 ATTODeviceInfo_t *pdevice = NULL;
4948 u16 ATTOFlags;
4949
4950 /* Save the Port Page 2 data
4951 * (reformat into a 32bit quantity)
4952 */
4953 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4954 pdevice = &pPP2->DeviceSettings[ii];
4955 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4956 data = 0;
4957
4958 /* Translate ATTO device flags to LSI format
4959 */
4960 if (ATTOFlags & ATTOFLAG_DISC)
4961 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4962 if (ATTOFlags & ATTOFLAG_ID_ENB)
4963 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4964 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4965 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4966 if (ATTOFlags & ATTOFLAG_TAGGED)
4967 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4968 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4969 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4970
4971 data = (data << 16) | (pdevice->Period << 8) | 10;
4972 ioc->spi_data.nvram[ii] = data;
4973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 } else {
4975 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4976 MpiDeviceInfo_t *pdevice = NULL;
4977
Moore, Ericd8e925d2006-01-16 18:53:06 -07004978 /*
4979 * Save "Set to Avoid SCSI Bus Resets" flag
4980 */
4981 ioc->spi_data.bus_reset =
4982 (le32_to_cpu(pPP2->PortFlags) &
4983 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4984 0 : 1 ;
4985
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 /* Save the Port Page 2 data
4987 * (reformat into a 32bit quantity)
4988 */
4989 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4990 ioc->spi_data.PortFlags = data;
4991 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4992 pdevice = &pPP2->DeviceSettings[ii];
4993 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4994 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4995 ioc->spi_data.nvram[ii] = data;
4996 }
4997 }
4998
4999 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5000 }
5001 }
5002
5003 /* Update Adapter limits with those from NVRAM
5004 * Comment: Don't need to do this. Target performance
5005 * parameters will never exceed the adapters limits.
5006 */
5007
5008 return rc;
5009}
5010
5011/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005012/**
5013 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 * @ioc: Pointer to a Adapter Strucutre
5015 * @portnum: IOC port number
5016 *
5017 * Return: -EFAULT if read of config page header fails
5018 * or 0 if success.
5019 */
5020static int
5021mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5022{
5023 CONFIGPARMS cfg;
5024 ConfigPageHeader_t header;
5025
5026 /* Read the SCSI Device Page 1 header
5027 */
5028 header.PageVersion = 0;
5029 header.PageLength = 0;
5030 header.PageNumber = 1;
5031 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005032 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 cfg.physAddr = -1;
5034 cfg.pageAddr = portnum;
5035 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5036 cfg.dir = 0;
5037 cfg.timeout = 0;
5038 if (mpt_config(ioc, &cfg) != 0)
5039 return -EFAULT;
5040
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005041 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5042 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043
5044 header.PageVersion = 0;
5045 header.PageLength = 0;
5046 header.PageNumber = 0;
5047 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5048 if (mpt_config(ioc, &cfg) != 0)
5049 return -EFAULT;
5050
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005051 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5052 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053
Prakash, Sathya436ace72007-07-24 15:42:08 +05305054 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5056
Prakash, Sathya436ace72007-07-24 15:42:08 +05305057 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5059 return 0;
5060}
5061
Eric Mooreb506ade2007-01-29 09:45:37 -07005062/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005063 * mpt_inactive_raid_list_free - This clears this link list.
5064 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005065 **/
5066static void
5067mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5068{
5069 struct inactive_raid_component_info *component_info, *pNext;
5070
5071 if (list_empty(&ioc->raid_data.inactive_list))
5072 return;
5073
5074 down(&ioc->raid_data.inactive_list_mutex);
5075 list_for_each_entry_safe(component_info, pNext,
5076 &ioc->raid_data.inactive_list, list) {
5077 list_del(&component_info->list);
5078 kfree(component_info);
5079 }
5080 up(&ioc->raid_data.inactive_list_mutex);
5081}
5082
5083/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005084 * 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 -07005085 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005086 * @ioc : pointer to per adapter structure
5087 * @channel : volume channel
5088 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005089 **/
5090static void
5091mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5092{
5093 CONFIGPARMS cfg;
5094 ConfigPageHeader_t hdr;
5095 dma_addr_t dma_handle;
5096 pRaidVolumePage0_t buffer = NULL;
5097 int i;
5098 RaidPhysDiskPage0_t phys_disk;
5099 struct inactive_raid_component_info *component_info;
5100 int handle_inactive_volumes;
5101
5102 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5103 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5104 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5105 cfg.pageAddr = (channel << 8) + id;
5106 cfg.cfghdr.hdr = &hdr;
5107 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5108
5109 if (mpt_config(ioc, &cfg) != 0)
5110 goto out;
5111
5112 if (!hdr.PageLength)
5113 goto out;
5114
5115 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5116 &dma_handle);
5117
5118 if (!buffer)
5119 goto out;
5120
5121 cfg.physAddr = dma_handle;
5122 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5123
5124 if (mpt_config(ioc, &cfg) != 0)
5125 goto out;
5126
5127 if (!buffer->NumPhysDisks)
5128 goto out;
5129
5130 handle_inactive_volumes =
5131 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5132 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5133 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5134 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5135
5136 if (!handle_inactive_volumes)
5137 goto out;
5138
5139 down(&ioc->raid_data.inactive_list_mutex);
5140 for (i = 0; i < buffer->NumPhysDisks; i++) {
5141 if(mpt_raid_phys_disk_pg0(ioc,
5142 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5143 continue;
5144
5145 if ((component_info = kmalloc(sizeof (*component_info),
5146 GFP_KERNEL)) == NULL)
5147 continue;
5148
5149 component_info->volumeID = id;
5150 component_info->volumeBus = channel;
5151 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5152 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5153 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5154 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5155
5156 list_add_tail(&component_info->list,
5157 &ioc->raid_data.inactive_list);
5158 }
5159 up(&ioc->raid_data.inactive_list_mutex);
5160
5161 out:
5162 if (buffer)
5163 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5164 dma_handle);
5165}
5166
5167/**
5168 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5169 * @ioc: Pointer to a Adapter Structure
5170 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5171 * @phys_disk: requested payload data returned
5172 *
5173 * Return:
5174 * 0 on success
5175 * -EFAULT if read of config page header fails or data pointer not NULL
5176 * -ENOMEM if pci_alloc failed
5177 **/
5178int
5179mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5180{
5181 CONFIGPARMS cfg;
5182 ConfigPageHeader_t hdr;
5183 dma_addr_t dma_handle;
5184 pRaidPhysDiskPage0_t buffer = NULL;
5185 int rc;
5186
5187 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5188 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5189
5190 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5191 cfg.cfghdr.hdr = &hdr;
5192 cfg.physAddr = -1;
5193 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5194
5195 if (mpt_config(ioc, &cfg) != 0) {
5196 rc = -EFAULT;
5197 goto out;
5198 }
5199
5200 if (!hdr.PageLength) {
5201 rc = -EFAULT;
5202 goto out;
5203 }
5204
5205 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5206 &dma_handle);
5207
5208 if (!buffer) {
5209 rc = -ENOMEM;
5210 goto out;
5211 }
5212
5213 cfg.physAddr = dma_handle;
5214 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5215 cfg.pageAddr = phys_disk_num;
5216
5217 if (mpt_config(ioc, &cfg) != 0) {
5218 rc = -EFAULT;
5219 goto out;
5220 }
5221
5222 rc = 0;
5223 memcpy(phys_disk, buffer, sizeof(*buffer));
5224 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5225
5226 out:
5227
5228 if (buffer)
5229 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5230 dma_handle);
5231
5232 return rc;
5233}
5234
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235/**
5236 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5237 * @ioc: Pointer to a Adapter Strucutre
5238 * @portnum: IOC port number
5239 *
5240 * Return:
5241 * 0 on success
5242 * -EFAULT if read of config page header fails or data pointer not NULL
5243 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005244 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245int
5246mpt_findImVolumes(MPT_ADAPTER *ioc)
5247{
5248 IOCPage2_t *pIoc2;
5249 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 dma_addr_t ioc2_dma;
5251 CONFIGPARMS cfg;
5252 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 int rc = 0;
5254 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005255 int i;
5256
5257 if (!ioc->ir_firmware)
5258 return 0;
5259
5260 /* Free the old page
5261 */
5262 kfree(ioc->raid_data.pIocPg2);
5263 ioc->raid_data.pIocPg2 = NULL;
5264 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265
5266 /* Read IOCP2 header then the page.
5267 */
5268 header.PageVersion = 0;
5269 header.PageLength = 0;
5270 header.PageNumber = 2;
5271 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005272 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 cfg.physAddr = -1;
5274 cfg.pageAddr = 0;
5275 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5276 cfg.dir = 0;
5277 cfg.timeout = 0;
5278 if (mpt_config(ioc, &cfg) != 0)
5279 return -EFAULT;
5280
5281 if (header.PageLength == 0)
5282 return -EFAULT;
5283
5284 iocpage2sz = header.PageLength * 4;
5285 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5286 if (!pIoc2)
5287 return -ENOMEM;
5288
5289 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5290 cfg.physAddr = ioc2_dma;
5291 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005292 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293
Eric Mooreb506ade2007-01-29 09:45:37 -07005294 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5295 if (!mem)
5296 goto out;
5297
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005299 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300
Eric Mooreb506ade2007-01-29 09:45:37 -07005301 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
Eric Mooreb506ade2007-01-29 09:45:37 -07005303 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5304 mpt_inactive_raid_volumes(ioc,
5305 pIoc2->RaidVolume[i].VolumeBus,
5306 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
Eric Mooreb506ade2007-01-29 09:45:37 -07005308 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5310
5311 return rc;
5312}
5313
Moore, Ericc972c702006-03-14 09:14:06 -07005314static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5316{
5317 IOCPage3_t *pIoc3;
5318 u8 *mem;
5319 CONFIGPARMS cfg;
5320 ConfigPageHeader_t header;
5321 dma_addr_t ioc3_dma;
5322 int iocpage3sz = 0;
5323
5324 /* Free the old page
5325 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005326 kfree(ioc->raid_data.pIocPg3);
5327 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328
5329 /* There is at least one physical disk.
5330 * Read and save IOC Page 3
5331 */
5332 header.PageVersion = 0;
5333 header.PageLength = 0;
5334 header.PageNumber = 3;
5335 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005336 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 cfg.physAddr = -1;
5338 cfg.pageAddr = 0;
5339 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5340 cfg.dir = 0;
5341 cfg.timeout = 0;
5342 if (mpt_config(ioc, &cfg) != 0)
5343 return 0;
5344
5345 if (header.PageLength == 0)
5346 return 0;
5347
5348 /* Read Header good, alloc memory
5349 */
5350 iocpage3sz = header.PageLength * 4;
5351 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5352 if (!pIoc3)
5353 return 0;
5354
5355 /* Read the Page and save the data
5356 * into malloc'd memory.
5357 */
5358 cfg.physAddr = ioc3_dma;
5359 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5360 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005361 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 if (mem) {
5363 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005364 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 }
5366 }
5367
5368 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5369
5370 return 0;
5371}
5372
5373static void
5374mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5375{
5376 IOCPage4_t *pIoc4;
5377 CONFIGPARMS cfg;
5378 ConfigPageHeader_t header;
5379 dma_addr_t ioc4_dma;
5380 int iocpage4sz;
5381
5382 /* Read and save IOC Page 4
5383 */
5384 header.PageVersion = 0;
5385 header.PageLength = 0;
5386 header.PageNumber = 4;
5387 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005388 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 cfg.physAddr = -1;
5390 cfg.pageAddr = 0;
5391 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5392 cfg.dir = 0;
5393 cfg.timeout = 0;
5394 if (mpt_config(ioc, &cfg) != 0)
5395 return;
5396
5397 if (header.PageLength == 0)
5398 return;
5399
5400 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5401 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5402 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5403 if (!pIoc4)
5404 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005405 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 } else {
5407 ioc4_dma = ioc->spi_data.IocPg4_dma;
5408 iocpage4sz = ioc->spi_data.IocPg4Sz;
5409 }
5410
5411 /* Read the Page into dma memory.
5412 */
5413 cfg.physAddr = ioc4_dma;
5414 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5415 if (mpt_config(ioc, &cfg) == 0) {
5416 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5417 ioc->spi_data.IocPg4_dma = ioc4_dma;
5418 ioc->spi_data.IocPg4Sz = iocpage4sz;
5419 } else {
5420 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5421 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005422 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 }
5424}
5425
5426static void
5427mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5428{
5429 IOCPage1_t *pIoc1;
5430 CONFIGPARMS cfg;
5431 ConfigPageHeader_t header;
5432 dma_addr_t ioc1_dma;
5433 int iocpage1sz = 0;
5434 u32 tmp;
5435
5436 /* Check the Coalescing Timeout in IOC Page 1
5437 */
5438 header.PageVersion = 0;
5439 header.PageLength = 0;
5440 header.PageNumber = 1;
5441 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005442 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 cfg.physAddr = -1;
5444 cfg.pageAddr = 0;
5445 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5446 cfg.dir = 0;
5447 cfg.timeout = 0;
5448 if (mpt_config(ioc, &cfg) != 0)
5449 return;
5450
5451 if (header.PageLength == 0)
5452 return;
5453
5454 /* Read Header good, alloc memory
5455 */
5456 iocpage1sz = header.PageLength * 4;
5457 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5458 if (!pIoc1)
5459 return;
5460
5461 /* Read the Page and check coalescing timeout
5462 */
5463 cfg.physAddr = ioc1_dma;
5464 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5465 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305466
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5468 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5469 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5470
Prakash, Sathya436ace72007-07-24 15:42:08 +05305471 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 ioc->name, tmp));
5473
5474 if (tmp > MPT_COALESCING_TIMEOUT) {
5475 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5476
5477 /* Write NVRAM and current
5478 */
5479 cfg.dir = 1;
5480 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5481 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305482 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 ioc->name, MPT_COALESCING_TIMEOUT));
5484
5485 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5486 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305487 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5488 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 ioc->name, MPT_COALESCING_TIMEOUT));
5490 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305491 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5492 "Reset NVRAM Coalescing Timeout Failed\n",
5493 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 }
5495
5496 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305497 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5498 "Reset of Current Coalescing Timeout Failed!\n",
5499 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 }
5501 }
5502
5503 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305504 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 }
5506 }
5507
5508 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5509
5510 return;
5511}
5512
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305513static void
5514mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5515{
5516 CONFIGPARMS cfg;
5517 ConfigPageHeader_t hdr;
5518 dma_addr_t buf_dma;
5519 ManufacturingPage0_t *pbuf = NULL;
5520
5521 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5522 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5523
5524 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5525 cfg.cfghdr.hdr = &hdr;
5526 cfg.physAddr = -1;
5527 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5528 cfg.timeout = 10;
5529
5530 if (mpt_config(ioc, &cfg) != 0)
5531 goto out;
5532
5533 if (!cfg.cfghdr.hdr->PageLength)
5534 goto out;
5535
5536 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5537 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5538 if (!pbuf)
5539 goto out;
5540
5541 cfg.physAddr = buf_dma;
5542
5543 if (mpt_config(ioc, &cfg) != 0)
5544 goto out;
5545
5546 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5547 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5548 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5549
5550 out:
5551
5552 if (pbuf)
5553 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5554}
5555
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005557/**
5558 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 * @ioc: Pointer to MPT_ADAPTER structure
5560 * @EvSwitch: Event switch flags
5561 */
5562static int
5563SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5564{
5565 EventNotification_t *evnp;
5566
5567 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5568 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305569 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 ioc->name));
5571 return 0;
5572 }
5573 memset(evnp, 0, sizeof(*evnp));
5574
Prakash, Sathya436ace72007-07-24 15:42:08 +05305575 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
5577 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5578 evnp->ChainOffset = 0;
5579 evnp->MsgFlags = 0;
5580 evnp->Switch = EvSwitch;
5581
5582 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5583
5584 return 0;
5585}
5586
5587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5588/**
5589 * SendEventAck - Send EventAck request to MPT adapter.
5590 * @ioc: Pointer to MPT_ADAPTER structure
5591 * @evnp: Pointer to original EventNotification request
5592 */
5593static int
5594SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5595{
5596 EventAck_t *pAck;
5597
5598 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305599 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005600 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 return -1;
5602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603
Prakash, Sathya436ace72007-07-24 15:42:08 +05305604 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605
5606 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5607 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005608 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005610 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 pAck->Event = evnp->Event;
5612 pAck->EventContext = evnp->EventContext;
5613
5614 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5615
5616 return 0;
5617}
5618
5619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5620/**
5621 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005622 * @ioc: Pointer to an adapter structure
5623 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 * action, page address, direction, physical address
5625 * and pointer to a configuration page header
5626 * Page header is updated.
5627 *
5628 * Returns 0 for success
5629 * -EPERM if not allowed due to ISR context
5630 * -EAGAIN if no msg frames currently available
5631 * -EFAULT for non-successful reply or no reply (timeout)
5632 */
5633int
5634mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5635{
5636 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005637 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 MPT_FRAME_HDR *mf;
5639 unsigned long flags;
5640 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005641 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 int in_isr;
5643
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005644 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 * to be in ISR context, because that is fatal!
5646 */
5647 in_isr = in_interrupt();
5648 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305649 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 ioc->name));
5651 return -EPERM;
5652 }
5653
5654 /* Get and Populate a free Frame
5655 */
5656 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305657 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 ioc->name));
5659 return -EAGAIN;
5660 }
5661 pReq = (Config_t *)mf;
5662 pReq->Action = pCfg->action;
5663 pReq->Reserved = 0;
5664 pReq->ChainOffset = 0;
5665 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005666
5667 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 pReq->ExtPageLength = 0;
5669 pReq->ExtPageType = 0;
5670 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005671
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 for (ii=0; ii < 8; ii++)
5673 pReq->Reserved2[ii] = 0;
5674
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005675 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5676 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5677 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5678 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5679
5680 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5681 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5682 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5683 pReq->ExtPageType = pExtHdr->ExtPageType;
5684 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5685
5686 /* Page Length must be treated as a reserved field for the extended header. */
5687 pReq->Header.PageLength = 0;
5688 }
5689
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5691
5692 /* Add a SGE to the config request.
5693 */
5694 if (pCfg->dir)
5695 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5696 else
5697 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5698
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005699 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5700 flagsLength |= pExtHdr->ExtPageLength * 4;
5701
Prakash, Sathya436ace72007-07-24 15:42:08 +05305702 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 +02005703 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5704 }
5705 else {
5706 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5707
Prakash, Sathya436ace72007-07-24 15:42:08 +05305708 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 +02005709 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
5712 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5713
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 /* Append pCfg pointer to end of mf
5715 */
5716 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5717
5718 /* Initalize the timer
5719 */
5720 init_timer(&pCfg->timer);
5721 pCfg->timer.data = (unsigned long) ioc;
5722 pCfg->timer.function = mpt_timer_expired;
5723 pCfg->wait_done = 0;
5724
5725 /* Set the timer; ensure 10 second minimum */
5726 if (pCfg->timeout < 10)
5727 pCfg->timer.expires = jiffies + HZ*10;
5728 else
5729 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5730
5731 /* Add to end of Q, set timer and then issue this command */
5732 spin_lock_irqsave(&ioc->FreeQlock, flags);
5733 list_add_tail(&pCfg->linkage, &ioc->configQ);
5734 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5735
5736 add_timer(&pCfg->timer);
5737 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5738 wait_event(mpt_waitq, pCfg->wait_done);
5739
5740 /* mf has been freed - do not access */
5741
5742 rc = pCfg->status;
5743
5744 return rc;
5745}
5746
5747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005748/**
5749 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 * Used only internal config functionality.
5751 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5752 */
5753static void
5754mpt_timer_expired(unsigned long data)
5755{
5756 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5757
Prakash, Sathya436ace72007-07-24 15:42:08 +05305758 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759
5760 /* Perform a FW reload */
5761 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5762 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5763
5764 /* No more processing.
5765 * Hard reset clean-up will wake up
5766 * process and free all resources.
5767 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305768 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769
5770 return;
5771}
5772
5773/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005774/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 * mpt_ioc_reset - Base cleanup for hard reset
5776 * @ioc: Pointer to the adapter structure
5777 * @reset_phase: Indicates pre- or post-reset functionality
5778 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005779 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 */
5781static int
5782mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5783{
5784 CONFIGPARMS *pCfg;
5785 unsigned long flags;
5786
Prakash, Sathya436ace72007-07-24 15:42:08 +05305787 dprintk(ioc, printk(KERN_DEBUG MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 ": IOC %s_reset routed to MPT base driver!\n",
5789 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5790 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5791
5792 if (reset_phase == MPT_IOC_SETUP_RESET) {
5793 ;
5794 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5795 /* If the internal config Q is not empty -
5796 * delete timer. MF resources will be freed when
5797 * the FIFO's are primed.
5798 */
5799 spin_lock_irqsave(&ioc->FreeQlock, flags);
5800 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5801 del_timer(&pCfg->timer);
5802 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5803
5804 } else {
5805 CONFIGPARMS *pNext;
5806
5807 /* Search the configQ for internal commands.
5808 * Flush the Q, and wake up all suspended threads.
5809 */
5810 spin_lock_irqsave(&ioc->FreeQlock, flags);
5811 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5812 list_del(&pCfg->linkage);
5813
5814 pCfg->status = MPT_CONFIG_ERROR;
5815 pCfg->wait_done = 1;
5816 wake_up(&mpt_waitq);
5817 }
5818 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5819 }
5820
5821 return 1; /* currently means nothing really */
5822}
5823
5824
5825#ifdef CONFIG_PROC_FS /* { */
5826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5827/*
5828 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5829 */
5830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005831/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5833 *
5834 * Returns 0 for success, non-zero for failure.
5835 */
5836static int
5837procmpt_create(void)
5838{
5839 struct proc_dir_entry *ent;
5840
5841 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5842 if (mpt_proc_root_dir == NULL)
5843 return -ENOTDIR;
5844
5845 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5846 if (ent)
5847 ent->read_proc = procmpt_summary_read;
5848
5849 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5850 if (ent)
5851 ent->read_proc = procmpt_version_read;
5852
5853 return 0;
5854}
5855
5856/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005857/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5859 *
5860 * Returns 0 for success, non-zero for failure.
5861 */
5862static void
5863procmpt_destroy(void)
5864{
5865 remove_proc_entry("version", mpt_proc_root_dir);
5866 remove_proc_entry("summary", mpt_proc_root_dir);
5867 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5868}
5869
5870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005871/**
5872 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 * @buf: Pointer to area to write information
5874 * @start: Pointer to start pointer
5875 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005876 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 * @eof: Pointer to EOF integer
5878 * @data: Pointer
5879 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005880 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 * Returns number of characters written to process performing the read.
5882 */
5883static int
5884procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5885{
5886 MPT_ADAPTER *ioc;
5887 char *out = buf;
5888 int len;
5889
5890 if (data) {
5891 int more = 0;
5892
5893 ioc = data;
5894 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5895
5896 out += more;
5897 } else {
5898 list_for_each_entry(ioc, &ioc_list, list) {
5899 int more = 0;
5900
5901 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5902
5903 out += more;
5904 if ((out-buf) >= request)
5905 break;
5906 }
5907 }
5908
5909 len = out - buf;
5910
5911 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5912}
5913
5914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005915/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 * procmpt_version_read - Handle read request from /proc/mpt/version.
5917 * @buf: Pointer to area to write information
5918 * @start: Pointer to start pointer
5919 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005920 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 * @eof: Pointer to EOF integer
5922 * @data: Pointer
5923 *
5924 * Returns number of characters written to process performing the read.
5925 */
5926static int
5927procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5928{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305929 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005930 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 char *drvname;
5932 int len;
5933
5934 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5935 len += sprintf(buf+len, " Fusion MPT base driver\n");
5936
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005937 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305938 for (cb_idx=MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305940 if (MptCallbacks[cb_idx]) {
5941 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005942 case MPTSPI_DRIVER:
5943 if (!scsi++) drvname = "SPI host";
5944 break;
5945 case MPTFC_DRIVER:
5946 if (!fc++) drvname = "FC host";
5947 break;
5948 case MPTSAS_DRIVER:
5949 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 break;
5951 case MPTLAN_DRIVER:
5952 if (!lan++) drvname = "LAN";
5953 break;
5954 case MPTSTM_DRIVER:
5955 if (!targ++) drvname = "SCSI target";
5956 break;
5957 case MPTCTL_DRIVER:
5958 if (!ctl++) drvname = "ioctl";
5959 break;
5960 }
5961
5962 if (drvname)
5963 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5964 }
5965 }
5966
5967 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5968}
5969
5970/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005971/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5973 * @buf: Pointer to area to write information
5974 * @start: Pointer to start pointer
5975 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005976 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 * @eof: Pointer to EOF integer
5978 * @data: Pointer
5979 *
5980 * Returns number of characters written to process performing the read.
5981 */
5982static int
5983procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5984{
5985 MPT_ADAPTER *ioc = data;
5986 int len;
5987 char expVer[32];
5988 int sz;
5989 int p;
5990
5991 mpt_get_fw_exp_ver(expVer, ioc);
5992
5993 len = sprintf(buf, "%s:", ioc->name);
5994 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5995 len += sprintf(buf+len, " (f/w download boot flag set)");
5996// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5997// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5998
5999 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6000 ioc->facts.ProductID,
6001 ioc->prod_name);
6002 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6003 if (ioc->facts.FWImageSize)
6004 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6005 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6006 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6007 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6008
6009 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6010 ioc->facts.CurrentHostMfaHighAddr);
6011 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6012 ioc->facts.CurrentSenseBufferHighAddr);
6013
6014 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6015 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6016
6017 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6018 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6019 /*
6020 * Rounding UP to nearest 4-kB boundary here...
6021 */
6022 sz = (ioc->req_sz * ioc->req_depth) + 128;
6023 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6024 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6025 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6026 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6027 4*ioc->facts.RequestFrameSize,
6028 ioc->facts.GlobalCredits);
6029
6030 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6031 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6032 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6033 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6034 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6035 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6036 ioc->facts.CurReplyFrameSize,
6037 ioc->facts.ReplyQueueDepth);
6038
6039 len += sprintf(buf+len, " MaxDevices = %d\n",
6040 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6041 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6042
6043 /* per-port info */
6044 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6045 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6046 p+1,
6047 ioc->facts.NumberOfPorts);
6048 if (ioc->bus_type == FC) {
6049 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6050 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6051 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6052 a[5], a[4], a[3], a[2], a[1], a[0]);
6053 }
6054 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6055 ioc->fc_port_page0[p].WWNN.High,
6056 ioc->fc_port_page0[p].WWNN.Low,
6057 ioc->fc_port_page0[p].WWPN.High,
6058 ioc->fc_port_page0[p].WWPN.Low);
6059 }
6060 }
6061
6062 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6063}
6064
6065#endif /* CONFIG_PROC_FS } */
6066
6067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6068static void
6069mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6070{
6071 buf[0] ='\0';
6072 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6073 sprintf(buf, " (Exp %02d%02d)",
6074 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6075 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6076
6077 /* insider hack! */
6078 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6079 strcat(buf, " [MDBG]");
6080 }
6081}
6082
6083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6084/**
6085 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6086 * @ioc: Pointer to MPT_ADAPTER structure
6087 * @buffer: Pointer to buffer where IOC summary info should be written
6088 * @size: Pointer to number of bytes we wrote (set by this routine)
6089 * @len: Offset at which to start writing in buffer
6090 * @showlan: Display LAN stuff?
6091 *
6092 * This routine writes (english readable) ASCII text, which represents
6093 * a summary of IOC information, to a buffer.
6094 */
6095void
6096mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6097{
6098 char expVer[32];
6099 int y;
6100
6101 mpt_get_fw_exp_ver(expVer, ioc);
6102
6103 /*
6104 * Shorter summary of attached ioc's...
6105 */
6106 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6107 ioc->name,
6108 ioc->prod_name,
6109 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6110 ioc->facts.FWVersion.Word,
6111 expVer,
6112 ioc->facts.NumberOfPorts,
6113 ioc->req_depth);
6114
6115 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6116 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6117 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6118 a[5], a[4], a[3], a[2], a[1], a[0]);
6119 }
6120
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122
6123 if (!ioc->active)
6124 y += sprintf(buffer+len+y, " (disabled)");
6125
6126 y += sprintf(buffer+len+y, "\n");
6127
6128 *size = y;
6129}
6130
6131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6132/*
6133 * Reset Handling
6134 */
6135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6136/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006137 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 * @ioc: Pointer to MPT_ADAPTER structure
6139 * @sleepFlag: Indicates if sleep or schedule must be called.
6140 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006141 * Issues SCSI Task Management call based on input arg values.
6142 * If TaskMgmt fails, returns associated SCSI request.
6143 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6145 * or a non-interrupt thread. In the former, must not call schedule().
6146 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006147 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148 * FW reload/initialization failed.
6149 *
6150 * Returns 0 for SUCCESS or -1 if FAILED.
6151 */
6152int
6153mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6154{
6155 int rc;
6156 unsigned long flags;
6157
Prakash, Sathya436ace72007-07-24 15:42:08 +05306158 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159#ifdef MFCNT
6160 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6161 printk("MF count 0x%x !\n", ioc->mfcnt);
6162#endif
6163
6164 /* Reset the adapter. Prevent more than 1 call to
6165 * mpt_do_ioc_recovery at any instant in time.
6166 */
6167 spin_lock_irqsave(&ioc->diagLock, flags);
6168 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6169 spin_unlock_irqrestore(&ioc->diagLock, flags);
6170 return 0;
6171 } else {
6172 ioc->diagPending = 1;
6173 }
6174 spin_unlock_irqrestore(&ioc->diagLock, flags);
6175
6176 /* FIXME: If do_ioc_recovery fails, repeat....
6177 */
6178
6179 /* The SCSI driver needs to adjust timeouts on all current
6180 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006181 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 * For all other protocol drivers, this is a no-op.
6183 */
6184 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306185 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186 int r = 0;
6187
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306188 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6189 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306190 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306191 ioc->name, cb_idx));
6192 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306194 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306195 ioc->name, ioc->alt_ioc->name, cb_idx));
6196 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 }
6198 }
6199 }
6200 }
6201
6202 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
6203 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
6204 rc, ioc->name);
6205 }
6206 ioc->reload_fw = 0;
6207 if (ioc->alt_ioc)
6208 ioc->alt_ioc->reload_fw = 0;
6209
6210 spin_lock_irqsave(&ioc->diagLock, flags);
6211 ioc->diagPending = 0;
6212 if (ioc->alt_ioc)
6213 ioc->alt_ioc->diagPending = 0;
6214 spin_unlock_irqrestore(&ioc->diagLock, flags);
6215
Prakash, Sathya436ace72007-07-24 15:42:08 +05306216 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217
6218 return rc;
6219}
6220
6221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006222static void
6223EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224{
Eric Moore509e5e52006-04-26 13:22:37 -06006225 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226
6227 switch(event) {
6228 case MPI_EVENT_NONE:
6229 ds = "None";
6230 break;
6231 case MPI_EVENT_LOG_DATA:
6232 ds = "Log Data";
6233 break;
6234 case MPI_EVENT_STATE_CHANGE:
6235 ds = "State Change";
6236 break;
6237 case MPI_EVENT_UNIT_ATTENTION:
6238 ds = "Unit Attention";
6239 break;
6240 case MPI_EVENT_IOC_BUS_RESET:
6241 ds = "IOC Bus Reset";
6242 break;
6243 case MPI_EVENT_EXT_BUS_RESET:
6244 ds = "External Bus Reset";
6245 break;
6246 case MPI_EVENT_RESCAN:
6247 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 break;
6249 case MPI_EVENT_LINK_STATUS_CHANGE:
6250 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6251 ds = "Link Status(FAILURE) Change";
6252 else
6253 ds = "Link Status(ACTIVE) Change";
6254 break;
6255 case MPI_EVENT_LOOP_STATE_CHANGE:
6256 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6257 ds = "Loop State(LIP) Change";
6258 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006259 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 else
Eric Moore509e5e52006-04-26 13:22:37 -06006261 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 break;
6263 case MPI_EVENT_LOGOUT:
6264 ds = "Logout";
6265 break;
6266 case MPI_EVENT_EVENT_CHANGE:
6267 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006268 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006270 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 break;
6272 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006273 {
6274 u8 ReasonCode = (u8)(evData0 >> 16);
6275 switch (ReasonCode) {
6276 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6277 ds = "Integrated Raid: Volume Created";
6278 break;
6279 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6280 ds = "Integrated Raid: Volume Deleted";
6281 break;
6282 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6283 ds = "Integrated Raid: Volume Settings Changed";
6284 break;
6285 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6286 ds = "Integrated Raid: Volume Status Changed";
6287 break;
6288 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6289 ds = "Integrated Raid: Volume Physdisk Changed";
6290 break;
6291 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6292 ds = "Integrated Raid: Physdisk Created";
6293 break;
6294 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6295 ds = "Integrated Raid: Physdisk Deleted";
6296 break;
6297 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6298 ds = "Integrated Raid: Physdisk Settings Changed";
6299 break;
6300 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6301 ds = "Integrated Raid: Physdisk Status Changed";
6302 break;
6303 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6304 ds = "Integrated Raid: Domain Validation Needed";
6305 break;
6306 case MPI_EVENT_RAID_RC_SMART_DATA :
6307 ds = "Integrated Raid; Smart Data";
6308 break;
6309 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6310 ds = "Integrated Raid: Replace Action Started";
6311 break;
6312 default:
6313 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006315 }
6316 break;
6317 }
6318 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6319 ds = "SCSI Device Status Change";
6320 break;
6321 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6322 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006323 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006324 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006325 u8 ReasonCode = (u8)(evData0 >> 16);
6326 switch (ReasonCode) {
6327 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006328 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006329 "SAS Device Status Change: Added: "
6330 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006331 break;
6332 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006333 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006334 "SAS Device Status Change: Deleted: "
6335 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006336 break;
6337 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006338 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006339 "SAS Device Status Change: SMART Data: "
6340 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006341 break;
6342 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006343 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006344 "SAS Device Status Change: No Persistancy: "
6345 "id=%d channel=%d", id, channel);
6346 break;
6347 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6348 snprintf(evStr, EVENT_DESCR_STR_SZ,
6349 "SAS Device Status Change: Unsupported Device "
6350 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006351 break;
6352 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6353 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006354 "SAS Device Status Change: Internal Device "
6355 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006356 break;
6357 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6358 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006359 "SAS Device Status Change: Internal Task "
6360 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006361 break;
6362 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6363 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006364 "SAS Device Status Change: Internal Abort "
6365 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006366 break;
6367 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6368 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006369 "SAS Device Status Change: Internal Clear "
6370 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006371 break;
6372 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6373 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006374 "SAS Device Status Change: Internal Query "
6375 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006376 break;
6377 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006378 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006379 "SAS Device Status Change: Unknown: "
6380 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006381 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006382 }
6383 break;
6384 }
6385 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6386 ds = "Bus Timer Expired";
6387 break;
6388 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006389 {
6390 u16 curr_depth = (u16)(evData0 >> 16);
6391 u8 channel = (u8)(evData0 >> 8);
6392 u8 id = (u8)(evData0);
6393
6394 snprintf(evStr, EVENT_DESCR_STR_SZ,
6395 "Queue Full: channel=%d id=%d depth=%d",
6396 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006397 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006398 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006399 case MPI_EVENT_SAS_SES:
6400 ds = "SAS SES Event";
6401 break;
6402 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6403 ds = "Persistent Table Full";
6404 break;
6405 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006406 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006407 u8 LinkRates = (u8)(evData0 >> 8);
6408 u8 PhyNumber = (u8)(evData0);
6409 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6410 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6411 switch (LinkRates) {
6412 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006413 snprintf(evStr, EVENT_DESCR_STR_SZ,
6414 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006415 " Rate Unknown",PhyNumber);
6416 break;
6417 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006418 snprintf(evStr, EVENT_DESCR_STR_SZ,
6419 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006420 " Phy Disabled",PhyNumber);
6421 break;
6422 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006423 snprintf(evStr, EVENT_DESCR_STR_SZ,
6424 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006425 " Failed Speed Nego",PhyNumber);
6426 break;
6427 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006428 snprintf(evStr, EVENT_DESCR_STR_SZ,
6429 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006430 " Sata OOB Completed",PhyNumber);
6431 break;
6432 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006433 snprintf(evStr, EVENT_DESCR_STR_SZ,
6434 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006435 " Rate 1.5 Gbps",PhyNumber);
6436 break;
6437 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006438 snprintf(evStr, EVENT_DESCR_STR_SZ,
6439 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006440 " Rate 3.0 Gpbs",PhyNumber);
6441 break;
6442 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006443 snprintf(evStr, EVENT_DESCR_STR_SZ,
6444 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006445 break;
6446 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006447 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006448 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006449 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6450 ds = "SAS Discovery Error";
6451 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006452 case MPI_EVENT_IR_RESYNC_UPDATE:
6453 {
6454 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006455 snprintf(evStr, EVENT_DESCR_STR_SZ,
6456 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006457 break;
6458 }
6459 case MPI_EVENT_IR2:
6460 {
6461 u8 ReasonCode = (u8)(evData0 >> 16);
6462 switch (ReasonCode) {
6463 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6464 ds = "IR2: LD State Changed";
6465 break;
6466 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6467 ds = "IR2: PD State Changed";
6468 break;
6469 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6470 ds = "IR2: Bad Block Table Full";
6471 break;
6472 case MPI_EVENT_IR2_RC_PD_INSERTED:
6473 ds = "IR2: PD Inserted";
6474 break;
6475 case MPI_EVENT_IR2_RC_PD_REMOVED:
6476 ds = "IR2: PD Removed";
6477 break;
6478 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6479 ds = "IR2: Foreign CFG Detected";
6480 break;
6481 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6482 ds = "IR2: Rebuild Medium Error";
6483 break;
6484 default:
6485 ds = "IR2";
6486 break;
6487 }
6488 break;
6489 }
6490 case MPI_EVENT_SAS_DISCOVERY:
6491 {
6492 if (evData0)
6493 ds = "SAS Discovery: Start";
6494 else
6495 ds = "SAS Discovery: Stop";
6496 break;
6497 }
6498 case MPI_EVENT_LOG_ENTRY_ADDED:
6499 ds = "SAS Log Entry Added";
6500 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006501
Eric Moorec6c727a2007-01-29 09:44:54 -07006502 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6503 {
6504 u8 phy_num = (u8)(evData0);
6505 u8 port_num = (u8)(evData0 >> 8);
6506 u8 port_width = (u8)(evData0 >> 16);
6507 u8 primative = (u8)(evData0 >> 24);
6508 snprintf(evStr, EVENT_DESCR_STR_SZ,
6509 "SAS Broadcase Primative: phy=%d port=%d "
6510 "width=%d primative=0x%02x",
6511 phy_num, port_num, port_width, primative);
6512 break;
6513 }
6514
6515 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6516 {
6517 u8 reason = (u8)(evData0);
6518 u8 port_num = (u8)(evData0 >> 8);
6519 u16 handle = le16_to_cpu(evData0 >> 16);
6520
6521 snprintf(evStr, EVENT_DESCR_STR_SZ,
6522 "SAS Initiator Device Status Change: reason=0x%02x "
6523 "port=%d handle=0x%04x",
6524 reason, port_num, handle);
6525 break;
6526 }
6527
6528 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6529 {
6530 u8 max_init = (u8)(evData0);
6531 u8 current_init = (u8)(evData0 >> 8);
6532
6533 snprintf(evStr, EVENT_DESCR_STR_SZ,
6534 "SAS Initiator Device Table Overflow: max initiators=%02d "
6535 "current initators=%02d",
6536 max_init, current_init);
6537 break;
6538 }
6539 case MPI_EVENT_SAS_SMP_ERROR:
6540 {
6541 u8 status = (u8)(evData0);
6542 u8 port_num = (u8)(evData0 >> 8);
6543 u8 result = (u8)(evData0 >> 16);
6544
6545 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6546 snprintf(evStr, EVENT_DESCR_STR_SZ,
6547 "SAS SMP Error: port=%d result=0x%02x",
6548 port_num, result);
6549 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6550 snprintf(evStr, EVENT_DESCR_STR_SZ,
6551 "SAS SMP Error: port=%d : CRC Error",
6552 port_num);
6553 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6554 snprintf(evStr, EVENT_DESCR_STR_SZ,
6555 "SAS SMP Error: port=%d : Timeout",
6556 port_num);
6557 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6558 snprintf(evStr, EVENT_DESCR_STR_SZ,
6559 "SAS SMP Error: port=%d : No Destination",
6560 port_num);
6561 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6562 snprintf(evStr, EVENT_DESCR_STR_SZ,
6563 "SAS SMP Error: port=%d : Bad Destination",
6564 port_num);
6565 else
6566 snprintf(evStr, EVENT_DESCR_STR_SZ,
6567 "SAS SMP Error: port=%d : status=0x%02x",
6568 port_num, status);
6569 break;
6570 }
6571
Linus Torvalds1da177e2005-04-16 15:20:36 -07006572 /*
6573 * MPT base "custom" events may be added here...
6574 */
6575 default:
6576 ds = "Unknown";
6577 break;
6578 }
Eric Moore509e5e52006-04-26 13:22:37 -06006579 if (ds)
6580 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581}
6582
6583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006584/**
6585 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586 * @ioc: Pointer to MPT_ADAPTER structure
6587 * @pEventReply: Pointer to EventNotification reply frame
6588 * @evHandlers: Pointer to integer, number of event handlers
6589 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006590 * Routes a received EventNotificationReply to all currently registered
6591 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006592 * Returns sum of event handlers return values.
6593 */
6594static int
6595ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6596{
6597 u16 evDataLen;
6598 u32 evData0 = 0;
6599// u32 evCtx;
6600 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306601 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 int r = 0;
6603 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006604 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605 u8 event;
6606
6607 /*
6608 * Do platform normalization of values
6609 */
6610 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6611// evCtx = le32_to_cpu(pEventReply->EventContext);
6612 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6613 if (evDataLen) {
6614 evData0 = le32_to_cpu(pEventReply->Data[0]);
6615 }
6616
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006617 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306618 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006620 event,
6621 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622
Prakash, Sathya436ace72007-07-24 15:42:08 +05306623#ifdef CONFIG_FUSION_LOGGING
6624 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
6625 ": Event data:\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306627 devtverboseprintk(ioc, printk(" %08x",
6628 le32_to_cpu(pEventReply->Data[ii])));
6629 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630#endif
6631
6632 /*
6633 * Do general / base driver event processing
6634 */
6635 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6637 if (evDataLen) {
6638 u8 evState = evData0 & 0xFF;
6639
6640 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6641
6642 /* Update EventState field in cached IocFacts */
6643 if (ioc->facts.Function) {
6644 ioc->facts.EventState = evState;
6645 }
6646 }
6647 break;
Moore, Ericece50912006-01-16 18:53:19 -07006648 case MPI_EVENT_INTEGRATED_RAID:
6649 mptbase_raid_process_event_data(ioc,
6650 (MpiEventDataRaid_t *)pEventReply->Data);
6651 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006652 default:
6653 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 }
6655
6656 /*
6657 * Should this event be logged? Events are written sequentially.
6658 * When buffer is full, start again at the top.
6659 */
6660 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6661 int idx;
6662
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006663 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
6665 ioc->events[idx].event = event;
6666 ioc->events[idx].eventContext = ioc->eventContext;
6667
6668 for (ii = 0; ii < 2; ii++) {
6669 if (ii < evDataLen)
6670 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6671 else
6672 ioc->events[idx].data[ii] = 0;
6673 }
6674
6675 ioc->eventContext++;
6676 }
6677
6678
6679 /*
6680 * Call each currently registered protocol event handler.
6681 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306682 for (cb_idx=MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6683 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306684 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306685 ioc->name, cb_idx));
6686 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687 handlers++;
6688 }
6689 }
6690 /* FIXME? Examine results here? */
6691
6692 /*
6693 * If needed, send (a single) EventAck.
6694 */
6695 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306696 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006697 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306699 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700 ioc->name, ii));
6701 }
6702 }
6703
6704 *evHandlers = handlers;
6705 return r;
6706}
6707
6708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006709/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6711 * @ioc: Pointer to MPT_ADAPTER structure
6712 * @log_info: U32 LogInfo reply word from the IOC
6713 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006714 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715 */
6716static void
6717mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6718{
Eric Moore7c431e52007-06-13 16:34:36 -06006719 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720
Eric Moore7c431e52007-06-13 16:34:36 -06006721 switch (log_info & 0xFF000000) {
6722 case MPI_IOCLOGINFO_FC_INIT_BASE:
6723 desc = "FCP Initiator";
6724 break;
6725 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6726 desc = "FCP Target";
6727 break;
6728 case MPI_IOCLOGINFO_FC_LAN_BASE:
6729 desc = "LAN";
6730 break;
6731 case MPI_IOCLOGINFO_FC_MSG_BASE:
6732 desc = "MPI Message Layer";
6733 break;
6734 case MPI_IOCLOGINFO_FC_LINK_BASE:
6735 desc = "FC Link";
6736 break;
6737 case MPI_IOCLOGINFO_FC_CTX_BASE:
6738 desc = "Context Manager";
6739 break;
6740 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6741 desc = "Invalid Field Offset";
6742 break;
6743 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6744 desc = "State Change Info";
6745 break;
6746 }
6747
6748 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6749 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750}
6751
6752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006753/**
Moore, Eric335a9412006-01-17 17:06:23 -07006754 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755 * @ioc: Pointer to MPT_ADAPTER structure
6756 * @mr: Pointer to MPT reply frame
6757 * @log_info: U32 LogInfo word from the IOC
6758 *
6759 * Refer to lsi/sp_log.h.
6760 */
6761static void
Moore, Eric335a9412006-01-17 17:06:23 -07006762mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763{
6764 u32 info = log_info & 0x00FF0000;
6765 char *desc = "unknown";
6766
6767 switch (info) {
6768 case 0x00010000:
6769 desc = "bug! MID not found";
6770 if (ioc->reload_fw == 0)
6771 ioc->reload_fw++;
6772 break;
6773
6774 case 0x00020000:
6775 desc = "Parity Error";
6776 break;
6777
6778 case 0x00030000:
6779 desc = "ASYNC Outbound Overrun";
6780 break;
6781
6782 case 0x00040000:
6783 desc = "SYNC Offset Error";
6784 break;
6785
6786 case 0x00050000:
6787 desc = "BM Change";
6788 break;
6789
6790 case 0x00060000:
6791 desc = "Msg In Overflow";
6792 break;
6793
6794 case 0x00070000:
6795 desc = "DMA Error";
6796 break;
6797
6798 case 0x00080000:
6799 desc = "Outbound DMA Overrun";
6800 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006801
Linus Torvalds1da177e2005-04-16 15:20:36 -07006802 case 0x00090000:
6803 desc = "Task Management";
6804 break;
6805
6806 case 0x000A0000:
6807 desc = "Device Problem";
6808 break;
6809
6810 case 0x000B0000:
6811 desc = "Invalid Phase Change";
6812 break;
6813
6814 case 0x000C0000:
6815 desc = "Untagged Table Size";
6816 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006817
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818 }
6819
6820 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6821}
6822
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006823/* strings for sas loginfo */
6824 static char *originator_str[] = {
6825 "IOP", /* 00h */
6826 "PL", /* 01h */
6827 "IR" /* 02h */
6828 };
6829 static char *iop_code_str[] = {
6830 NULL, /* 00h */
6831 "Invalid SAS Address", /* 01h */
6832 NULL, /* 02h */
6833 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006834 "Diag Message Error", /* 04h */
6835 "Task Terminated", /* 05h */
6836 "Enclosure Management", /* 06h */
6837 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006838 };
6839 static char *pl_code_str[] = {
6840 NULL, /* 00h */
6841 "Open Failure", /* 01h */
6842 "Invalid Scatter Gather List", /* 02h */
6843 "Wrong Relative Offset or Frame Length", /* 03h */
6844 "Frame Transfer Error", /* 04h */
6845 "Transmit Frame Connected Low", /* 05h */
6846 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6847 "SATA Read Log Receive Data Error", /* 07h */
6848 "SATA NCQ Fail All Commands After Error", /* 08h */
6849 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6850 "Receive Frame Invalid Message", /* 0Ah */
6851 "Receive Context Message Valid Error", /* 0Bh */
6852 "Receive Frame Current Frame Error", /* 0Ch */
6853 "SATA Link Down", /* 0Dh */
6854 "Discovery SATA Init W IOS", /* 0Eh */
6855 "Config Invalid Page", /* 0Fh */
6856 "Discovery SATA Init Timeout", /* 10h */
6857 "Reset", /* 11h */
6858 "Abort", /* 12h */
6859 "IO Not Yet Executed", /* 13h */
6860 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006861 "Persistent Reservation Out Not Affiliation "
6862 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006863 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006864 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006865 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006866 NULL, /* 19h */
6867 NULL, /* 1Ah */
6868 NULL, /* 1Bh */
6869 NULL, /* 1Ch */
6870 NULL, /* 1Dh */
6871 NULL, /* 1Eh */
6872 NULL, /* 1Fh */
6873 "Enclosure Management" /* 20h */
6874 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006875 static char *ir_code_str[] = {
6876 "Raid Action Error", /* 00h */
6877 NULL, /* 00h */
6878 NULL, /* 01h */
6879 NULL, /* 02h */
6880 NULL, /* 03h */
6881 NULL, /* 04h */
6882 NULL, /* 05h */
6883 NULL, /* 06h */
6884 NULL /* 07h */
6885 };
6886 static char *raid_sub_code_str[] = {
6887 NULL, /* 00h */
6888 "Volume Creation Failed: Data Passed too "
6889 "Large", /* 01h */
6890 "Volume Creation Failed: Duplicate Volumes "
6891 "Attempted", /* 02h */
6892 "Volume Creation Failed: Max Number "
6893 "Supported Volumes Exceeded", /* 03h */
6894 "Volume Creation Failed: DMA Error", /* 04h */
6895 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6896 "Volume Creation Failed: Error Reading "
6897 "MFG Page 4", /* 06h */
6898 "Volume Creation Failed: Creating Internal "
6899 "Structures", /* 07h */
6900 NULL, /* 08h */
6901 NULL, /* 09h */
6902 NULL, /* 0Ah */
6903 NULL, /* 0Bh */
6904 NULL, /* 0Ch */
6905 NULL, /* 0Dh */
6906 NULL, /* 0Eh */
6907 NULL, /* 0Fh */
6908 "Activation failed: Already Active Volume", /* 10h */
6909 "Activation failed: Unsupported Volume Type", /* 11h */
6910 "Activation failed: Too Many Active Volumes", /* 12h */
6911 "Activation failed: Volume ID in Use", /* 13h */
6912 "Activation failed: Reported Failure", /* 14h */
6913 "Activation failed: Importing a Volume", /* 15h */
6914 NULL, /* 16h */
6915 NULL, /* 17h */
6916 NULL, /* 18h */
6917 NULL, /* 19h */
6918 NULL, /* 1Ah */
6919 NULL, /* 1Bh */
6920 NULL, /* 1Ch */
6921 NULL, /* 1Dh */
6922 NULL, /* 1Eh */
6923 NULL, /* 1Fh */
6924 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6925 "Phys Disk failed: Data Passed too Large", /* 21h */
6926 "Phys Disk failed: DMA Error", /* 22h */
6927 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6928 "Phys Disk failed: Creating Phys Disk Config "
6929 "Page", /* 24h */
6930 NULL, /* 25h */
6931 NULL, /* 26h */
6932 NULL, /* 27h */
6933 NULL, /* 28h */
6934 NULL, /* 29h */
6935 NULL, /* 2Ah */
6936 NULL, /* 2Bh */
6937 NULL, /* 2Ch */
6938 NULL, /* 2Dh */
6939 NULL, /* 2Eh */
6940 NULL, /* 2Fh */
6941 "Compatibility Error: IR Disabled", /* 30h */
6942 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6943 "Compatibility Error: Device not Direct Access "
6944 "Device ", /* 32h */
6945 "Compatibility Error: Removable Device Found", /* 33h */
6946 "Compatibility Error: Device SCSI Version not "
6947 "2 or Higher", /* 34h */
6948 "Compatibility Error: SATA Device, 48 BIT LBA "
6949 "not Supported", /* 35h */
6950 "Compatibility Error: Device doesn't have "
6951 "512 Byte Block Sizes", /* 36h */
6952 "Compatibility Error: Volume Type Check Failed", /* 37h */
6953 "Compatibility Error: Volume Type is "
6954 "Unsupported by FW", /* 38h */
6955 "Compatibility Error: Disk Drive too Small for "
6956 "use in Volume", /* 39h */
6957 "Compatibility Error: Phys Disk for Create "
6958 "Volume not Found", /* 3Ah */
6959 "Compatibility Error: Too Many or too Few "
6960 "Disks for Volume Type", /* 3Bh */
6961 "Compatibility Error: Disk stripe Sizes "
6962 "Must be 64KB", /* 3Ch */
6963 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6964 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006965
6966/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006967/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006968 * mpt_sas_log_info - Log information returned from SAS IOC.
6969 * @ioc: Pointer to MPT_ADAPTER structure
6970 * @log_info: U32 LogInfo reply word from the IOC
6971 *
6972 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006973 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006974static void
6975mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6976{
6977union loginfo_type {
6978 u32 loginfo;
6979 struct {
6980 u32 subcode:16;
6981 u32 code:8;
6982 u32 originator:4;
6983 u32 bus_type:4;
6984 }dw;
6985};
6986 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006987 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006988 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006989 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006990
6991 sas_loginfo.loginfo = log_info;
6992 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6993 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6994 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006995
6996 originator_desc = originator_str[sas_loginfo.dw.originator];
6997
6998 switch (sas_loginfo.dw.originator) {
6999
7000 case 0: /* IOP */
7001 if (sas_loginfo.dw.code <
7002 sizeof(iop_code_str)/sizeof(char*))
7003 code_desc = iop_code_str[sas_loginfo.dw.code];
7004 break;
7005 case 1: /* PL */
7006 if (sas_loginfo.dw.code <
7007 sizeof(pl_code_str)/sizeof(char*))
7008 code_desc = pl_code_str[sas_loginfo.dw.code];
7009 break;
7010 case 2: /* IR */
7011 if (sas_loginfo.dw.code >=
7012 sizeof(ir_code_str)/sizeof(char*))
7013 break;
7014 code_desc = ir_code_str[sas_loginfo.dw.code];
7015 if (sas_loginfo.dw.subcode >=
7016 sizeof(raid_sub_code_str)/sizeof(char*))
7017 break;
7018 if (sas_loginfo.dw.code == 0)
7019 sub_code_desc =
7020 raid_sub_code_str[sas_loginfo.dw.subcode];
7021 break;
7022 default:
7023 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007024 }
7025
Eric Moorec6c727a2007-01-29 09:44:54 -07007026 if (sub_code_desc != NULL)
7027 printk(MYIOC_s_INFO_FMT
7028 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7029 " SubCode={%s}\n",
7030 ioc->name, log_info, originator_desc, code_desc,
7031 sub_code_desc);
7032 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007033 printk(MYIOC_s_INFO_FMT
7034 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7035 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007036 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007037 sas_loginfo.dw.subcode);
7038 else
7039 printk(MYIOC_s_INFO_FMT
7040 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7041 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007042 ioc->name, log_info, originator_desc,
7043 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007044}
7045
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007047/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007048 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7049 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007050 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007051 * @mf: Pointer to MPT request frame
7052 *
7053 * Refer to lsi/mpi.h.
7054 **/
7055static void
7056mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7057{
7058 Config_t *pReq = (Config_t *)mf;
7059 char extend_desc[EVENT_DESCR_STR_SZ];
7060 char *desc = NULL;
7061 u32 form;
7062 u8 page_type;
7063
7064 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7065 page_type = pReq->ExtPageType;
7066 else
7067 page_type = pReq->Header.PageType;
7068
7069 /*
7070 * ignore invalid page messages for GET_NEXT_HANDLE
7071 */
7072 form = le32_to_cpu(pReq->PageAddress);
7073 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7074 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7075 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7076 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7077 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7078 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7079 return;
7080 }
7081 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7082 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7083 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7084 return;
7085 }
7086
7087 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7088 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7089 page_type, pReq->Header.PageNumber, pReq->Action, form);
7090
7091 switch (ioc_status) {
7092
7093 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7094 desc = "Config Page Invalid Action";
7095 break;
7096
7097 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7098 desc = "Config Page Invalid Type";
7099 break;
7100
7101 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7102 desc = "Config Page Invalid Page";
7103 break;
7104
7105 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7106 desc = "Config Page Invalid Data";
7107 break;
7108
7109 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7110 desc = "Config Page No Defaults";
7111 break;
7112
7113 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7114 desc = "Config Page Can't Commit";
7115 break;
7116 }
7117
7118 if (!desc)
7119 return;
7120
7121 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
7122 ioc->name, ioc_status, desc, extend_desc);
7123}
7124
7125/**
7126 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127 * @ioc: Pointer to MPT_ADAPTER structure
7128 * @ioc_status: U32 IOCStatus word from IOC
7129 * @mf: Pointer to MPT request frame
7130 *
7131 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007132 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007134mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135{
7136 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007137 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
7139 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007140
7141/****************************************************************************/
7142/* Common IOCStatus values for all replies */
7143/****************************************************************************/
7144
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7146 desc = "Invalid Function";
7147 break;
7148
7149 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7150 desc = "Busy";
7151 break;
7152
7153 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7154 desc = "Invalid SGL";
7155 break;
7156
7157 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7158 desc = "Internal Error";
7159 break;
7160
7161 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7162 desc = "Reserved";
7163 break;
7164
7165 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7166 desc = "Insufficient Resources";
7167 break;
7168
7169 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7170 desc = "Invalid Field";
7171 break;
7172
7173 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7174 desc = "Invalid State";
7175 break;
7176
Eric Moorec6c727a2007-01-29 09:44:54 -07007177/****************************************************************************/
7178/* Config IOCStatus values */
7179/****************************************************************************/
7180
Linus Torvalds1da177e2005-04-16 15:20:36 -07007181 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7182 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7183 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7184 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7185 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7186 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007187 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 break;
7189
Eric Moorec6c727a2007-01-29 09:44:54 -07007190/****************************************************************************/
7191/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7192/* */
7193/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7194/* */
7195/****************************************************************************/
7196
Linus Torvalds1da177e2005-04-16 15:20:36 -07007197 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007199 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7200 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7201 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7202 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007206 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007209 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210 break;
7211
Eric Moorec6c727a2007-01-29 09:44:54 -07007212/****************************************************************************/
7213/* SCSI Target values */
7214/****************************************************************************/
7215
7216 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7217 desc = "Target: Priority IO";
7218 break;
7219
7220 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7221 desc = "Target: Invalid Port";
7222 break;
7223
7224 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7225 desc = "Target Invalid IO Index:";
7226 break;
7227
7228 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7229 desc = "Target: Aborted";
7230 break;
7231
7232 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7233 desc = "Target: No Conn Retryable";
7234 break;
7235
7236 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7237 desc = "Target: No Connection";
7238 break;
7239
7240 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7241 desc = "Target: Transfer Count Mismatch";
7242 break;
7243
7244 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7245 desc = "Target: STS Data not Sent";
7246 break;
7247
7248 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7249 desc = "Target: Data Offset Error";
7250 break;
7251
7252 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7253 desc = "Target: Too Much Write Data";
7254 break;
7255
7256 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7257 desc = "Target: IU Too Short";
7258 break;
7259
7260 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7261 desc = "Target: ACK NAK Timeout";
7262 break;
7263
7264 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7265 desc = "Target: Nak Received";
7266 break;
7267
7268/****************************************************************************/
7269/* Fibre Channel Direct Access values */
7270/****************************************************************************/
7271
7272 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7273 desc = "FC: Aborted";
7274 break;
7275
7276 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7277 desc = "FC: RX ID Invalid";
7278 break;
7279
7280 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7281 desc = "FC: DID Invalid";
7282 break;
7283
7284 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7285 desc = "FC: Node Logged Out";
7286 break;
7287
7288 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7289 desc = "FC: Exchange Canceled";
7290 break;
7291
7292/****************************************************************************/
7293/* LAN values */
7294/****************************************************************************/
7295
7296 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7297 desc = "LAN: Device not Found";
7298 break;
7299
7300 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7301 desc = "LAN: Device Failure";
7302 break;
7303
7304 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7305 desc = "LAN: Transmit Error";
7306 break;
7307
7308 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7309 desc = "LAN: Transmit Aborted";
7310 break;
7311
7312 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7313 desc = "LAN: Receive Error";
7314 break;
7315
7316 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7317 desc = "LAN: Receive Aborted";
7318 break;
7319
7320 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7321 desc = "LAN: Partial Packet";
7322 break;
7323
7324 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7325 desc = "LAN: Canceled";
7326 break;
7327
7328/****************************************************************************/
7329/* Serial Attached SCSI values */
7330/****************************************************************************/
7331
7332 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7333 desc = "SAS: SMP Request Failed";
7334 break;
7335
7336 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7337 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007338 break;
7339
7340 default:
7341 desc = "Others";
7342 break;
7343 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007344
7345 if (!desc)
7346 return;
7347
7348 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349}
7350
7351/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007352EXPORT_SYMBOL(mpt_attach);
7353EXPORT_SYMBOL(mpt_detach);
7354#ifdef CONFIG_PM
7355EXPORT_SYMBOL(mpt_resume);
7356EXPORT_SYMBOL(mpt_suspend);
7357#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007358EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007359EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007360EXPORT_SYMBOL(mpt_register);
7361EXPORT_SYMBOL(mpt_deregister);
7362EXPORT_SYMBOL(mpt_event_register);
7363EXPORT_SYMBOL(mpt_event_deregister);
7364EXPORT_SYMBOL(mpt_reset_register);
7365EXPORT_SYMBOL(mpt_reset_deregister);
7366EXPORT_SYMBOL(mpt_device_driver_register);
7367EXPORT_SYMBOL(mpt_device_driver_deregister);
7368EXPORT_SYMBOL(mpt_get_msg_frame);
7369EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307370EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371EXPORT_SYMBOL(mpt_free_msg_frame);
7372EXPORT_SYMBOL(mpt_add_sge);
7373EXPORT_SYMBOL(mpt_send_handshake_request);
7374EXPORT_SYMBOL(mpt_verify_adapter);
7375EXPORT_SYMBOL(mpt_GetIocState);
7376EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377EXPORT_SYMBOL(mpt_HardResetHandler);
7378EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380EXPORT_SYMBOL(mpt_alloc_fw_memory);
7381EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007382EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007383EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007386/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387 * fusion_init - Fusion MPT base driver initialization routine.
7388 *
7389 * Returns 0 for success, non-zero for failure.
7390 */
7391static int __init
7392fusion_init(void)
7393{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307394 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007395
7396 show_mptmod_ver(my_NAME, my_VERSION);
7397 printk(KERN_INFO COPYRIGHT "\n");
7398
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307399 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7400 MptCallbacks[cb_idx] = NULL;
7401 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7402 MptEvHandlers[cb_idx] = NULL;
7403 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404 }
7405
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007406 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007407 * EventNotification handling.
7408 */
7409 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7410
7411 /* Register for hard reset handling callbacks.
7412 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307413 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414
7415#ifdef CONFIG_PROC_FS
7416 (void) procmpt_create();
7417#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007418 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007419}
7420
7421/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007422/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007423 * fusion_exit - Perform driver unload cleanup.
7424 *
7425 * This routine frees all resources associated with each MPT adapter
7426 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7427 */
7428static void __exit
7429fusion_exit(void)
7430{
7431
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432 mpt_reset_deregister(mpt_base_index);
7433
7434#ifdef CONFIG_PROC_FS
7435 procmpt_destroy();
7436#endif
7437}
7438
Linus Torvalds1da177e2005-04-16 15:20:36 -07007439module_init(fusion_init);
7440module_exit(fusion_exit);