blob: 635defd25925264bbcc4e76cd1b1475480e7fa09 [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 if (mpt_debug_level)
1462 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1463
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if (pci_enable_device(pdev))
1465 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001466
Jesper Juhl56876192007-08-10 14:50:51 -07001467 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1468 if (ioc == NULL) {
1469 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1470 return -ENOMEM;
1471 }
1472 ioc->debug_level = mpt_debug_level;
1473
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");
Jesper Juhl56876192007-08-10 14:50:51 -07001481 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 return r;
1483 }
1484
Prakash, Sathya436ace72007-07-24 15:42:08 +05301485 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1486 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 ": Using 64 bit consistent mask\n"));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301488 } else {
1489 dprintk(ioc, printk(KERN_INFO MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 ": Not using 64 bit consistent mask\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301492
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 ioc->alloc_total = sizeof(MPT_ADAPTER);
1494 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1495 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 ioc->pcidev = pdev;
1498 ioc->diagPending = 0;
1499 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001500 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 /* Initialize the event logging.
1503 */
1504 ioc->eventTypes = 0; /* None */
1505 ioc->eventContext = 0;
1506 ioc->eventLogSize = 0;
1507 ioc->events = NULL;
1508
1509#ifdef MFCNT
1510 ioc->mfcnt = 0;
1511#endif
1512
1513 ioc->cached_fw = NULL;
1514
1515 /* Initilize SCSI Config Data structure
1516 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001517 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
1519 /* Initialize the running configQ head.
1520 */
1521 INIT_LIST_HEAD(&ioc->configQ);
1522
Michael Reed05e8ec12006-01-13 14:31:54 -06001523 /* Initialize the fc rport list head.
1524 */
1525 INIT_LIST_HEAD(&ioc->fc_rports);
1526
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* Find lookup slot. */
1528 INIT_LIST_HEAD(&ioc->list);
1529 ioc->id = mpt_ids++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 mem_phys = msize = 0;
1532 port = psize = 0;
1533 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1534 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001535 if (psize)
1536 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /* Get I/O space! */
1538 port = pci_resource_start(pdev, ii);
1539 psize = pci_resource_len(pdev,ii);
1540 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001541 if (msize)
1542 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 /* Get memmap */
1544 mem_phys = pci_resource_start(pdev, ii);
1545 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547 }
1548 ioc->mem_size = msize;
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 mem = NULL;
1551 /* Get logical ptr for PciMem0 space */
1552 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001553 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 if (mem == NULL) {
1555 printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
1556 kfree(ioc);
1557 return -EINVAL;
1558 }
1559 ioc->memmap = mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301560 dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
Prakash, Sathya436ace72007-07-24 15:42:08 +05301562 dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 &ioc->facts, &ioc->pfacts[0]));
1564
1565 ioc->mem_phys = mem_phys;
1566 ioc->chip = (SYSIF_REGS __iomem *)mem;
1567
1568 /* Save Port IO values in case we need to do downloadboot */
1569 {
1570 u8 *pmem = (u8*)port;
1571 ioc->pio_mem_phys = port;
1572 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1573 }
1574
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301575 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1576 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1577
1578 switch (pdev->device)
1579 {
1580 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1581 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1582 ioc->errata_flag_1064 = 1;
1583 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1584 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1585 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1586 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301588 break;
1589
1590 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 /* 929X Chip Fix. Set Split transactions level
1593 * for PCIX. Set MOST bits to zero.
1594 */
1595 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1596 pcixcmd &= 0x8F;
1597 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1598 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 /* 929XL Chip Fix. Set MMRBC to 0x08.
1600 */
1601 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1602 pcixcmd |= 0x08;
1603 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301606 break;
1607
1608 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 /* 919X Chip Fix. Set Split transactions level
1610 * for PCIX. Set MOST bits to zero.
1611 */
1612 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1613 pcixcmd &= 0x8F;
1614 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001615 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301616 break;
1617
1618 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 /* 1030 Chip Fix. Disable Split transactions
1620 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1621 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (revision < C0_1030) {
1623 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1624 pcixcmd &= 0x8F;
1625 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1626 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301627
1628 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001629 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301630 break;
1631
1632 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1633 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001634 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301635
1636 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1637 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1638 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001639 ioc->bus_type = SAS;
1640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001642 if (ioc->errata_flag_1064)
1643 pci_disable_io_access(pdev);
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 sprintf(ioc->name, "ioc%d", ioc->id);
1646
1647 spin_lock_init(&ioc->FreeQlock);
1648
1649 /* Disable all! */
1650 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1651 ioc->active = 0;
1652 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1653
1654 /* Set lookup ptr. */
1655 list_add_tail(&ioc->list, &ioc_list);
1656
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001657 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 */
1659 mpt_detect_bound_ports(ioc, pdev);
1660
James Bottomleyc92f2222006-03-01 09:02:49 -06001661 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1662 CAN_SLEEP)) != 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 printk(KERN_WARNING MYNAM
1664 ": WARNING - %s did not initialize properly! (%d)\n",
1665 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001666
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001668 if (ioc->alt_ioc)
1669 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 iounmap(mem);
1671 kfree(ioc);
1672 pci_set_drvdata(pdev, NULL);
1673 return r;
1674 }
1675
1676 /* call per device driver probe entry point */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301677 for(cb_idx=0; cb_idx<MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
1678 if(MptDeviceDriverHandlers[cb_idx] &&
1679 MptDeviceDriverHandlers[cb_idx]->probe) {
1680 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
1682 }
1683
1684#ifdef CONFIG_PROC_FS
1685 /*
1686 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1687 */
1688 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1689 if (dent) {
1690 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1691 if (ent) {
1692 ent->read_proc = procmpt_iocinfo_read;
1693 ent->data = ioc;
1694 }
1695 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1696 if (ent) {
1697 ent->read_proc = procmpt_summary_read;
1698 ent->data = ioc;
1699 }
1700 }
1701#endif
1702
1703 return 0;
1704}
1705
1706/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001707/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001708 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 */
1711
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001712void
1713mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1716 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301717 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1720 remove_proc_entry(pname, NULL);
1721 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1722 remove_proc_entry(pname, NULL);
1723 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1724 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 /* call per device driver remove entry point */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301727 for(cb_idx=0; cb_idx<MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
1728 if(MptDeviceDriverHandlers[cb_idx] &&
1729 MptDeviceDriverHandlers[cb_idx]->remove) {
1730 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
1732 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001733
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* Disable interrupts! */
1735 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1736
1737 ioc->active = 0;
1738 synchronize_irq(pdev->irq);
1739
1740 /* Clear any lingering interrupt */
1741 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1742
1743 CHIPREG_READ32(&ioc->chip->IntStatus);
1744
1745 mpt_adapter_dispose(ioc);
1746
1747 pci_set_drvdata(pdev, NULL);
1748}
1749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750/**************************************************************************
1751 * Power Management
1752 */
1753#ifdef CONFIG_PM
1754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001755/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001756 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001757 * @pdev: Pointer to pci_dev structure
1758 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001760int
1761mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
1763 u32 device_state;
1764 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Pavel Machek2a569572005-07-07 17:56:40 -07001766 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 printk(MYIOC_s_INFO_FMT
1769 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1770 ioc->name, pdev, pci_name(pdev), device_state);
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 pci_save_state(pdev);
1773
1774 /* put ioc into READY_STATE */
1775 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1776 printk(MYIOC_s_ERR_FMT
1777 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1778 }
1779
1780 /* disable interrupts */
1781 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1782 ioc->active = 0;
1783
1784 /* Clear any lingering interrupt */
1785 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1786
1787 pci_disable_device(pdev);
1788 pci_set_power_state(pdev, device_state);
1789
1790 return 0;
1791}
1792
1793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001794/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001795 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001796 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001798int
1799mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800{
1801 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1802 u32 device_state = pdev->current_state;
1803 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001804 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 printk(MYIOC_s_INFO_FMT
1807 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1808 ioc->name, pdev, pci_name(pdev), device_state);
1809
1810 pci_set_power_state(pdev, 0);
1811 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001812 err = pci_enable_device(pdev);
1813 if (err)
1814 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001817 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 ioc->active = 1;
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 printk(MYIOC_s_INFO_FMT
1821 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1822 ioc->name,
1823 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1824 CHIPREG_READ32(&ioc->chip->Doorbell));
1825
1826 /* bring ioc to operational state */
1827 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1828 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1829 printk(MYIOC_s_INFO_FMT
1830 "pci-resume: Cannot recover, error:[%x]\n",
1831 ioc->name, recovery_state);
1832 } else {
1833 printk(MYIOC_s_INFO_FMT
1834 "pci-resume: success\n", ioc->name);
1835 }
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 return 0;
1838}
1839#endif
1840
James Bottomley4ff42a62006-05-17 18:06:52 -05001841static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301842mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001843{
1844 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1845 ioc->bus_type != SPI) ||
1846 (MptDriverClass[index] == MPTFC_DRIVER &&
1847 ioc->bus_type != FC) ||
1848 (MptDriverClass[index] == MPTSAS_DRIVER &&
1849 ioc->bus_type != SAS))
1850 /* make sure we only call the relevant reset handler
1851 * for the bus */
1852 return 0;
1853 return (MptResetHandlers[index])(ioc, reset_phase);
1854}
1855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001857/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1859 * @ioc: Pointer to MPT adapter structure
1860 * @reason: Event word / reason
1861 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1862 *
1863 * This routine performs all the steps necessary to bring the IOC
1864 * to a OPERATIONAL state.
1865 *
1866 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1867 * MPT adapter.
1868 *
1869 * Returns:
1870 * 0 for success
1871 * -1 if failed to get board READY
1872 * -2 if READY but IOCFacts Failed
1873 * -3 if READY but PrimeIOCFifos Failed
1874 * -4 if READY but IOCInit Failed
1875 */
1876static int
1877mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1878{
1879 int hard_reset_done = 0;
1880 int alt_ioc_ready = 0;
1881 int hard;
1882 int rc=0;
1883 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301884 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 int handlers;
1886 int ret = 0;
1887 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001888 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301889 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 printk(KERN_INFO MYNAM ": Initiating %s %s\n",
1892 ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
1893
1894 /* Disable reply interrupts (also blocks FreeQ) */
1895 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1896 ioc->active = 0;
1897
1898 if (ioc->alt_ioc) {
1899 if (ioc->alt_ioc->active)
1900 reset_alt_ioc_active = 1;
1901
1902 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1903 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1904 ioc->alt_ioc->active = 0;
1905 }
1906
1907 hard = 1;
1908 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1909 hard = 0;
1910
1911 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1912 if (hard_reset_done == -4) {
1913 printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
1914 ioc->name);
1915
1916 if (reset_alt_ioc_active && ioc->alt_ioc) {
1917 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05301918 dprintk(ioc, printk(KERN_INFO MYNAM
1919 ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001921 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 ioc->alt_ioc->active = 1;
1923 }
1924
1925 } else {
1926 printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
1927 ioc->name);
1928 }
1929 return -1;
1930 }
1931
1932 /* hard_reset_done = 0 if a soft reset was performed
1933 * and 1 if a hard reset was performed.
1934 */
1935 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1936 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1937 alt_ioc_ready = 1;
1938 else
1939 printk(KERN_WARNING MYNAM
1940 ": alt-%s: Not ready WARNING!\n",
1941 ioc->alt_ioc->name);
1942 }
1943
1944 for (ii=0; ii<5; ii++) {
1945 /* Get IOC facts! Allow 5 retries */
1946 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1947 break;
1948 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
1951 if (ii == 5) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301952 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 ret = -2;
1954 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1955 MptDisplayIocCapabilities(ioc);
1956 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (alt_ioc_ready) {
1959 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301960 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1961 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 /* Retry - alt IOC was initialized once
1963 */
1964 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1965 }
1966 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301967 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1968 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 alt_ioc_ready = 0;
1970 reset_alt_ioc_active = 0;
1971 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1972 MptDisplayIocCapabilities(ioc->alt_ioc);
1973 }
1974 }
1975
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001976 /*
1977 * Device is reset now. It must have de-asserted the interrupt line
1978 * (if it was asserted) and it should be safe to register for the
1979 * interrupt now.
1980 */
1981 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1982 ioc->pci_irq = -1;
1983 if (ioc->pcidev->irq) {
1984 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1985 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
1986 ioc->name);
1987 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001988 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001989 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001990 printk(MYIOC_s_ERR_FMT "Unable to allocate "
1991 "interrupt %d!\n", ioc->name,
1992 ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001993 if (mpt_msi_enable)
1994 pci_disable_msi(ioc->pcidev);
1995 return -EBUSY;
1996 }
1997 irq_allocated = 1;
1998 ioc->pci_irq = ioc->pcidev->irq;
1999 pci_set_master(ioc->pcidev); /* ?? */
2000 pci_set_drvdata(ioc->pcidev, ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302001 dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002002 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002003 }
2004 }
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 /* Prime reply & request queues!
2007 * (mucho alloc's) Must be done prior to
2008 * init as upper addresses are needed for init.
2009 * If fails, continue with alt-ioc processing
2010 */
2011 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2012 ret = -3;
2013
2014 /* May need to check/upload firmware & data here!
2015 * If fails, continue with alt-ioc processing
2016 */
2017 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2018 ret = -4;
2019// NEW!
2020 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
2021 printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
2022 ioc->alt_ioc->name, rc);
2023 alt_ioc_ready = 0;
2024 reset_alt_ioc_active = 0;
2025 }
2026
2027 if (alt_ioc_ready) {
2028 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2029 alt_ioc_ready = 0;
2030 reset_alt_ioc_active = 0;
2031 printk(KERN_WARNING MYNAM
2032 ": alt-%s: (%d) init failure WARNING!\n",
2033 ioc->alt_ioc->name, rc);
2034 }
2035 }
2036
2037 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2038 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302039 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 "firmware upload required!\n", ioc->name));
2041
2042 /* Controller is not operational, cannot do upload
2043 */
2044 if (ret == 0) {
2045 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002046 if (rc == 0) {
2047 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2048 /*
2049 * Maintain only one pointer to FW memory
2050 * so there will not be two attempt to
2051 * downloadboot onboard dual function
2052 * chips (mpt_adapter_disable,
2053 * mpt_diag_reset)
2054 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302055 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2056 ": mpt_upload: alt_%s has cached_fw=%p \n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002057 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002058 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002059 }
2060 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002062 ret = -5;
2063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
2065 }
2066 }
2067
2068 if (ret == 0) {
2069 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002070 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 ioc->active = 1;
2072 }
2073
2074 if (reset_alt_ioc_active && ioc->alt_ioc) {
2075 /* (re)Enable alt-IOC! (reply interrupt) */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302076 dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002078 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 ioc->alt_ioc->active = 1;
2080 }
2081
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002082 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 * and EventAck handling.
2084 */
2085 if ((ret == 0) && (!ioc->facts.EventState))
2086 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2087
2088 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2089 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2090
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002091 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2093 * recursive scenario; GetLanConfigPages times out, timer expired
2094 * routine calls HardResetHandler, which calls into here again,
2095 * and we try GetLanConfigPages again...
2096 */
2097 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002098
2099 /*
2100 * Initalize link list for inactive raid volumes.
2101 */
2102 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2103 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2104
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002105 if (ioc->bus_type == SAS) {
2106
2107 /* clear persistency table */
2108 if(ioc->facts.IOCExceptions &
2109 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2110 ret = mptbase_sas_persist_operation(ioc,
2111 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2112 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002113 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002114 }
2115
2116 /* Find IM volumes
2117 */
2118 mpt_findImVolumes(ioc);
2119
2120 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2122 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2123 /*
2124 * Pre-fetch the ports LAN MAC address!
2125 * (LANPage1_t stuff)
2126 */
2127 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302128 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2129 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2130 "LanAddr = %02X:%02X:%02X:"
2131 "%02X:%02X:%02X\n",
2132 ioc->name, a[5], a[4],
2133 a[3], a[2], a[1], a[0] ));
2134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 }
2136 } else {
2137 /* Get NVRAM and adapter maximums from SPP 0 and 2
2138 */
2139 mpt_GetScsiPortSettings(ioc, 0);
2140
2141 /* Get version and length of SDP 1
2142 */
2143 mpt_readScsiDevicePageHeaders(ioc, 0);
2144
2145 /* Find IM volumes
2146 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002147 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 mpt_findImVolumes(ioc);
2149
2150 /* Check, and possibly reset, the coalescing value
2151 */
2152 mpt_read_ioc_pg_1(ioc);
2153
2154 mpt_read_ioc_pg_4(ioc);
2155 }
2156
2157 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302158 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160
2161 /*
2162 * Call each currently registered protocol IOC reset handler
2163 * with post-reset indication.
2164 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2165 * MptResetHandlers[] registered yet.
2166 */
2167 if (hard_reset_done) {
2168 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302169 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2170 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2172 "Calling IOC post_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302173 ioc->name, cb_idx));
2174 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 handlers++;
2176 }
2177
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302178 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302179 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2180 "Calling alt-%s post_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302181 ioc->name, ioc->alt_ioc->name, cb_idx));
2182 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 handlers++;
2184 }
2185 }
2186 /* FIXME? Examine results here? */
2187 }
2188
Eric Moore0ccdb002006-07-11 17:33:13 -06002189 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002190 if ((ret != 0) && irq_allocated) {
2191 free_irq(ioc->pci_irq, ioc);
2192 if (mpt_msi_enable)
2193 pci_disable_msi(ioc->pcidev);
2194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 return ret;
2196}
2197
2198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002199/**
2200 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 * @ioc: Pointer to MPT adapter structure
2202 * @pdev: Pointer to (struct pci_dev) structure
2203 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002204 * Search for PCI bus/dev_function which matches
2205 * PCI bus/dev_function (+/-1) for newly discovered 929,
2206 * 929X, 1030 or 1035.
2207 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2209 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2210 */
2211static void
2212mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2213{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002214 struct pci_dev *peer=NULL;
2215 unsigned int slot = PCI_SLOT(pdev->devfn);
2216 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 MPT_ADAPTER *ioc_srch;
2218
Prakash, Sathya436ace72007-07-24 15:42:08 +05302219 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002220 " searching for devfn match on %x or %x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002221 ioc->name, pci_name(pdev), pdev->bus->number,
2222 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002223
2224 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2225 if (!peer) {
2226 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2227 if (!peer)
2228 return;
2229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 list_for_each_entry(ioc_srch, &ioc_list, list) {
2232 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002233 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 /* Paranoia checks */
2235 if (ioc->alt_ioc != NULL) {
2236 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002237 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 break;
2239 } else if (ioc_srch->alt_ioc != NULL) {
2240 printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002241 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 break;
2243 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302244 dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002245 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ioc_srch->alt_ioc = ioc;
2247 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002250 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251}
2252
2253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002254/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002256 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 */
2258static void
2259mpt_adapter_disable(MPT_ADAPTER *ioc)
2260{
2261 int sz;
2262 int ret;
2263
2264 if (ioc->cached_fw != NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302265 ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002266 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 printk(KERN_WARNING MYNAM
2268 ": firmware downloadboot failure (%d)!\n", ret);
2269 }
2270 }
2271
2272 /* Disable adapter interrupts! */
2273 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2274 ioc->active = 0;
2275 /* Clear any lingering interrupt */
2276 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2277
2278 if (ioc->alloc != NULL) {
2279 sz = ioc->alloc_sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302280 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 ioc->name, ioc->alloc, ioc->alloc_sz));
2282 pci_free_consistent(ioc->pcidev, sz,
2283 ioc->alloc, ioc->alloc_dma);
2284 ioc->reply_frames = NULL;
2285 ioc->req_frames = NULL;
2286 ioc->alloc = NULL;
2287 ioc->alloc_total -= sz;
2288 }
2289
2290 if (ioc->sense_buf_pool != NULL) {
2291 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2292 pci_free_consistent(ioc->pcidev, sz,
2293 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2294 ioc->sense_buf_pool = NULL;
2295 ioc->alloc_total -= sz;
2296 }
2297
2298 if (ioc->events != NULL){
2299 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2300 kfree(ioc->events);
2301 ioc->events = NULL;
2302 ioc->alloc_total -= sz;
2303 }
2304
2305 if (ioc->cached_fw != NULL) {
2306 sz = ioc->facts.FWImageSize;
2307 pci_free_consistent(ioc->pcidev, sz,
2308 ioc->cached_fw, ioc->cached_fw_dma);
2309 ioc->cached_fw = NULL;
2310 ioc->alloc_total -= sz;
2311 }
2312
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002313 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002314 mpt_inactive_raid_list_free(ioc);
2315 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002316 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002317 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002318 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
2320 if (ioc->spi_data.pIocPg4 != NULL) {
2321 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302322 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 ioc->spi_data.pIocPg4,
2324 ioc->spi_data.IocPg4_dma);
2325 ioc->spi_data.pIocPg4 = NULL;
2326 ioc->alloc_total -= sz;
2327 }
2328
2329 if (ioc->ReqToChain != NULL) {
2330 kfree(ioc->ReqToChain);
2331 kfree(ioc->RequestNB);
2332 ioc->ReqToChain = NULL;
2333 }
2334
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002335 kfree(ioc->ChainToChain);
2336 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002337
2338 if (ioc->HostPageBuffer != NULL) {
2339 if((ret = mpt_host_page_access_control(ioc,
2340 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
2341 printk(KERN_ERR MYNAM
2342 ": %s: host page buffers free failed (%d)!\n",
2343 __FUNCTION__, ret);
2344 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302345 dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002346 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2347 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
2348 ioc->HostPageBuffer,
2349 ioc->HostPageBuffer_dma);
2350 ioc->HostPageBuffer = NULL;
2351 ioc->HostPageBuffer_sz = 0;
2352 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354}
2355
2356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002357/**
2358 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 * @ioc: Pointer to MPT adapter structure
2360 *
2361 * This routine unregisters h/w resources and frees all alloc'd memory
2362 * associated with a MPT adapter structure.
2363 */
2364static void
2365mpt_adapter_dispose(MPT_ADAPTER *ioc)
2366{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002367 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002369 if (ioc == NULL)
2370 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002374 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002376 if (ioc->pci_irq != -1) {
2377 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002378 if (mpt_msi_enable)
2379 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002380 ioc->pci_irq = -1;
2381 }
2382
2383 if (ioc->memmap != NULL) {
2384 iounmap(ioc->memmap);
2385 ioc->memmap = NULL;
2386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002389 if (ioc->mtrr_reg > 0) {
2390 mtrr_del(ioc->mtrr_reg, 0, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302391 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393#endif
2394
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002395 /* Zap the adapter lookup ptr! */
2396 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002398 sz_last = ioc->alloc_total;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302399 dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002400 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002401
2402 if (ioc->alt_ioc)
2403 ioc->alt_ioc->alt_ioc = NULL;
2404
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002405 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406}
2407
2408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002409/**
2410 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 * @ioc: Pointer to MPT adapter structure
2412 */
2413static void
2414MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2415{
2416 int i = 0;
2417
2418 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302419 if (ioc->prod_name)
2420 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 printk("Capabilities={");
2422
2423 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2424 printk("Initiator");
2425 i++;
2426 }
2427
2428 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2429 printk("%sTarget", i ? "," : "");
2430 i++;
2431 }
2432
2433 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2434 printk("%sLAN", i ? "," : "");
2435 i++;
2436 }
2437
2438#if 0
2439 /*
2440 * This would probably evoke more questions than it's worth
2441 */
2442 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2443 printk("%sLogBusAddr", i ? "," : "");
2444 i++;
2445 }
2446#endif
2447
2448 printk("}\n");
2449}
2450
2451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002452/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2454 * @ioc: Pointer to MPT_ADAPTER structure
2455 * @force: Force hard KickStart of IOC
2456 * @sleepFlag: Specifies whether the process can sleep
2457 *
2458 * Returns:
2459 * 1 - DIAG reset and READY
2460 * 0 - READY initially OR soft reset and READY
2461 * -1 - Any failure on KickStart
2462 * -2 - Msg Unit Reset Failed
2463 * -3 - IO Unit Reset Failed
2464 * -4 - IOC owned by a PEER
2465 */
2466static int
2467MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2468{
2469 u32 ioc_state;
2470 int statefault = 0;
2471 int cntdn;
2472 int hard_reset_done = 0;
2473 int r;
2474 int ii;
2475 int whoinit;
2476
2477 /* Get current [raw] IOC state */
2478 ioc_state = mpt_GetIocState(ioc, 0);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302479 dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
2481 /*
2482 * Check to see if IOC got left/stuck in doorbell handshake
2483 * grip of death. If so, hard reset the IOC.
2484 */
2485 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2486 statefault = 1;
2487 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2488 ioc->name);
2489 }
2490
2491 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002492 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 return 0;
2494
2495 /*
2496 * Check to see if IOC is in FAULT state.
2497 */
2498 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2499 statefault = 2;
2500 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
2501 ioc->name);
2502 printk(KERN_WARNING " FAULT code = %04xh\n",
2503 ioc_state & MPI_DOORBELL_DATA_MASK);
2504 }
2505
2506 /*
2507 * Hmmm... Did it get left operational?
2508 */
2509 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302510 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 ioc->name));
2512
2513 /* Check WhoInit.
2514 * If PCI Peer, exit.
2515 * Else, if no fault conditions are present, issue a MessageUnitReset
2516 * Else, fall through to KickStart case
2517 */
2518 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302519 dinitprintk(ioc, printk(KERN_INFO MYNAM
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002520 ": whoinit 0x%x statefault %d force %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 whoinit, statefault, force));
2522 if (whoinit == MPI_WHOINIT_PCI_PEER)
2523 return -4;
2524 else {
2525 if ((statefault == 0 ) && (force == 0)) {
2526 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2527 return 0;
2528 }
2529 statefault = 3;
2530 }
2531 }
2532
2533 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2534 if (hard_reset_done < 0)
2535 return -1;
2536
2537 /*
2538 * Loop here waiting for IOC to come READY.
2539 */
2540 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002541 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2544 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2545 /*
2546 * BIOS or previous driver load left IOC in OP state.
2547 * Reset messaging FIFOs.
2548 */
2549 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2550 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2551 return -2;
2552 }
2553 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2554 /*
2555 * Something is wrong. Try to get IOC back
2556 * to a known state.
2557 */
2558 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2559 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2560 return -3;
2561 }
2562 }
2563
2564 ii++; cntdn--;
2565 if (!cntdn) {
2566 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2567 ioc->name, (int)((ii+5)/HZ));
2568 return -ETIME;
2569 }
2570
2571 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002572 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 } else {
2574 mdelay (1); /* 1 msec delay */
2575 }
2576
2577 }
2578
2579 if (statefault < 3) {
2580 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2581 ioc->name,
2582 statefault==1 ? "stuck handshake" : "IOC FAULT");
2583 }
2584
2585 return hard_reset_done;
2586}
2587
2588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002589/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 * mpt_GetIocState - Get the current state of a MPT adapter.
2591 * @ioc: Pointer to MPT_ADAPTER structure
2592 * @cooked: Request raw or cooked IOC state
2593 *
2594 * Returns all IOC Doorbell register bits if cooked==0, else just the
2595 * Doorbell bits in MPI_IOC_STATE_MASK.
2596 */
2597u32
2598mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2599{
2600 u32 s, sc;
2601
2602 /* Get! */
2603 s = CHIPREG_READ32(&ioc->chip->Doorbell);
2604// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
2605 sc = s & MPI_IOC_STATE_MASK;
2606
2607 /* Save! */
2608 ioc->last_state = sc;
2609
2610 return cooked ? sc : s;
2611}
2612
2613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002614/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 * GetIocFacts - Send IOCFacts request to MPT adapter.
2616 * @ioc: Pointer to MPT_ADAPTER structure
2617 * @sleepFlag: Specifies whether the process can sleep
2618 * @reason: If recovery, only update facts.
2619 *
2620 * Returns 0 for success, non-zero for failure.
2621 */
2622static int
2623GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2624{
2625 IOCFacts_t get_facts;
2626 IOCFactsReply_t *facts;
2627 int r;
2628 int req_sz;
2629 int reply_sz;
2630 int sz;
2631 u32 status, vv;
2632 u8 shiftFactor=1;
2633
2634 /* IOC *must* NOT be in RESET state! */
2635 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2636 printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
2637 ioc->name,
2638 ioc->last_state );
2639 return -44;
2640 }
2641
2642 facts = &ioc->facts;
2643
2644 /* Destination (reply area)... */
2645 reply_sz = sizeof(*facts);
2646 memset(facts, 0, reply_sz);
2647
2648 /* Request area (get_facts on the stack right now!) */
2649 req_sz = sizeof(get_facts);
2650 memset(&get_facts, 0, req_sz);
2651
2652 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2653 /* Assert: All other get_facts fields are zero! */
2654
Prakash, Sathya436ace72007-07-24 15:42:08 +05302655 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002656 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 ioc->name, req_sz, reply_sz));
2658
2659 /* No non-zero fields in the get_facts request are greater than
2660 * 1 byte in size, so we can just fire it off as is.
2661 */
2662 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2663 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2664 if (r != 0)
2665 return r;
2666
2667 /*
2668 * Now byte swap (GRRR) the necessary fields before any further
2669 * inspection of reply contents.
2670 *
2671 * But need to do some sanity checks on MsgLength (byte) field
2672 * to make sure we don't zero IOC's req_sz!
2673 */
2674 /* Did we get a valid reply? */
2675 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2676 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2677 /*
2678 * If not been here, done that, save off first WhoInit value
2679 */
2680 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2681 ioc->FirstWhoInit = facts->WhoInit;
2682 }
2683
2684 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2685 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2686 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2687 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2688 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002689 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 /* CHECKME! IOCStatus, IOCLogInfo */
2691
2692 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2693 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2694
2695 /*
2696 * FC f/w version changed between 1.1 and 1.2
2697 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2698 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2699 */
2700 if (facts->MsgVersion < 0x0102) {
2701 /*
2702 * Handle old FC f/w style, convert to new...
2703 */
2704 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2705 facts->FWVersion.Word =
2706 ((oldv<<12) & 0xFF000000) |
2707 ((oldv<<8) & 0x000FFF00);
2708 } else
2709 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2710
2711 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002712 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2713 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2714 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 facts->CurrentHostMfaHighAddr =
2716 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2717 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2718 facts->CurrentSenseBufferHighAddr =
2719 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2720 facts->CurReplyFrameSize =
2721 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002722 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723
2724 /*
2725 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2726 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2727 * to 14 in MPI-1.01.0x.
2728 */
2729 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2730 facts->MsgVersion > 0x0100) {
2731 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2732 }
2733
2734 sz = facts->FWImageSize;
2735 if ( sz & 0x01 )
2736 sz += 1;
2737 if ( sz & 0x02 )
2738 sz += 2;
2739 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002740
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (!facts->RequestFrameSize) {
2742 /* Something is wrong! */
2743 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2744 ioc->name);
2745 return -55;
2746 }
2747
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002748 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 vv = ((63 / (sz * 4)) + 1) & 0x03;
2750 ioc->NB_for_64_byte_frame = vv;
2751 while ( sz )
2752 {
2753 shiftFactor++;
2754 sz = sz >> 1;
2755 }
2756 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302757 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2758 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2759 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002760
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2762 /*
2763 * Set values for this IOC's request & reply frame sizes,
2764 * and request & reply queue depths...
2765 */
2766 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2767 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2768 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2769 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2770
Prakash, Sathya436ace72007-07-24 15:42:08 +05302771 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302773 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 ioc->name, ioc->req_sz, ioc->req_depth));
2775
2776 /* Get port facts! */
2777 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2778 return r;
2779 }
2780 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2783 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2784 RequestFrameSize)/sizeof(u32)));
2785 return -66;
2786 }
2787
2788 return 0;
2789}
2790
2791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002792/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 * GetPortFacts - Send PortFacts request to MPT adapter.
2794 * @ioc: Pointer to MPT_ADAPTER structure
2795 * @portnum: Port number
2796 * @sleepFlag: Specifies whether the process can sleep
2797 *
2798 * Returns 0 for success, non-zero for failure.
2799 */
2800static int
2801GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2802{
2803 PortFacts_t get_pfacts;
2804 PortFactsReply_t *pfacts;
2805 int ii;
2806 int req_sz;
2807 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002808 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
2810 /* IOC *must* NOT be in RESET state! */
2811 if (ioc->last_state == MPI_IOC_STATE_RESET) {
2812 printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
2813 ioc->name,
2814 ioc->last_state );
2815 return -4;
2816 }
2817
2818 pfacts = &ioc->pfacts[portnum];
2819
2820 /* Destination (reply area)... */
2821 reply_sz = sizeof(*pfacts);
2822 memset(pfacts, 0, reply_sz);
2823
2824 /* Request area (get_pfacts on the stack right now!) */
2825 req_sz = sizeof(get_pfacts);
2826 memset(&get_pfacts, 0, req_sz);
2827
2828 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2829 get_pfacts.PortNumber = portnum;
2830 /* Assert: All other get_pfacts fields are zero! */
2831
Prakash, Sathya436ace72007-07-24 15:42:08 +05302832 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 ioc->name, portnum));
2834
2835 /* No non-zero fields in the get_pfacts request are greater than
2836 * 1 byte in size, so we can just fire it off as is.
2837 */
2838 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2839 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2840 if (ii != 0)
2841 return ii;
2842
2843 /* Did we get a valid reply? */
2844
2845 /* Now byte swap the necessary fields in the response. */
2846 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2847 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2848 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2849 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2850 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2851 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2852 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2853 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2854 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2855
Eric Moore793955f2007-01-29 09:42:20 -07002856 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2857 pfacts->MaxDevices;
2858 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2859 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2860
2861 /*
2862 * Place all the devices on channels
2863 *
2864 * (for debuging)
2865 */
2866 if (mpt_channel_mapping) {
2867 ioc->devices_per_bus = 1;
2868 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2869 }
2870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 return 0;
2872}
2873
2874/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002875/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 * SendIocInit - Send IOCInit request to MPT adapter.
2877 * @ioc: Pointer to MPT_ADAPTER structure
2878 * @sleepFlag: Specifies whether the process can sleep
2879 *
2880 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2881 *
2882 * Returns 0 for success, non-zero for failure.
2883 */
2884static int
2885SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2886{
2887 IOCInit_t ioc_init;
2888 MPIDefaultReply_t init_reply;
2889 u32 state;
2890 int r;
2891 int count;
2892 int cntdn;
2893
2894 memset(&ioc_init, 0, sizeof(ioc_init));
2895 memset(&init_reply, 0, sizeof(init_reply));
2896
2897 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2898 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2899
2900 /* If we are in a recovery mode and we uploaded the FW image,
2901 * then this pointer is not NULL. Skip the upload a second time.
2902 * Set this flag if cached_fw set for either IOC.
2903 */
2904 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2905 ioc->upload_fw = 1;
2906 else
2907 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302908 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2910
Eric Moore793955f2007-01-29 09:42:20 -07002911 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2912 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302913 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002914 ioc->name, ioc->facts.MsgVersion));
2915 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2916 // set MsgVersion and HeaderVersion host driver was built with
2917 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2918 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002920 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2921 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2922 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2923 return -99;
2924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2926
2927 if (sizeof(dma_addr_t) == sizeof(u64)) {
2928 /* Save the upper 32-bits of the request
2929 * (reply) and sense buffers.
2930 */
2931 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2932 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2933 } else {
2934 /* Force 32-bit addressing */
2935 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2936 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2937 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002938
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2940 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002941 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2942 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Prakash, Sathya436ace72007-07-24 15:42:08 +05302944 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 ioc->name, &ioc_init));
2946
2947 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2948 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002949 if (r != 0) {
2950 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
2954 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002955 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 */
2957
Prakash, Sathya436ace72007-07-24 15:42:08 +05302958 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002960
2961 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2962 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
2966 /* YIKES! SUPER IMPORTANT!!!
2967 * Poll IocState until _OPERATIONAL while IOC is doing
2968 * LoopInit and TargetDiscovery!
2969 */
2970 count = 0;
2971 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2972 state = mpt_GetIocState(ioc, 1);
2973 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2974 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002975 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 } else {
2977 mdelay(1);
2978 }
2979
2980 if (!cntdn) {
2981 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2982 ioc->name, (int)((count+5)/HZ));
2983 return -9;
2984 }
2985
2986 state = mpt_GetIocState(ioc, 1);
2987 count++;
2988 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05302989 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 ioc->name, count));
2991
Eric Mooreba856d32006-07-11 17:34:01 -06002992 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return r;
2994}
2995
2996/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002997/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 * SendPortEnable - Send PortEnable request to MPT adapter port.
2999 * @ioc: Pointer to MPT_ADAPTER structure
3000 * @portnum: Port number to enable
3001 * @sleepFlag: Specifies whether the process can sleep
3002 *
3003 * Send PortEnable to bring IOC to OPERATIONAL state.
3004 *
3005 * Returns 0 for success, non-zero for failure.
3006 */
3007static int
3008SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3009{
3010 PortEnable_t port_enable;
3011 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003012 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 int req_sz;
3014 int reply_sz;
3015
3016 /* Destination... */
3017 reply_sz = sizeof(MPIDefaultReply_t);
3018 memset(&reply_buf, 0, reply_sz);
3019
3020 req_sz = sizeof(PortEnable_t);
3021 memset(&port_enable, 0, req_sz);
3022
3023 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3024 port_enable.PortNumber = portnum;
3025/* port_enable.ChainOffset = 0; */
3026/* port_enable.MsgFlags = 0; */
3027/* port_enable.MsgContext = 0; */
3028
Prakash, Sathya436ace72007-07-24 15:42:08 +05303029 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 ioc->name, portnum, &port_enable));
3031
3032 /* RAID FW may take a long time to enable
3033 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003034 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003035 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3036 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3037 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003038 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003039 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3040 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3041 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003043 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044}
3045
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003046/**
3047 * mpt_alloc_fw_memory - allocate firmware memory
3048 * @ioc: Pointer to MPT_ADAPTER structure
3049 * @size: total FW bytes
3050 *
3051 * If memory has already been allocated, the same (cached) value
3052 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 */
3054void
3055mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3056{
3057 if (ioc->cached_fw)
3058 return; /* use already allocated memory */
3059 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3060 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3061 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003062 ioc->alloc_total += size;
3063 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 } else {
3065 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3066 ioc->alloc_total += size;
3067 }
3068}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003069/**
3070 * mpt_free_fw_memory - free firmware memory
3071 * @ioc: Pointer to MPT_ADAPTER structure
3072 *
3073 * If alt_img is NULL, delete from ioc structure.
3074 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 */
3076void
3077mpt_free_fw_memory(MPT_ADAPTER *ioc)
3078{
3079 int sz;
3080
3081 sz = ioc->facts.FWImageSize;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303082 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 -07003083 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3084 pci_free_consistent(ioc->pcidev, sz,
3085 ioc->cached_fw, ioc->cached_fw_dma);
3086 ioc->cached_fw = NULL;
3087
3088 return;
3089}
3090
3091
3092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003093/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3095 * @ioc: Pointer to MPT_ADAPTER structure
3096 * @sleepFlag: Specifies whether the process can sleep
3097 *
3098 * Returns 0 for success, >0 for handshake failure
3099 * <0 for fw upload failure.
3100 *
3101 * Remark: If bound IOC and a successful FWUpload was performed
3102 * on the bound IOC, the second image is discarded
3103 * and memory is free'd. Both channels must upload to prevent
3104 * IOC from running in degraded mode.
3105 */
3106static int
3107mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3108{
3109 u8 request[ioc->req_sz];
3110 u8 reply[sizeof(FWUploadReply_t)];
3111 FWUpload_t *prequest;
3112 FWUploadReply_t *preply;
3113 FWUploadTCSGE_t *ptcsge;
3114 int sgeoffset;
3115 u32 flagsLength;
3116 int ii, sz, reply_sz;
3117 int cmdStatus;
3118
3119 /* If the image size is 0, we are done.
3120 */
3121 if ((sz = ioc->facts.FWImageSize) == 0)
3122 return 0;
3123
3124 mpt_alloc_fw_memory(ioc, sz);
3125
Prakash, Sathya436ace72007-07-24 15:42:08 +05303126 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 if (ioc->cached_fw == NULL) {
3130 /* Major Failure.
3131 */
3132 return -ENOMEM;
3133 }
3134
3135 prequest = (FWUpload_t *)&request;
3136 preply = (FWUploadReply_t *)&reply;
3137
3138 /* Destination... */
3139 memset(prequest, 0, ioc->req_sz);
3140
3141 reply_sz = sizeof(reply);
3142 memset(preply, 0, reply_sz);
3143
3144 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3145 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3146
3147 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3148 ptcsge->DetailsLength = 12;
3149 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3150 ptcsge->ImageSize = cpu_to_le32(sz);
3151
3152 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3153
3154 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3155 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3156
3157 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303158 dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 prequest, sgeoffset));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303160 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
3162 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3163 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3164
Prakash, Sathya436ace72007-07-24 15:42:08 +05303165 dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
3167 cmdStatus = -EFAULT;
3168 if (ii == 0) {
3169 /* Handshake transfer was complete and successful.
3170 * Check the Reply Frame.
3171 */
3172 int status, transfer_sz;
3173 status = le16_to_cpu(preply->IOCStatus);
3174 if (status == MPI_IOCSTATUS_SUCCESS) {
3175 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3176 if (transfer_sz == sz)
3177 cmdStatus = 0;
3178 }
3179 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303180 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 ioc->name, cmdStatus));
3182
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003183
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 if (cmdStatus) {
3185
Prakash, Sathya436ace72007-07-24 15:42:08 +05303186 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 ioc->name));
3188 mpt_free_fw_memory(ioc);
3189 }
3190
3191 return cmdStatus;
3192}
3193
3194/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003195/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 * mpt_downloadboot - DownloadBoot code
3197 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003198 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 * @sleepFlag: Specifies whether the process can sleep
3200 *
3201 * FwDownloadBoot requires Programmed IO access.
3202 *
3203 * Returns 0 for success
3204 * -1 FW Image size is 0
3205 * -2 No valid cached_fw Pointer
3206 * <0 for fw upload failure.
3207 */
3208static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003209mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 MpiExtImageHeader_t *pExtImage;
3212 u32 fwSize;
3213 u32 diag0val;
3214 int count;
3215 u32 *ptrFw;
3216 u32 diagRwData;
3217 u32 nextImage;
3218 u32 load_addr;
3219 u32 ioc_state=0;
3220
Prakash, Sathya436ace72007-07-24 15:42:08 +05303221 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003222 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003223
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3225 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3226 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3227 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3228 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3229 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3230
3231 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3232
3233 /* wait 1 msec */
3234 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003235 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 } else {
3237 mdelay (1);
3238 }
3239
3240 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3241 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3242
3243 for (count = 0; count < 30; count ++) {
3244 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3245 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303246 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 ioc->name, count));
3248 break;
3249 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003250 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003252 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003254 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256 }
3257
3258 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303259 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003260 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 ioc->name, diag0val));
3262 return -3;
3263 }
3264
3265 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3266 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3267 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3268 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3269 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3270 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3271
3272 /* Set the DiagRwEn and Disable ARM bits */
3273 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 fwSize = (pFwHeader->ImageSize + 3)/4;
3276 ptrFw = (u32 *) pFwHeader;
3277
3278 /* Write the LoadStartAddress to the DiagRw Address Register
3279 * using Programmed IO
3280 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003281 if (ioc->errata_flag_1064)
3282 pci_enable_io_access(ioc->pcidev);
3283
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303285 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 ioc->name, pFwHeader->LoadStartAddress));
3287
Prakash, Sathya436ace72007-07-24 15:42:08 +05303288 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 ioc->name, fwSize*4, ptrFw));
3290 while (fwSize--) {
3291 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3292 }
3293
3294 nextImage = pFwHeader->NextImageHeaderOffset;
3295 while (nextImage) {
3296 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3297
3298 load_addr = pExtImage->LoadStartAddress;
3299
3300 fwSize = (pExtImage->ImageSize + 3) >> 2;
3301 ptrFw = (u32 *)pExtImage;
3302
Prakash, Sathya436ace72007-07-24 15:42:08 +05303303 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 +02003304 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3306
3307 while (fwSize--) {
3308 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3309 }
3310 nextImage = pExtImage->NextImageHeaderOffset;
3311 }
3312
3313 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303314 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3316
3317 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303318 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3320
3321 /* Clear the internal flash bad bit - autoincrementing register,
3322 * so must do two writes.
3323 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003324 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003325 /*
3326 * 1030 and 1035 H/W errata, workaround to access
3327 * the ClearFlashBadSignatureBit
3328 */
3329 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3330 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3331 diagRwData |= 0x40000000;
3332 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3333 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3334
3335 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3336 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3337 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3338 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3339
3340 /* wait 1 msec */
3341 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003342 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003343 } else {
3344 mdelay (1);
3345 }
3346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003348 if (ioc->errata_flag_1064)
3349 pci_disable_io_access(ioc->pcidev);
3350
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303352 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003353 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003355 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303356 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 ioc->name, diag0val));
3358 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3359
3360 /* Write 0xFF to reset the sequencer */
3361 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3362
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003363 if (ioc->bus_type == SAS) {
3364 ioc_state = mpt_GetIocState(ioc, 0);
3365 if ( (GetIocFacts(ioc, sleepFlag,
3366 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303367 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003368 ioc->name, ioc_state));
3369 return -EFAULT;
3370 }
3371 }
3372
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 for (count=0; count<HZ*20; count++) {
3374 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303375 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3376 "downloadboot successful! (count=%d) IocState=%x\n",
3377 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003378 if (ioc->bus_type == SAS) {
3379 return 0;
3380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303382 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3383 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 ioc->name));
3385 return -EFAULT;
3386 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303387 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3388 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 ioc->name));
3390 return 0;
3391 }
3392 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003393 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 } else {
3395 mdelay (10);
3396 }
3397 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303398 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3399 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 return -EFAULT;
3401}
3402
3403/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003404/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 * KickStart - Perform hard reset of MPT adapter.
3406 * @ioc: Pointer to MPT_ADAPTER structure
3407 * @force: Force hard reset
3408 * @sleepFlag: Specifies whether the process can sleep
3409 *
3410 * This routine places MPT adapter in diagnostic mode via the
3411 * WriteSequence register, and then performs a hard reset of adapter
3412 * via the Diagnostic register.
3413 *
3414 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3415 * or NO_SLEEP (interrupt thread, use mdelay)
3416 * force - 1 if doorbell active, board fault state
3417 * board operational, IOC_RECOVERY or
3418 * IOC_BRINGUP and there is an alt_ioc.
3419 * 0 else
3420 *
3421 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003422 * 1 - hard reset, READY
3423 * 0 - no reset due to History bit, READY
3424 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 * OR reset but failed to come READY
3426 * -2 - no reset, could not enter DIAG mode
3427 * -3 - reset but bad FW bit
3428 */
3429static int
3430KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3431{
3432 int hard_reset_done = 0;
3433 u32 ioc_state=0;
3434 int cnt,cntdn;
3435
Prakash, Sathya436ace72007-07-24 15:42:08 +05303436 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003437 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 /* Always issue a Msg Unit Reset first. This will clear some
3439 * SCSI bus hang conditions.
3440 */
3441 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3442
3443 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003444 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 } else {
3446 mdelay (1000);
3447 }
3448 }
3449
3450 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3451 if (hard_reset_done < 0)
3452 return hard_reset_done;
3453
Prakash, Sathya436ace72007-07-24 15:42:08 +05303454 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 ioc->name));
3456
3457 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3458 for (cnt=0; cnt<cntdn; cnt++) {
3459 ioc_state = mpt_GetIocState(ioc, 1);
3460 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 ioc->name, cnt));
3463 return hard_reset_done;
3464 }
3465 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003466 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 } else {
3468 mdelay (10);
3469 }
3470 }
3471
3472 printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3473 ioc->name, ioc_state);
3474 return -1;
3475}
3476
3477/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003478/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 * mpt_diag_reset - Perform hard reset of the adapter.
3480 * @ioc: Pointer to MPT_ADAPTER structure
3481 * @ignore: Set if to honor and clear to ignore
3482 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003483 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 * else set to NO_SLEEP (use mdelay instead)
3485 *
3486 * This routine places the adapter in diagnostic mode via the
3487 * WriteSequence register and then performs a hard reset of adapter
3488 * via the Diagnostic register. Adapter should be in ready state
3489 * upon successful completion.
3490 *
3491 * Returns: 1 hard reset successful
3492 * 0 no reset performed because reset history bit set
3493 * -2 enabling diagnostic mode failed
3494 * -3 diagnostic reset failed
3495 */
3496static int
3497mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3498{
Eric Moore0ccdb002006-07-11 17:33:13 -06003499 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 u32 diag0val;
3501 u32 doorbell;
3502 int hard_reset_done = 0;
3503 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
Eric Moorecd2c6192007-01-29 09:47:47 -07003506 /* Clear any existing interrupts */
3507 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3508
Eric Moore87cf8982006-06-27 16:09:26 -06003509 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303510 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003511 "address=%p\n", ioc->name, __FUNCTION__,
3512 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3513 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3514 if (sleepFlag == CAN_SLEEP)
3515 msleep(1);
3516 else
3517 mdelay(1);
3518
3519 for (count = 0; count < 60; count ++) {
3520 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3521 doorbell &= MPI_IOC_STATE_MASK;
3522
Prakash, Sathya436ace72007-07-24 15:42:08 +05303523 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003524 "looking for READY STATE: doorbell=%x"
3525 " count=%d\n",
3526 ioc->name, doorbell, count));
3527 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003528 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003529 }
3530
3531 /* wait 1 sec */
3532 if (sleepFlag == CAN_SLEEP)
3533 msleep(1000);
3534 else
3535 mdelay(1000);
3536 }
3537 return -1;
3538 }
3539
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 /* Use "Diagnostic reset" method! (only thing available!) */
3541 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3542
Prakash, Sathya436ace72007-07-24 15:42:08 +05303543 if (ioc->debug_level & MPT_DEBUG) {
3544 if (ioc->alt_ioc)
3545 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3546 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 /* Do the reset if we are told to ignore the reset history
3551 * or if the reset history is 0
3552 */
3553 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3554 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3555 /* Write magic sequence to WriteSequence register
3556 * Loop until in diagnostic mode
3557 */
3558 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3559 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3560 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3561 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3562 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3563 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3564
3565 /* wait 100 msec */
3566 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003567 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 } else {
3569 mdelay (100);
3570 }
3571
3572 count++;
3573 if (count > 20) {
3574 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3575 ioc->name, diag0val);
3576 return -2;
3577
3578 }
3579
3580 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3581
Prakash, Sathya436ace72007-07-24 15:42:08 +05303582 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 ioc->name, diag0val));
3584 }
3585
Prakash, Sathya436ace72007-07-24 15:42:08 +05303586 if (ioc->debug_level & MPT_DEBUG) {
3587 if (ioc->alt_ioc)
3588 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3589 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 /*
3593 * Disable the ARM (Bug fix)
3594 *
3595 */
3596 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003597 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599 /*
3600 * Now hit the reset bit in the Diagnostic register
3601 * (THE BIG HAMMER!) (Clears DRWE bit).
3602 */
3603 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3604 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303605 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 ioc->name));
3607
3608 /*
3609 * Call each currently registered protocol IOC reset handler
3610 * with pre-reset indication.
3611 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3612 * MptResetHandlers[] registered yet.
3613 */
3614 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303615 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 int r = 0;
3617
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303618 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3619 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303620 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3621 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303622 ioc->name, cb_idx));
3623 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303625 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3626 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303627 ioc->name, ioc->alt_ioc->name, cb_idx));
3628 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 }
3630 }
3631 }
3632 /* FIXME? Examine results here? */
3633 }
3634
Eric Moore0ccdb002006-07-11 17:33:13 -06003635 if (ioc->cached_fw)
3636 iocp = ioc;
3637 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3638 iocp = ioc->alt_ioc;
3639 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 /* If the DownloadBoot operation fails, the
3641 * IOC will be left unusable. This is a fatal error
3642 * case. _diag_reset will return < 0
3643 */
3644 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003645 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3647 break;
3648 }
3649
Prakash, Sathya436ace72007-07-24 15:42:08 +05303650 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003651 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 /* wait 1 sec */
3653 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003654 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 } else {
3656 mdelay (1000);
3657 }
3658 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003659 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003660 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 printk(KERN_WARNING MYNAM
3662 ": firmware downloadboot failure (%d)!\n", count);
3663 }
3664
3665 } else {
3666 /* Wait for FW to reload and for board
3667 * to go to the READY state.
3668 * Maximum wait is 60 seconds.
3669 * If fail, no error will check again
3670 * with calling program.
3671 */
3672 for (count = 0; count < 60; count ++) {
3673 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3674 doorbell &= MPI_IOC_STATE_MASK;
3675
3676 if (doorbell == MPI_IOC_STATE_READY) {
3677 break;
3678 }
3679
3680 /* wait 1 sec */
3681 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003682 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 } else {
3684 mdelay (1000);
3685 }
3686 }
3687 }
3688 }
3689
3690 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303691 if (ioc->debug_level & MPT_DEBUG) {
3692 if (ioc->alt_ioc)
3693 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3694 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3695 ioc->name, diag0val, diag1val));
3696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697
3698 /* Clear RESET_HISTORY bit! Place board in the
3699 * diagnostic mode to update the diag register.
3700 */
3701 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3702 count = 0;
3703 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3704 /* Write magic sequence to WriteSequence register
3705 * Loop until in diagnostic mode
3706 */
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3708 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3710 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3711 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3712 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3713
3714 /* wait 100 msec */
3715 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003716 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 } else {
3718 mdelay (100);
3719 }
3720
3721 count++;
3722 if (count > 20) {
3723 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3724 ioc->name, diag0val);
3725 break;
3726 }
3727 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3728 }
3729 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3730 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3731 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3732 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3733 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3734 ioc->name);
3735 }
3736
3737 /* Disable Diagnostic Mode
3738 */
3739 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3740
3741 /* Check FW reload status flags.
3742 */
3743 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3744 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3745 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3746 ioc->name, diag0val);
3747 return -3;
3748 }
3749
Prakash, Sathya436ace72007-07-24 15:42:08 +05303750 if (ioc->debug_level & MPT_DEBUG) {
3751 if (ioc->alt_ioc)
3752 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3753 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
3757 /*
3758 * Reset flag that says we've enabled event notification
3759 */
3760 ioc->facts.EventState = 0;
3761
3762 if (ioc->alt_ioc)
3763 ioc->alt_ioc->facts.EventState = 0;
3764
3765 return hard_reset_done;
3766}
3767
3768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003769/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 * SendIocReset - Send IOCReset request to MPT adapter.
3771 * @ioc: Pointer to MPT_ADAPTER structure
3772 * @reset_type: reset type, expected values are
3773 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003774 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 *
3776 * Send IOCReset request to the MPT adapter.
3777 *
3778 * Returns 0 for success, non-zero for failure.
3779 */
3780static int
3781SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3782{
3783 int r;
3784 u32 state;
3785 int cntdn, count;
3786
Prakash, Sathya436ace72007-07-24 15:42:08 +05303787 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 ioc->name, reset_type));
3789 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3790 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3791 return r;
3792
3793 /* FW ACK'd request, wait for READY state
3794 */
3795 count = 0;
3796 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3797
3798 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3799 cntdn--;
3800 count++;
3801 if (!cntdn) {
3802 if (sleepFlag != CAN_SLEEP)
3803 count *= 10;
3804
3805 printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
3806 ioc->name, (int)((count+5)/HZ));
3807 return -ETIME;
3808 }
3809
3810 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003811 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 } else {
3813 mdelay (1); /* 1 msec delay */
3814 }
3815 }
3816
3817 /* TODO!
3818 * Cleanup all event stuff for this IOC; re-issue EventNotification
3819 * request if needed.
3820 */
3821 if (ioc->facts.Function)
3822 ioc->facts.EventState = 0;
3823
3824 return 0;
3825}
3826
3827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003828/**
3829 * initChainBuffers - Allocate memory for and initialize chain buffers
3830 * @ioc: Pointer to MPT_ADAPTER structure
3831 *
3832 * Allocates memory for and initializes chain buffers,
3833 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 */
3835static int
3836initChainBuffers(MPT_ADAPTER *ioc)
3837{
3838 u8 *mem;
3839 int sz, ii, num_chain;
3840 int scale, num_sge, numSGE;
3841
3842 /* ReqToChain size must equal the req_depth
3843 * index = req_idx
3844 */
3845 if (ioc->ReqToChain == NULL) {
3846 sz = ioc->req_depth * sizeof(int);
3847 mem = kmalloc(sz, GFP_ATOMIC);
3848 if (mem == NULL)
3849 return -1;
3850
3851 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303852 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 ioc->name, mem, sz));
3854 mem = kmalloc(sz, GFP_ATOMIC);
3855 if (mem == NULL)
3856 return -1;
3857
3858 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303859 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 ioc->name, mem, sz));
3861 }
3862 for (ii = 0; ii < ioc->req_depth; ii++) {
3863 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3864 }
3865
3866 /* ChainToChain size must equal the total number
3867 * of chain buffers to be allocated.
3868 * index = chain_idx
3869 *
3870 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003871 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 *
3873 * num_sge = num sge in request frame + last chain buffer
3874 * scale = num sge per chain buffer if no chain element
3875 */
3876 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3877 if (sizeof(dma_addr_t) == sizeof(u64))
3878 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3879 else
3880 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3881
3882 if (sizeof(dma_addr_t) == sizeof(u64)) {
3883 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3884 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3885 } else {
3886 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3887 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3888 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303889 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 ioc->name, num_sge, numSGE));
3891
3892 if ( numSGE > MPT_SCSI_SG_DEPTH )
3893 numSGE = MPT_SCSI_SG_DEPTH;
3894
3895 num_chain = 1;
3896 while (numSGE - num_sge > 0) {
3897 num_chain++;
3898 num_sge += (scale - 1);
3899 }
3900 num_chain++;
3901
Prakash, Sathya436ace72007-07-24 15:42:08 +05303902 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 ioc->name, numSGE, num_sge, num_chain));
3904
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003905 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 num_chain *= MPT_SCSI_CAN_QUEUE;
3907 else
3908 num_chain *= MPT_FC_CAN_QUEUE;
3909
3910 ioc->num_chain = num_chain;
3911
3912 sz = num_chain * sizeof(int);
3913 if (ioc->ChainToChain == NULL) {
3914 mem = kmalloc(sz, GFP_ATOMIC);
3915 if (mem == NULL)
3916 return -1;
3917
3918 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303919 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 ioc->name, mem, sz));
3921 } else {
3922 mem = (u8 *) ioc->ChainToChain;
3923 }
3924 memset(mem, 0xFF, sz);
3925 return num_chain;
3926}
3927
3928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003929/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3931 * @ioc: Pointer to MPT_ADAPTER structure
3932 *
3933 * This routine allocates memory for the MPT reply and request frame
3934 * pools (if necessary), and primes the IOC reply FIFO with
3935 * reply frames.
3936 *
3937 * Returns 0 for success, non-zero for failure.
3938 */
3939static int
3940PrimeIocFifos(MPT_ADAPTER *ioc)
3941{
3942 MPT_FRAME_HDR *mf;
3943 unsigned long flags;
3944 dma_addr_t alloc_dma;
3945 u8 *mem;
3946 int i, reply_sz, sz, total_size, num_chain;
3947
3948 /* Prime reply FIFO... */
3949
3950 if (ioc->reply_frames == NULL) {
3951 if ( (num_chain = initChainBuffers(ioc)) < 0)
3952 return -1;
3953
3954 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303955 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303957 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 ioc->name, reply_sz, reply_sz));
3959
3960 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303961 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303963 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 ioc->name, sz, sz));
3965 total_size += sz;
3966
3967 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303968 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 ioc->name, sz, sz, num_chain));
3972
3973 total_size += sz;
3974 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3975 if (mem == NULL) {
3976 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3977 ioc->name);
3978 goto out_fail;
3979 }
3980
Prakash, Sathya436ace72007-07-24 15:42:08 +05303981 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3983
3984 memset(mem, 0, total_size);
3985 ioc->alloc_total += total_size;
3986 ioc->alloc = mem;
3987 ioc->alloc_dma = alloc_dma;
3988 ioc->alloc_sz = total_size;
3989 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3990 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3991
Prakash, Sathya436ace72007-07-24 15:42:08 +05303992 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003993 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3994
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 alloc_dma += reply_sz;
3996 mem += reply_sz;
3997
3998 /* Request FIFO - WE manage this! */
3999
4000 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4001 ioc->req_frames_dma = alloc_dma;
4002
Prakash, Sathya436ace72007-07-24 15:42:08 +05304003 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 ioc->name, mem, (void *)(ulong)alloc_dma));
4005
4006 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4007
4008#if defined(CONFIG_MTRR) && 0
4009 /*
4010 * Enable Write Combining MTRR for IOC's memory region.
4011 * (at least as much as we can; "size and base must be
4012 * multiples of 4 kiB"
4013 */
4014 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4015 sz,
4016 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304017 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 ioc->name, ioc->req_frames_dma, sz));
4019#endif
4020
4021 for (i = 0; i < ioc->req_depth; i++) {
4022 alloc_dma += ioc->req_sz;
4023 mem += ioc->req_sz;
4024 }
4025
4026 ioc->ChainBuffer = mem;
4027 ioc->ChainBufferDMA = alloc_dma;
4028
Prakash, Sathya436ace72007-07-24 15:42:08 +05304029 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4031
4032 /* Initialize the free chain Q.
4033 */
4034
4035 INIT_LIST_HEAD(&ioc->FreeChainQ);
4036
4037 /* Post the chain buffers to the FreeChainQ.
4038 */
4039 mem = (u8 *)ioc->ChainBuffer;
4040 for (i=0; i < num_chain; i++) {
4041 mf = (MPT_FRAME_HDR *) mem;
4042 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4043 mem += ioc->req_sz;
4044 }
4045
4046 /* Initialize Request frames linked list
4047 */
4048 alloc_dma = ioc->req_frames_dma;
4049 mem = (u8 *) ioc->req_frames;
4050
4051 spin_lock_irqsave(&ioc->FreeQlock, flags);
4052 INIT_LIST_HEAD(&ioc->FreeQ);
4053 for (i = 0; i < ioc->req_depth; i++) {
4054 mf = (MPT_FRAME_HDR *) mem;
4055
4056 /* Queue REQUESTs *internally*! */
4057 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4058
4059 mem += ioc->req_sz;
4060 }
4061 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4062
4063 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4064 ioc->sense_buf_pool =
4065 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4066 if (ioc->sense_buf_pool == NULL) {
4067 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4068 ioc->name);
4069 goto out_fail;
4070 }
4071
4072 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4073 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304074 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4076
4077 }
4078
4079 /* Post Reply frames to FIFO
4080 */
4081 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304082 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4084
4085 for (i = 0; i < ioc->reply_depth; i++) {
4086 /* Write each address to the IOC! */
4087 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4088 alloc_dma += ioc->reply_sz;
4089 }
4090
4091 return 0;
4092
4093out_fail:
4094 if (ioc->alloc != NULL) {
4095 sz = ioc->alloc_sz;
4096 pci_free_consistent(ioc->pcidev,
4097 sz,
4098 ioc->alloc, ioc->alloc_dma);
4099 ioc->reply_frames = NULL;
4100 ioc->req_frames = NULL;
4101 ioc->alloc_total -= sz;
4102 }
4103 if (ioc->sense_buf_pool != NULL) {
4104 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4105 pci_free_consistent(ioc->pcidev,
4106 sz,
4107 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4108 ioc->sense_buf_pool = NULL;
4109 }
4110 return -1;
4111}
4112
4113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4114/**
4115 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4116 * from IOC via doorbell handshake method.
4117 * @ioc: Pointer to MPT_ADAPTER structure
4118 * @reqBytes: Size of the request in bytes
4119 * @req: Pointer to MPT request frame
4120 * @replyBytes: Expected size of the reply in bytes
4121 * @u16reply: Pointer to area where reply should be written
4122 * @maxwait: Max wait time for a reply (in seconds)
4123 * @sleepFlag: Specifies whether the process can sleep
4124 *
4125 * NOTES: It is the callers responsibility to byte-swap fields in the
4126 * request which are greater than 1 byte in size. It is also the
4127 * callers responsibility to byte-swap response fields which are
4128 * greater than 1 byte in size.
4129 *
4130 * Returns 0 for success, non-zero for failure.
4131 */
4132static int
4133mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004134 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
4136 MPIDefaultReply_t *mptReply;
4137 int failcnt = 0;
4138 int t;
4139
4140 /*
4141 * Get ready to cache a handshake reply
4142 */
4143 ioc->hs_reply_idx = 0;
4144 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4145 mptReply->MsgLength = 0;
4146
4147 /*
4148 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4149 * then tell IOC that we want to handshake a request of N words.
4150 * (WRITE u32val to Doorbell reg).
4151 */
4152 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4156
4157 /*
4158 * Wait for IOC's doorbell handshake int
4159 */
4160 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4161 failcnt++;
4162
Prakash, Sathya436ace72007-07-24 15:42:08 +05304163 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4165
4166 /* Read doorbell and check for active bit */
4167 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4168 return -1;
4169
4170 /*
4171 * Clear doorbell int (WRITE 0 to IntStatus reg),
4172 * then wait for IOC to ACKnowledge that it's ready for
4173 * our handshake request.
4174 */
4175 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4176 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4177 failcnt++;
4178
4179 if (!failcnt) {
4180 int ii;
4181 u8 *req_as_bytes = (u8 *) req;
4182
4183 /*
4184 * Stuff request words via doorbell handshake,
4185 * with ACK from IOC for each.
4186 */
4187 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4188 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4189 (req_as_bytes[(ii*4) + 1] << 8) |
4190 (req_as_bytes[(ii*4) + 2] << 16) |
4191 (req_as_bytes[(ii*4) + 3] << 24));
4192
4193 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4194 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4195 failcnt++;
4196 }
4197
Prakash, Sathya436ace72007-07-24 15:42:08 +05304198 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
4199 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200
Prakash, Sathya436ace72007-07-24 15:42:08 +05304201 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4203
4204 /*
4205 * Wait for completion of doorbell handshake reply from the IOC
4206 */
4207 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4208 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004209
Prakash, Sathya436ace72007-07-24 15:42:08 +05304210 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4212
4213 /*
4214 * Copy out the cached reply...
4215 */
4216 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4217 u16reply[ii] = ioc->hs_reply[ii];
4218 } else {
4219 return -99;
4220 }
4221
4222 return -failcnt;
4223}
4224
4225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004226/**
4227 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 * @ioc: Pointer to MPT_ADAPTER structure
4229 * @howlong: How long to wait (in seconds)
4230 * @sleepFlag: Specifies whether the process can sleep
4231 *
4232 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004233 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4234 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 *
4236 * Returns a negative value on failure, else wait loop count.
4237 */
4238static int
4239WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4240{
4241 int cntdn;
4242 int count = 0;
4243 u32 intstat=0;
4244
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004245 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
4247 if (sleepFlag == CAN_SLEEP) {
4248 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004249 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4251 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4252 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 count++;
4254 }
4255 } else {
4256 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004257 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4259 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4260 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 count++;
4262 }
4263 }
4264
4265 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304266 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 ioc->name, count));
4268 return count;
4269 }
4270
4271 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4272 ioc->name, count, intstat);
4273 return -1;
4274}
4275
4276/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004277/**
4278 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 * @ioc: Pointer to MPT_ADAPTER structure
4280 * @howlong: How long to wait (in seconds)
4281 * @sleepFlag: Specifies whether the process can sleep
4282 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004283 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4284 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 *
4286 * Returns a negative value on failure, else wait loop count.
4287 */
4288static int
4289WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4290{
4291 int cntdn;
4292 int count = 0;
4293 u32 intstat=0;
4294
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004295 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 if (sleepFlag == CAN_SLEEP) {
4297 while (--cntdn) {
4298 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4299 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4300 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004301 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 count++;
4303 }
4304 } else {
4305 while (--cntdn) {
4306 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4307 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4308 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004309 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 count++;
4311 }
4312 }
4313
4314 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304315 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 ioc->name, count, howlong));
4317 return count;
4318 }
4319
4320 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4321 ioc->name, count, intstat);
4322 return -1;
4323}
4324
4325/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004326/**
4327 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 * @ioc: Pointer to MPT_ADAPTER structure
4329 * @howlong: How long to wait (in seconds)
4330 * @sleepFlag: Specifies whether the process can sleep
4331 *
4332 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4333 * Reply is cached to IOC private area large enough to hold a maximum
4334 * of 128 bytes of reply data.
4335 *
4336 * Returns a negative value on failure, else size of reply in WORDS.
4337 */
4338static int
4339WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4340{
4341 int u16cnt = 0;
4342 int failcnt = 0;
4343 int t;
4344 u16 *hs_reply = ioc->hs_reply;
4345 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4346 u16 hword;
4347
4348 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4349
4350 /*
4351 * Get first two u16's so we can look at IOC's intended reply MsgLength
4352 */
4353 u16cnt=0;
4354 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4355 failcnt++;
4356 } else {
4357 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4358 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4359 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4360 failcnt++;
4361 else {
4362 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4363 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4364 }
4365 }
4366
Prakash, Sathya436ace72007-07-24 15:42:08 +05304367 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004368 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4370
4371 /*
4372 * If no error (and IOC said MsgLength is > 0), piece together
4373 * reply 16 bits at a time.
4374 */
4375 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4376 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4377 failcnt++;
4378 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4379 /* don't overflow our IOC hs_reply[] buffer! */
4380 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4381 hs_reply[u16cnt] = hword;
4382 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4383 }
4384
4385 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4386 failcnt++;
4387 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4388
4389 if (failcnt) {
4390 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4391 ioc->name);
4392 return -failcnt;
4393 }
4394#if 0
4395 else if (u16cnt != (2 * mptReply->MsgLength)) {
4396 return -101;
4397 }
4398 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4399 return -102;
4400 }
4401#endif
4402
Prakash, Sathya436ace72007-07-24 15:42:08 +05304403 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
4404 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405
Prakash, Sathya436ace72007-07-24 15:42:08 +05304406 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 ioc->name, t, u16cnt/2));
4408 return u16cnt/2;
4409}
4410
4411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004412/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 * GetLanConfigPages - Fetch LANConfig pages.
4414 * @ioc: Pointer to MPT_ADAPTER structure
4415 *
4416 * Return: 0 for success
4417 * -ENOMEM if no memory available
4418 * -EPERM if not allowed due to ISR context
4419 * -EAGAIN if no msg frames currently available
4420 * -EFAULT for non-successful reply or no reply (timeout)
4421 */
4422static int
4423GetLanConfigPages(MPT_ADAPTER *ioc)
4424{
4425 ConfigPageHeader_t hdr;
4426 CONFIGPARMS cfg;
4427 LANPage0_t *ppage0_alloc;
4428 dma_addr_t page0_dma;
4429 LANPage1_t *ppage1_alloc;
4430 dma_addr_t page1_dma;
4431 int rc = 0;
4432 int data_sz;
4433 int copy_sz;
4434
4435 /* Get LAN Page 0 header */
4436 hdr.PageVersion = 0;
4437 hdr.PageLength = 0;
4438 hdr.PageNumber = 0;
4439 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004440 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 cfg.physAddr = -1;
4442 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4443 cfg.dir = 0;
4444 cfg.pageAddr = 0;
4445 cfg.timeout = 0;
4446
4447 if ((rc = mpt_config(ioc, &cfg)) != 0)
4448 return rc;
4449
4450 if (hdr.PageLength > 0) {
4451 data_sz = hdr.PageLength * 4;
4452 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4453 rc = -ENOMEM;
4454 if (ppage0_alloc) {
4455 memset((u8 *)ppage0_alloc, 0, data_sz);
4456 cfg.physAddr = page0_dma;
4457 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4458
4459 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4460 /* save the data */
4461 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4462 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4463
4464 }
4465
4466 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4467
4468 /* FIXME!
4469 * Normalize endianness of structure data,
4470 * by byte-swapping all > 1 byte fields!
4471 */
4472
4473 }
4474
4475 if (rc)
4476 return rc;
4477 }
4478
4479 /* Get LAN Page 1 header */
4480 hdr.PageVersion = 0;
4481 hdr.PageLength = 0;
4482 hdr.PageNumber = 1;
4483 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004484 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 cfg.physAddr = -1;
4486 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4487 cfg.dir = 0;
4488 cfg.pageAddr = 0;
4489
4490 if ((rc = mpt_config(ioc, &cfg)) != 0)
4491 return rc;
4492
4493 if (hdr.PageLength == 0)
4494 return 0;
4495
4496 data_sz = hdr.PageLength * 4;
4497 rc = -ENOMEM;
4498 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4499 if (ppage1_alloc) {
4500 memset((u8 *)ppage1_alloc, 0, data_sz);
4501 cfg.physAddr = page1_dma;
4502 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4503
4504 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4505 /* save the data */
4506 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4507 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4508 }
4509
4510 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4511
4512 /* FIXME!
4513 * Normalize endianness of structure data,
4514 * by byte-swapping all > 1 byte fields!
4515 */
4516
4517 }
4518
4519 return rc;
4520}
4521
4522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004523/**
4524 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004525 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004526 * @persist_opcode: see below
4527 *
4528 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4529 * devices not currently present.
4530 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4531 *
4532 * NOTE: Don't use not this function during interrupt time.
4533 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004534 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004535 */
4536
4537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4538int
4539mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4540{
4541 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4542 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4543 MPT_FRAME_HDR *mf = NULL;
4544 MPIHeader_t *mpi_hdr;
4545
4546
4547 /* insure garbage is not sent to fw */
4548 switch(persist_opcode) {
4549
4550 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4551 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4552 break;
4553
4554 default:
4555 return -1;
4556 break;
4557 }
4558
4559 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4560
4561 /* Get a MF for this command.
4562 */
4563 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4564 printk("%s: no msg frames!\n",__FUNCTION__);
4565 return -1;
4566 }
4567
4568 mpi_hdr = (MPIHeader_t *) mf;
4569 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4570 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4571 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4572 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4573 sasIoUnitCntrReq->Operation = persist_opcode;
4574
4575 init_timer(&ioc->persist_timer);
4576 ioc->persist_timer.data = (unsigned long) ioc;
4577 ioc->persist_timer.function = mpt_timer_expired;
4578 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4579 ioc->persist_wait_done=0;
4580 add_timer(&ioc->persist_timer);
4581 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4582 wait_event(mpt_waitq, ioc->persist_wait_done);
4583
4584 sasIoUnitCntrReply =
4585 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4586 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4587 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4588 __FUNCTION__,
4589 sasIoUnitCntrReply->IOCStatus,
4590 sasIoUnitCntrReply->IOCLogInfo);
4591 return -1;
4592 }
4593
4594 printk("%s: success\n",__FUNCTION__);
4595 return 0;
4596}
4597
4598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004599
4600static void
4601mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4602 MpiEventDataRaid_t * pRaidEventData)
4603{
4604 int volume;
4605 int reason;
4606 int disk;
4607 int status;
4608 int flags;
4609 int state;
4610
4611 volume = pRaidEventData->VolumeID;
4612 reason = pRaidEventData->ReasonCode;
4613 disk = pRaidEventData->PhysDiskNum;
4614 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4615 flags = (status >> 0) & 0xff;
4616 state = (status >> 8) & 0xff;
4617
4618 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4619 return;
4620 }
4621
4622 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4623 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4624 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004625 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4626 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004627 } else {
4628 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4629 ioc->name, volume);
4630 }
4631
4632 switch(reason) {
4633 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4634 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4635 ioc->name);
4636 break;
4637
4638 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4639
4640 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4641 ioc->name);
4642 break;
4643
4644 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4645 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4646 ioc->name);
4647 break;
4648
4649 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4650 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4651 ioc->name,
4652 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4653 ? "optimal"
4654 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4655 ? "degraded"
4656 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4657 ? "failed"
4658 : "state unknown",
4659 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4660 ? ", enabled" : "",
4661 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4662 ? ", quiesced" : "",
4663 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4664 ? ", resync in progress" : "" );
4665 break;
4666
4667 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4668 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4669 ioc->name, disk);
4670 break;
4671
4672 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4673 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4674 ioc->name);
4675 break;
4676
4677 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4678 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4679 ioc->name);
4680 break;
4681
4682 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4683 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4684 ioc->name);
4685 break;
4686
4687 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4688 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4689 ioc->name,
4690 state == MPI_PHYSDISK0_STATUS_ONLINE
4691 ? "online"
4692 : state == MPI_PHYSDISK0_STATUS_MISSING
4693 ? "missing"
4694 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4695 ? "not compatible"
4696 : state == MPI_PHYSDISK0_STATUS_FAILED
4697 ? "failed"
4698 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4699 ? "initializing"
4700 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4701 ? "offline requested"
4702 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4703 ? "failed requested"
4704 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4705 ? "offline"
4706 : "state unknown",
4707 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4708 ? ", out of sync" : "",
4709 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4710 ? ", quiesced" : "" );
4711 break;
4712
4713 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4714 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4715 ioc->name, disk);
4716 break;
4717
4718 case MPI_EVENT_RAID_RC_SMART_DATA:
4719 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4720 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4721 break;
4722
4723 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4724 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4725 ioc->name, disk);
4726 break;
4727 }
4728}
4729
4730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004731/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4733 * @ioc: Pointer to MPT_ADAPTER structure
4734 *
4735 * Returns: 0 for success
4736 * -ENOMEM if no memory available
4737 * -EPERM if not allowed due to ISR context
4738 * -EAGAIN if no msg frames currently available
4739 * -EFAULT for non-successful reply or no reply (timeout)
4740 */
4741static int
4742GetIoUnitPage2(MPT_ADAPTER *ioc)
4743{
4744 ConfigPageHeader_t hdr;
4745 CONFIGPARMS cfg;
4746 IOUnitPage2_t *ppage_alloc;
4747 dma_addr_t page_dma;
4748 int data_sz;
4749 int rc;
4750
4751 /* Get the page header */
4752 hdr.PageVersion = 0;
4753 hdr.PageLength = 0;
4754 hdr.PageNumber = 2;
4755 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004756 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 cfg.physAddr = -1;
4758 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4759 cfg.dir = 0;
4760 cfg.pageAddr = 0;
4761 cfg.timeout = 0;
4762
4763 if ((rc = mpt_config(ioc, &cfg)) != 0)
4764 return rc;
4765
4766 if (hdr.PageLength == 0)
4767 return 0;
4768
4769 /* Read the config page */
4770 data_sz = hdr.PageLength * 4;
4771 rc = -ENOMEM;
4772 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4773 if (ppage_alloc) {
4774 memset((u8 *)ppage_alloc, 0, data_sz);
4775 cfg.physAddr = page_dma;
4776 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4777
4778 /* If Good, save data */
4779 if ((rc = mpt_config(ioc, &cfg)) == 0)
4780 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4781
4782 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4783 }
4784
4785 return rc;
4786}
4787
4788/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004789/**
4790 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 * @ioc: Pointer to a Adapter Strucutre
4792 * @portnum: IOC port number
4793 *
4794 * Return: -EFAULT if read of config page header fails
4795 * or if no nvram
4796 * If read of SCSI Port Page 0 fails,
4797 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4798 * Adapter settings: async, narrow
4799 * Return 1
4800 * If read of SCSI Port Page 2 fails,
4801 * Adapter settings valid
4802 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4803 * Return 1
4804 * Else
4805 * Both valid
4806 * Return 0
4807 * CHECK - what type of locking mechanisms should be used????
4808 */
4809static int
4810mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4811{
4812 u8 *pbuf;
4813 dma_addr_t buf_dma;
4814 CONFIGPARMS cfg;
4815 ConfigPageHeader_t header;
4816 int ii;
4817 int data, rc = 0;
4818
4819 /* Allocate memory
4820 */
4821 if (!ioc->spi_data.nvram) {
4822 int sz;
4823 u8 *mem;
4824 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4825 mem = kmalloc(sz, GFP_ATOMIC);
4826 if (mem == NULL)
4827 return -EFAULT;
4828
4829 ioc->spi_data.nvram = (int *) mem;
4830
Prakash, Sathya436ace72007-07-24 15:42:08 +05304831 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 ioc->name, ioc->spi_data.nvram, sz));
4833 }
4834
4835 /* Invalidate NVRAM information
4836 */
4837 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4838 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4839 }
4840
4841 /* Read SPP0 header, allocate memory, then read page.
4842 */
4843 header.PageVersion = 0;
4844 header.PageLength = 0;
4845 header.PageNumber = 0;
4846 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004847 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 cfg.physAddr = -1;
4849 cfg.pageAddr = portnum;
4850 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4851 cfg.dir = 0;
4852 cfg.timeout = 0; /* use default */
4853 if (mpt_config(ioc, &cfg) != 0)
4854 return -EFAULT;
4855
4856 if (header.PageLength > 0) {
4857 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4858 if (pbuf) {
4859 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4860 cfg.physAddr = buf_dma;
4861 if (mpt_config(ioc, &cfg) != 0) {
4862 ioc->spi_data.maxBusWidth = MPT_NARROW;
4863 ioc->spi_data.maxSyncOffset = 0;
4864 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4865 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4866 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304867 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4868 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004869 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 } else {
4871 /* Save the Port Page 0 data
4872 */
4873 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4874 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4875 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4876
4877 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4878 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304879 ddvprintk(ioc, printk(KERN_INFO MYNAM
4880 " :%s noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 ioc->name, pPP0->Capabilities));
4882 }
4883 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4884 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4885 if (data) {
4886 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4887 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4888 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304889 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4890 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004891 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 } else {
4893 ioc->spi_data.maxSyncOffset = 0;
4894 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4895 }
4896
4897 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4898
4899 /* Update the minSyncFactor based on bus type.
4900 */
4901 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4902 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4903
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004904 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304906 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4907 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004908 ioc->name, ioc->spi_data.minSyncFactor));
4909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 }
4911 }
4912 if (pbuf) {
4913 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4914 }
4915 }
4916 }
4917
4918 /* SCSI Port Page 2 - Read the header then the page.
4919 */
4920 header.PageVersion = 0;
4921 header.PageLength = 0;
4922 header.PageNumber = 2;
4923 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004924 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 cfg.physAddr = -1;
4926 cfg.pageAddr = portnum;
4927 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4928 cfg.dir = 0;
4929 if (mpt_config(ioc, &cfg) != 0)
4930 return -EFAULT;
4931
4932 if (header.PageLength > 0) {
4933 /* Allocate memory and read SCSI Port Page 2
4934 */
4935 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4936 if (pbuf) {
4937 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4938 cfg.physAddr = buf_dma;
4939 if (mpt_config(ioc, &cfg) != 0) {
4940 /* Nvram data is left with INVALID mark
4941 */
4942 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004943 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4944
4945 /* This is an ATTO adapter, read Page2 accordingly
4946 */
4947 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4948 ATTODeviceInfo_t *pdevice = NULL;
4949 u16 ATTOFlags;
4950
4951 /* Save the Port Page 2 data
4952 * (reformat into a 32bit quantity)
4953 */
4954 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4955 pdevice = &pPP2->DeviceSettings[ii];
4956 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4957 data = 0;
4958
4959 /* Translate ATTO device flags to LSI format
4960 */
4961 if (ATTOFlags & ATTOFLAG_DISC)
4962 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4963 if (ATTOFlags & ATTOFLAG_ID_ENB)
4964 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4965 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4966 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4967 if (ATTOFlags & ATTOFLAG_TAGGED)
4968 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4969 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4970 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4971
4972 data = (data << 16) | (pdevice->Period << 8) | 10;
4973 ioc->spi_data.nvram[ii] = data;
4974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 } else {
4976 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4977 MpiDeviceInfo_t *pdevice = NULL;
4978
Moore, Ericd8e925d2006-01-16 18:53:06 -07004979 /*
4980 * Save "Set to Avoid SCSI Bus Resets" flag
4981 */
4982 ioc->spi_data.bus_reset =
4983 (le32_to_cpu(pPP2->PortFlags) &
4984 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4985 0 : 1 ;
4986
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 /* Save the Port Page 2 data
4988 * (reformat into a 32bit quantity)
4989 */
4990 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4991 ioc->spi_data.PortFlags = data;
4992 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4993 pdevice = &pPP2->DeviceSettings[ii];
4994 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4995 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4996 ioc->spi_data.nvram[ii] = data;
4997 }
4998 }
4999
5000 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5001 }
5002 }
5003
5004 /* Update Adapter limits with those from NVRAM
5005 * Comment: Don't need to do this. Target performance
5006 * parameters will never exceed the adapters limits.
5007 */
5008
5009 return rc;
5010}
5011
5012/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005013/**
5014 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 * @ioc: Pointer to a Adapter Strucutre
5016 * @portnum: IOC port number
5017 *
5018 * Return: -EFAULT if read of config page header fails
5019 * or 0 if success.
5020 */
5021static int
5022mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5023{
5024 CONFIGPARMS cfg;
5025 ConfigPageHeader_t header;
5026
5027 /* Read the SCSI Device Page 1 header
5028 */
5029 header.PageVersion = 0;
5030 header.PageLength = 0;
5031 header.PageNumber = 1;
5032 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005033 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 cfg.physAddr = -1;
5035 cfg.pageAddr = portnum;
5036 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5037 cfg.dir = 0;
5038 cfg.timeout = 0;
5039 if (mpt_config(ioc, &cfg) != 0)
5040 return -EFAULT;
5041
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005042 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5043 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044
5045 header.PageVersion = 0;
5046 header.PageLength = 0;
5047 header.PageNumber = 0;
5048 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5049 if (mpt_config(ioc, &cfg) != 0)
5050 return -EFAULT;
5051
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005052 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5053 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
Prakash, Sathya436ace72007-07-24 15:42:08 +05305055 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5057
Prakash, Sathya436ace72007-07-24 15:42:08 +05305058 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5060 return 0;
5061}
5062
Eric Mooreb506ade2007-01-29 09:45:37 -07005063/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005064 * mpt_inactive_raid_list_free - This clears this link list.
5065 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005066 **/
5067static void
5068mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5069{
5070 struct inactive_raid_component_info *component_info, *pNext;
5071
5072 if (list_empty(&ioc->raid_data.inactive_list))
5073 return;
5074
5075 down(&ioc->raid_data.inactive_list_mutex);
5076 list_for_each_entry_safe(component_info, pNext,
5077 &ioc->raid_data.inactive_list, list) {
5078 list_del(&component_info->list);
5079 kfree(component_info);
5080 }
5081 up(&ioc->raid_data.inactive_list_mutex);
5082}
5083
5084/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005085 * 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 -07005086 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005087 * @ioc : pointer to per adapter structure
5088 * @channel : volume channel
5089 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005090 **/
5091static void
5092mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5093{
5094 CONFIGPARMS cfg;
5095 ConfigPageHeader_t hdr;
5096 dma_addr_t dma_handle;
5097 pRaidVolumePage0_t buffer = NULL;
5098 int i;
5099 RaidPhysDiskPage0_t phys_disk;
5100 struct inactive_raid_component_info *component_info;
5101 int handle_inactive_volumes;
5102
5103 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5104 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5105 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5106 cfg.pageAddr = (channel << 8) + id;
5107 cfg.cfghdr.hdr = &hdr;
5108 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5109
5110 if (mpt_config(ioc, &cfg) != 0)
5111 goto out;
5112
5113 if (!hdr.PageLength)
5114 goto out;
5115
5116 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5117 &dma_handle);
5118
5119 if (!buffer)
5120 goto out;
5121
5122 cfg.physAddr = dma_handle;
5123 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5124
5125 if (mpt_config(ioc, &cfg) != 0)
5126 goto out;
5127
5128 if (!buffer->NumPhysDisks)
5129 goto out;
5130
5131 handle_inactive_volumes =
5132 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5133 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5134 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5135 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5136
5137 if (!handle_inactive_volumes)
5138 goto out;
5139
5140 down(&ioc->raid_data.inactive_list_mutex);
5141 for (i = 0; i < buffer->NumPhysDisks; i++) {
5142 if(mpt_raid_phys_disk_pg0(ioc,
5143 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5144 continue;
5145
5146 if ((component_info = kmalloc(sizeof (*component_info),
5147 GFP_KERNEL)) == NULL)
5148 continue;
5149
5150 component_info->volumeID = id;
5151 component_info->volumeBus = channel;
5152 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5153 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5154 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5155 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5156
5157 list_add_tail(&component_info->list,
5158 &ioc->raid_data.inactive_list);
5159 }
5160 up(&ioc->raid_data.inactive_list_mutex);
5161
5162 out:
5163 if (buffer)
5164 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5165 dma_handle);
5166}
5167
5168/**
5169 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5170 * @ioc: Pointer to a Adapter Structure
5171 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5172 * @phys_disk: requested payload data returned
5173 *
5174 * Return:
5175 * 0 on success
5176 * -EFAULT if read of config page header fails or data pointer not NULL
5177 * -ENOMEM if pci_alloc failed
5178 **/
5179int
5180mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5181{
5182 CONFIGPARMS cfg;
5183 ConfigPageHeader_t hdr;
5184 dma_addr_t dma_handle;
5185 pRaidPhysDiskPage0_t buffer = NULL;
5186 int rc;
5187
5188 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5189 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5190
5191 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5192 cfg.cfghdr.hdr = &hdr;
5193 cfg.physAddr = -1;
5194 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5195
5196 if (mpt_config(ioc, &cfg) != 0) {
5197 rc = -EFAULT;
5198 goto out;
5199 }
5200
5201 if (!hdr.PageLength) {
5202 rc = -EFAULT;
5203 goto out;
5204 }
5205
5206 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5207 &dma_handle);
5208
5209 if (!buffer) {
5210 rc = -ENOMEM;
5211 goto out;
5212 }
5213
5214 cfg.physAddr = dma_handle;
5215 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5216 cfg.pageAddr = phys_disk_num;
5217
5218 if (mpt_config(ioc, &cfg) != 0) {
5219 rc = -EFAULT;
5220 goto out;
5221 }
5222
5223 rc = 0;
5224 memcpy(phys_disk, buffer, sizeof(*buffer));
5225 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5226
5227 out:
5228
5229 if (buffer)
5230 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5231 dma_handle);
5232
5233 return rc;
5234}
5235
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236/**
5237 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5238 * @ioc: Pointer to a Adapter Strucutre
5239 * @portnum: IOC port number
5240 *
5241 * Return:
5242 * 0 on success
5243 * -EFAULT if read of config page header fails or data pointer not NULL
5244 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005245 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246int
5247mpt_findImVolumes(MPT_ADAPTER *ioc)
5248{
5249 IOCPage2_t *pIoc2;
5250 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 dma_addr_t ioc2_dma;
5252 CONFIGPARMS cfg;
5253 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 int rc = 0;
5255 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005256 int i;
5257
5258 if (!ioc->ir_firmware)
5259 return 0;
5260
5261 /* Free the old page
5262 */
5263 kfree(ioc->raid_data.pIocPg2);
5264 ioc->raid_data.pIocPg2 = NULL;
5265 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
5267 /* Read IOCP2 header then the page.
5268 */
5269 header.PageVersion = 0;
5270 header.PageLength = 0;
5271 header.PageNumber = 2;
5272 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005273 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 cfg.physAddr = -1;
5275 cfg.pageAddr = 0;
5276 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5277 cfg.dir = 0;
5278 cfg.timeout = 0;
5279 if (mpt_config(ioc, &cfg) != 0)
5280 return -EFAULT;
5281
5282 if (header.PageLength == 0)
5283 return -EFAULT;
5284
5285 iocpage2sz = header.PageLength * 4;
5286 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5287 if (!pIoc2)
5288 return -ENOMEM;
5289
5290 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5291 cfg.physAddr = ioc2_dma;
5292 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005293 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
Eric Mooreb506ade2007-01-29 09:45:37 -07005295 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5296 if (!mem)
5297 goto out;
5298
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005300 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301
Eric Mooreb506ade2007-01-29 09:45:37 -07005302 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
Eric Mooreb506ade2007-01-29 09:45:37 -07005304 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5305 mpt_inactive_raid_volumes(ioc,
5306 pIoc2->RaidVolume[i].VolumeBus,
5307 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
Eric Mooreb506ade2007-01-29 09:45:37 -07005309 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5311
5312 return rc;
5313}
5314
Moore, Ericc972c702006-03-14 09:14:06 -07005315static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5317{
5318 IOCPage3_t *pIoc3;
5319 u8 *mem;
5320 CONFIGPARMS cfg;
5321 ConfigPageHeader_t header;
5322 dma_addr_t ioc3_dma;
5323 int iocpage3sz = 0;
5324
5325 /* Free the old page
5326 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005327 kfree(ioc->raid_data.pIocPg3);
5328 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329
5330 /* There is at least one physical disk.
5331 * Read and save IOC Page 3
5332 */
5333 header.PageVersion = 0;
5334 header.PageLength = 0;
5335 header.PageNumber = 3;
5336 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005337 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 cfg.physAddr = -1;
5339 cfg.pageAddr = 0;
5340 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5341 cfg.dir = 0;
5342 cfg.timeout = 0;
5343 if (mpt_config(ioc, &cfg) != 0)
5344 return 0;
5345
5346 if (header.PageLength == 0)
5347 return 0;
5348
5349 /* Read Header good, alloc memory
5350 */
5351 iocpage3sz = header.PageLength * 4;
5352 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5353 if (!pIoc3)
5354 return 0;
5355
5356 /* Read the Page and save the data
5357 * into malloc'd memory.
5358 */
5359 cfg.physAddr = ioc3_dma;
5360 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5361 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005362 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 if (mem) {
5364 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005365 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 }
5367 }
5368
5369 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5370
5371 return 0;
5372}
5373
5374static void
5375mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5376{
5377 IOCPage4_t *pIoc4;
5378 CONFIGPARMS cfg;
5379 ConfigPageHeader_t header;
5380 dma_addr_t ioc4_dma;
5381 int iocpage4sz;
5382
5383 /* Read and save IOC Page 4
5384 */
5385 header.PageVersion = 0;
5386 header.PageLength = 0;
5387 header.PageNumber = 4;
5388 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005389 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 cfg.physAddr = -1;
5391 cfg.pageAddr = 0;
5392 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5393 cfg.dir = 0;
5394 cfg.timeout = 0;
5395 if (mpt_config(ioc, &cfg) != 0)
5396 return;
5397
5398 if (header.PageLength == 0)
5399 return;
5400
5401 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5402 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5403 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5404 if (!pIoc4)
5405 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005406 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 } else {
5408 ioc4_dma = ioc->spi_data.IocPg4_dma;
5409 iocpage4sz = ioc->spi_data.IocPg4Sz;
5410 }
5411
5412 /* Read the Page into dma memory.
5413 */
5414 cfg.physAddr = ioc4_dma;
5415 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5416 if (mpt_config(ioc, &cfg) == 0) {
5417 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5418 ioc->spi_data.IocPg4_dma = ioc4_dma;
5419 ioc->spi_data.IocPg4Sz = iocpage4sz;
5420 } else {
5421 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5422 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005423 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 }
5425}
5426
5427static void
5428mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5429{
5430 IOCPage1_t *pIoc1;
5431 CONFIGPARMS cfg;
5432 ConfigPageHeader_t header;
5433 dma_addr_t ioc1_dma;
5434 int iocpage1sz = 0;
5435 u32 tmp;
5436
5437 /* Check the Coalescing Timeout in IOC Page 1
5438 */
5439 header.PageVersion = 0;
5440 header.PageLength = 0;
5441 header.PageNumber = 1;
5442 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005443 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 cfg.physAddr = -1;
5445 cfg.pageAddr = 0;
5446 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5447 cfg.dir = 0;
5448 cfg.timeout = 0;
5449 if (mpt_config(ioc, &cfg) != 0)
5450 return;
5451
5452 if (header.PageLength == 0)
5453 return;
5454
5455 /* Read Header good, alloc memory
5456 */
5457 iocpage1sz = header.PageLength * 4;
5458 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5459 if (!pIoc1)
5460 return;
5461
5462 /* Read the Page and check coalescing timeout
5463 */
5464 cfg.physAddr = ioc1_dma;
5465 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5466 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305467
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5469 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5470 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5471
Prakash, Sathya436ace72007-07-24 15:42:08 +05305472 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 ioc->name, tmp));
5474
5475 if (tmp > MPT_COALESCING_TIMEOUT) {
5476 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5477
5478 /* Write NVRAM and current
5479 */
5480 cfg.dir = 1;
5481 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5482 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305483 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 ioc->name, MPT_COALESCING_TIMEOUT));
5485
5486 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5487 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305488 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5489 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 ioc->name, MPT_COALESCING_TIMEOUT));
5491 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305492 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5493 "Reset NVRAM Coalescing Timeout Failed\n",
5494 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 }
5496
5497 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305498 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5499 "Reset of Current Coalescing Timeout Failed!\n",
5500 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 }
5502 }
5503
5504 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305505 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 }
5507 }
5508
5509 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5510
5511 return;
5512}
5513
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305514static void
5515mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5516{
5517 CONFIGPARMS cfg;
5518 ConfigPageHeader_t hdr;
5519 dma_addr_t buf_dma;
5520 ManufacturingPage0_t *pbuf = NULL;
5521
5522 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5523 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5524
5525 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5526 cfg.cfghdr.hdr = &hdr;
5527 cfg.physAddr = -1;
5528 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5529 cfg.timeout = 10;
5530
5531 if (mpt_config(ioc, &cfg) != 0)
5532 goto out;
5533
5534 if (!cfg.cfghdr.hdr->PageLength)
5535 goto out;
5536
5537 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5538 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5539 if (!pbuf)
5540 goto out;
5541
5542 cfg.physAddr = buf_dma;
5543
5544 if (mpt_config(ioc, &cfg) != 0)
5545 goto out;
5546
5547 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5548 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5549 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5550
5551 out:
5552
5553 if (pbuf)
5554 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5555}
5556
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005558/**
5559 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 * @ioc: Pointer to MPT_ADAPTER structure
5561 * @EvSwitch: Event switch flags
5562 */
5563static int
5564SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5565{
5566 EventNotification_t *evnp;
5567
5568 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5569 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305570 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 ioc->name));
5572 return 0;
5573 }
5574 memset(evnp, 0, sizeof(*evnp));
5575
Prakash, Sathya436ace72007-07-24 15:42:08 +05305576 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
5578 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5579 evnp->ChainOffset = 0;
5580 evnp->MsgFlags = 0;
5581 evnp->Switch = EvSwitch;
5582
5583 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5584
5585 return 0;
5586}
5587
5588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5589/**
5590 * SendEventAck - Send EventAck request to MPT adapter.
5591 * @ioc: Pointer to MPT_ADAPTER structure
5592 * @evnp: Pointer to original EventNotification request
5593 */
5594static int
5595SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5596{
5597 EventAck_t *pAck;
5598
5599 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305600 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005601 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 return -1;
5603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604
Prakash, Sathya436ace72007-07-24 15:42:08 +05305605 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
5607 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5608 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005609 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005611 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 pAck->Event = evnp->Event;
5613 pAck->EventContext = evnp->EventContext;
5614
5615 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5616
5617 return 0;
5618}
5619
5620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5621/**
5622 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005623 * @ioc: Pointer to an adapter structure
5624 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 * action, page address, direction, physical address
5626 * and pointer to a configuration page header
5627 * Page header is updated.
5628 *
5629 * Returns 0 for success
5630 * -EPERM if not allowed due to ISR context
5631 * -EAGAIN if no msg frames currently available
5632 * -EFAULT for non-successful reply or no reply (timeout)
5633 */
5634int
5635mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5636{
5637 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005638 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 MPT_FRAME_HDR *mf;
5640 unsigned long flags;
5641 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005642 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 int in_isr;
5644
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005645 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 * to be in ISR context, because that is fatal!
5647 */
5648 in_isr = in_interrupt();
5649 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305650 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 ioc->name));
5652 return -EPERM;
5653 }
5654
5655 /* Get and Populate a free Frame
5656 */
5657 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305658 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 ioc->name));
5660 return -EAGAIN;
5661 }
5662 pReq = (Config_t *)mf;
5663 pReq->Action = pCfg->action;
5664 pReq->Reserved = 0;
5665 pReq->ChainOffset = 0;
5666 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005667
5668 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 pReq->ExtPageLength = 0;
5670 pReq->ExtPageType = 0;
5671 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005672
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 for (ii=0; ii < 8; ii++)
5674 pReq->Reserved2[ii] = 0;
5675
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005676 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5677 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5678 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5679 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5680
5681 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5682 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5683 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5684 pReq->ExtPageType = pExtHdr->ExtPageType;
5685 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5686
5687 /* Page Length must be treated as a reserved field for the extended header. */
5688 pReq->Header.PageLength = 0;
5689 }
5690
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5692
5693 /* Add a SGE to the config request.
5694 */
5695 if (pCfg->dir)
5696 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5697 else
5698 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5699
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005700 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5701 flagsLength |= pExtHdr->ExtPageLength * 4;
5702
Prakash, Sathya436ace72007-07-24 15:42:08 +05305703 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 +02005704 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5705 }
5706 else {
5707 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5708
Prakash, Sathya436ace72007-07-24 15:42:08 +05305709 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 +02005710 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712
5713 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5714
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 /* Append pCfg pointer to end of mf
5716 */
5717 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5718
5719 /* Initalize the timer
5720 */
5721 init_timer(&pCfg->timer);
5722 pCfg->timer.data = (unsigned long) ioc;
5723 pCfg->timer.function = mpt_timer_expired;
5724 pCfg->wait_done = 0;
5725
5726 /* Set the timer; ensure 10 second minimum */
5727 if (pCfg->timeout < 10)
5728 pCfg->timer.expires = jiffies + HZ*10;
5729 else
5730 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5731
5732 /* Add to end of Q, set timer and then issue this command */
5733 spin_lock_irqsave(&ioc->FreeQlock, flags);
5734 list_add_tail(&pCfg->linkage, &ioc->configQ);
5735 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5736
5737 add_timer(&pCfg->timer);
5738 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5739 wait_event(mpt_waitq, pCfg->wait_done);
5740
5741 /* mf has been freed - do not access */
5742
5743 rc = pCfg->status;
5744
5745 return rc;
5746}
5747
5748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005749/**
5750 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 * Used only internal config functionality.
5752 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5753 */
5754static void
5755mpt_timer_expired(unsigned long data)
5756{
5757 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5758
Prakash, Sathya436ace72007-07-24 15:42:08 +05305759 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
5761 /* Perform a FW reload */
5762 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5763 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5764
5765 /* No more processing.
5766 * Hard reset clean-up will wake up
5767 * process and free all resources.
5768 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305769 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
5771 return;
5772}
5773
5774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005775/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 * mpt_ioc_reset - Base cleanup for hard reset
5777 * @ioc: Pointer to the adapter structure
5778 * @reset_phase: Indicates pre- or post-reset functionality
5779 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005780 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 */
5782static int
5783mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5784{
5785 CONFIGPARMS *pCfg;
5786 unsigned long flags;
5787
Prakash, Sathya436ace72007-07-24 15:42:08 +05305788 dprintk(ioc, printk(KERN_DEBUG MYNAM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 ": IOC %s_reset routed to MPT base driver!\n",
5790 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5791 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
5792
5793 if (reset_phase == MPT_IOC_SETUP_RESET) {
5794 ;
5795 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5796 /* If the internal config Q is not empty -
5797 * delete timer. MF resources will be freed when
5798 * the FIFO's are primed.
5799 */
5800 spin_lock_irqsave(&ioc->FreeQlock, flags);
5801 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5802 del_timer(&pCfg->timer);
5803 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5804
5805 } else {
5806 CONFIGPARMS *pNext;
5807
5808 /* Search the configQ for internal commands.
5809 * Flush the Q, and wake up all suspended threads.
5810 */
5811 spin_lock_irqsave(&ioc->FreeQlock, flags);
5812 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5813 list_del(&pCfg->linkage);
5814
5815 pCfg->status = MPT_CONFIG_ERROR;
5816 pCfg->wait_done = 1;
5817 wake_up(&mpt_waitq);
5818 }
5819 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5820 }
5821
5822 return 1; /* currently means nothing really */
5823}
5824
5825
5826#ifdef CONFIG_PROC_FS /* { */
5827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5828/*
5829 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5830 */
5831/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005832/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5834 *
5835 * Returns 0 for success, non-zero for failure.
5836 */
5837static int
5838procmpt_create(void)
5839{
5840 struct proc_dir_entry *ent;
5841
5842 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5843 if (mpt_proc_root_dir == NULL)
5844 return -ENOTDIR;
5845
5846 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5847 if (ent)
5848 ent->read_proc = procmpt_summary_read;
5849
5850 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5851 if (ent)
5852 ent->read_proc = procmpt_version_read;
5853
5854 return 0;
5855}
5856
5857/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005858/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5860 *
5861 * Returns 0 for success, non-zero for failure.
5862 */
5863static void
5864procmpt_destroy(void)
5865{
5866 remove_proc_entry("version", mpt_proc_root_dir);
5867 remove_proc_entry("summary", mpt_proc_root_dir);
5868 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5869}
5870
5871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005872/**
5873 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874 * @buf: Pointer to area to write information
5875 * @start: Pointer to start pointer
5876 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005877 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 * @eof: Pointer to EOF integer
5879 * @data: Pointer
5880 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005881 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 * Returns number of characters written to process performing the read.
5883 */
5884static int
5885procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5886{
5887 MPT_ADAPTER *ioc;
5888 char *out = buf;
5889 int len;
5890
5891 if (data) {
5892 int more = 0;
5893
5894 ioc = data;
5895 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5896
5897 out += more;
5898 } else {
5899 list_for_each_entry(ioc, &ioc_list, list) {
5900 int more = 0;
5901
5902 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5903
5904 out += more;
5905 if ((out-buf) >= request)
5906 break;
5907 }
5908 }
5909
5910 len = out - buf;
5911
5912 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5913}
5914
5915/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005916/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 * procmpt_version_read - Handle read request from /proc/mpt/version.
5918 * @buf: Pointer to area to write information
5919 * @start: Pointer to start pointer
5920 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005921 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 * @eof: Pointer to EOF integer
5923 * @data: Pointer
5924 *
5925 * Returns number of characters written to process performing the read.
5926 */
5927static int
5928procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5929{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305930 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005931 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 char *drvname;
5933 int len;
5934
5935 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5936 len += sprintf(buf+len, " Fusion MPT base driver\n");
5937
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005938 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305939 for (cb_idx=MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305941 if (MptCallbacks[cb_idx]) {
5942 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005943 case MPTSPI_DRIVER:
5944 if (!scsi++) drvname = "SPI host";
5945 break;
5946 case MPTFC_DRIVER:
5947 if (!fc++) drvname = "FC host";
5948 break;
5949 case MPTSAS_DRIVER:
5950 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 break;
5952 case MPTLAN_DRIVER:
5953 if (!lan++) drvname = "LAN";
5954 break;
5955 case MPTSTM_DRIVER:
5956 if (!targ++) drvname = "SCSI target";
5957 break;
5958 case MPTCTL_DRIVER:
5959 if (!ctl++) drvname = "ioctl";
5960 break;
5961 }
5962
5963 if (drvname)
5964 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5965 }
5966 }
5967
5968 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5969}
5970
5971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005972/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5974 * @buf: Pointer to area to write information
5975 * @start: Pointer to start pointer
5976 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005977 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 * @eof: Pointer to EOF integer
5979 * @data: Pointer
5980 *
5981 * Returns number of characters written to process performing the read.
5982 */
5983static int
5984procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5985{
5986 MPT_ADAPTER *ioc = data;
5987 int len;
5988 char expVer[32];
5989 int sz;
5990 int p;
5991
5992 mpt_get_fw_exp_ver(expVer, ioc);
5993
5994 len = sprintf(buf, "%s:", ioc->name);
5995 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5996 len += sprintf(buf+len, " (f/w download boot flag set)");
5997// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5998// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5999
6000 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6001 ioc->facts.ProductID,
6002 ioc->prod_name);
6003 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6004 if (ioc->facts.FWImageSize)
6005 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6006 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6007 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6008 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6009
6010 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6011 ioc->facts.CurrentHostMfaHighAddr);
6012 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6013 ioc->facts.CurrentSenseBufferHighAddr);
6014
6015 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6016 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6017
6018 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6019 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6020 /*
6021 * Rounding UP to nearest 4-kB boundary here...
6022 */
6023 sz = (ioc->req_sz * ioc->req_depth) + 128;
6024 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6025 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6026 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6027 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6028 4*ioc->facts.RequestFrameSize,
6029 ioc->facts.GlobalCredits);
6030
6031 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6032 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6033 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6034 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6035 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6036 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6037 ioc->facts.CurReplyFrameSize,
6038 ioc->facts.ReplyQueueDepth);
6039
6040 len += sprintf(buf+len, " MaxDevices = %d\n",
6041 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6042 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6043
6044 /* per-port info */
6045 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6046 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6047 p+1,
6048 ioc->facts.NumberOfPorts);
6049 if (ioc->bus_type == FC) {
6050 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6051 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6052 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6053 a[5], a[4], a[3], a[2], a[1], a[0]);
6054 }
6055 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6056 ioc->fc_port_page0[p].WWNN.High,
6057 ioc->fc_port_page0[p].WWNN.Low,
6058 ioc->fc_port_page0[p].WWPN.High,
6059 ioc->fc_port_page0[p].WWPN.Low);
6060 }
6061 }
6062
6063 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6064}
6065
6066#endif /* CONFIG_PROC_FS } */
6067
6068/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6069static void
6070mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6071{
6072 buf[0] ='\0';
6073 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6074 sprintf(buf, " (Exp %02d%02d)",
6075 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6076 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6077
6078 /* insider hack! */
6079 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6080 strcat(buf, " [MDBG]");
6081 }
6082}
6083
6084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6085/**
6086 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6087 * @ioc: Pointer to MPT_ADAPTER structure
6088 * @buffer: Pointer to buffer where IOC summary info should be written
6089 * @size: Pointer to number of bytes we wrote (set by this routine)
6090 * @len: Offset at which to start writing in buffer
6091 * @showlan: Display LAN stuff?
6092 *
6093 * This routine writes (english readable) ASCII text, which represents
6094 * a summary of IOC information, to a buffer.
6095 */
6096void
6097mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6098{
6099 char expVer[32];
6100 int y;
6101
6102 mpt_get_fw_exp_ver(expVer, ioc);
6103
6104 /*
6105 * Shorter summary of attached ioc's...
6106 */
6107 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6108 ioc->name,
6109 ioc->prod_name,
6110 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6111 ioc->facts.FWVersion.Word,
6112 expVer,
6113 ioc->facts.NumberOfPorts,
6114 ioc->req_depth);
6115
6116 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6117 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6118 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6119 a[5], a[4], a[3], a[2], a[1], a[0]);
6120 }
6121
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
6124 if (!ioc->active)
6125 y += sprintf(buffer+len+y, " (disabled)");
6126
6127 y += sprintf(buffer+len+y, "\n");
6128
6129 *size = y;
6130}
6131
6132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6133/*
6134 * Reset Handling
6135 */
6136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6137/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006138 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 * @ioc: Pointer to MPT_ADAPTER structure
6140 * @sleepFlag: Indicates if sleep or schedule must be called.
6141 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006142 * Issues SCSI Task Management call based on input arg values.
6143 * If TaskMgmt fails, returns associated SCSI request.
6144 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6146 * or a non-interrupt thread. In the former, must not call schedule().
6147 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006148 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 * FW reload/initialization failed.
6150 *
6151 * Returns 0 for SUCCESS or -1 if FAILED.
6152 */
6153int
6154mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6155{
6156 int rc;
6157 unsigned long flags;
6158
Prakash, Sathya436ace72007-07-24 15:42:08 +05306159 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160#ifdef MFCNT
6161 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6162 printk("MF count 0x%x !\n", ioc->mfcnt);
6163#endif
6164
6165 /* Reset the adapter. Prevent more than 1 call to
6166 * mpt_do_ioc_recovery at any instant in time.
6167 */
6168 spin_lock_irqsave(&ioc->diagLock, flags);
6169 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6170 spin_unlock_irqrestore(&ioc->diagLock, flags);
6171 return 0;
6172 } else {
6173 ioc->diagPending = 1;
6174 }
6175 spin_unlock_irqrestore(&ioc->diagLock, flags);
6176
6177 /* FIXME: If do_ioc_recovery fails, repeat....
6178 */
6179
6180 /* The SCSI driver needs to adjust timeouts on all current
6181 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006182 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183 * For all other protocol drivers, this is a no-op.
6184 */
6185 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306186 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 int r = 0;
6188
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306189 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6190 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306191 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306192 ioc->name, cb_idx));
6193 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306195 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306196 ioc->name, ioc->alt_ioc->name, cb_idx));
6197 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 }
6199 }
6200 }
6201 }
6202
6203 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
6204 printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
6205 rc, ioc->name);
6206 }
6207 ioc->reload_fw = 0;
6208 if (ioc->alt_ioc)
6209 ioc->alt_ioc->reload_fw = 0;
6210
6211 spin_lock_irqsave(&ioc->diagLock, flags);
6212 ioc->diagPending = 0;
6213 if (ioc->alt_ioc)
6214 ioc->alt_ioc->diagPending = 0;
6215 spin_unlock_irqrestore(&ioc->diagLock, flags);
6216
Prakash, Sathya436ace72007-07-24 15:42:08 +05306217 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218
6219 return rc;
6220}
6221
6222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006223static void
6224EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225{
Eric Moore509e5e52006-04-26 13:22:37 -06006226 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
6228 switch(event) {
6229 case MPI_EVENT_NONE:
6230 ds = "None";
6231 break;
6232 case MPI_EVENT_LOG_DATA:
6233 ds = "Log Data";
6234 break;
6235 case MPI_EVENT_STATE_CHANGE:
6236 ds = "State Change";
6237 break;
6238 case MPI_EVENT_UNIT_ATTENTION:
6239 ds = "Unit Attention";
6240 break;
6241 case MPI_EVENT_IOC_BUS_RESET:
6242 ds = "IOC Bus Reset";
6243 break;
6244 case MPI_EVENT_EXT_BUS_RESET:
6245 ds = "External Bus Reset";
6246 break;
6247 case MPI_EVENT_RESCAN:
6248 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 break;
6250 case MPI_EVENT_LINK_STATUS_CHANGE:
6251 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6252 ds = "Link Status(FAILURE) Change";
6253 else
6254 ds = "Link Status(ACTIVE) Change";
6255 break;
6256 case MPI_EVENT_LOOP_STATE_CHANGE:
6257 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6258 ds = "Loop State(LIP) Change";
6259 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006260 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 else
Eric Moore509e5e52006-04-26 13:22:37 -06006262 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 break;
6264 case MPI_EVENT_LOGOUT:
6265 ds = "Logout";
6266 break;
6267 case MPI_EVENT_EVENT_CHANGE:
6268 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006269 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006271 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 break;
6273 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006274 {
6275 u8 ReasonCode = (u8)(evData0 >> 16);
6276 switch (ReasonCode) {
6277 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6278 ds = "Integrated Raid: Volume Created";
6279 break;
6280 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6281 ds = "Integrated Raid: Volume Deleted";
6282 break;
6283 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6284 ds = "Integrated Raid: Volume Settings Changed";
6285 break;
6286 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6287 ds = "Integrated Raid: Volume Status Changed";
6288 break;
6289 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6290 ds = "Integrated Raid: Volume Physdisk Changed";
6291 break;
6292 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6293 ds = "Integrated Raid: Physdisk Created";
6294 break;
6295 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6296 ds = "Integrated Raid: Physdisk Deleted";
6297 break;
6298 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6299 ds = "Integrated Raid: Physdisk Settings Changed";
6300 break;
6301 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6302 ds = "Integrated Raid: Physdisk Status Changed";
6303 break;
6304 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6305 ds = "Integrated Raid: Domain Validation Needed";
6306 break;
6307 case MPI_EVENT_RAID_RC_SMART_DATA :
6308 ds = "Integrated Raid; Smart Data";
6309 break;
6310 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6311 ds = "Integrated Raid: Replace Action Started";
6312 break;
6313 default:
6314 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006316 }
6317 break;
6318 }
6319 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6320 ds = "SCSI Device Status Change";
6321 break;
6322 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6323 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006324 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006325 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006326 u8 ReasonCode = (u8)(evData0 >> 16);
6327 switch (ReasonCode) {
6328 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006329 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006330 "SAS Device Status Change: Added: "
6331 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006332 break;
6333 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006334 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006335 "SAS Device Status Change: Deleted: "
6336 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006337 break;
6338 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006339 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006340 "SAS Device Status Change: SMART Data: "
6341 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006342 break;
6343 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006344 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006345 "SAS Device Status Change: No Persistancy: "
6346 "id=%d channel=%d", id, channel);
6347 break;
6348 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6349 snprintf(evStr, EVENT_DESCR_STR_SZ,
6350 "SAS Device Status Change: Unsupported Device "
6351 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006352 break;
6353 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6354 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006355 "SAS Device Status Change: Internal Device "
6356 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006357 break;
6358 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6359 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006360 "SAS Device Status Change: Internal Task "
6361 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006362 break;
6363 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6364 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006365 "SAS Device Status Change: Internal Abort "
6366 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006367 break;
6368 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6369 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006370 "SAS Device Status Change: Internal Clear "
6371 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006372 break;
6373 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6374 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006375 "SAS Device Status Change: Internal Query "
6376 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006377 break;
6378 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006379 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006380 "SAS Device Status Change: Unknown: "
6381 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006382 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006383 }
6384 break;
6385 }
6386 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6387 ds = "Bus Timer Expired";
6388 break;
6389 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006390 {
6391 u16 curr_depth = (u16)(evData0 >> 16);
6392 u8 channel = (u8)(evData0 >> 8);
6393 u8 id = (u8)(evData0);
6394
6395 snprintf(evStr, EVENT_DESCR_STR_SZ,
6396 "Queue Full: channel=%d id=%d depth=%d",
6397 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006398 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006399 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006400 case MPI_EVENT_SAS_SES:
6401 ds = "SAS SES Event";
6402 break;
6403 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6404 ds = "Persistent Table Full";
6405 break;
6406 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006407 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006408 u8 LinkRates = (u8)(evData0 >> 8);
6409 u8 PhyNumber = (u8)(evData0);
6410 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6411 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6412 switch (LinkRates) {
6413 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006414 snprintf(evStr, EVENT_DESCR_STR_SZ,
6415 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006416 " Rate Unknown",PhyNumber);
6417 break;
6418 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006419 snprintf(evStr, EVENT_DESCR_STR_SZ,
6420 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006421 " Phy Disabled",PhyNumber);
6422 break;
6423 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006424 snprintf(evStr, EVENT_DESCR_STR_SZ,
6425 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006426 " Failed Speed Nego",PhyNumber);
6427 break;
6428 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006429 snprintf(evStr, EVENT_DESCR_STR_SZ,
6430 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006431 " Sata OOB Completed",PhyNumber);
6432 break;
6433 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006434 snprintf(evStr, EVENT_DESCR_STR_SZ,
6435 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006436 " Rate 1.5 Gbps",PhyNumber);
6437 break;
6438 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006439 snprintf(evStr, EVENT_DESCR_STR_SZ,
6440 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006441 " Rate 3.0 Gpbs",PhyNumber);
6442 break;
6443 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006444 snprintf(evStr, EVENT_DESCR_STR_SZ,
6445 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006446 break;
6447 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006448 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006449 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006450 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6451 ds = "SAS Discovery Error";
6452 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006453 case MPI_EVENT_IR_RESYNC_UPDATE:
6454 {
6455 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006456 snprintf(evStr, EVENT_DESCR_STR_SZ,
6457 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006458 break;
6459 }
6460 case MPI_EVENT_IR2:
6461 {
6462 u8 ReasonCode = (u8)(evData0 >> 16);
6463 switch (ReasonCode) {
6464 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6465 ds = "IR2: LD State Changed";
6466 break;
6467 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6468 ds = "IR2: PD State Changed";
6469 break;
6470 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6471 ds = "IR2: Bad Block Table Full";
6472 break;
6473 case MPI_EVENT_IR2_RC_PD_INSERTED:
6474 ds = "IR2: PD Inserted";
6475 break;
6476 case MPI_EVENT_IR2_RC_PD_REMOVED:
6477 ds = "IR2: PD Removed";
6478 break;
6479 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6480 ds = "IR2: Foreign CFG Detected";
6481 break;
6482 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6483 ds = "IR2: Rebuild Medium Error";
6484 break;
6485 default:
6486 ds = "IR2";
6487 break;
6488 }
6489 break;
6490 }
6491 case MPI_EVENT_SAS_DISCOVERY:
6492 {
6493 if (evData0)
6494 ds = "SAS Discovery: Start";
6495 else
6496 ds = "SAS Discovery: Stop";
6497 break;
6498 }
6499 case MPI_EVENT_LOG_ENTRY_ADDED:
6500 ds = "SAS Log Entry Added";
6501 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006502
Eric Moorec6c727a2007-01-29 09:44:54 -07006503 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6504 {
6505 u8 phy_num = (u8)(evData0);
6506 u8 port_num = (u8)(evData0 >> 8);
6507 u8 port_width = (u8)(evData0 >> 16);
6508 u8 primative = (u8)(evData0 >> 24);
6509 snprintf(evStr, EVENT_DESCR_STR_SZ,
6510 "SAS Broadcase Primative: phy=%d port=%d "
6511 "width=%d primative=0x%02x",
6512 phy_num, port_num, port_width, primative);
6513 break;
6514 }
6515
6516 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6517 {
6518 u8 reason = (u8)(evData0);
6519 u8 port_num = (u8)(evData0 >> 8);
6520 u16 handle = le16_to_cpu(evData0 >> 16);
6521
6522 snprintf(evStr, EVENT_DESCR_STR_SZ,
6523 "SAS Initiator Device Status Change: reason=0x%02x "
6524 "port=%d handle=0x%04x",
6525 reason, port_num, handle);
6526 break;
6527 }
6528
6529 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6530 {
6531 u8 max_init = (u8)(evData0);
6532 u8 current_init = (u8)(evData0 >> 8);
6533
6534 snprintf(evStr, EVENT_DESCR_STR_SZ,
6535 "SAS Initiator Device Table Overflow: max initiators=%02d "
6536 "current initators=%02d",
6537 max_init, current_init);
6538 break;
6539 }
6540 case MPI_EVENT_SAS_SMP_ERROR:
6541 {
6542 u8 status = (u8)(evData0);
6543 u8 port_num = (u8)(evData0 >> 8);
6544 u8 result = (u8)(evData0 >> 16);
6545
6546 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6547 snprintf(evStr, EVENT_DESCR_STR_SZ,
6548 "SAS SMP Error: port=%d result=0x%02x",
6549 port_num, result);
6550 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6551 snprintf(evStr, EVENT_DESCR_STR_SZ,
6552 "SAS SMP Error: port=%d : CRC Error",
6553 port_num);
6554 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6555 snprintf(evStr, EVENT_DESCR_STR_SZ,
6556 "SAS SMP Error: port=%d : Timeout",
6557 port_num);
6558 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6559 snprintf(evStr, EVENT_DESCR_STR_SZ,
6560 "SAS SMP Error: port=%d : No Destination",
6561 port_num);
6562 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6563 snprintf(evStr, EVENT_DESCR_STR_SZ,
6564 "SAS SMP Error: port=%d : Bad Destination",
6565 port_num);
6566 else
6567 snprintf(evStr, EVENT_DESCR_STR_SZ,
6568 "SAS SMP Error: port=%d : status=0x%02x",
6569 port_num, status);
6570 break;
6571 }
6572
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 /*
6574 * MPT base "custom" events may be added here...
6575 */
6576 default:
6577 ds = "Unknown";
6578 break;
6579 }
Eric Moore509e5e52006-04-26 13:22:37 -06006580 if (ds)
6581 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582}
6583
6584/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006585/**
6586 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006587 * @ioc: Pointer to MPT_ADAPTER structure
6588 * @pEventReply: Pointer to EventNotification reply frame
6589 * @evHandlers: Pointer to integer, number of event handlers
6590 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006591 * Routes a received EventNotificationReply to all currently registered
6592 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593 * Returns sum of event handlers return values.
6594 */
6595static int
6596ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6597{
6598 u16 evDataLen;
6599 u32 evData0 = 0;
6600// u32 evCtx;
6601 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306602 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603 int r = 0;
6604 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006605 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 u8 event;
6607
6608 /*
6609 * Do platform normalization of values
6610 */
6611 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6612// evCtx = le32_to_cpu(pEventReply->EventContext);
6613 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6614 if (evDataLen) {
6615 evData0 = le32_to_cpu(pEventReply->Data[0]);
6616 }
6617
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006618 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306619 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006621 event,
6622 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623
Prakash, Sathya436ace72007-07-24 15:42:08 +05306624#ifdef CONFIG_FUSION_LOGGING
6625 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
6626 ": Event data:\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306628 devtverboseprintk(ioc, printk(" %08x",
6629 le32_to_cpu(pEventReply->Data[ii])));
6630 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631#endif
6632
6633 /*
6634 * Do general / base driver event processing
6635 */
6636 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6638 if (evDataLen) {
6639 u8 evState = evData0 & 0xFF;
6640
6641 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6642
6643 /* Update EventState field in cached IocFacts */
6644 if (ioc->facts.Function) {
6645 ioc->facts.EventState = evState;
6646 }
6647 }
6648 break;
Moore, Ericece50912006-01-16 18:53:19 -07006649 case MPI_EVENT_INTEGRATED_RAID:
6650 mptbase_raid_process_event_data(ioc,
6651 (MpiEventDataRaid_t *)pEventReply->Data);
6652 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006653 default:
6654 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655 }
6656
6657 /*
6658 * Should this event be logged? Events are written sequentially.
6659 * When buffer is full, start again at the top.
6660 */
6661 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6662 int idx;
6663
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006664 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
6666 ioc->events[idx].event = event;
6667 ioc->events[idx].eventContext = ioc->eventContext;
6668
6669 for (ii = 0; ii < 2; ii++) {
6670 if (ii < evDataLen)
6671 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6672 else
6673 ioc->events[idx].data[ii] = 0;
6674 }
6675
6676 ioc->eventContext++;
6677 }
6678
6679
6680 /*
6681 * Call each currently registered protocol event handler.
6682 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306683 for (cb_idx=MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6684 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306685 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306686 ioc->name, cb_idx));
6687 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006688 handlers++;
6689 }
6690 }
6691 /* FIXME? Examine results here? */
6692
6693 /*
6694 * If needed, send (a single) EventAck.
6695 */
6696 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306697 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006698 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306700 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 ioc->name, ii));
6702 }
6703 }
6704
6705 *evHandlers = handlers;
6706 return r;
6707}
6708
6709/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006710/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6712 * @ioc: Pointer to MPT_ADAPTER structure
6713 * @log_info: U32 LogInfo reply word from the IOC
6714 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006715 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716 */
6717static void
6718mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6719{
Eric Moore7c431e52007-06-13 16:34:36 -06006720 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721
Eric Moore7c431e52007-06-13 16:34:36 -06006722 switch (log_info & 0xFF000000) {
6723 case MPI_IOCLOGINFO_FC_INIT_BASE:
6724 desc = "FCP Initiator";
6725 break;
6726 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6727 desc = "FCP Target";
6728 break;
6729 case MPI_IOCLOGINFO_FC_LAN_BASE:
6730 desc = "LAN";
6731 break;
6732 case MPI_IOCLOGINFO_FC_MSG_BASE:
6733 desc = "MPI Message Layer";
6734 break;
6735 case MPI_IOCLOGINFO_FC_LINK_BASE:
6736 desc = "FC Link";
6737 break;
6738 case MPI_IOCLOGINFO_FC_CTX_BASE:
6739 desc = "Context Manager";
6740 break;
6741 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6742 desc = "Invalid Field Offset";
6743 break;
6744 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6745 desc = "State Change Info";
6746 break;
6747 }
6748
6749 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6750 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751}
6752
6753/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006754/**
Moore, Eric335a9412006-01-17 17:06:23 -07006755 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006756 * @ioc: Pointer to MPT_ADAPTER structure
6757 * @mr: Pointer to MPT reply frame
6758 * @log_info: U32 LogInfo word from the IOC
6759 *
6760 * Refer to lsi/sp_log.h.
6761 */
6762static void
Moore, Eric335a9412006-01-17 17:06:23 -07006763mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764{
6765 u32 info = log_info & 0x00FF0000;
6766 char *desc = "unknown";
6767
6768 switch (info) {
6769 case 0x00010000:
6770 desc = "bug! MID not found";
6771 if (ioc->reload_fw == 0)
6772 ioc->reload_fw++;
6773 break;
6774
6775 case 0x00020000:
6776 desc = "Parity Error";
6777 break;
6778
6779 case 0x00030000:
6780 desc = "ASYNC Outbound Overrun";
6781 break;
6782
6783 case 0x00040000:
6784 desc = "SYNC Offset Error";
6785 break;
6786
6787 case 0x00050000:
6788 desc = "BM Change";
6789 break;
6790
6791 case 0x00060000:
6792 desc = "Msg In Overflow";
6793 break;
6794
6795 case 0x00070000:
6796 desc = "DMA Error";
6797 break;
6798
6799 case 0x00080000:
6800 desc = "Outbound DMA Overrun";
6801 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006802
Linus Torvalds1da177e2005-04-16 15:20:36 -07006803 case 0x00090000:
6804 desc = "Task Management";
6805 break;
6806
6807 case 0x000A0000:
6808 desc = "Device Problem";
6809 break;
6810
6811 case 0x000B0000:
6812 desc = "Invalid Phase Change";
6813 break;
6814
6815 case 0x000C0000:
6816 desc = "Untagged Table Size";
6817 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006818
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819 }
6820
6821 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6822}
6823
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006824/* strings for sas loginfo */
6825 static char *originator_str[] = {
6826 "IOP", /* 00h */
6827 "PL", /* 01h */
6828 "IR" /* 02h */
6829 };
6830 static char *iop_code_str[] = {
6831 NULL, /* 00h */
6832 "Invalid SAS Address", /* 01h */
6833 NULL, /* 02h */
6834 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006835 "Diag Message Error", /* 04h */
6836 "Task Terminated", /* 05h */
6837 "Enclosure Management", /* 06h */
6838 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006839 };
6840 static char *pl_code_str[] = {
6841 NULL, /* 00h */
6842 "Open Failure", /* 01h */
6843 "Invalid Scatter Gather List", /* 02h */
6844 "Wrong Relative Offset or Frame Length", /* 03h */
6845 "Frame Transfer Error", /* 04h */
6846 "Transmit Frame Connected Low", /* 05h */
6847 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6848 "SATA Read Log Receive Data Error", /* 07h */
6849 "SATA NCQ Fail All Commands After Error", /* 08h */
6850 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6851 "Receive Frame Invalid Message", /* 0Ah */
6852 "Receive Context Message Valid Error", /* 0Bh */
6853 "Receive Frame Current Frame Error", /* 0Ch */
6854 "SATA Link Down", /* 0Dh */
6855 "Discovery SATA Init W IOS", /* 0Eh */
6856 "Config Invalid Page", /* 0Fh */
6857 "Discovery SATA Init Timeout", /* 10h */
6858 "Reset", /* 11h */
6859 "Abort", /* 12h */
6860 "IO Not Yet Executed", /* 13h */
6861 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006862 "Persistent Reservation Out Not Affiliation "
6863 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006864 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006865 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006866 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006867 NULL, /* 19h */
6868 NULL, /* 1Ah */
6869 NULL, /* 1Bh */
6870 NULL, /* 1Ch */
6871 NULL, /* 1Dh */
6872 NULL, /* 1Eh */
6873 NULL, /* 1Fh */
6874 "Enclosure Management" /* 20h */
6875 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006876 static char *ir_code_str[] = {
6877 "Raid Action Error", /* 00h */
6878 NULL, /* 00h */
6879 NULL, /* 01h */
6880 NULL, /* 02h */
6881 NULL, /* 03h */
6882 NULL, /* 04h */
6883 NULL, /* 05h */
6884 NULL, /* 06h */
6885 NULL /* 07h */
6886 };
6887 static char *raid_sub_code_str[] = {
6888 NULL, /* 00h */
6889 "Volume Creation Failed: Data Passed too "
6890 "Large", /* 01h */
6891 "Volume Creation Failed: Duplicate Volumes "
6892 "Attempted", /* 02h */
6893 "Volume Creation Failed: Max Number "
6894 "Supported Volumes Exceeded", /* 03h */
6895 "Volume Creation Failed: DMA Error", /* 04h */
6896 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6897 "Volume Creation Failed: Error Reading "
6898 "MFG Page 4", /* 06h */
6899 "Volume Creation Failed: Creating Internal "
6900 "Structures", /* 07h */
6901 NULL, /* 08h */
6902 NULL, /* 09h */
6903 NULL, /* 0Ah */
6904 NULL, /* 0Bh */
6905 NULL, /* 0Ch */
6906 NULL, /* 0Dh */
6907 NULL, /* 0Eh */
6908 NULL, /* 0Fh */
6909 "Activation failed: Already Active Volume", /* 10h */
6910 "Activation failed: Unsupported Volume Type", /* 11h */
6911 "Activation failed: Too Many Active Volumes", /* 12h */
6912 "Activation failed: Volume ID in Use", /* 13h */
6913 "Activation failed: Reported Failure", /* 14h */
6914 "Activation failed: Importing a Volume", /* 15h */
6915 NULL, /* 16h */
6916 NULL, /* 17h */
6917 NULL, /* 18h */
6918 NULL, /* 19h */
6919 NULL, /* 1Ah */
6920 NULL, /* 1Bh */
6921 NULL, /* 1Ch */
6922 NULL, /* 1Dh */
6923 NULL, /* 1Eh */
6924 NULL, /* 1Fh */
6925 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6926 "Phys Disk failed: Data Passed too Large", /* 21h */
6927 "Phys Disk failed: DMA Error", /* 22h */
6928 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6929 "Phys Disk failed: Creating Phys Disk Config "
6930 "Page", /* 24h */
6931 NULL, /* 25h */
6932 NULL, /* 26h */
6933 NULL, /* 27h */
6934 NULL, /* 28h */
6935 NULL, /* 29h */
6936 NULL, /* 2Ah */
6937 NULL, /* 2Bh */
6938 NULL, /* 2Ch */
6939 NULL, /* 2Dh */
6940 NULL, /* 2Eh */
6941 NULL, /* 2Fh */
6942 "Compatibility Error: IR Disabled", /* 30h */
6943 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6944 "Compatibility Error: Device not Direct Access "
6945 "Device ", /* 32h */
6946 "Compatibility Error: Removable Device Found", /* 33h */
6947 "Compatibility Error: Device SCSI Version not "
6948 "2 or Higher", /* 34h */
6949 "Compatibility Error: SATA Device, 48 BIT LBA "
6950 "not Supported", /* 35h */
6951 "Compatibility Error: Device doesn't have "
6952 "512 Byte Block Sizes", /* 36h */
6953 "Compatibility Error: Volume Type Check Failed", /* 37h */
6954 "Compatibility Error: Volume Type is "
6955 "Unsupported by FW", /* 38h */
6956 "Compatibility Error: Disk Drive too Small for "
6957 "use in Volume", /* 39h */
6958 "Compatibility Error: Phys Disk for Create "
6959 "Volume not Found", /* 3Ah */
6960 "Compatibility Error: Too Many or too Few "
6961 "Disks for Volume Type", /* 3Bh */
6962 "Compatibility Error: Disk stripe Sizes "
6963 "Must be 64KB", /* 3Ch */
6964 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6965 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006966
6967/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006968/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006969 * mpt_sas_log_info - Log information returned from SAS IOC.
6970 * @ioc: Pointer to MPT_ADAPTER structure
6971 * @log_info: U32 LogInfo reply word from the IOC
6972 *
6973 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006974 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006975static void
6976mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6977{
6978union loginfo_type {
6979 u32 loginfo;
6980 struct {
6981 u32 subcode:16;
6982 u32 code:8;
6983 u32 originator:4;
6984 u32 bus_type:4;
6985 }dw;
6986};
6987 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006988 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006989 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006990 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006991
6992 sas_loginfo.loginfo = log_info;
6993 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6994 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6995 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006996
6997 originator_desc = originator_str[sas_loginfo.dw.originator];
6998
6999 switch (sas_loginfo.dw.originator) {
7000
7001 case 0: /* IOP */
7002 if (sas_loginfo.dw.code <
7003 sizeof(iop_code_str)/sizeof(char*))
7004 code_desc = iop_code_str[sas_loginfo.dw.code];
7005 break;
7006 case 1: /* PL */
7007 if (sas_loginfo.dw.code <
7008 sizeof(pl_code_str)/sizeof(char*))
7009 code_desc = pl_code_str[sas_loginfo.dw.code];
7010 break;
7011 case 2: /* IR */
7012 if (sas_loginfo.dw.code >=
7013 sizeof(ir_code_str)/sizeof(char*))
7014 break;
7015 code_desc = ir_code_str[sas_loginfo.dw.code];
7016 if (sas_loginfo.dw.subcode >=
7017 sizeof(raid_sub_code_str)/sizeof(char*))
7018 break;
7019 if (sas_loginfo.dw.code == 0)
7020 sub_code_desc =
7021 raid_sub_code_str[sas_loginfo.dw.subcode];
7022 break;
7023 default:
7024 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007025 }
7026
Eric Moorec6c727a2007-01-29 09:44:54 -07007027 if (sub_code_desc != NULL)
7028 printk(MYIOC_s_INFO_FMT
7029 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7030 " SubCode={%s}\n",
7031 ioc->name, log_info, originator_desc, code_desc,
7032 sub_code_desc);
7033 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007034 printk(MYIOC_s_INFO_FMT
7035 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7036 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007037 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007038 sas_loginfo.dw.subcode);
7039 else
7040 printk(MYIOC_s_INFO_FMT
7041 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7042 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007043 ioc->name, log_info, originator_desc,
7044 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007045}
7046
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007048/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007049 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7050 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007051 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007052 * @mf: Pointer to MPT request frame
7053 *
7054 * Refer to lsi/mpi.h.
7055 **/
7056static void
7057mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7058{
7059 Config_t *pReq = (Config_t *)mf;
7060 char extend_desc[EVENT_DESCR_STR_SZ];
7061 char *desc = NULL;
7062 u32 form;
7063 u8 page_type;
7064
7065 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7066 page_type = pReq->ExtPageType;
7067 else
7068 page_type = pReq->Header.PageType;
7069
7070 /*
7071 * ignore invalid page messages for GET_NEXT_HANDLE
7072 */
7073 form = le32_to_cpu(pReq->PageAddress);
7074 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7075 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7076 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7077 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7078 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7079 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7080 return;
7081 }
7082 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7083 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7084 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7085 return;
7086 }
7087
7088 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7089 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7090 page_type, pReq->Header.PageNumber, pReq->Action, form);
7091
7092 switch (ioc_status) {
7093
7094 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7095 desc = "Config Page Invalid Action";
7096 break;
7097
7098 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7099 desc = "Config Page Invalid Type";
7100 break;
7101
7102 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7103 desc = "Config Page Invalid Page";
7104 break;
7105
7106 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7107 desc = "Config Page Invalid Data";
7108 break;
7109
7110 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7111 desc = "Config Page No Defaults";
7112 break;
7113
7114 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7115 desc = "Config Page Can't Commit";
7116 break;
7117 }
7118
7119 if (!desc)
7120 return;
7121
7122 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
7123 ioc->name, ioc_status, desc, extend_desc);
7124}
7125
7126/**
7127 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007128 * @ioc: Pointer to MPT_ADAPTER structure
7129 * @ioc_status: U32 IOCStatus word from IOC
7130 * @mf: Pointer to MPT request frame
7131 *
7132 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007133 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007134static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007135mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136{
7137 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007138 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139
7140 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007141
7142/****************************************************************************/
7143/* Common IOCStatus values for all replies */
7144/****************************************************************************/
7145
Linus Torvalds1da177e2005-04-16 15:20:36 -07007146 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7147 desc = "Invalid Function";
7148 break;
7149
7150 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7151 desc = "Busy";
7152 break;
7153
7154 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7155 desc = "Invalid SGL";
7156 break;
7157
7158 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7159 desc = "Internal Error";
7160 break;
7161
7162 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7163 desc = "Reserved";
7164 break;
7165
7166 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7167 desc = "Insufficient Resources";
7168 break;
7169
7170 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7171 desc = "Invalid Field";
7172 break;
7173
7174 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7175 desc = "Invalid State";
7176 break;
7177
Eric Moorec6c727a2007-01-29 09:44:54 -07007178/****************************************************************************/
7179/* Config IOCStatus values */
7180/****************************************************************************/
7181
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7183 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7184 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7185 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7186 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7187 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007188 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189 break;
7190
Eric Moorec6c727a2007-01-29 09:44:54 -07007191/****************************************************************************/
7192/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7193/* */
7194/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7195/* */
7196/****************************************************************************/
7197
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007200 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7201 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7202 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7203 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007206 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007210 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211 break;
7212
Eric Moorec6c727a2007-01-29 09:44:54 -07007213/****************************************************************************/
7214/* SCSI Target values */
7215/****************************************************************************/
7216
7217 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7218 desc = "Target: Priority IO";
7219 break;
7220
7221 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7222 desc = "Target: Invalid Port";
7223 break;
7224
7225 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7226 desc = "Target Invalid IO Index:";
7227 break;
7228
7229 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7230 desc = "Target: Aborted";
7231 break;
7232
7233 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7234 desc = "Target: No Conn Retryable";
7235 break;
7236
7237 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7238 desc = "Target: No Connection";
7239 break;
7240
7241 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7242 desc = "Target: Transfer Count Mismatch";
7243 break;
7244
7245 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7246 desc = "Target: STS Data not Sent";
7247 break;
7248
7249 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7250 desc = "Target: Data Offset Error";
7251 break;
7252
7253 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7254 desc = "Target: Too Much Write Data";
7255 break;
7256
7257 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7258 desc = "Target: IU Too Short";
7259 break;
7260
7261 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7262 desc = "Target: ACK NAK Timeout";
7263 break;
7264
7265 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7266 desc = "Target: Nak Received";
7267 break;
7268
7269/****************************************************************************/
7270/* Fibre Channel Direct Access values */
7271/****************************************************************************/
7272
7273 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7274 desc = "FC: Aborted";
7275 break;
7276
7277 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7278 desc = "FC: RX ID Invalid";
7279 break;
7280
7281 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7282 desc = "FC: DID Invalid";
7283 break;
7284
7285 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7286 desc = "FC: Node Logged Out";
7287 break;
7288
7289 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7290 desc = "FC: Exchange Canceled";
7291 break;
7292
7293/****************************************************************************/
7294/* LAN values */
7295/****************************************************************************/
7296
7297 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7298 desc = "LAN: Device not Found";
7299 break;
7300
7301 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7302 desc = "LAN: Device Failure";
7303 break;
7304
7305 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7306 desc = "LAN: Transmit Error";
7307 break;
7308
7309 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7310 desc = "LAN: Transmit Aborted";
7311 break;
7312
7313 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7314 desc = "LAN: Receive Error";
7315 break;
7316
7317 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7318 desc = "LAN: Receive Aborted";
7319 break;
7320
7321 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7322 desc = "LAN: Partial Packet";
7323 break;
7324
7325 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7326 desc = "LAN: Canceled";
7327 break;
7328
7329/****************************************************************************/
7330/* Serial Attached SCSI values */
7331/****************************************************************************/
7332
7333 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7334 desc = "SAS: SMP Request Failed";
7335 break;
7336
7337 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7338 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007339 break;
7340
7341 default:
7342 desc = "Others";
7343 break;
7344 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007345
7346 if (!desc)
7347 return;
7348
7349 printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350}
7351
7352/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007353EXPORT_SYMBOL(mpt_attach);
7354EXPORT_SYMBOL(mpt_detach);
7355#ifdef CONFIG_PM
7356EXPORT_SYMBOL(mpt_resume);
7357EXPORT_SYMBOL(mpt_suspend);
7358#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007360EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361EXPORT_SYMBOL(mpt_register);
7362EXPORT_SYMBOL(mpt_deregister);
7363EXPORT_SYMBOL(mpt_event_register);
7364EXPORT_SYMBOL(mpt_event_deregister);
7365EXPORT_SYMBOL(mpt_reset_register);
7366EXPORT_SYMBOL(mpt_reset_deregister);
7367EXPORT_SYMBOL(mpt_device_driver_register);
7368EXPORT_SYMBOL(mpt_device_driver_deregister);
7369EXPORT_SYMBOL(mpt_get_msg_frame);
7370EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307371EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372EXPORT_SYMBOL(mpt_free_msg_frame);
7373EXPORT_SYMBOL(mpt_add_sge);
7374EXPORT_SYMBOL(mpt_send_handshake_request);
7375EXPORT_SYMBOL(mpt_verify_adapter);
7376EXPORT_SYMBOL(mpt_GetIocState);
7377EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378EXPORT_SYMBOL(mpt_HardResetHandler);
7379EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381EXPORT_SYMBOL(mpt_alloc_fw_memory);
7382EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007383EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007384EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007387/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 * fusion_init - Fusion MPT base driver initialization routine.
7389 *
7390 * Returns 0 for success, non-zero for failure.
7391 */
7392static int __init
7393fusion_init(void)
7394{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307395 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396
7397 show_mptmod_ver(my_NAME, my_VERSION);
7398 printk(KERN_INFO COPYRIGHT "\n");
7399
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307400 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7401 MptCallbacks[cb_idx] = NULL;
7402 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7403 MptEvHandlers[cb_idx] = NULL;
7404 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405 }
7406
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007407 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408 * EventNotification handling.
7409 */
7410 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7411
7412 /* Register for hard reset handling callbacks.
7413 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307414 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
7416#ifdef CONFIG_PROC_FS
7417 (void) procmpt_create();
7418#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007419 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420}
7421
7422/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007423/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007424 * fusion_exit - Perform driver unload cleanup.
7425 *
7426 * This routine frees all resources associated with each MPT adapter
7427 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7428 */
7429static void __exit
7430fusion_exit(void)
7431{
7432
Linus Torvalds1da177e2005-04-16 15:20:36 -07007433 mpt_reset_deregister(mpt_base_index);
7434
7435#ifdef CONFIG_PROC_FS
7436 procmpt_destroy();
7437#endif
7438}
7439
Linus Torvalds1da177e2005-04-16 15:20:36 -07007440module_init(fusion_init);
7441module_exit(fusion_exit);