blob: bfda731696f74a67966ac647ec52e6eca00d44ec [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05308 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600256/*
257 * Process turbo (context) reply...
258 */
259static void
260mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
261{
262 MPT_FRAME_HDR *mf = NULL;
263 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264 u16 req_idx = 0;
265 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600266
Prakash, Sathya436ace72007-07-24 15:42:08 +0530267 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600268 ioc->name, pa));
269
270 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
271 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
272 req_idx = pa & 0x0000FFFF;
273 cb_idx = (pa & 0x00FF0000) >> 16;
274 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
275 break;
276 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530277 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600278 /*
279 * Blind set of mf to NULL here was fatal
280 * after lan_reply says "freeme"
281 * Fix sort of combined with an optimization here;
282 * added explicit check for case where lan_reply
283 * was just returning 1 and doing nothing else.
284 * For this case skip the callback, but set up
285 * proper mf value first here:-)
286 */
287 if ((pa & 0x58000000) == 0x58000000) {
288 req_idx = pa & 0x0000FFFF;
289 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
290 mpt_free_msg_frame(ioc, mf);
291 mb();
292 return;
293 break;
294 }
295 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
296 break;
297 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530298 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600299 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
300 break;
301 default:
302 cb_idx = 0;
303 BUG();
304 }
305
306 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530307 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600308 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600309 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
310 __FUNCTION__, ioc->name, cb_idx);
311 goto out;
312 }
313
314 if (MptCallbacks[cb_idx](ioc, mf, mr))
315 mpt_free_msg_frame(ioc, mf);
316 out:
317 mb();
318}
319
320static void
321mpt_reply(MPT_ADAPTER *ioc, u32 pa)
322{
323 MPT_FRAME_HDR *mf;
324 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530325 u16 req_idx;
326 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 int freeme;
328
329 u32 reply_dma_low;
330 u16 ioc_stat;
331
332 /* non-TURBO reply! Hmmm, something may be up...
333 * Newest turbo reply mechanism; get address
334 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
335 */
336
337 /* Map DMA address of reply header to cpu address.
338 * pa is 32 bits - but the dma address may be 32 or 64 bits
339 * get offset based only only the low addresses
340 */
341
342 reply_dma_low = (pa <<= 1);
343 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
344 (reply_dma_low - ioc->reply_frames_low_dma));
345
346 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
347 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
348 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
349
Prakash, Sathya436ace72007-07-24 15:42:08 +0530350 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600351 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600352 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600353
354 /* Check/log IOC log info
355 */
356 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
357 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
358 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
359 if (ioc->bus_type == FC)
360 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700361 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700362 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600363 else if (ioc->bus_type == SAS)
364 mpt_sas_log_info(ioc, log_info);
365 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600366
Eric Moorec6c727a2007-01-29 09:44:54 -0700367 if (ioc_stat & MPI_IOCSTATUS_MASK)
368 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600369
370 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530371 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600372 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
374 __FUNCTION__, ioc->name, cb_idx);
375 freeme = 0;
376 goto out;
377 }
378
379 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
380
381 out:
382 /* Flush (non-TURBO) reply with a WRITE! */
383 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
384
385 if (freeme)
386 mpt_free_msg_frame(ioc, mf);
387 mb();
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
393 * @irq: irq number (not used)
394 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 *
396 * This routine is registered via the request_irq() kernel API call,
397 * and handles all interrupts generated from a specific MPT adapter
398 * (also referred to as a IO Controller or IOC).
399 * This routine must clear the interrupt from the adapter and does
400 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 *
403 * This routine handles register-level access of the adapter but
404 * dispatches (calls) a protocol-specific callback routine to handle
405 * the protocol-specific details of the MPT request completion.
406 */
407static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100408mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600410 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600411 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
412
413 if (pa == 0xFFFFFFFF)
414 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 /*
417 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600419 do {
420 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600421 mpt_reply(ioc, pa);
422 else
423 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600424 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
425 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 return IRQ_HANDLED;
428}
429
430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800431/**
432 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 * @ioc: Pointer to MPT_ADAPTER structure
434 * @mf: Pointer to original MPT request frame
435 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
436 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800437 * MPT base driver's callback routine; all base driver
438 * "internal" request/reply processing is routed here.
439 * Currently used for EventNotification and EventAck handling.
440 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 * should be freed, or 0 if it shouldn't.
443 */
444static int
445mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
446{
447 int freereq = 1;
448 u8 func;
449
Prakash, Sathya436ace72007-07-24 15:42:08 +0530450 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
451#ifdef CONFIG_FUSION_LOGGING
452 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
453 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
455 ioc->name, mf));
456 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530461 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 ioc->name, func));
463
464 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
465 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
466 int evHandlers = 0;
467 int results;
468
469 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
470 if (results != evHandlers) {
471 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530472 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 ioc->name, evHandlers, results));
474 }
475
476 /*
477 * Hmmm... It seems that EventNotificationReply is an exception
478 * to the rule of one reply per request.
479 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200480 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200482 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530483 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200484 ioc->name, pEvReply));
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487#ifdef CONFIG_PROC_FS
488// LogEvent(ioc, pEvReply);
489#endif
490
491 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530492 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700494 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 CONFIGPARMS *pCfg;
496 unsigned long flags;
497
Prakash, Sathya436ace72007-07-24 15:42:08 +0530498 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ioc->name, mf, reply));
500
501 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
502
503 if (pCfg) {
504 /* disable timer and remove from linked list */
505 del_timer(&pCfg->timer);
506
507 spin_lock_irqsave(&ioc->FreeQlock, flags);
508 list_del(&pCfg->linkage);
509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
510
511 /*
512 * If IOC Status is SUCCESS, save the header
513 * and set the status code to GOOD.
514 */
515 pCfg->status = MPT_CONFIG_ERROR;
516 if (reply) {
517 ConfigReply_t *pReply = (ConfigReply_t *)reply;
518 u16 status;
519
520 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600521 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
522 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 pCfg->status = status;
525 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200526 if ((pReply->Header.PageType &
527 MPI_CONFIG_PAGETYPE_MASK) ==
528 MPI_CONFIG_PAGETYPE_EXTENDED) {
529 pCfg->cfghdr.ehdr->ExtPageLength =
530 le16_to_cpu(pReply->ExtPageLength);
531 pCfg->cfghdr.ehdr->ExtPageType =
532 pReply->ExtPageType;
533 }
534 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
535
536 /* If this is a regular header, save PageLength. */
537 /* LMP Do this better so not using a reserved field! */
538 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
539 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
540 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542 }
543
544 /*
545 * Wake up the original calling thread
546 */
547 pCfg->wait_done = 1;
548 wake_up(&mpt_waitq);
549 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200550 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
551 /* we should be always getting a reply frame */
552 memcpy(ioc->persist_reply_frame, reply,
553 min(MPT_DEFAULT_FRAME_SIZE,
554 4*reply->u.reply.MsgLength));
555 del_timer(&ioc->persist_timer);
556 ioc->persist_wait_done = 1;
557 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
559 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
560 ioc->name, func);
561 }
562
563 /*
564 * Conditionally tell caller to free the original
565 * EventNotification/EventAck/unexpected request frame!
566 */
567 return freereq;
568}
569
570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
571/**
572 * mpt_register - Register protocol-specific main callback handler.
573 * @cbfunc: callback function pointer
574 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
575 *
576 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800577 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 * protocol-specific driver must do this before it will be able to
579 * use any IOC resources, such as obtaining request frames.
580 *
581 * NOTES: The SCSI protocol driver currently calls this routine thrice
582 * in order to register separate callbacks; one for "normal" SCSI IO;
583 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
584 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530585 * Returns u8 valued "handle" in the range (and S.O.D. order)
586 * {N,...,7,6,5,...,1} if successful.
587 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
588 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530590u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
592{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530593 u8 cb_idx;
594 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /*
597 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
598 * (slot/handle 0 is reserved!)
599 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530600 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
601 if (MptCallbacks[cb_idx] == NULL) {
602 MptCallbacks[cb_idx] = cbfunc;
603 MptDriverClass[cb_idx] = dclass;
604 MptEvHandlers[cb_idx] = NULL;
605 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 break;
607 }
608 }
609
610 return last_drv_idx;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
614/**
615 * mpt_deregister - Deregister a protocol drivers resources.
616 * @cb_idx: previously registered callback handle
617 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800618 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 * module is unloaded.
620 */
621void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530622mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600624 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 MptCallbacks[cb_idx] = NULL;
626 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
627 MptEvHandlers[cb_idx] = NULL;
628
629 last_drv_idx++;
630 }
631}
632
633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
634/**
635 * mpt_event_register - Register protocol-specific event callback
636 * handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @ev_cbfunc: callback function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of MPT events.
642 *
643 * Returns 0 for success.
644 */
645int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600648 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -1;
650
651 MptEvHandlers[cb_idx] = ev_cbfunc;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_event_deregister - Deregister protocol-specific event callback
658 * handler.
659 * @cb_idx: previously registered callback handle
660 *
661 * Each protocol-specific driver should call this routine
662 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800663 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 */
665void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530666mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600668 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return;
670
671 MptEvHandlers[cb_idx] = NULL;
672}
673
674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
675/**
676 * mpt_reset_register - Register protocol-specific IOC reset handler.
677 * @cb_idx: previously registered (via mpt_register) callback handle
678 * @reset_func: reset function
679 *
680 * This routine can be called by one or more protocol-specific drivers
681 * if/when they choose to be notified of IOC resets.
682 *
683 * Returns 0 for success.
684 */
685int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530688 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return -1;
690
691 MptResetHandlers[cb_idx] = reset_func;
692 return 0;
693}
694
695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
696/**
697 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
698 * @cb_idx: previously registered callback handle
699 *
700 * Each protocol-specific driver should call this routine
701 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800702 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 */
704void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530705mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530707 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
710 MptResetHandlers[cb_idx] = NULL;
711}
712
713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
714/**
715 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * @dd_cbfunc: driver callbacks struct
717 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600723 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Eric Moore8d6d83e2007-09-14 18:47:40 -0600725 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400726 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
729
730 /* call per pci device probe entry point */
731 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600732 id = ioc->pcidev->driver ?
733 ioc->pcidev->driver->id_table : NULL;
734 if (dd_cbfunc->probe)
735 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400738 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
742/**
743 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800744 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 */
746void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530747mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 struct mpt_pci_driver *dd_cbfunc;
750 MPT_ADAPTER *ioc;
751
Eric Moore8d6d83e2007-09-14 18:47:40 -0600752 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return;
754
755 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
756
757 list_for_each_entry(ioc, &ioc_list, list) {
758 if (dd_cbfunc->remove)
759 dd_cbfunc->remove(ioc->pcidev);
760 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 MptDeviceDriverHandlers[cb_idx] = NULL;
763}
764
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
769 * allocated per MPT adapter.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530770 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 * @ioc: Pointer to MPT adapter structure
772 *
773 * Returns pointer to a MPT request frame or %NULL if none are available
774 * or IOC is not active.
775 */
776MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 MPT_FRAME_HDR *mf;
780 unsigned long flags;
781 u16 req_idx; /* Request index */
782
783 /* validate handle and ioc identifier */
784
785#ifdef MFCNT
786 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600787 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
788 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789#endif
790
791 /* If interrupts are not attached, do not return a request frame */
792 if (!ioc->active)
793 return NULL;
794
795 spin_lock_irqsave(&ioc->FreeQlock, flags);
796 if (!list_empty(&ioc->FreeQ)) {
797 int req_offset;
798
799 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
800 u.frame.linkage.list);
801 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200802 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530803 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
805 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500806 req_idx = req_offset / ioc->req_sz;
807 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 /* Default, will be changed if necessary in SG generation */
810 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811#ifdef MFCNT
812 ioc->mfcnt++;
813#endif
814 }
815 else
816 mf = NULL;
817 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
818
819#ifdef MFCNT
820 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600821 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
822 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
823 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 mfcounter++;
825 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600826 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
827 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828#endif
829
Eric Moore29dd3602007-09-14 18:46:51 -0600830 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
831 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return mf;
833}
834
835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
836/**
837 * mpt_put_msg_frame - Send a protocol specific MPT request frame
838 * to a IOC.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530839 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 * @ioc: Pointer to MPT adapter structure
841 * @mf: Pointer to MPT request frame
842 *
843 * This routine posts a MPT request frame to the request post FIFO of a
844 * specific MPT adapter.
845 */
846void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530847mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 u32 mf_dma_addr;
850 int req_offset;
851 u16 req_idx; /* Request index */
852
853 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530854 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
856 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500857 req_idx = req_offset / ioc->req_sz;
858 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
860
Prakash, Sathya436ace72007-07-24 15:42:08 +0530861 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200863 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600864 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
865 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
866 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
868}
869
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530870/**
871 * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
872 * to a IOC using hi priority request queue.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530873 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530874 * @ioc: Pointer to MPT adapter structure
875 * @mf: Pointer to MPT request frame
876 *
877 * This routine posts a MPT request frame to the request post FIFO of a
878 * specific MPT adapter.
879 **/
880void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530881mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530882{
883 u32 mf_dma_addr;
884 int req_offset;
885 u16 req_idx; /* Request index */
886
887 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530888 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530889 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
890 req_idx = req_offset / ioc->req_sz;
891 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
892 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
893
894 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
895
896 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
897 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
898 ioc->name, mf_dma_addr, req_idx));
899 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
900}
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
903/**
904 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
905 * @handle: Handle of registered MPT protocol driver
906 * @ioc: Pointer to MPT adapter structure
907 * @mf: Pointer to MPT request frame
908 *
909 * This routine places a MPT request frame back on the MPT adapter's
910 * FreeQ.
911 */
912void
913mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
914{
915 unsigned long flags;
916
917 /* Put Request back on FreeQ! */
918 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200919 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
921#ifdef MFCNT
922 ioc->mfcnt--;
923#endif
924 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
925}
926
927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
928/**
929 * mpt_add_sge - Place a simple SGE at address pAddr.
930 * @pAddr: virtual address for SGE
931 * @flagslength: SGE flags and data transfer length
932 * @dma_addr: Physical address
933 *
934 * This routine places a MPT request frame back on the MPT adapter's
935 * FreeQ.
936 */
937void
938mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
939{
940 if (sizeof(dma_addr_t) == sizeof(u64)) {
941 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
942 u32 tmp = dma_addr & 0xFFFFFFFF;
943
944 pSge->FlagsLength = cpu_to_le32(flagslength);
945 pSge->Address.Low = cpu_to_le32(tmp);
946 tmp = (u32) ((u64)dma_addr >> 32);
947 pSge->Address.High = cpu_to_le32(tmp);
948
949 } else {
950 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
951 pSge->FlagsLength = cpu_to_le32(flagslength);
952 pSge->Address = cpu_to_le32(dma_addr);
953 }
954}
955
956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
957/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800958 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530959 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 * @ioc: Pointer to MPT adapter structure
961 * @reqBytes: Size of the request in bytes
962 * @req: Pointer to MPT request frame
963 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
964 *
965 * This routine is used exclusively to send MptScsiTaskMgmt
966 * requests since they are required to be sent via doorbell handshake.
967 *
968 * NOTE: It is the callers responsibility to byte-swap fields in the
969 * request which are greater than 1 byte in size.
970 *
971 * Returns 0 for success, non-zero for failure.
972 */
973int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530974mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Eric Moorecd2c6192007-01-29 09:47:47 -0700976 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 u8 *req_as_bytes;
978 int ii;
979
980 /* State is known to be good upon entering
981 * this function so issue the bus reset
982 * request.
983 */
984
985 /*
986 * Emulate what mpt_put_msg_frame() does /wrt to sanity
987 * setting cb_idx/req_idx. But ONLY if this request
988 * is in proper (pre-alloc'd) request buffer range...
989 */
990 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
991 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
992 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
993 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530994 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
996
997 /* Make sure there are no doorbells */
998 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1001 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1002 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1003
1004 /* Wait for IOC doorbell int */
1005 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1006 return ii;
1007 }
1008
1009 /* Read doorbell and check for active bit */
1010 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1011 return -5;
1012
Eric Moore29dd3602007-09-14 18:46:51 -06001013 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001014 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1017
1018 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1019 return -2;
1020 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 /* Send request via doorbell handshake */
1023 req_as_bytes = (u8 *) req;
1024 for (ii = 0; ii < reqBytes/4; ii++) {
1025 u32 word;
1026
1027 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1028 (req_as_bytes[(ii*4) + 1] << 8) |
1029 (req_as_bytes[(ii*4) + 2] << 16) |
1030 (req_as_bytes[(ii*4) + 3] << 24));
1031 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1032 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1033 r = -3;
1034 break;
1035 }
1036 }
1037
1038 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1039 r = 0;
1040 else
1041 r = -4;
1042
1043 /* Make sure there are no doorbells */
1044 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return r;
1047}
1048
1049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1050/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001051 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001052 * @ioc: Pointer to MPT adapter structure
1053 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001054 * @sleepFlag: Specifies whether the process can sleep
1055 *
1056 * Provides mechanism for the host driver to control the IOC's
1057 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001058 *
1059 * Access Control Value - bits[15:12]
1060 * 0h Reserved
1061 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1062 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1063 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1064 *
1065 * Returns 0 for success, non-zero for failure.
1066 */
1067
1068static int
1069mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1070{
1071 int r = 0;
1072
1073 /* return if in use */
1074 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1075 & MPI_DOORBELL_ACTIVE)
1076 return -1;
1077
1078 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1079
1080 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1081 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1082 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1083 (access_control_value<<12)));
1084
1085 /* Wait for IOC to clear Doorbell Status bit */
1086 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1087 return -2;
1088 }else
1089 return 0;
1090}
1091
1092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1093/**
1094 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001095 * @ioc: Pointer to pointer to IOC adapter
1096 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001098 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001099 * Returns 0 for success, non-zero for failure.
1100 */
1101static int
1102mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1103{
1104 char *psge;
1105 int flags_length;
1106 u32 host_page_buffer_sz=0;
1107
1108 if(!ioc->HostPageBuffer) {
1109
1110 host_page_buffer_sz =
1111 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1112
1113 if(!host_page_buffer_sz)
1114 return 0; /* fw doesn't need any host buffers */
1115
1116 /* spin till we get enough memory */
1117 while(host_page_buffer_sz > 0) {
1118
1119 if((ioc->HostPageBuffer = pci_alloc_consistent(
1120 ioc->pcidev,
1121 host_page_buffer_sz,
1122 &ioc->HostPageBuffer_dma)) != NULL) {
1123
Prakash, Sathya436ace72007-07-24 15:42:08 +05301124 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001125 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001126 ioc->name, ioc->HostPageBuffer,
1127 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001128 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001129 ioc->alloc_total += host_page_buffer_sz;
1130 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1131 break;
1132 }
1133
1134 host_page_buffer_sz -= (4*1024);
1135 }
1136 }
1137
1138 if(!ioc->HostPageBuffer) {
1139 printk(MYIOC_s_ERR_FMT
1140 "Failed to alloc memory for host_page_buffer!\n",
1141 ioc->name);
1142 return -999;
1143 }
1144
1145 psge = (char *)&ioc_init->HostPageBufferSGE;
1146 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1147 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1148 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1149 MPI_SGE_FLAGS_HOST_TO_IOC |
1150 MPI_SGE_FLAGS_END_OF_BUFFER;
1151 if (sizeof(dma_addr_t) == sizeof(u64)) {
1152 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1153 }
1154 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1155 flags_length |= ioc->HostPageBuffer_sz;
1156 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1157 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1158
1159return 0;
1160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001164 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 * @iocid: IOC unique identifier (integer)
1166 * @iocpp: Pointer to pointer to IOC adapter
1167 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001168 * Given a unique IOC identifier, set pointer to the associated MPT
1169 * adapter structure.
1170 *
1171 * Returns iocid and sets iocpp if iocid is found.
1172 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 */
1174int
1175mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1176{
1177 MPT_ADAPTER *ioc;
1178
1179 list_for_each_entry(ioc,&ioc_list,list) {
1180 if (ioc->id == iocid) {
1181 *iocpp =ioc;
1182 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 *iocpp = NULL;
1187 return -1;
1188}
1189
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301190/**
1191 * mpt_get_product_name - returns product string
1192 * @vendor: pci vendor id
1193 * @device: pci device id
1194 * @revision: pci revision id
1195 * @prod_name: string returned
1196 *
1197 * Returns product string displayed when driver loads,
1198 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1199 *
1200 **/
1201static void
1202mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1203{
1204 char *product_str = NULL;
1205
1206 if (vendor == PCI_VENDOR_ID_BROCADE) {
1207 switch (device)
1208 {
1209 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1210 switch (revision)
1211 {
1212 case 0x00:
1213 product_str = "BRE040 A0";
1214 break;
1215 case 0x01:
1216 product_str = "BRE040 A1";
1217 break;
1218 default:
1219 product_str = "BRE040";
1220 break;
1221 }
1222 break;
1223 }
1224 goto out;
1225 }
1226
1227 switch (device)
1228 {
1229 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1230 product_str = "LSIFC909 B1";
1231 break;
1232 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1233 product_str = "LSIFC919 B0";
1234 break;
1235 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1236 product_str = "LSIFC929 B0";
1237 break;
1238 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1239 if (revision < 0x80)
1240 product_str = "LSIFC919X A0";
1241 else
1242 product_str = "LSIFC919XL A1";
1243 break;
1244 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1245 if (revision < 0x80)
1246 product_str = "LSIFC929X A0";
1247 else
1248 product_str = "LSIFC929XL A1";
1249 break;
1250 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1251 product_str = "LSIFC939X A1";
1252 break;
1253 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1254 product_str = "LSIFC949X A1";
1255 break;
1256 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1257 switch (revision)
1258 {
1259 case 0x00:
1260 product_str = "LSIFC949E A0";
1261 break;
1262 case 0x01:
1263 product_str = "LSIFC949E A1";
1264 break;
1265 default:
1266 product_str = "LSIFC949E";
1267 break;
1268 }
1269 break;
1270 case MPI_MANUFACTPAGE_DEVID_53C1030:
1271 switch (revision)
1272 {
1273 case 0x00:
1274 product_str = "LSI53C1030 A0";
1275 break;
1276 case 0x01:
1277 product_str = "LSI53C1030 B0";
1278 break;
1279 case 0x03:
1280 product_str = "LSI53C1030 B1";
1281 break;
1282 case 0x07:
1283 product_str = "LSI53C1030 B2";
1284 break;
1285 case 0x08:
1286 product_str = "LSI53C1030 C0";
1287 break;
1288 case 0x80:
1289 product_str = "LSI53C1030T A0";
1290 break;
1291 case 0x83:
1292 product_str = "LSI53C1030T A2";
1293 break;
1294 case 0x87:
1295 product_str = "LSI53C1030T A3";
1296 break;
1297 case 0xc1:
1298 product_str = "LSI53C1020A A1";
1299 break;
1300 default:
1301 product_str = "LSI53C1030";
1302 break;
1303 }
1304 break;
1305 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1306 switch (revision)
1307 {
1308 case 0x03:
1309 product_str = "LSI53C1035 A2";
1310 break;
1311 case 0x04:
1312 product_str = "LSI53C1035 B0";
1313 break;
1314 default:
1315 product_str = "LSI53C1035";
1316 break;
1317 }
1318 break;
1319 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1320 switch (revision)
1321 {
1322 case 0x00:
1323 product_str = "LSISAS1064 A1";
1324 break;
1325 case 0x01:
1326 product_str = "LSISAS1064 A2";
1327 break;
1328 case 0x02:
1329 product_str = "LSISAS1064 A3";
1330 break;
1331 case 0x03:
1332 product_str = "LSISAS1064 A4";
1333 break;
1334 default:
1335 product_str = "LSISAS1064";
1336 break;
1337 }
1338 break;
1339 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1340 switch (revision)
1341 {
1342 case 0x00:
1343 product_str = "LSISAS1064E A0";
1344 break;
1345 case 0x01:
1346 product_str = "LSISAS1064E B0";
1347 break;
1348 case 0x02:
1349 product_str = "LSISAS1064E B1";
1350 break;
1351 case 0x04:
1352 product_str = "LSISAS1064E B2";
1353 break;
1354 case 0x08:
1355 product_str = "LSISAS1064E B3";
1356 break;
1357 default:
1358 product_str = "LSISAS1064E";
1359 break;
1360 }
1361 break;
1362 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "LSISAS1068 A0";
1367 break;
1368 case 0x01:
1369 product_str = "LSISAS1068 B0";
1370 break;
1371 case 0x02:
1372 product_str = "LSISAS1068 B1";
1373 break;
1374 default:
1375 product_str = "LSISAS1068";
1376 break;
1377 }
1378 break;
1379 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1380 switch (revision)
1381 {
1382 case 0x00:
1383 product_str = "LSISAS1068E A0";
1384 break;
1385 case 0x01:
1386 product_str = "LSISAS1068E B0";
1387 break;
1388 case 0x02:
1389 product_str = "LSISAS1068E B1";
1390 break;
1391 case 0x04:
1392 product_str = "LSISAS1068E B2";
1393 break;
1394 case 0x08:
1395 product_str = "LSISAS1068E B3";
1396 break;
1397 default:
1398 product_str = "LSISAS1068E";
1399 break;
1400 }
1401 break;
1402 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1403 switch (revision)
1404 {
1405 case 0x00:
1406 product_str = "LSISAS1078 A0";
1407 break;
1408 case 0x01:
1409 product_str = "LSISAS1078 B0";
1410 break;
1411 case 0x02:
1412 product_str = "LSISAS1078 C0";
1413 break;
1414 case 0x03:
1415 product_str = "LSISAS1078 C1";
1416 break;
1417 case 0x04:
1418 product_str = "LSISAS1078 C2";
1419 break;
1420 default:
1421 product_str = "LSISAS1078";
1422 break;
1423 }
1424 break;
1425 }
1426
1427 out:
1428 if (product_str)
1429 sprintf(prod_name, "%s", product_str);
1430}
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001433/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001434 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *
1438 * This routine performs all the steps necessary to bring the IOC of
1439 * a MPT adapter to a OPERATIONAL state. This includes registering
1440 * memory regions, registering the interrupt, and allocating request
1441 * and reply memory pools.
1442 *
1443 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1444 * MPT adapter.
1445 *
1446 * Returns 0 for success, non-zero for failure.
1447 *
1448 * TODO: Add support for polled controllers
1449 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001450int
1451mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 MPT_ADAPTER *ioc;
1454 u8 __iomem *mem;
Eric Moorebc6e0892007-09-29 10:16:28 -06001455 u8 __iomem *pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long mem_phys;
1457 unsigned long port;
1458 u32 msize;
1459 u32 psize;
1460 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301461 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 u8 revision;
1464 u8 pcixcmd;
1465 static int mpt_ids = 0;
1466#ifdef CONFIG_PROC_FS
1467 struct proc_dir_entry *dent, *ent;
1468#endif
1469
Prakash, Sathya436ace72007-07-24 15:42:08 +05301470 if (mpt_debug_level)
1471 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1472
Jesper Juhl56876192007-08-10 14:50:51 -07001473 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1474 if (ioc == NULL) {
1475 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1476 return -ENOMEM;
1477 }
1478 ioc->debug_level = mpt_debug_level;
Eric Moore29dd3602007-09-14 18:46:51 -06001479 ioc->id = mpt_ids++;
1480 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001481
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301482 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1483 if (pci_enable_device_mem(pdev)) {
1484 kfree(ioc);
1485 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1486 "failed\n", ioc->name);
1487 return r;
1488 }
1489 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1490 kfree(ioc);
1491 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1492 "MEM failed\n", ioc->name);
1493 return r;
1494 }
1495
Eric Moore29dd3602007-09-14 18:46:51 -06001496 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001497
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001498 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001499 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1500 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001501 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001502 printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
1503 ioc->name);
Jesper Juhl56876192007-08-10 14:50:51 -07001504 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 return r;
1506 }
1507
Prakash, Sathya436ace72007-07-24 15:42:08 +05301508 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001509 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1510 ": Using 64 bit consistent mask\n", ioc->name));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301511 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001512 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1513 ": Not using 64 bit consistent mask\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301515
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 ioc->alloc_total = sizeof(MPT_ADAPTER);
1517 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1518 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 ioc->pcidev = pdev;
1521 ioc->diagPending = 0;
1522 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001523 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 /* Initialize the event logging.
1526 */
1527 ioc->eventTypes = 0; /* None */
1528 ioc->eventContext = 0;
1529 ioc->eventLogSize = 0;
1530 ioc->events = NULL;
1531
1532#ifdef MFCNT
1533 ioc->mfcnt = 0;
1534#endif
1535
1536 ioc->cached_fw = NULL;
1537
1538 /* Initilize SCSI Config Data structure
1539 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001540 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542 /* Initialize the running configQ head.
1543 */
1544 INIT_LIST_HEAD(&ioc->configQ);
1545
Michael Reed05e8ec12006-01-13 14:31:54 -06001546 /* Initialize the fc rport list head.
1547 */
1548 INIT_LIST_HEAD(&ioc->fc_rports);
1549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 /* Find lookup slot. */
1551 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 mem_phys = msize = 0;
1554 port = psize = 0;
1555 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1556 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001557 if (psize)
1558 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* Get I/O space! */
1560 port = pci_resource_start(pdev, ii);
1561 psize = pci_resource_len(pdev,ii);
1562 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001563 if (msize)
1564 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 /* Get memmap */
1566 mem_phys = pci_resource_start(pdev, ii);
1567 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 }
1569 }
1570 ioc->mem_size = msize;
1571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 mem = NULL;
1573 /* Get logical ptr for PciMem0 space */
1574 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001575 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 if (mem == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001577 printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 kfree(ioc);
1579 return -EINVAL;
1580 }
1581 ioc->memmap = mem;
Eric Moore29dd3602007-09-14 18:46:51 -06001582 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Eric Moore29dd3602007-09-14 18:46:51 -06001584 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1585 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 ioc->mem_phys = mem_phys;
1588 ioc->chip = (SYSIF_REGS __iomem *)mem;
1589
1590 /* Save Port IO values in case we need to do downloadboot */
Eric Moorebc6e0892007-09-29 10:16:28 -06001591 ioc->pio_mem_phys = port;
1592 pmem = (u8 __iomem *)port;
1593 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301595 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1596 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1597
1598 switch (pdev->device)
1599 {
1600 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1601 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1602 ioc->errata_flag_1064 = 1;
1603 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1604 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1605 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1606 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301608 break;
1609
1610 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 /* 929X Chip Fix. Set Split transactions level
1613 * for PCIX. Set MOST bits to zero.
1614 */
1615 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1616 pcixcmd &= 0x8F;
1617 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1618 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 /* 929XL Chip Fix. Set MMRBC to 0x08.
1620 */
1621 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1622 pcixcmd |= 0x08;
1623 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301626 break;
1627
1628 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* 919X Chip Fix. Set Split transactions level
1630 * for PCIX. Set MOST bits to zero.
1631 */
1632 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1633 pcixcmd &= 0x8F;
1634 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001635 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301636 break;
1637
1638 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 /* 1030 Chip Fix. Disable Split transactions
1640 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1641 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 if (revision < C0_1030) {
1643 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1644 pcixcmd &= 0x8F;
1645 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1646 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301647
1648 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001649 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301650 break;
1651
1652 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1653 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001654 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301655
1656 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1657 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1658 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001659 ioc->bus_type = SAS;
1660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001662 if (ioc->errata_flag_1064)
1663 pci_disable_io_access(pdev);
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 spin_lock_init(&ioc->FreeQlock);
1666
1667 /* Disable all! */
1668 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1669 ioc->active = 0;
1670 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1671
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301672 /* Set IOC ptr in the pcidev's driver data. */
1673 pci_set_drvdata(ioc->pcidev, ioc);
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 /* Set lookup ptr. */
1676 list_add_tail(&ioc->list, &ioc_list);
1677
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001678 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 */
1680 mpt_detect_bound_ports(ioc, pdev);
1681
James Bottomleyc92f2222006-03-01 09:02:49 -06001682 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1683 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001684 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1685 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001688 if (ioc->alt_ioc)
1689 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 iounmap(mem);
1691 kfree(ioc);
1692 pci_set_drvdata(pdev, NULL);
1693 return r;
1694 }
1695
1696 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001697 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301698 if(MptDeviceDriverHandlers[cb_idx] &&
1699 MptDeviceDriverHandlers[cb_idx]->probe) {
1700 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 }
1702 }
1703
1704#ifdef CONFIG_PROC_FS
1705 /*
1706 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1707 */
1708 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1709 if (dent) {
1710 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1711 if (ent) {
1712 ent->read_proc = procmpt_iocinfo_read;
1713 ent->data = ioc;
1714 }
1715 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1716 if (ent) {
1717 ent->read_proc = procmpt_summary_read;
1718 ent->data = ioc;
1719 }
1720 }
1721#endif
1722
1723 return 0;
1724}
1725
1726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001727/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001728 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 */
1731
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001732void
1733mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734{
1735 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1736 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301737 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1740 remove_proc_entry(pname, NULL);
1741 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1742 remove_proc_entry(pname, NULL);
1743 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1744 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001747 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301748 if(MptDeviceDriverHandlers[cb_idx] &&
1749 MptDeviceDriverHandlers[cb_idx]->remove) {
1750 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001753
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 /* Disable interrupts! */
1755 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1756
1757 ioc->active = 0;
1758 synchronize_irq(pdev->irq);
1759
1760 /* Clear any lingering interrupt */
1761 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1762
1763 CHIPREG_READ32(&ioc->chip->IntStatus);
1764
1765 mpt_adapter_dispose(ioc);
1766
1767 pci_set_drvdata(pdev, NULL);
1768}
1769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770/**************************************************************************
1771 * Power Management
1772 */
1773#ifdef CONFIG_PM
1774/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001775/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001776 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001777 * @pdev: Pointer to pci_dev structure
1778 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001780int
1781mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782{
1783 u32 device_state;
1784 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Pavel Machek2a569572005-07-07 17:56:40 -07001786 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 printk(MYIOC_s_INFO_FMT
1789 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1790 ioc->name, pdev, pci_name(pdev), device_state);
1791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 pci_save_state(pdev);
1793
1794 /* put ioc into READY_STATE */
1795 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1796 printk(MYIOC_s_ERR_FMT
1797 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1798 }
1799
1800 /* disable interrupts */
1801 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1802 ioc->active = 0;
1803
1804 /* Clear any lingering interrupt */
1805 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1806
1807 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301808 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 pci_set_power_state(pdev, device_state);
1810
1811 return 0;
1812}
1813
1814/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001815/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001816 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001817 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001819int
1820mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1823 u32 device_state = pdev->current_state;
1824 int recovery_state;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 printk(MYIOC_s_INFO_FMT
1827 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1828 ioc->name, pdev, pci_name(pdev), device_state);
1829
1830 pci_set_power_state(pdev, 0);
1831 pci_restore_state(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301832 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
1833 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
1834 IORESOURCE_IO);
1835 if (pci_enable_device(pdev))
1836 return 0;
1837 } else {
1838 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1839 if (pci_enable_device_mem(pdev))
1840 return 0;
1841 }
1842 if (pci_request_selected_regions(pdev, ioc->bars, "mpt"))
1843 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001846 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 ioc->active = 1;
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 printk(MYIOC_s_INFO_FMT
1850 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1851 ioc->name,
1852 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1853 CHIPREG_READ32(&ioc->chip->Doorbell));
1854
1855 /* bring ioc to operational state */
1856 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1857 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1858 printk(MYIOC_s_INFO_FMT
1859 "pci-resume: Cannot recover, error:[%x]\n",
1860 ioc->name, recovery_state);
1861 } else {
1862 printk(MYIOC_s_INFO_FMT
1863 "pci-resume: success\n", ioc->name);
1864 }
1865
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 return 0;
1867}
1868#endif
1869
James Bottomley4ff42a62006-05-17 18:06:52 -05001870static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301871mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001872{
1873 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1874 ioc->bus_type != SPI) ||
1875 (MptDriverClass[index] == MPTFC_DRIVER &&
1876 ioc->bus_type != FC) ||
1877 (MptDriverClass[index] == MPTSAS_DRIVER &&
1878 ioc->bus_type != SAS))
1879 /* make sure we only call the relevant reset handler
1880 * for the bus */
1881 return 0;
1882 return (MptResetHandlers[index])(ioc, reset_phase);
1883}
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001886/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1888 * @ioc: Pointer to MPT adapter structure
1889 * @reason: Event word / reason
1890 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1891 *
1892 * This routine performs all the steps necessary to bring the IOC
1893 * to a OPERATIONAL state.
1894 *
1895 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1896 * MPT adapter.
1897 *
1898 * Returns:
1899 * 0 for success
1900 * -1 if failed to get board READY
1901 * -2 if READY but IOCFacts Failed
1902 * -3 if READY but PrimeIOCFifos Failed
1903 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301904 * -5 if failed to enable_device and/or request_selected_regions
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 */
1906static int
1907mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1908{
1909 int hard_reset_done = 0;
1910 int alt_ioc_ready = 0;
1911 int hard;
1912 int rc=0;
1913 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301914 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 int handlers;
1916 int ret = 0;
1917 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001918 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301919 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Eric Moore29dd3602007-09-14 18:46:51 -06001921 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1922 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 /* Disable reply interrupts (also blocks FreeQ) */
1925 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1926 ioc->active = 0;
1927
1928 if (ioc->alt_ioc) {
1929 if (ioc->alt_ioc->active)
1930 reset_alt_ioc_active = 1;
1931
1932 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1933 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1934 ioc->alt_ioc->active = 0;
1935 }
1936
1937 hard = 1;
1938 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1939 hard = 0;
1940
1941 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1942 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001943 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1944 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 if (reset_alt_ioc_active && ioc->alt_ioc) {
1947 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001948 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1949 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001950 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 ioc->alt_ioc->active = 1;
1952 }
1953
1954 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001955 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957 return -1;
1958 }
1959
1960 /* hard_reset_done = 0 if a soft reset was performed
1961 * and 1 if a hard reset was performed.
1962 */
1963 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1964 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1965 alt_ioc_ready = 1;
1966 else
Eric Moore29dd3602007-09-14 18:46:51 -06001967 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
1969
1970 for (ii=0; ii<5; ii++) {
1971 /* Get IOC facts! Allow 5 retries */
1972 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1973 break;
1974 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06001978 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1979 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 ret = -2;
1981 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1982 MptDisplayIocCapabilities(ioc);
1983 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 if (alt_ioc_ready) {
1986 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301987 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001988 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 /* Retry - alt IOC was initialized once
1990 */
1991 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1992 }
1993 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301994 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001995 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 alt_ioc_ready = 0;
1997 reset_alt_ioc_active = 0;
1998 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1999 MptDisplayIocCapabilities(ioc->alt_ioc);
2000 }
2001 }
2002
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302003 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2004 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2005 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2006 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2007 IORESOURCE_IO);
2008 if (pci_enable_device(ioc->pcidev))
2009 return -5;
2010 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2011 "mpt"))
2012 return -5;
2013 }
2014
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002015 /*
2016 * Device is reset now. It must have de-asserted the interrupt line
2017 * (if it was asserted) and it should be safe to register for the
2018 * interrupt now.
2019 */
2020 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2021 ioc->pci_irq = -1;
2022 if (ioc->pcidev->irq) {
2023 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
2024 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002025 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002026 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002027 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002028 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002029 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002030 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002031 if (mpt_msi_enable)
2032 pci_disable_msi(ioc->pcidev);
2033 return -EBUSY;
2034 }
2035 irq_allocated = 1;
2036 ioc->pci_irq = ioc->pcidev->irq;
2037 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002038 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2039 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002040 }
2041 }
2042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 /* Prime reply & request queues!
2044 * (mucho alloc's) Must be done prior to
2045 * init as upper addresses are needed for init.
2046 * If fails, continue with alt-ioc processing
2047 */
2048 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2049 ret = -3;
2050
2051 /* May need to check/upload firmware & data here!
2052 * If fails, continue with alt-ioc processing
2053 */
2054 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2055 ret = -4;
2056// NEW!
2057 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002058 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2059 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 alt_ioc_ready = 0;
2061 reset_alt_ioc_active = 0;
2062 }
2063
2064 if (alt_ioc_ready) {
2065 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2066 alt_ioc_ready = 0;
2067 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002068 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2069 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 }
2071 }
2072
2073 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2074 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302075 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002076 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078 /* Controller is not operational, cannot do upload
2079 */
2080 if (ret == 0) {
2081 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002082 if (rc == 0) {
2083 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2084 /*
2085 * Maintain only one pointer to FW memory
2086 * so there will not be two attempt to
2087 * downloadboot onboard dual function
2088 * chips (mpt_adapter_disable,
2089 * mpt_diag_reset)
2090 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302091 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002092 "mpt_upload: alt_%s has cached_fw=%p \n",
2093 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302094 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002095 }
2096 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002097 printk(MYIOC_s_WARN_FMT
2098 "firmware upload failure!\n", ioc->name);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002099 ret = -5;
2100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 }
2102 }
2103 }
2104
2105 if (ret == 0) {
2106 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002107 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 ioc->active = 1;
2109 }
2110
2111 if (reset_alt_ioc_active && ioc->alt_ioc) {
2112 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002113 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2114 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002115 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 ioc->alt_ioc->active = 1;
2117 }
2118
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002119 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 * and EventAck handling.
2121 */
2122 if ((ret == 0) && (!ioc->facts.EventState))
2123 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2124
2125 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2126 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2127
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002128 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2130 * recursive scenario; GetLanConfigPages times out, timer expired
2131 * routine calls HardResetHandler, which calls into here again,
2132 * and we try GetLanConfigPages again...
2133 */
2134 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002135
2136 /*
2137 * Initalize link list for inactive raid volumes.
2138 */
2139 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2140 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2141
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002142 if (ioc->bus_type == SAS) {
2143
2144 /* clear persistency table */
2145 if(ioc->facts.IOCExceptions &
2146 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2147 ret = mptbase_sas_persist_operation(ioc,
2148 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2149 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002150 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002151 }
2152
2153 /* Find IM volumes
2154 */
2155 mpt_findImVolumes(ioc);
2156
2157 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2159 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2160 /*
2161 * Pre-fetch the ports LAN MAC address!
2162 * (LANPage1_t stuff)
2163 */
2164 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302165 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2166 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002167 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2168 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302169
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 }
2171 } else {
2172 /* Get NVRAM and adapter maximums from SPP 0 and 2
2173 */
2174 mpt_GetScsiPortSettings(ioc, 0);
2175
2176 /* Get version and length of SDP 1
2177 */
2178 mpt_readScsiDevicePageHeaders(ioc, 0);
2179
2180 /* Find IM volumes
2181 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002182 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 mpt_findImVolumes(ioc);
2184
2185 /* Check, and possibly reset, the coalescing value
2186 */
2187 mpt_read_ioc_pg_1(ioc);
2188
2189 mpt_read_ioc_pg_4(ioc);
2190 }
2191
2192 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302193 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195
2196 /*
2197 * Call each currently registered protocol IOC reset handler
2198 * with post-reset indication.
2199 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2200 * MptResetHandlers[] registered yet.
2201 */
2202 if (hard_reset_done) {
2203 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302204 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2205 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302206 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002207 "Calling IOC post_reset handler #%d\n",
2208 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302209 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 handlers++;
2211 }
2212
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302213 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302214 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002215 "Calling IOC post_reset handler #%d\n",
2216 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302217 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 handlers++;
2219 }
2220 }
2221 /* FIXME? Examine results here? */
2222 }
2223
Eric Moore0ccdb002006-07-11 17:33:13 -06002224 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002225 if ((ret != 0) && irq_allocated) {
2226 free_irq(ioc->pci_irq, ioc);
2227 if (mpt_msi_enable)
2228 pci_disable_msi(ioc->pcidev);
2229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 return ret;
2231}
2232
2233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002234/**
2235 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 * @ioc: Pointer to MPT adapter structure
2237 * @pdev: Pointer to (struct pci_dev) structure
2238 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002239 * Search for PCI bus/dev_function which matches
2240 * PCI bus/dev_function (+/-1) for newly discovered 929,
2241 * 929X, 1030 or 1035.
2242 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2244 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2245 */
2246static void
2247mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2248{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002249 struct pci_dev *peer=NULL;
2250 unsigned int slot = PCI_SLOT(pdev->devfn);
2251 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 MPT_ADAPTER *ioc_srch;
2253
Prakash, Sathya436ace72007-07-24 15:42:08 +05302254 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002255 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002256 ioc->name, pci_name(pdev), pdev->bus->number,
2257 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002258
2259 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2260 if (!peer) {
2261 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2262 if (!peer)
2263 return;
2264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266 list_for_each_entry(ioc_srch, &ioc_list, list) {
2267 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002268 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 /* Paranoia checks */
2270 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002271 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002272 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 break;
2274 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002275 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002276 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 break;
2278 }
Eric Moore29dd3602007-09-14 18:46:51 -06002279 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002280 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 ioc_srch->alt_ioc = ioc;
2282 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 }
2284 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002285 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286}
2287
2288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002289/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002291 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 */
2293static void
2294mpt_adapter_disable(MPT_ADAPTER *ioc)
2295{
2296 int sz;
2297 int ret;
2298
2299 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302300 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2301 "adapter\n", __FUNCTION__, ioc->name));
2302 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2303 ioc->cached_fw, CAN_SLEEP)) < 0) {
2304 printk(MYIOC_s_WARN_FMT
2305 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002306 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 }
2308 }
2309
2310 /* Disable adapter interrupts! */
2311 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2312 ioc->active = 0;
2313 /* Clear any lingering interrupt */
2314 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2315
2316 if (ioc->alloc != NULL) {
2317 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002318 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2319 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 pci_free_consistent(ioc->pcidev, sz,
2321 ioc->alloc, ioc->alloc_dma);
2322 ioc->reply_frames = NULL;
2323 ioc->req_frames = NULL;
2324 ioc->alloc = NULL;
2325 ioc->alloc_total -= sz;
2326 }
2327
2328 if (ioc->sense_buf_pool != NULL) {
2329 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2330 pci_free_consistent(ioc->pcidev, sz,
2331 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2332 ioc->sense_buf_pool = NULL;
2333 ioc->alloc_total -= sz;
2334 }
2335
2336 if (ioc->events != NULL){
2337 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2338 kfree(ioc->events);
2339 ioc->events = NULL;
2340 ioc->alloc_total -= sz;
2341 }
2342
Prakash, Sathya984621b2008-01-11 14:42:17 +05302343 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002345 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002346 mpt_inactive_raid_list_free(ioc);
2347 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002348 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002349 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002350 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
2352 if (ioc->spi_data.pIocPg4 != NULL) {
2353 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302354 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 ioc->spi_data.pIocPg4,
2356 ioc->spi_data.IocPg4_dma);
2357 ioc->spi_data.pIocPg4 = NULL;
2358 ioc->alloc_total -= sz;
2359 }
2360
2361 if (ioc->ReqToChain != NULL) {
2362 kfree(ioc->ReqToChain);
2363 kfree(ioc->RequestNB);
2364 ioc->ReqToChain = NULL;
2365 }
2366
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002367 kfree(ioc->ChainToChain);
2368 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002369
2370 if (ioc->HostPageBuffer != NULL) {
2371 if((ret = mpt_host_page_access_control(ioc,
2372 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002373 printk(MYIOC_s_ERR_FMT
2374 "host page buffers free failed (%d)!\n",
2375 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002376 }
Eric Moore29dd3602007-09-14 18:46:51 -06002377 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002378 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2379 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002380 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002381 ioc->HostPageBuffer = NULL;
2382 ioc->HostPageBuffer_sz = 0;
2383 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385}
2386
2387/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002388/**
2389 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 * @ioc: Pointer to MPT adapter structure
2391 *
2392 * This routine unregisters h/w resources and frees all alloc'd memory
2393 * associated with a MPT adapter structure.
2394 */
2395static void
2396mpt_adapter_dispose(MPT_ADAPTER *ioc)
2397{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002398 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002400 if (ioc == NULL)
2401 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002403 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002405 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002407 if (ioc->pci_irq != -1) {
2408 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002409 if (mpt_msi_enable)
2410 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002411 ioc->pci_irq = -1;
2412 }
2413
2414 if (ioc->memmap != NULL) {
2415 iounmap(ioc->memmap);
2416 ioc->memmap = NULL;
2417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302419 pci_disable_device(ioc->pcidev);
2420 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2421
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002423 if (ioc->mtrr_reg > 0) {
2424 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002425 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427#endif
2428
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002429 /* Zap the adapter lookup ptr! */
2430 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002432 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002433 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2434 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002435
2436 if (ioc->alt_ioc)
2437 ioc->alt_ioc->alt_ioc = NULL;
2438
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002439 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440}
2441
2442/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002443/**
2444 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 * @ioc: Pointer to MPT adapter structure
2446 */
2447static void
2448MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2449{
2450 int i = 0;
2451
2452 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302453 if (ioc->prod_name)
2454 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 printk("Capabilities={");
2456
2457 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2458 printk("Initiator");
2459 i++;
2460 }
2461
2462 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2463 printk("%sTarget", i ? "," : "");
2464 i++;
2465 }
2466
2467 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2468 printk("%sLAN", i ? "," : "");
2469 i++;
2470 }
2471
2472#if 0
2473 /*
2474 * This would probably evoke more questions than it's worth
2475 */
2476 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2477 printk("%sLogBusAddr", i ? "," : "");
2478 i++;
2479 }
2480#endif
2481
2482 printk("}\n");
2483}
2484
2485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002486/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2488 * @ioc: Pointer to MPT_ADAPTER structure
2489 * @force: Force hard KickStart of IOC
2490 * @sleepFlag: Specifies whether the process can sleep
2491 *
2492 * Returns:
2493 * 1 - DIAG reset and READY
2494 * 0 - READY initially OR soft reset and READY
2495 * -1 - Any failure on KickStart
2496 * -2 - Msg Unit Reset Failed
2497 * -3 - IO Unit Reset Failed
2498 * -4 - IOC owned by a PEER
2499 */
2500static int
2501MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2502{
2503 u32 ioc_state;
2504 int statefault = 0;
2505 int cntdn;
2506 int hard_reset_done = 0;
2507 int r;
2508 int ii;
2509 int whoinit;
2510
2511 /* Get current [raw] IOC state */
2512 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002513 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 /*
2516 * Check to see if IOC got left/stuck in doorbell handshake
2517 * grip of death. If so, hard reset the IOC.
2518 */
2519 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2520 statefault = 1;
2521 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2522 ioc->name);
2523 }
2524
2525 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002526 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 return 0;
2528
2529 /*
2530 * Check to see if IOC is in FAULT state.
2531 */
2532 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2533 statefault = 2;
2534 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002535 ioc->name);
2536 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2537 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 }
2539
2540 /*
2541 * Hmmm... Did it get left operational?
2542 */
2543 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302544 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 ioc->name));
2546
2547 /* Check WhoInit.
2548 * If PCI Peer, exit.
2549 * Else, if no fault conditions are present, issue a MessageUnitReset
2550 * Else, fall through to KickStart case
2551 */
2552 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002553 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2554 "whoinit 0x%x statefault %d force %d\n",
2555 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 if (whoinit == MPI_WHOINIT_PCI_PEER)
2557 return -4;
2558 else {
2559 if ((statefault == 0 ) && (force == 0)) {
2560 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2561 return 0;
2562 }
2563 statefault = 3;
2564 }
2565 }
2566
2567 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2568 if (hard_reset_done < 0)
2569 return -1;
2570
2571 /*
2572 * Loop here waiting for IOC to come READY.
2573 */
2574 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002575 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
2577 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2578 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2579 /*
2580 * BIOS or previous driver load left IOC in OP state.
2581 * Reset messaging FIFOs.
2582 */
2583 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2584 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2585 return -2;
2586 }
2587 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2588 /*
2589 * Something is wrong. Try to get IOC back
2590 * to a known state.
2591 */
2592 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2593 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2594 return -3;
2595 }
2596 }
2597
2598 ii++; cntdn--;
2599 if (!cntdn) {
2600 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2601 ioc->name, (int)((ii+5)/HZ));
2602 return -ETIME;
2603 }
2604
2605 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002606 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 } else {
2608 mdelay (1); /* 1 msec delay */
2609 }
2610
2611 }
2612
2613 if (statefault < 3) {
2614 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2615 ioc->name,
2616 statefault==1 ? "stuck handshake" : "IOC FAULT");
2617 }
2618
2619 return hard_reset_done;
2620}
2621
2622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002623/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 * mpt_GetIocState - Get the current state of a MPT adapter.
2625 * @ioc: Pointer to MPT_ADAPTER structure
2626 * @cooked: Request raw or cooked IOC state
2627 *
2628 * Returns all IOC Doorbell register bits if cooked==0, else just the
2629 * Doorbell bits in MPI_IOC_STATE_MASK.
2630 */
2631u32
2632mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2633{
2634 u32 s, sc;
2635
2636 /* Get! */
2637 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 sc = s & MPI_IOC_STATE_MASK;
2639
2640 /* Save! */
2641 ioc->last_state = sc;
2642
2643 return cooked ? sc : s;
2644}
2645
2646/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002647/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 * GetIocFacts - Send IOCFacts request to MPT adapter.
2649 * @ioc: Pointer to MPT_ADAPTER structure
2650 * @sleepFlag: Specifies whether the process can sleep
2651 * @reason: If recovery, only update facts.
2652 *
2653 * Returns 0 for success, non-zero for failure.
2654 */
2655static int
2656GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2657{
2658 IOCFacts_t get_facts;
2659 IOCFactsReply_t *facts;
2660 int r;
2661 int req_sz;
2662 int reply_sz;
2663 int sz;
2664 u32 status, vv;
2665 u8 shiftFactor=1;
2666
2667 /* IOC *must* NOT be in RESET state! */
2668 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002669 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2670 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return -44;
2672 }
2673
2674 facts = &ioc->facts;
2675
2676 /* Destination (reply area)... */
2677 reply_sz = sizeof(*facts);
2678 memset(facts, 0, reply_sz);
2679
2680 /* Request area (get_facts on the stack right now!) */
2681 req_sz = sizeof(get_facts);
2682 memset(&get_facts, 0, req_sz);
2683
2684 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2685 /* Assert: All other get_facts fields are zero! */
2686
Prakash, Sathya436ace72007-07-24 15:42:08 +05302687 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002688 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 ioc->name, req_sz, reply_sz));
2690
2691 /* No non-zero fields in the get_facts request are greater than
2692 * 1 byte in size, so we can just fire it off as is.
2693 */
2694 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2695 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2696 if (r != 0)
2697 return r;
2698
2699 /*
2700 * Now byte swap (GRRR) the necessary fields before any further
2701 * inspection of reply contents.
2702 *
2703 * But need to do some sanity checks on MsgLength (byte) field
2704 * to make sure we don't zero IOC's req_sz!
2705 */
2706 /* Did we get a valid reply? */
2707 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2708 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2709 /*
2710 * If not been here, done that, save off first WhoInit value
2711 */
2712 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2713 ioc->FirstWhoInit = facts->WhoInit;
2714 }
2715
2716 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2717 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2718 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2719 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2720 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002721 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 /* CHECKME! IOCStatus, IOCLogInfo */
2723
2724 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2725 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2726
2727 /*
2728 * FC f/w version changed between 1.1 and 1.2
2729 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2730 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2731 */
2732 if (facts->MsgVersion < 0x0102) {
2733 /*
2734 * Handle old FC f/w style, convert to new...
2735 */
2736 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2737 facts->FWVersion.Word =
2738 ((oldv<<12) & 0xFF000000) |
2739 ((oldv<<8) & 0x000FFF00);
2740 } else
2741 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2742
2743 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002744 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2745 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2746 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 facts->CurrentHostMfaHighAddr =
2748 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2749 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2750 facts->CurrentSenseBufferHighAddr =
2751 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2752 facts->CurReplyFrameSize =
2753 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002754 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
2756 /*
2757 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2758 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2759 * to 14 in MPI-1.01.0x.
2760 */
2761 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2762 facts->MsgVersion > 0x0100) {
2763 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2764 }
2765
2766 sz = facts->FWImageSize;
2767 if ( sz & 0x01 )
2768 sz += 1;
2769 if ( sz & 0x02 )
2770 sz += 2;
2771 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 if (!facts->RequestFrameSize) {
2774 /* Something is wrong! */
2775 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2776 ioc->name);
2777 return -55;
2778 }
2779
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002780 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 vv = ((63 / (sz * 4)) + 1) & 0x03;
2782 ioc->NB_for_64_byte_frame = vv;
2783 while ( sz )
2784 {
2785 shiftFactor++;
2786 sz = sz >> 1;
2787 }
2788 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302789 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002790 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2791 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002792
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2794 /*
2795 * Set values for this IOC's request & reply frame sizes,
2796 * and request & reply queue depths...
2797 */
2798 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2799 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2800 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2801 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2802
Prakash, Sathya436ace72007-07-24 15:42:08 +05302803 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302805 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 ioc->name, ioc->req_sz, ioc->req_depth));
2807
2808 /* Get port facts! */
2809 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2810 return r;
2811 }
2812 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002813 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2815 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2816 RequestFrameSize)/sizeof(u32)));
2817 return -66;
2818 }
2819
2820 return 0;
2821}
2822
2823/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002824/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 * GetPortFacts - Send PortFacts request to MPT adapter.
2826 * @ioc: Pointer to MPT_ADAPTER structure
2827 * @portnum: Port number
2828 * @sleepFlag: Specifies whether the process can sleep
2829 *
2830 * Returns 0 for success, non-zero for failure.
2831 */
2832static int
2833GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2834{
2835 PortFacts_t get_pfacts;
2836 PortFactsReply_t *pfacts;
2837 int ii;
2838 int req_sz;
2839 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002840 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842 /* IOC *must* NOT be in RESET state! */
2843 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002844 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2845 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 return -4;
2847 }
2848
2849 pfacts = &ioc->pfacts[portnum];
2850
2851 /* Destination (reply area)... */
2852 reply_sz = sizeof(*pfacts);
2853 memset(pfacts, 0, reply_sz);
2854
2855 /* Request area (get_pfacts on the stack right now!) */
2856 req_sz = sizeof(get_pfacts);
2857 memset(&get_pfacts, 0, req_sz);
2858
2859 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2860 get_pfacts.PortNumber = portnum;
2861 /* Assert: All other get_pfacts fields are zero! */
2862
Prakash, Sathya436ace72007-07-24 15:42:08 +05302863 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 ioc->name, portnum));
2865
2866 /* No non-zero fields in the get_pfacts request are greater than
2867 * 1 byte in size, so we can just fire it off as is.
2868 */
2869 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2870 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2871 if (ii != 0)
2872 return ii;
2873
2874 /* Did we get a valid reply? */
2875
2876 /* Now byte swap the necessary fields in the response. */
2877 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2878 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2879 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2880 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2881 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2882 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2883 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2884 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2885 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2886
Eric Moore793955f2007-01-29 09:42:20 -07002887 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2888 pfacts->MaxDevices;
2889 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2890 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2891
2892 /*
2893 * Place all the devices on channels
2894 *
2895 * (for debuging)
2896 */
2897 if (mpt_channel_mapping) {
2898 ioc->devices_per_bus = 1;
2899 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2900 }
2901
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 return 0;
2903}
2904
2905/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002906/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 * SendIocInit - Send IOCInit request to MPT adapter.
2908 * @ioc: Pointer to MPT_ADAPTER structure
2909 * @sleepFlag: Specifies whether the process can sleep
2910 *
2911 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2912 *
2913 * Returns 0 for success, non-zero for failure.
2914 */
2915static int
2916SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2917{
2918 IOCInit_t ioc_init;
2919 MPIDefaultReply_t init_reply;
2920 u32 state;
2921 int r;
2922 int count;
2923 int cntdn;
2924
2925 memset(&ioc_init, 0, sizeof(ioc_init));
2926 memset(&init_reply, 0, sizeof(init_reply));
2927
2928 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2929 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2930
2931 /* If we are in a recovery mode and we uploaded the FW image,
2932 * then this pointer is not NULL. Skip the upload a second time.
2933 * Set this flag if cached_fw set for either IOC.
2934 */
2935 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2936 ioc->upload_fw = 1;
2937 else
2938 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302939 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2941
Eric Moore793955f2007-01-29 09:42:20 -07002942 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2943 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302944 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002945 ioc->name, ioc->facts.MsgVersion));
2946 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2947 // set MsgVersion and HeaderVersion host driver was built with
2948 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2949 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002951 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2952 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2953 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2954 return -99;
2955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2957
2958 if (sizeof(dma_addr_t) == sizeof(u64)) {
2959 /* Save the upper 32-bits of the request
2960 * (reply) and sense buffers.
2961 */
2962 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2963 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2964 } else {
2965 /* Force 32-bit addressing */
2966 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2967 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2968 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2971 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002972 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2973 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
Prakash, Sathya436ace72007-07-24 15:42:08 +05302975 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 ioc->name, &ioc_init));
2977
2978 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2979 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002980 if (r != 0) {
2981 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002986 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 */
2988
Prakash, Sathya436ace72007-07-24 15:42:08 +05302989 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002991
2992 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2993 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
2997 /* YIKES! SUPER IMPORTANT!!!
2998 * Poll IocState until _OPERATIONAL while IOC is doing
2999 * LoopInit and TargetDiscovery!
3000 */
3001 count = 0;
3002 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3003 state = mpt_GetIocState(ioc, 1);
3004 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3005 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003006 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 } else {
3008 mdelay(1);
3009 }
3010
3011 if (!cntdn) {
3012 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3013 ioc->name, (int)((count+5)/HZ));
3014 return -9;
3015 }
3016
3017 state = mpt_GetIocState(ioc, 1);
3018 count++;
3019 }
Eric Moore29dd3602007-09-14 18:46:51 -06003020 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 ioc->name, count));
3022
Eric Mooreba856d32006-07-11 17:34:01 -06003023 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 return r;
3025}
3026
3027/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003028/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 * SendPortEnable - Send PortEnable request to MPT adapter port.
3030 * @ioc: Pointer to MPT_ADAPTER structure
3031 * @portnum: Port number to enable
3032 * @sleepFlag: Specifies whether the process can sleep
3033 *
3034 * Send PortEnable to bring IOC to OPERATIONAL state.
3035 *
3036 * Returns 0 for success, non-zero for failure.
3037 */
3038static int
3039SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3040{
3041 PortEnable_t port_enable;
3042 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003043 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 int req_sz;
3045 int reply_sz;
3046
3047 /* Destination... */
3048 reply_sz = sizeof(MPIDefaultReply_t);
3049 memset(&reply_buf, 0, reply_sz);
3050
3051 req_sz = sizeof(PortEnable_t);
3052 memset(&port_enable, 0, req_sz);
3053
3054 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3055 port_enable.PortNumber = portnum;
3056/* port_enable.ChainOffset = 0; */
3057/* port_enable.MsgFlags = 0; */
3058/* port_enable.MsgContext = 0; */
3059
Prakash, Sathya436ace72007-07-24 15:42:08 +05303060 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 ioc->name, portnum, &port_enable));
3062
3063 /* RAID FW may take a long time to enable
3064 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003065 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003066 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3067 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3068 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003069 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003070 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3071 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3072 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003074 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075}
3076
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003077/**
3078 * mpt_alloc_fw_memory - allocate firmware memory
3079 * @ioc: Pointer to MPT_ADAPTER structure
3080 * @size: total FW bytes
3081 *
3082 * If memory has already been allocated, the same (cached) value
3083 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303084 *
3085 * Return 0 if successfull, or non-zero for failure
3086 **/
3087int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3089{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303090 int rc;
3091
3092 if (ioc->cached_fw) {
3093 rc = 0; /* use already allocated memory */
3094 goto out;
3095 }
3096 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3098 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303099 rc = 0;
3100 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303102 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3103 if (!ioc->cached_fw) {
3104 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3105 ioc->name);
3106 rc = -1;
3107 } else {
3108 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3109 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3110 ioc->alloc_total += size;
3111 rc = 0;
3112 }
3113 out:
3114 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303116
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003117/**
3118 * mpt_free_fw_memory - free firmware memory
3119 * @ioc: Pointer to MPT_ADAPTER structure
3120 *
3121 * If alt_img is NULL, delete from ioc structure.
3122 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303123 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124void
3125mpt_free_fw_memory(MPT_ADAPTER *ioc)
3126{
3127 int sz;
3128
Prakash, Sathya984621b2008-01-11 14:42:17 +05303129 if (!ioc->cached_fw)
3130 return;
3131
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303133 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3134 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003135 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303136 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138}
3139
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003141/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3143 * @ioc: Pointer to MPT_ADAPTER structure
3144 * @sleepFlag: Specifies whether the process can sleep
3145 *
3146 * Returns 0 for success, >0 for handshake failure
3147 * <0 for fw upload failure.
3148 *
3149 * Remark: If bound IOC and a successful FWUpload was performed
3150 * on the bound IOC, the second image is discarded
3151 * and memory is free'd. Both channels must upload to prevent
3152 * IOC from running in degraded mode.
3153 */
3154static int
3155mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3156{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 u8 reply[sizeof(FWUploadReply_t)];
3158 FWUpload_t *prequest;
3159 FWUploadReply_t *preply;
3160 FWUploadTCSGE_t *ptcsge;
3161 int sgeoffset;
3162 u32 flagsLength;
3163 int ii, sz, reply_sz;
3164 int cmdStatus;
3165
3166 /* If the image size is 0, we are done.
3167 */
3168 if ((sz = ioc->facts.FWImageSize) == 0)
3169 return 0;
3170
Prakash, Sathya984621b2008-01-11 14:42:17 +05303171 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3172 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173
Eric Moore29dd3602007-09-14 18:46:51 -06003174 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3175 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003176
Eric Moorebc6e0892007-09-29 10:16:28 -06003177 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3178 kzalloc(ioc->req_sz, GFP_KERNEL);
3179 if (!prequest) {
3180 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3181 "while allocating memory \n", ioc->name));
3182 mpt_free_fw_memory(ioc);
3183 return -ENOMEM;
3184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Eric Moorebc6e0892007-09-29 10:16:28 -06003186 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
3188 reply_sz = sizeof(reply);
3189 memset(preply, 0, reply_sz);
3190
3191 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3192 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3193
3194 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3195 ptcsge->DetailsLength = 12;
3196 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3197 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003198 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
3200 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3201
3202 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003203 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
3205 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003206 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3207 ioc->name, prequest, sgeoffset));
3208 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3211 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3212
Eric Moore29dd3602007-09-14 18:46:51 -06003213 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 cmdStatus = -EFAULT;
3216 if (ii == 0) {
3217 /* Handshake transfer was complete and successful.
3218 * Check the Reply Frame.
3219 */
3220 int status, transfer_sz;
3221 status = le16_to_cpu(preply->IOCStatus);
3222 if (status == MPI_IOCSTATUS_SUCCESS) {
3223 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3224 if (transfer_sz == sz)
3225 cmdStatus = 0;
3226 }
3227 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303228 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 ioc->name, cmdStatus));
3230
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003231
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 if (cmdStatus) {
3233
Prakash, Sathya436ace72007-07-24 15:42:08 +05303234 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 ioc->name));
3236 mpt_free_fw_memory(ioc);
3237 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003238 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 return cmdStatus;
3241}
3242
3243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003244/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 * mpt_downloadboot - DownloadBoot code
3246 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003247 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 * @sleepFlag: Specifies whether the process can sleep
3249 *
3250 * FwDownloadBoot requires Programmed IO access.
3251 *
3252 * Returns 0 for success
3253 * -1 FW Image size is 0
3254 * -2 No valid cached_fw Pointer
3255 * <0 for fw upload failure.
3256 */
3257static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003258mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 MpiExtImageHeader_t *pExtImage;
3261 u32 fwSize;
3262 u32 diag0val;
3263 int count;
3264 u32 *ptrFw;
3265 u32 diagRwData;
3266 u32 nextImage;
3267 u32 load_addr;
3268 u32 ioc_state=0;
3269
Prakash, Sathya436ace72007-07-24 15:42:08 +05303270 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003271 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003272
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3274 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3275 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3276 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3277 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3279
3280 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3281
3282 /* wait 1 msec */
3283 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003284 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 } else {
3286 mdelay (1);
3287 }
3288
3289 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3290 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3291
3292 for (count = 0; count < 30; count ++) {
3293 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3294 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303295 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 ioc->name, count));
3297 break;
3298 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003299 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003301 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003303 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 }
3305 }
3306
3307 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303308 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003309 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 ioc->name, diag0val));
3311 return -3;
3312 }
3313
3314 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3315 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3316 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3317 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3318 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3319 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3320
3321 /* Set the DiagRwEn and Disable ARM bits */
3322 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3323
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 fwSize = (pFwHeader->ImageSize + 3)/4;
3325 ptrFw = (u32 *) pFwHeader;
3326
3327 /* Write the LoadStartAddress to the DiagRw Address Register
3328 * using Programmed IO
3329 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003330 if (ioc->errata_flag_1064)
3331 pci_enable_io_access(ioc->pcidev);
3332
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303334 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 ioc->name, pFwHeader->LoadStartAddress));
3336
Prakash, Sathya436ace72007-07-24 15:42:08 +05303337 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 ioc->name, fwSize*4, ptrFw));
3339 while (fwSize--) {
3340 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3341 }
3342
3343 nextImage = pFwHeader->NextImageHeaderOffset;
3344 while (nextImage) {
3345 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3346
3347 load_addr = pExtImage->LoadStartAddress;
3348
3349 fwSize = (pExtImage->ImageSize + 3) >> 2;
3350 ptrFw = (u32 *)pExtImage;
3351
Prakash, Sathya436ace72007-07-24 15:42:08 +05303352 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 +02003353 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3355
3356 while (fwSize--) {
3357 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3358 }
3359 nextImage = pExtImage->NextImageHeaderOffset;
3360 }
3361
3362 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303363 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3365
3366 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303367 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3369
3370 /* Clear the internal flash bad bit - autoincrementing register,
3371 * so must do two writes.
3372 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003373 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003374 /*
3375 * 1030 and 1035 H/W errata, workaround to access
3376 * the ClearFlashBadSignatureBit
3377 */
3378 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3379 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3380 diagRwData |= 0x40000000;
3381 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3382 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3383
3384 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3385 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3386 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3387 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3388
3389 /* wait 1 msec */
3390 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003391 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003392 } else {
3393 mdelay (1);
3394 }
3395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003397 if (ioc->errata_flag_1064)
3398 pci_disable_io_access(ioc->pcidev);
3399
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303401 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003402 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003404 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303405 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 ioc->name, diag0val));
3407 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3408
3409 /* Write 0xFF to reset the sequencer */
3410 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3411
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003412 if (ioc->bus_type == SAS) {
3413 ioc_state = mpt_GetIocState(ioc, 0);
3414 if ( (GetIocFacts(ioc, sleepFlag,
3415 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303416 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003417 ioc->name, ioc_state));
3418 return -EFAULT;
3419 }
3420 }
3421
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 for (count=0; count<HZ*20; count++) {
3423 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303424 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3425 "downloadboot successful! (count=%d) IocState=%x\n",
3426 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003427 if (ioc->bus_type == SAS) {
3428 return 0;
3429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303431 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3432 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 ioc->name));
3434 return -EFAULT;
3435 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303436 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3437 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 ioc->name));
3439 return 0;
3440 }
3441 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003442 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 } else {
3444 mdelay (10);
3445 }
3446 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303447 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3448 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 return -EFAULT;
3450}
3451
3452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003453/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 * KickStart - Perform hard reset of MPT adapter.
3455 * @ioc: Pointer to MPT_ADAPTER structure
3456 * @force: Force hard reset
3457 * @sleepFlag: Specifies whether the process can sleep
3458 *
3459 * This routine places MPT adapter in diagnostic mode via the
3460 * WriteSequence register, and then performs a hard reset of adapter
3461 * via the Diagnostic register.
3462 *
3463 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3464 * or NO_SLEEP (interrupt thread, use mdelay)
3465 * force - 1 if doorbell active, board fault state
3466 * board operational, IOC_RECOVERY or
3467 * IOC_BRINGUP and there is an alt_ioc.
3468 * 0 else
3469 *
3470 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003471 * 1 - hard reset, READY
3472 * 0 - no reset due to History bit, READY
3473 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 * OR reset but failed to come READY
3475 * -2 - no reset, could not enter DIAG mode
3476 * -3 - reset but bad FW bit
3477 */
3478static int
3479KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3480{
3481 int hard_reset_done = 0;
3482 u32 ioc_state=0;
3483 int cnt,cntdn;
3484
Eric Moore29dd3602007-09-14 18:46:51 -06003485 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003486 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 /* Always issue a Msg Unit Reset first. This will clear some
3488 * SCSI bus hang conditions.
3489 */
3490 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3491
3492 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003493 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 } else {
3495 mdelay (1000);
3496 }
3497 }
3498
3499 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3500 if (hard_reset_done < 0)
3501 return hard_reset_done;
3502
Prakash, Sathya436ace72007-07-24 15:42:08 +05303503 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003504 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
3506 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3507 for (cnt=0; cnt<cntdn; cnt++) {
3508 ioc_state = mpt_GetIocState(ioc, 1);
3509 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303510 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 ioc->name, cnt));
3512 return hard_reset_done;
3513 }
3514 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003515 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 } else {
3517 mdelay (10);
3518 }
3519 }
3520
Eric Moore29dd3602007-09-14 18:46:51 -06003521 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3522 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 return -1;
3524}
3525
3526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003527/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 * mpt_diag_reset - Perform hard reset of the adapter.
3529 * @ioc: Pointer to MPT_ADAPTER structure
3530 * @ignore: Set if to honor and clear to ignore
3531 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003532 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 * else set to NO_SLEEP (use mdelay instead)
3534 *
3535 * This routine places the adapter in diagnostic mode via the
3536 * WriteSequence register and then performs a hard reset of adapter
3537 * via the Diagnostic register. Adapter should be in ready state
3538 * upon successful completion.
3539 *
3540 * Returns: 1 hard reset successful
3541 * 0 no reset performed because reset history bit set
3542 * -2 enabling diagnostic mode failed
3543 * -3 diagnostic reset failed
3544 */
3545static int
3546mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3547{
3548 u32 diag0val;
3549 u32 doorbell;
3550 int hard_reset_done = 0;
3551 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303553 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
Eric Moorecd2c6192007-01-29 09:47:47 -07003555 /* Clear any existing interrupts */
3556 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3557
Eric Moore87cf8982006-06-27 16:09:26 -06003558 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303559 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003560 "address=%p\n", ioc->name, __FUNCTION__,
3561 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3562 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3563 if (sleepFlag == CAN_SLEEP)
3564 msleep(1);
3565 else
3566 mdelay(1);
3567
3568 for (count = 0; count < 60; count ++) {
3569 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3570 doorbell &= MPI_IOC_STATE_MASK;
3571
Prakash, Sathya436ace72007-07-24 15:42:08 +05303572 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003573 "looking for READY STATE: doorbell=%x"
3574 " count=%d\n",
3575 ioc->name, doorbell, count));
3576 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003577 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003578 }
3579
3580 /* wait 1 sec */
3581 if (sleepFlag == CAN_SLEEP)
3582 msleep(1000);
3583 else
3584 mdelay(1000);
3585 }
3586 return -1;
3587 }
3588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 /* Use "Diagnostic reset" method! (only thing available!) */
3590 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3591
Prakash, Sathya436ace72007-07-24 15:42:08 +05303592 if (ioc->debug_level & MPT_DEBUG) {
3593 if (ioc->alt_ioc)
3594 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3595 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599 /* Do the reset if we are told to ignore the reset history
3600 * or if the reset history is 0
3601 */
3602 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3603 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3604 /* Write magic sequence to WriteSequence register
3605 * Loop until in diagnostic mode
3606 */
3607 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3608 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3609 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3610 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3611 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3612 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3613
3614 /* wait 100 msec */
3615 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003616 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 } else {
3618 mdelay (100);
3619 }
3620
3621 count++;
3622 if (count > 20) {
3623 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3624 ioc->name, diag0val);
3625 return -2;
3626
3627 }
3628
3629 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3630
Prakash, Sathya436ace72007-07-24 15:42:08 +05303631 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 ioc->name, diag0val));
3633 }
3634
Prakash, Sathya436ace72007-07-24 15:42:08 +05303635 if (ioc->debug_level & MPT_DEBUG) {
3636 if (ioc->alt_ioc)
3637 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3638 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 /*
3642 * Disable the ARM (Bug fix)
3643 *
3644 */
3645 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003646 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648 /*
3649 * Now hit the reset bit in the Diagnostic register
3650 * (THE BIG HAMMER!) (Clears DRWE bit).
3651 */
3652 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3653 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303654 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 ioc->name));
3656
3657 /*
3658 * Call each currently registered protocol IOC reset handler
3659 * with pre-reset indication.
3660 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3661 * MptResetHandlers[] registered yet.
3662 */
3663 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303664 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 int r = 0;
3666
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303667 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3668 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303669 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3670 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303671 ioc->name, cb_idx));
3672 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303674 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3675 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303676 ioc->name, ioc->alt_ioc->name, cb_idx));
3677 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 }
3679 }
3680 }
3681 /* FIXME? Examine results here? */
3682 }
3683
Eric Moore0ccdb002006-07-11 17:33:13 -06003684 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303685 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003686 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303687 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3688 else
3689 cached_fw = NULL;
3690 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 /* If the DownloadBoot operation fails, the
3692 * IOC will be left unusable. This is a fatal error
3693 * case. _diag_reset will return < 0
3694 */
3695 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303696 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3698 break;
3699 }
3700
Prakash, Sathya436ace72007-07-24 15:42:08 +05303701 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303702 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 /* wait 1 sec */
3704 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003705 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 } else {
3707 mdelay (1000);
3708 }
3709 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303710 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003711 printk(MYIOC_s_WARN_FMT
3712 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
3714
3715 } else {
3716 /* Wait for FW to reload and for board
3717 * to go to the READY state.
3718 * Maximum wait is 60 seconds.
3719 * If fail, no error will check again
3720 * with calling program.
3721 */
3722 for (count = 0; count < 60; count ++) {
3723 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3724 doorbell &= MPI_IOC_STATE_MASK;
3725
3726 if (doorbell == MPI_IOC_STATE_READY) {
3727 break;
3728 }
3729
3730 /* wait 1 sec */
3731 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003732 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 } else {
3734 mdelay (1000);
3735 }
3736 }
3737 }
3738 }
3739
3740 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303741 if (ioc->debug_level & MPT_DEBUG) {
3742 if (ioc->alt_ioc)
3743 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3744 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3745 ioc->name, diag0val, diag1val));
3746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747
3748 /* Clear RESET_HISTORY bit! Place board in the
3749 * diagnostic mode to update the diag register.
3750 */
3751 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3752 count = 0;
3753 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3754 /* Write magic sequence to WriteSequence register
3755 * Loop until in diagnostic mode
3756 */
3757 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3758 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3759 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3760 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3761 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3762 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3763
3764 /* wait 100 msec */
3765 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003766 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 } else {
3768 mdelay (100);
3769 }
3770
3771 count++;
3772 if (count > 20) {
3773 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3774 ioc->name, diag0val);
3775 break;
3776 }
3777 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3778 }
3779 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3780 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3781 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3782 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3783 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3784 ioc->name);
3785 }
3786
3787 /* Disable Diagnostic Mode
3788 */
3789 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3790
3791 /* Check FW reload status flags.
3792 */
3793 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3794 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3795 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3796 ioc->name, diag0val);
3797 return -3;
3798 }
3799
Prakash, Sathya436ace72007-07-24 15:42:08 +05303800 if (ioc->debug_level & MPT_DEBUG) {
3801 if (ioc->alt_ioc)
3802 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3803 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
3807 /*
3808 * Reset flag that says we've enabled event notification
3809 */
3810 ioc->facts.EventState = 0;
3811
3812 if (ioc->alt_ioc)
3813 ioc->alt_ioc->facts.EventState = 0;
3814
3815 return hard_reset_done;
3816}
3817
3818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003819/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 * SendIocReset - Send IOCReset request to MPT adapter.
3821 * @ioc: Pointer to MPT_ADAPTER structure
3822 * @reset_type: reset type, expected values are
3823 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003824 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 *
3826 * Send IOCReset request to the MPT adapter.
3827 *
3828 * Returns 0 for success, non-zero for failure.
3829 */
3830static int
3831SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3832{
3833 int r;
3834 u32 state;
3835 int cntdn, count;
3836
Prakash, Sathya436ace72007-07-24 15:42:08 +05303837 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 ioc->name, reset_type));
3839 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3840 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3841 return r;
3842
3843 /* FW ACK'd request, wait for READY state
3844 */
3845 count = 0;
3846 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3847
3848 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3849 cntdn--;
3850 count++;
3851 if (!cntdn) {
3852 if (sleepFlag != CAN_SLEEP)
3853 count *= 10;
3854
Eric Moore29dd3602007-09-14 18:46:51 -06003855 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3856 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 return -ETIME;
3858 }
3859
3860 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003861 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 } else {
3863 mdelay (1); /* 1 msec delay */
3864 }
3865 }
3866
3867 /* TODO!
3868 * Cleanup all event stuff for this IOC; re-issue EventNotification
3869 * request if needed.
3870 */
3871 if (ioc->facts.Function)
3872 ioc->facts.EventState = 0;
3873
3874 return 0;
3875}
3876
3877/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003878/**
3879 * initChainBuffers - Allocate memory for and initialize chain buffers
3880 * @ioc: Pointer to MPT_ADAPTER structure
3881 *
3882 * Allocates memory for and initializes chain buffers,
3883 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 */
3885static int
3886initChainBuffers(MPT_ADAPTER *ioc)
3887{
3888 u8 *mem;
3889 int sz, ii, num_chain;
3890 int scale, num_sge, numSGE;
3891
3892 /* ReqToChain size must equal the req_depth
3893 * index = req_idx
3894 */
3895 if (ioc->ReqToChain == NULL) {
3896 sz = ioc->req_depth * sizeof(int);
3897 mem = kmalloc(sz, GFP_ATOMIC);
3898 if (mem == NULL)
3899 return -1;
3900
3901 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303902 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 ioc->name, mem, sz));
3904 mem = kmalloc(sz, GFP_ATOMIC);
3905 if (mem == NULL)
3906 return -1;
3907
3908 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303909 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 ioc->name, mem, sz));
3911 }
3912 for (ii = 0; ii < ioc->req_depth; ii++) {
3913 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3914 }
3915
3916 /* ChainToChain size must equal the total number
3917 * of chain buffers to be allocated.
3918 * index = chain_idx
3919 *
3920 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003921 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 *
3923 * num_sge = num sge in request frame + last chain buffer
3924 * scale = num sge per chain buffer if no chain element
3925 */
3926 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3927 if (sizeof(dma_addr_t) == sizeof(u64))
3928 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3929 else
3930 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3931
3932 if (sizeof(dma_addr_t) == sizeof(u64)) {
3933 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3934 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3935 } else {
3936 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3937 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3938 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303939 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 ioc->name, num_sge, numSGE));
3941
3942 if ( numSGE > MPT_SCSI_SG_DEPTH )
3943 numSGE = MPT_SCSI_SG_DEPTH;
3944
3945 num_chain = 1;
3946 while (numSGE - num_sge > 0) {
3947 num_chain++;
3948 num_sge += (scale - 1);
3949 }
3950 num_chain++;
3951
Prakash, Sathya436ace72007-07-24 15:42:08 +05303952 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 ioc->name, numSGE, num_sge, num_chain));
3954
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003955 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 num_chain *= MPT_SCSI_CAN_QUEUE;
3957 else
3958 num_chain *= MPT_FC_CAN_QUEUE;
3959
3960 ioc->num_chain = num_chain;
3961
3962 sz = num_chain * sizeof(int);
3963 if (ioc->ChainToChain == NULL) {
3964 mem = kmalloc(sz, GFP_ATOMIC);
3965 if (mem == NULL)
3966 return -1;
3967
3968 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 ioc->name, mem, sz));
3971 } else {
3972 mem = (u8 *) ioc->ChainToChain;
3973 }
3974 memset(mem, 0xFF, sz);
3975 return num_chain;
3976}
3977
3978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003979/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3981 * @ioc: Pointer to MPT_ADAPTER structure
3982 *
3983 * This routine allocates memory for the MPT reply and request frame
3984 * pools (if necessary), and primes the IOC reply FIFO with
3985 * reply frames.
3986 *
3987 * Returns 0 for success, non-zero for failure.
3988 */
3989static int
3990PrimeIocFifos(MPT_ADAPTER *ioc)
3991{
3992 MPT_FRAME_HDR *mf;
3993 unsigned long flags;
3994 dma_addr_t alloc_dma;
3995 u8 *mem;
3996 int i, reply_sz, sz, total_size, num_chain;
3997
3998 /* Prime reply FIFO... */
3999
4000 if (ioc->reply_frames == NULL) {
4001 if ( (num_chain = initChainBuffers(ioc)) < 0)
4002 return -1;
4003
4004 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304005 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304007 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 ioc->name, reply_sz, reply_sz));
4009
4010 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304011 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 ioc->name, sz, sz));
4015 total_size += sz;
4016
4017 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304020 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 ioc->name, sz, sz, num_chain));
4022
4023 total_size += sz;
4024 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4025 if (mem == NULL) {
4026 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4027 ioc->name);
4028 goto out_fail;
4029 }
4030
Prakash, Sathya436ace72007-07-24 15:42:08 +05304031 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4033
4034 memset(mem, 0, total_size);
4035 ioc->alloc_total += total_size;
4036 ioc->alloc = mem;
4037 ioc->alloc_dma = alloc_dma;
4038 ioc->alloc_sz = total_size;
4039 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4040 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4041
Prakash, Sathya436ace72007-07-24 15:42:08 +05304042 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004043 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4044
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 alloc_dma += reply_sz;
4046 mem += reply_sz;
4047
4048 /* Request FIFO - WE manage this! */
4049
4050 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4051 ioc->req_frames_dma = alloc_dma;
4052
Prakash, Sathya436ace72007-07-24 15:42:08 +05304053 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 ioc->name, mem, (void *)(ulong)alloc_dma));
4055
4056 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4057
4058#if defined(CONFIG_MTRR) && 0
4059 /*
4060 * Enable Write Combining MTRR for IOC's memory region.
4061 * (at least as much as we can; "size and base must be
4062 * multiples of 4 kiB"
4063 */
4064 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4065 sz,
4066 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304067 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 ioc->name, ioc->req_frames_dma, sz));
4069#endif
4070
4071 for (i = 0; i < ioc->req_depth; i++) {
4072 alloc_dma += ioc->req_sz;
4073 mem += ioc->req_sz;
4074 }
4075
4076 ioc->ChainBuffer = mem;
4077 ioc->ChainBufferDMA = alloc_dma;
4078
Prakash, Sathya436ace72007-07-24 15:42:08 +05304079 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4081
4082 /* Initialize the free chain Q.
4083 */
4084
4085 INIT_LIST_HEAD(&ioc->FreeChainQ);
4086
4087 /* Post the chain buffers to the FreeChainQ.
4088 */
4089 mem = (u8 *)ioc->ChainBuffer;
4090 for (i=0; i < num_chain; i++) {
4091 mf = (MPT_FRAME_HDR *) mem;
4092 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4093 mem += ioc->req_sz;
4094 }
4095
4096 /* Initialize Request frames linked list
4097 */
4098 alloc_dma = ioc->req_frames_dma;
4099 mem = (u8 *) ioc->req_frames;
4100
4101 spin_lock_irqsave(&ioc->FreeQlock, flags);
4102 INIT_LIST_HEAD(&ioc->FreeQ);
4103 for (i = 0; i < ioc->req_depth; i++) {
4104 mf = (MPT_FRAME_HDR *) mem;
4105
4106 /* Queue REQUESTs *internally*! */
4107 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4108
4109 mem += ioc->req_sz;
4110 }
4111 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4112
4113 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4114 ioc->sense_buf_pool =
4115 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4116 if (ioc->sense_buf_pool == NULL) {
4117 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4118 ioc->name);
4119 goto out_fail;
4120 }
4121
4122 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4123 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304124 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4126
4127 }
4128
4129 /* Post Reply frames to FIFO
4130 */
4131 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304132 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4134
4135 for (i = 0; i < ioc->reply_depth; i++) {
4136 /* Write each address to the IOC! */
4137 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4138 alloc_dma += ioc->reply_sz;
4139 }
4140
4141 return 0;
4142
4143out_fail:
4144 if (ioc->alloc != NULL) {
4145 sz = ioc->alloc_sz;
4146 pci_free_consistent(ioc->pcidev,
4147 sz,
4148 ioc->alloc, ioc->alloc_dma);
4149 ioc->reply_frames = NULL;
4150 ioc->req_frames = NULL;
4151 ioc->alloc_total -= sz;
4152 }
4153 if (ioc->sense_buf_pool != NULL) {
4154 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4155 pci_free_consistent(ioc->pcidev,
4156 sz,
4157 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4158 ioc->sense_buf_pool = NULL;
4159 }
4160 return -1;
4161}
4162
4163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4164/**
4165 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4166 * from IOC via doorbell handshake method.
4167 * @ioc: Pointer to MPT_ADAPTER structure
4168 * @reqBytes: Size of the request in bytes
4169 * @req: Pointer to MPT request frame
4170 * @replyBytes: Expected size of the reply in bytes
4171 * @u16reply: Pointer to area where reply should be written
4172 * @maxwait: Max wait time for a reply (in seconds)
4173 * @sleepFlag: Specifies whether the process can sleep
4174 *
4175 * NOTES: It is the callers responsibility to byte-swap fields in the
4176 * request which are greater than 1 byte in size. It is also the
4177 * callers responsibility to byte-swap response fields which are
4178 * greater than 1 byte in size.
4179 *
4180 * Returns 0 for success, non-zero for failure.
4181 */
4182static int
4183mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004184 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185{
4186 MPIDefaultReply_t *mptReply;
4187 int failcnt = 0;
4188 int t;
4189
4190 /*
4191 * Get ready to cache a handshake reply
4192 */
4193 ioc->hs_reply_idx = 0;
4194 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4195 mptReply->MsgLength = 0;
4196
4197 /*
4198 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4199 * then tell IOC that we want to handshake a request of N words.
4200 * (WRITE u32val to Doorbell reg).
4201 */
4202 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4203 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4204 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4205 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4206
4207 /*
4208 * Wait for IOC's doorbell handshake int
4209 */
4210 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4211 failcnt++;
4212
Prakash, Sathya436ace72007-07-24 15:42:08 +05304213 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4215
4216 /* Read doorbell and check for active bit */
4217 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4218 return -1;
4219
4220 /*
4221 * Clear doorbell int (WRITE 0 to IntStatus reg),
4222 * then wait for IOC to ACKnowledge that it's ready for
4223 * our handshake request.
4224 */
4225 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4226 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4227 failcnt++;
4228
4229 if (!failcnt) {
4230 int ii;
4231 u8 *req_as_bytes = (u8 *) req;
4232
4233 /*
4234 * Stuff request words via doorbell handshake,
4235 * with ACK from IOC for each.
4236 */
4237 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4238 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4239 (req_as_bytes[(ii*4) + 1] << 8) |
4240 (req_as_bytes[(ii*4) + 2] << 16) |
4241 (req_as_bytes[(ii*4) + 3] << 24));
4242
4243 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4244 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4245 failcnt++;
4246 }
4247
Prakash, Sathya436ace72007-07-24 15:42:08 +05304248 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004249 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250
Prakash, Sathya436ace72007-07-24 15:42:08 +05304251 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4253
4254 /*
4255 * Wait for completion of doorbell handshake reply from the IOC
4256 */
4257 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4258 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004259
Prakash, Sathya436ace72007-07-24 15:42:08 +05304260 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4262
4263 /*
4264 * Copy out the cached reply...
4265 */
4266 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4267 u16reply[ii] = ioc->hs_reply[ii];
4268 } else {
4269 return -99;
4270 }
4271
4272 return -failcnt;
4273}
4274
4275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004276/**
4277 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 * @ioc: Pointer to MPT_ADAPTER structure
4279 * @howlong: How long to wait (in seconds)
4280 * @sleepFlag: Specifies whether the process can sleep
4281 *
4282 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004283 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4284 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 *
4286 * Returns a negative value on failure, else wait loop count.
4287 */
4288static int
4289WaitForDoorbellAck(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
4297 if (sleepFlag == CAN_SLEEP) {
4298 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004299 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4301 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4302 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 count++;
4304 }
4305 } else {
4306 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004307 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4309 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4310 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 count++;
4312 }
4313 }
4314
4315 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304316 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 ioc->name, count));
4318 return count;
4319 }
4320
4321 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4322 ioc->name, count, intstat);
4323 return -1;
4324}
4325
4326/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004327/**
4328 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 * @ioc: Pointer to MPT_ADAPTER structure
4330 * @howlong: How long to wait (in seconds)
4331 * @sleepFlag: Specifies whether the process can sleep
4332 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004333 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4334 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 *
4336 * Returns a negative value on failure, else wait loop count.
4337 */
4338static int
4339WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4340{
4341 int cntdn;
4342 int count = 0;
4343 u32 intstat=0;
4344
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004345 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 if (sleepFlag == CAN_SLEEP) {
4347 while (--cntdn) {
4348 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4349 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4350 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004351 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 count++;
4353 }
4354 } else {
4355 while (--cntdn) {
4356 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4357 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4358 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004359 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 count++;
4361 }
4362 }
4363
4364 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304365 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 ioc->name, count, howlong));
4367 return count;
4368 }
4369
4370 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4371 ioc->name, count, intstat);
4372 return -1;
4373}
4374
4375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004376/**
4377 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 * @ioc: Pointer to MPT_ADAPTER structure
4379 * @howlong: How long to wait (in seconds)
4380 * @sleepFlag: Specifies whether the process can sleep
4381 *
4382 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4383 * Reply is cached to IOC private area large enough to hold a maximum
4384 * of 128 bytes of reply data.
4385 *
4386 * Returns a negative value on failure, else size of reply in WORDS.
4387 */
4388static int
4389WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4390{
4391 int u16cnt = 0;
4392 int failcnt = 0;
4393 int t;
4394 u16 *hs_reply = ioc->hs_reply;
4395 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4396 u16 hword;
4397
4398 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4399
4400 /*
4401 * Get first two u16's so we can look at IOC's intended reply MsgLength
4402 */
4403 u16cnt=0;
4404 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4405 failcnt++;
4406 } else {
4407 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4408 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4409 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4410 failcnt++;
4411 else {
4412 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4413 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4414 }
4415 }
4416
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004418 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4420
4421 /*
4422 * If no error (and IOC said MsgLength is > 0), piece together
4423 * reply 16 bits at a time.
4424 */
4425 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4426 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4427 failcnt++;
4428 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4429 /* don't overflow our IOC hs_reply[] buffer! */
4430 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4431 hs_reply[u16cnt] = hword;
4432 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4433 }
4434
4435 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4436 failcnt++;
4437 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4438
4439 if (failcnt) {
4440 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4441 ioc->name);
4442 return -failcnt;
4443 }
4444#if 0
4445 else if (u16cnt != (2 * mptReply->MsgLength)) {
4446 return -101;
4447 }
4448 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4449 return -102;
4450 }
4451#endif
4452
Prakash, Sathya436ace72007-07-24 15:42:08 +05304453 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004454 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Prakash, Sathya436ace72007-07-24 15:42:08 +05304456 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 ioc->name, t, u16cnt/2));
4458 return u16cnt/2;
4459}
4460
4461/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004462/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 * GetLanConfigPages - Fetch LANConfig pages.
4464 * @ioc: Pointer to MPT_ADAPTER structure
4465 *
4466 * Return: 0 for success
4467 * -ENOMEM if no memory available
4468 * -EPERM if not allowed due to ISR context
4469 * -EAGAIN if no msg frames currently available
4470 * -EFAULT for non-successful reply or no reply (timeout)
4471 */
4472static int
4473GetLanConfigPages(MPT_ADAPTER *ioc)
4474{
4475 ConfigPageHeader_t hdr;
4476 CONFIGPARMS cfg;
4477 LANPage0_t *ppage0_alloc;
4478 dma_addr_t page0_dma;
4479 LANPage1_t *ppage1_alloc;
4480 dma_addr_t page1_dma;
4481 int rc = 0;
4482 int data_sz;
4483 int copy_sz;
4484
4485 /* Get LAN Page 0 header */
4486 hdr.PageVersion = 0;
4487 hdr.PageLength = 0;
4488 hdr.PageNumber = 0;
4489 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004490 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 cfg.physAddr = -1;
4492 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4493 cfg.dir = 0;
4494 cfg.pageAddr = 0;
4495 cfg.timeout = 0;
4496
4497 if ((rc = mpt_config(ioc, &cfg)) != 0)
4498 return rc;
4499
4500 if (hdr.PageLength > 0) {
4501 data_sz = hdr.PageLength * 4;
4502 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4503 rc = -ENOMEM;
4504 if (ppage0_alloc) {
4505 memset((u8 *)ppage0_alloc, 0, data_sz);
4506 cfg.physAddr = page0_dma;
4507 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4508
4509 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4510 /* save the data */
4511 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4512 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4513
4514 }
4515
4516 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4517
4518 /* FIXME!
4519 * Normalize endianness of structure data,
4520 * by byte-swapping all > 1 byte fields!
4521 */
4522
4523 }
4524
4525 if (rc)
4526 return rc;
4527 }
4528
4529 /* Get LAN Page 1 header */
4530 hdr.PageVersion = 0;
4531 hdr.PageLength = 0;
4532 hdr.PageNumber = 1;
4533 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004534 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 cfg.physAddr = -1;
4536 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4537 cfg.dir = 0;
4538 cfg.pageAddr = 0;
4539
4540 if ((rc = mpt_config(ioc, &cfg)) != 0)
4541 return rc;
4542
4543 if (hdr.PageLength == 0)
4544 return 0;
4545
4546 data_sz = hdr.PageLength * 4;
4547 rc = -ENOMEM;
4548 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4549 if (ppage1_alloc) {
4550 memset((u8 *)ppage1_alloc, 0, data_sz);
4551 cfg.physAddr = page1_dma;
4552 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4553
4554 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4555 /* save the data */
4556 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4557 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4558 }
4559
4560 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4561
4562 /* FIXME!
4563 * Normalize endianness of structure data,
4564 * by byte-swapping all > 1 byte fields!
4565 */
4566
4567 }
4568
4569 return rc;
4570}
4571
4572/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004573/**
4574 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004575 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004576 * @persist_opcode: see below
4577 *
4578 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4579 * devices not currently present.
4580 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4581 *
4582 * NOTE: Don't use not this function during interrupt time.
4583 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004584 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004585 */
4586
4587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4588int
4589mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4590{
4591 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4592 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4593 MPT_FRAME_HDR *mf = NULL;
4594 MPIHeader_t *mpi_hdr;
4595
4596
4597 /* insure garbage is not sent to fw */
4598 switch(persist_opcode) {
4599
4600 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4601 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4602 break;
4603
4604 default:
4605 return -1;
4606 break;
4607 }
4608
4609 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4610
4611 /* Get a MF for this command.
4612 */
4613 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4614 printk("%s: no msg frames!\n",__FUNCTION__);
4615 return -1;
4616 }
4617
4618 mpi_hdr = (MPIHeader_t *) mf;
4619 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4620 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4621 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4622 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4623 sasIoUnitCntrReq->Operation = persist_opcode;
4624
4625 init_timer(&ioc->persist_timer);
4626 ioc->persist_timer.data = (unsigned long) ioc;
4627 ioc->persist_timer.function = mpt_timer_expired;
4628 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4629 ioc->persist_wait_done=0;
4630 add_timer(&ioc->persist_timer);
4631 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4632 wait_event(mpt_waitq, ioc->persist_wait_done);
4633
4634 sasIoUnitCntrReply =
4635 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4636 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4637 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4638 __FUNCTION__,
4639 sasIoUnitCntrReply->IOCStatus,
4640 sasIoUnitCntrReply->IOCLogInfo);
4641 return -1;
4642 }
4643
4644 printk("%s: success\n",__FUNCTION__);
4645 return 0;
4646}
4647
4648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004649
4650static void
4651mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4652 MpiEventDataRaid_t * pRaidEventData)
4653{
4654 int volume;
4655 int reason;
4656 int disk;
4657 int status;
4658 int flags;
4659 int state;
4660
4661 volume = pRaidEventData->VolumeID;
4662 reason = pRaidEventData->ReasonCode;
4663 disk = pRaidEventData->PhysDiskNum;
4664 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4665 flags = (status >> 0) & 0xff;
4666 state = (status >> 8) & 0xff;
4667
4668 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4669 return;
4670 }
4671
4672 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4673 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4674 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004675 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4676 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004677 } else {
4678 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4679 ioc->name, volume);
4680 }
4681
4682 switch(reason) {
4683 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4684 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4685 ioc->name);
4686 break;
4687
4688 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4689
4690 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4691 ioc->name);
4692 break;
4693
4694 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4695 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4696 ioc->name);
4697 break;
4698
4699 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4700 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4701 ioc->name,
4702 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4703 ? "optimal"
4704 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4705 ? "degraded"
4706 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4707 ? "failed"
4708 : "state unknown",
4709 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4710 ? ", enabled" : "",
4711 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4712 ? ", quiesced" : "",
4713 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4714 ? ", resync in progress" : "" );
4715 break;
4716
4717 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4718 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4719 ioc->name, disk);
4720 break;
4721
4722 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4723 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4724 ioc->name);
4725 break;
4726
4727 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4728 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4729 ioc->name);
4730 break;
4731
4732 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4733 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4734 ioc->name);
4735 break;
4736
4737 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4738 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4739 ioc->name,
4740 state == MPI_PHYSDISK0_STATUS_ONLINE
4741 ? "online"
4742 : state == MPI_PHYSDISK0_STATUS_MISSING
4743 ? "missing"
4744 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4745 ? "not compatible"
4746 : state == MPI_PHYSDISK0_STATUS_FAILED
4747 ? "failed"
4748 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4749 ? "initializing"
4750 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4751 ? "offline requested"
4752 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4753 ? "failed requested"
4754 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4755 ? "offline"
4756 : "state unknown",
4757 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4758 ? ", out of sync" : "",
4759 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4760 ? ", quiesced" : "" );
4761 break;
4762
4763 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4764 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4765 ioc->name, disk);
4766 break;
4767
4768 case MPI_EVENT_RAID_RC_SMART_DATA:
4769 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4770 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4771 break;
4772
4773 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4774 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4775 ioc->name, disk);
4776 break;
4777 }
4778}
4779
4780/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004781/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4783 * @ioc: Pointer to MPT_ADAPTER structure
4784 *
4785 * Returns: 0 for success
4786 * -ENOMEM if no memory available
4787 * -EPERM if not allowed due to ISR context
4788 * -EAGAIN if no msg frames currently available
4789 * -EFAULT for non-successful reply or no reply (timeout)
4790 */
4791static int
4792GetIoUnitPage2(MPT_ADAPTER *ioc)
4793{
4794 ConfigPageHeader_t hdr;
4795 CONFIGPARMS cfg;
4796 IOUnitPage2_t *ppage_alloc;
4797 dma_addr_t page_dma;
4798 int data_sz;
4799 int rc;
4800
4801 /* Get the page header */
4802 hdr.PageVersion = 0;
4803 hdr.PageLength = 0;
4804 hdr.PageNumber = 2;
4805 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004806 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 cfg.physAddr = -1;
4808 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4809 cfg.dir = 0;
4810 cfg.pageAddr = 0;
4811 cfg.timeout = 0;
4812
4813 if ((rc = mpt_config(ioc, &cfg)) != 0)
4814 return rc;
4815
4816 if (hdr.PageLength == 0)
4817 return 0;
4818
4819 /* Read the config page */
4820 data_sz = hdr.PageLength * 4;
4821 rc = -ENOMEM;
4822 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4823 if (ppage_alloc) {
4824 memset((u8 *)ppage_alloc, 0, data_sz);
4825 cfg.physAddr = page_dma;
4826 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4827
4828 /* If Good, save data */
4829 if ((rc = mpt_config(ioc, &cfg)) == 0)
4830 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4831
4832 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4833 }
4834
4835 return rc;
4836}
4837
4838/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004839/**
4840 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 * @ioc: Pointer to a Adapter Strucutre
4842 * @portnum: IOC port number
4843 *
4844 * Return: -EFAULT if read of config page header fails
4845 * or if no nvram
4846 * If read of SCSI Port Page 0 fails,
4847 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4848 * Adapter settings: async, narrow
4849 * Return 1
4850 * If read of SCSI Port Page 2 fails,
4851 * Adapter settings valid
4852 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4853 * Return 1
4854 * Else
4855 * Both valid
4856 * Return 0
4857 * CHECK - what type of locking mechanisms should be used????
4858 */
4859static int
4860mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4861{
4862 u8 *pbuf;
4863 dma_addr_t buf_dma;
4864 CONFIGPARMS cfg;
4865 ConfigPageHeader_t header;
4866 int ii;
4867 int data, rc = 0;
4868
4869 /* Allocate memory
4870 */
4871 if (!ioc->spi_data.nvram) {
4872 int sz;
4873 u8 *mem;
4874 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4875 mem = kmalloc(sz, GFP_ATOMIC);
4876 if (mem == NULL)
4877 return -EFAULT;
4878
4879 ioc->spi_data.nvram = (int *) mem;
4880
Prakash, Sathya436ace72007-07-24 15:42:08 +05304881 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 ioc->name, ioc->spi_data.nvram, sz));
4883 }
4884
4885 /* Invalidate NVRAM information
4886 */
4887 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4888 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4889 }
4890
4891 /* Read SPP0 header, allocate memory, then read page.
4892 */
4893 header.PageVersion = 0;
4894 header.PageLength = 0;
4895 header.PageNumber = 0;
4896 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004897 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 cfg.physAddr = -1;
4899 cfg.pageAddr = portnum;
4900 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4901 cfg.dir = 0;
4902 cfg.timeout = 0; /* use default */
4903 if (mpt_config(ioc, &cfg) != 0)
4904 return -EFAULT;
4905
4906 if (header.PageLength > 0) {
4907 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4908 if (pbuf) {
4909 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4910 cfg.physAddr = buf_dma;
4911 if (mpt_config(ioc, &cfg) != 0) {
4912 ioc->spi_data.maxBusWidth = MPT_NARROW;
4913 ioc->spi_data.maxSyncOffset = 0;
4914 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4915 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4916 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304917 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4918 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004919 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 } else {
4921 /* Save the Port Page 0 data
4922 */
4923 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4924 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4925 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4926
4927 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4928 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004929 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4930 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 ioc->name, pPP0->Capabilities));
4932 }
4933 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4934 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4935 if (data) {
4936 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4937 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4938 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304939 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4940 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004941 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 } else {
4943 ioc->spi_data.maxSyncOffset = 0;
4944 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4945 }
4946
4947 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4948
4949 /* Update the minSyncFactor based on bus type.
4950 */
4951 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4952 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4953
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004954 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304956 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4957 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004958 ioc->name, ioc->spi_data.minSyncFactor));
4959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 }
4961 }
4962 if (pbuf) {
4963 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4964 }
4965 }
4966 }
4967
4968 /* SCSI Port Page 2 - Read the header then the page.
4969 */
4970 header.PageVersion = 0;
4971 header.PageLength = 0;
4972 header.PageNumber = 2;
4973 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004974 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 cfg.physAddr = -1;
4976 cfg.pageAddr = portnum;
4977 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4978 cfg.dir = 0;
4979 if (mpt_config(ioc, &cfg) != 0)
4980 return -EFAULT;
4981
4982 if (header.PageLength > 0) {
4983 /* Allocate memory and read SCSI Port Page 2
4984 */
4985 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4986 if (pbuf) {
4987 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4988 cfg.physAddr = buf_dma;
4989 if (mpt_config(ioc, &cfg) != 0) {
4990 /* Nvram data is left with INVALID mark
4991 */
4992 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004993 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4994
4995 /* This is an ATTO adapter, read Page2 accordingly
4996 */
4997 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4998 ATTODeviceInfo_t *pdevice = NULL;
4999 u16 ATTOFlags;
5000
5001 /* Save the Port Page 2 data
5002 * (reformat into a 32bit quantity)
5003 */
5004 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5005 pdevice = &pPP2->DeviceSettings[ii];
5006 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5007 data = 0;
5008
5009 /* Translate ATTO device flags to LSI format
5010 */
5011 if (ATTOFlags & ATTOFLAG_DISC)
5012 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5013 if (ATTOFlags & ATTOFLAG_ID_ENB)
5014 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5015 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5016 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5017 if (ATTOFlags & ATTOFLAG_TAGGED)
5018 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5019 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5020 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5021
5022 data = (data << 16) | (pdevice->Period << 8) | 10;
5023 ioc->spi_data.nvram[ii] = data;
5024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 } else {
5026 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5027 MpiDeviceInfo_t *pdevice = NULL;
5028
Moore, Ericd8e925d2006-01-16 18:53:06 -07005029 /*
5030 * Save "Set to Avoid SCSI Bus Resets" flag
5031 */
5032 ioc->spi_data.bus_reset =
5033 (le32_to_cpu(pPP2->PortFlags) &
5034 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5035 0 : 1 ;
5036
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 /* Save the Port Page 2 data
5038 * (reformat into a 32bit quantity)
5039 */
5040 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5041 ioc->spi_data.PortFlags = data;
5042 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5043 pdevice = &pPP2->DeviceSettings[ii];
5044 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5045 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5046 ioc->spi_data.nvram[ii] = data;
5047 }
5048 }
5049
5050 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5051 }
5052 }
5053
5054 /* Update Adapter limits with those from NVRAM
5055 * Comment: Don't need to do this. Target performance
5056 * parameters will never exceed the adapters limits.
5057 */
5058
5059 return rc;
5060}
5061
5062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005063/**
5064 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 * @ioc: Pointer to a Adapter Strucutre
5066 * @portnum: IOC port number
5067 *
5068 * Return: -EFAULT if read of config page header fails
5069 * or 0 if success.
5070 */
5071static int
5072mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5073{
5074 CONFIGPARMS cfg;
5075 ConfigPageHeader_t header;
5076
5077 /* Read the SCSI Device Page 1 header
5078 */
5079 header.PageVersion = 0;
5080 header.PageLength = 0;
5081 header.PageNumber = 1;
5082 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005083 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 cfg.physAddr = -1;
5085 cfg.pageAddr = portnum;
5086 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5087 cfg.dir = 0;
5088 cfg.timeout = 0;
5089 if (mpt_config(ioc, &cfg) != 0)
5090 return -EFAULT;
5091
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005092 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5093 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094
5095 header.PageVersion = 0;
5096 header.PageLength = 0;
5097 header.PageNumber = 0;
5098 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5099 if (mpt_config(ioc, &cfg) != 0)
5100 return -EFAULT;
5101
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005102 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5103 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
Prakash, Sathya436ace72007-07-24 15:42:08 +05305105 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5107
Prakash, Sathya436ace72007-07-24 15:42:08 +05305108 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5110 return 0;
5111}
5112
Eric Mooreb506ade2007-01-29 09:45:37 -07005113/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005114 * mpt_inactive_raid_list_free - This clears this link list.
5115 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005116 **/
5117static void
5118mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5119{
5120 struct inactive_raid_component_info *component_info, *pNext;
5121
5122 if (list_empty(&ioc->raid_data.inactive_list))
5123 return;
5124
5125 down(&ioc->raid_data.inactive_list_mutex);
5126 list_for_each_entry_safe(component_info, pNext,
5127 &ioc->raid_data.inactive_list, list) {
5128 list_del(&component_info->list);
5129 kfree(component_info);
5130 }
5131 up(&ioc->raid_data.inactive_list_mutex);
5132}
5133
5134/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005135 * 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 -07005136 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005137 * @ioc : pointer to per adapter structure
5138 * @channel : volume channel
5139 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005140 **/
5141static void
5142mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5143{
5144 CONFIGPARMS cfg;
5145 ConfigPageHeader_t hdr;
5146 dma_addr_t dma_handle;
5147 pRaidVolumePage0_t buffer = NULL;
5148 int i;
5149 RaidPhysDiskPage0_t phys_disk;
5150 struct inactive_raid_component_info *component_info;
5151 int handle_inactive_volumes;
5152
5153 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5154 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5155 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5156 cfg.pageAddr = (channel << 8) + id;
5157 cfg.cfghdr.hdr = &hdr;
5158 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5159
5160 if (mpt_config(ioc, &cfg) != 0)
5161 goto out;
5162
5163 if (!hdr.PageLength)
5164 goto out;
5165
5166 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5167 &dma_handle);
5168
5169 if (!buffer)
5170 goto out;
5171
5172 cfg.physAddr = dma_handle;
5173 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5174
5175 if (mpt_config(ioc, &cfg) != 0)
5176 goto out;
5177
5178 if (!buffer->NumPhysDisks)
5179 goto out;
5180
5181 handle_inactive_volumes =
5182 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5183 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5184 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5185 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5186
5187 if (!handle_inactive_volumes)
5188 goto out;
5189
5190 down(&ioc->raid_data.inactive_list_mutex);
5191 for (i = 0; i < buffer->NumPhysDisks; i++) {
5192 if(mpt_raid_phys_disk_pg0(ioc,
5193 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5194 continue;
5195
5196 if ((component_info = kmalloc(sizeof (*component_info),
5197 GFP_KERNEL)) == NULL)
5198 continue;
5199
5200 component_info->volumeID = id;
5201 component_info->volumeBus = channel;
5202 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5203 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5204 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5205 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5206
5207 list_add_tail(&component_info->list,
5208 &ioc->raid_data.inactive_list);
5209 }
5210 up(&ioc->raid_data.inactive_list_mutex);
5211
5212 out:
5213 if (buffer)
5214 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5215 dma_handle);
5216}
5217
5218/**
5219 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5220 * @ioc: Pointer to a Adapter Structure
5221 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5222 * @phys_disk: requested payload data returned
5223 *
5224 * Return:
5225 * 0 on success
5226 * -EFAULT if read of config page header fails or data pointer not NULL
5227 * -ENOMEM if pci_alloc failed
5228 **/
5229int
5230mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5231{
5232 CONFIGPARMS cfg;
5233 ConfigPageHeader_t hdr;
5234 dma_addr_t dma_handle;
5235 pRaidPhysDiskPage0_t buffer = NULL;
5236 int rc;
5237
5238 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5239 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5240
5241 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5242 cfg.cfghdr.hdr = &hdr;
5243 cfg.physAddr = -1;
5244 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5245
5246 if (mpt_config(ioc, &cfg) != 0) {
5247 rc = -EFAULT;
5248 goto out;
5249 }
5250
5251 if (!hdr.PageLength) {
5252 rc = -EFAULT;
5253 goto out;
5254 }
5255
5256 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5257 &dma_handle);
5258
5259 if (!buffer) {
5260 rc = -ENOMEM;
5261 goto out;
5262 }
5263
5264 cfg.physAddr = dma_handle;
5265 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5266 cfg.pageAddr = phys_disk_num;
5267
5268 if (mpt_config(ioc, &cfg) != 0) {
5269 rc = -EFAULT;
5270 goto out;
5271 }
5272
5273 rc = 0;
5274 memcpy(phys_disk, buffer, sizeof(*buffer));
5275 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5276
5277 out:
5278
5279 if (buffer)
5280 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5281 dma_handle);
5282
5283 return rc;
5284}
5285
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286/**
5287 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5288 * @ioc: Pointer to a Adapter Strucutre
5289 * @portnum: IOC port number
5290 *
5291 * Return:
5292 * 0 on success
5293 * -EFAULT if read of config page header fails or data pointer not NULL
5294 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005295 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296int
5297mpt_findImVolumes(MPT_ADAPTER *ioc)
5298{
5299 IOCPage2_t *pIoc2;
5300 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 dma_addr_t ioc2_dma;
5302 CONFIGPARMS cfg;
5303 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 int rc = 0;
5305 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005306 int i;
5307
5308 if (!ioc->ir_firmware)
5309 return 0;
5310
5311 /* Free the old page
5312 */
5313 kfree(ioc->raid_data.pIocPg2);
5314 ioc->raid_data.pIocPg2 = NULL;
5315 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316
5317 /* Read IOCP2 header then the page.
5318 */
5319 header.PageVersion = 0;
5320 header.PageLength = 0;
5321 header.PageNumber = 2;
5322 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005323 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 cfg.physAddr = -1;
5325 cfg.pageAddr = 0;
5326 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5327 cfg.dir = 0;
5328 cfg.timeout = 0;
5329 if (mpt_config(ioc, &cfg) != 0)
5330 return -EFAULT;
5331
5332 if (header.PageLength == 0)
5333 return -EFAULT;
5334
5335 iocpage2sz = header.PageLength * 4;
5336 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5337 if (!pIoc2)
5338 return -ENOMEM;
5339
5340 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5341 cfg.physAddr = ioc2_dma;
5342 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005343 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Eric Mooreb506ade2007-01-29 09:45:37 -07005345 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5346 if (!mem)
5347 goto out;
5348
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005350 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351
Eric Mooreb506ade2007-01-29 09:45:37 -07005352 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353
Eric Mooreb506ade2007-01-29 09:45:37 -07005354 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5355 mpt_inactive_raid_volumes(ioc,
5356 pIoc2->RaidVolume[i].VolumeBus,
5357 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358
Eric Mooreb506ade2007-01-29 09:45:37 -07005359 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5361
5362 return rc;
5363}
5364
Moore, Ericc972c702006-03-14 09:14:06 -07005365static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5367{
5368 IOCPage3_t *pIoc3;
5369 u8 *mem;
5370 CONFIGPARMS cfg;
5371 ConfigPageHeader_t header;
5372 dma_addr_t ioc3_dma;
5373 int iocpage3sz = 0;
5374
5375 /* Free the old page
5376 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005377 kfree(ioc->raid_data.pIocPg3);
5378 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379
5380 /* There is at least one physical disk.
5381 * Read and save IOC Page 3
5382 */
5383 header.PageVersion = 0;
5384 header.PageLength = 0;
5385 header.PageNumber = 3;
5386 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005387 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 cfg.physAddr = -1;
5389 cfg.pageAddr = 0;
5390 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5391 cfg.dir = 0;
5392 cfg.timeout = 0;
5393 if (mpt_config(ioc, &cfg) != 0)
5394 return 0;
5395
5396 if (header.PageLength == 0)
5397 return 0;
5398
5399 /* Read Header good, alloc memory
5400 */
5401 iocpage3sz = header.PageLength * 4;
5402 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5403 if (!pIoc3)
5404 return 0;
5405
5406 /* Read the Page and save the data
5407 * into malloc'd memory.
5408 */
5409 cfg.physAddr = ioc3_dma;
5410 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5411 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005412 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 if (mem) {
5414 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005415 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 }
5417 }
5418
5419 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5420
5421 return 0;
5422}
5423
5424static void
5425mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5426{
5427 IOCPage4_t *pIoc4;
5428 CONFIGPARMS cfg;
5429 ConfigPageHeader_t header;
5430 dma_addr_t ioc4_dma;
5431 int iocpage4sz;
5432
5433 /* Read and save IOC Page 4
5434 */
5435 header.PageVersion = 0;
5436 header.PageLength = 0;
5437 header.PageNumber = 4;
5438 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005439 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 cfg.physAddr = -1;
5441 cfg.pageAddr = 0;
5442 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5443 cfg.dir = 0;
5444 cfg.timeout = 0;
5445 if (mpt_config(ioc, &cfg) != 0)
5446 return;
5447
5448 if (header.PageLength == 0)
5449 return;
5450
5451 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5452 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5453 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5454 if (!pIoc4)
5455 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005456 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 } else {
5458 ioc4_dma = ioc->spi_data.IocPg4_dma;
5459 iocpage4sz = ioc->spi_data.IocPg4Sz;
5460 }
5461
5462 /* Read the Page into dma memory.
5463 */
5464 cfg.physAddr = ioc4_dma;
5465 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5466 if (mpt_config(ioc, &cfg) == 0) {
5467 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5468 ioc->spi_data.IocPg4_dma = ioc4_dma;
5469 ioc->spi_data.IocPg4Sz = iocpage4sz;
5470 } else {
5471 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5472 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005473 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 }
5475}
5476
5477static void
5478mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5479{
5480 IOCPage1_t *pIoc1;
5481 CONFIGPARMS cfg;
5482 ConfigPageHeader_t header;
5483 dma_addr_t ioc1_dma;
5484 int iocpage1sz = 0;
5485 u32 tmp;
5486
5487 /* Check the Coalescing Timeout in IOC Page 1
5488 */
5489 header.PageVersion = 0;
5490 header.PageLength = 0;
5491 header.PageNumber = 1;
5492 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005493 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 cfg.physAddr = -1;
5495 cfg.pageAddr = 0;
5496 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5497 cfg.dir = 0;
5498 cfg.timeout = 0;
5499 if (mpt_config(ioc, &cfg) != 0)
5500 return;
5501
5502 if (header.PageLength == 0)
5503 return;
5504
5505 /* Read Header good, alloc memory
5506 */
5507 iocpage1sz = header.PageLength * 4;
5508 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5509 if (!pIoc1)
5510 return;
5511
5512 /* Read the Page and check coalescing timeout
5513 */
5514 cfg.physAddr = ioc1_dma;
5515 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5516 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305517
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5519 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5520 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5521
Prakash, Sathya436ace72007-07-24 15:42:08 +05305522 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 ioc->name, tmp));
5524
5525 if (tmp > MPT_COALESCING_TIMEOUT) {
5526 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5527
5528 /* Write NVRAM and current
5529 */
5530 cfg.dir = 1;
5531 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5532 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305533 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 ioc->name, MPT_COALESCING_TIMEOUT));
5535
5536 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5537 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305538 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5539 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 ioc->name, MPT_COALESCING_TIMEOUT));
5541 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305542 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5543 "Reset NVRAM Coalescing Timeout Failed\n",
5544 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 }
5546
5547 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305548 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5549 "Reset of Current Coalescing Timeout Failed!\n",
5550 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 }
5552 }
5553
5554 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305555 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 }
5557 }
5558
5559 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5560
5561 return;
5562}
5563
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305564static void
5565mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5566{
5567 CONFIGPARMS cfg;
5568 ConfigPageHeader_t hdr;
5569 dma_addr_t buf_dma;
5570 ManufacturingPage0_t *pbuf = NULL;
5571
5572 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5573 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5574
5575 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5576 cfg.cfghdr.hdr = &hdr;
5577 cfg.physAddr = -1;
5578 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5579 cfg.timeout = 10;
5580
5581 if (mpt_config(ioc, &cfg) != 0)
5582 goto out;
5583
5584 if (!cfg.cfghdr.hdr->PageLength)
5585 goto out;
5586
5587 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5588 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5589 if (!pbuf)
5590 goto out;
5591
5592 cfg.physAddr = buf_dma;
5593
5594 if (mpt_config(ioc, &cfg) != 0)
5595 goto out;
5596
5597 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5598 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5599 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5600
5601 out:
5602
5603 if (pbuf)
5604 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5605}
5606
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005608/**
5609 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 * @ioc: Pointer to MPT_ADAPTER structure
5611 * @EvSwitch: Event switch flags
5612 */
5613static int
5614SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5615{
5616 EventNotification_t *evnp;
5617
5618 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5619 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305620 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 ioc->name));
5622 return 0;
5623 }
5624 memset(evnp, 0, sizeof(*evnp));
5625
Prakash, Sathya436ace72007-07-24 15:42:08 +05305626 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627
5628 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5629 evnp->ChainOffset = 0;
5630 evnp->MsgFlags = 0;
5631 evnp->Switch = EvSwitch;
5632
5633 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5634
5635 return 0;
5636}
5637
5638/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5639/**
5640 * SendEventAck - Send EventAck request to MPT adapter.
5641 * @ioc: Pointer to MPT_ADAPTER structure
5642 * @evnp: Pointer to original EventNotification request
5643 */
5644static int
5645SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5646{
5647 EventAck_t *pAck;
5648
5649 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305650 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005651 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 return -1;
5653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654
Prakash, Sathya436ace72007-07-24 15:42:08 +05305655 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656
5657 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5658 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005659 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005661 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 pAck->Event = evnp->Event;
5663 pAck->EventContext = evnp->EventContext;
5664
5665 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5666
5667 return 0;
5668}
5669
5670/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5671/**
5672 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005673 * @ioc: Pointer to an adapter structure
5674 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 * action, page address, direction, physical address
5676 * and pointer to a configuration page header
5677 * Page header is updated.
5678 *
5679 * Returns 0 for success
5680 * -EPERM if not allowed due to ISR context
5681 * -EAGAIN if no msg frames currently available
5682 * -EFAULT for non-successful reply or no reply (timeout)
5683 */
5684int
5685mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5686{
5687 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005688 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 MPT_FRAME_HDR *mf;
5690 unsigned long flags;
5691 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005692 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 int in_isr;
5694
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005695 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 * to be in ISR context, because that is fatal!
5697 */
5698 in_isr = in_interrupt();
5699 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305700 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 ioc->name));
5702 return -EPERM;
5703 }
5704
5705 /* Get and Populate a free Frame
5706 */
5707 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305708 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 ioc->name));
5710 return -EAGAIN;
5711 }
5712 pReq = (Config_t *)mf;
5713 pReq->Action = pCfg->action;
5714 pReq->Reserved = 0;
5715 pReq->ChainOffset = 0;
5716 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005717
5718 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 pReq->ExtPageLength = 0;
5720 pReq->ExtPageType = 0;
5721 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005722
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 for (ii=0; ii < 8; ii++)
5724 pReq->Reserved2[ii] = 0;
5725
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005726 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5727 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5728 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5729 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5730
5731 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5732 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5733 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5734 pReq->ExtPageType = pExtHdr->ExtPageType;
5735 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5736
5737 /* Page Length must be treated as a reserved field for the extended header. */
5738 pReq->Header.PageLength = 0;
5739 }
5740
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5742
5743 /* Add a SGE to the config request.
5744 */
5745 if (pCfg->dir)
5746 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5747 else
5748 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5749
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005750 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5751 flagsLength |= pExtHdr->ExtPageLength * 4;
5752
Prakash, Sathya436ace72007-07-24 15:42:08 +05305753 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 +02005754 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5755 }
5756 else {
5757 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5758
Prakash, Sathya436ace72007-07-24 15:42:08 +05305759 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 +02005760 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5764
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 /* Append pCfg pointer to end of mf
5766 */
5767 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5768
5769 /* Initalize the timer
5770 */
5771 init_timer(&pCfg->timer);
5772 pCfg->timer.data = (unsigned long) ioc;
5773 pCfg->timer.function = mpt_timer_expired;
5774 pCfg->wait_done = 0;
5775
5776 /* Set the timer; ensure 10 second minimum */
5777 if (pCfg->timeout < 10)
5778 pCfg->timer.expires = jiffies + HZ*10;
5779 else
5780 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5781
5782 /* Add to end of Q, set timer and then issue this command */
5783 spin_lock_irqsave(&ioc->FreeQlock, flags);
5784 list_add_tail(&pCfg->linkage, &ioc->configQ);
5785 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5786
5787 add_timer(&pCfg->timer);
5788 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5789 wait_event(mpt_waitq, pCfg->wait_done);
5790
5791 /* mf has been freed - do not access */
5792
5793 rc = pCfg->status;
5794
5795 return rc;
5796}
5797
5798/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005799/**
5800 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 * Used only internal config functionality.
5802 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5803 */
5804static void
5805mpt_timer_expired(unsigned long data)
5806{
5807 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5808
Prakash, Sathya436ace72007-07-24 15:42:08 +05305809 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
5811 /* Perform a FW reload */
5812 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5813 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5814
5815 /* No more processing.
5816 * Hard reset clean-up will wake up
5817 * process and free all resources.
5818 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305819 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820
5821 return;
5822}
5823
5824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005825/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 * mpt_ioc_reset - Base cleanup for hard reset
5827 * @ioc: Pointer to the adapter structure
5828 * @reset_phase: Indicates pre- or post-reset functionality
5829 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005830 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 */
5832static int
5833mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5834{
5835 CONFIGPARMS *pCfg;
5836 unsigned long flags;
5837
Eric Moore29dd3602007-09-14 18:46:51 -06005838 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5839 ": IOC %s_reset routed to MPT base driver!\n",
5840 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5841 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
5843 if (reset_phase == MPT_IOC_SETUP_RESET) {
5844 ;
5845 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5846 /* If the internal config Q is not empty -
5847 * delete timer. MF resources will be freed when
5848 * the FIFO's are primed.
5849 */
5850 spin_lock_irqsave(&ioc->FreeQlock, flags);
5851 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5852 del_timer(&pCfg->timer);
5853 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5854
5855 } else {
5856 CONFIGPARMS *pNext;
5857
5858 /* Search the configQ for internal commands.
5859 * Flush the Q, and wake up all suspended threads.
5860 */
5861 spin_lock_irqsave(&ioc->FreeQlock, flags);
5862 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5863 list_del(&pCfg->linkage);
5864
5865 pCfg->status = MPT_CONFIG_ERROR;
5866 pCfg->wait_done = 1;
5867 wake_up(&mpt_waitq);
5868 }
5869 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5870 }
5871
5872 return 1; /* currently means nothing really */
5873}
5874
5875
5876#ifdef CONFIG_PROC_FS /* { */
5877/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5878/*
5879 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5880 */
5881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005882/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5884 *
5885 * Returns 0 for success, non-zero for failure.
5886 */
5887static int
5888procmpt_create(void)
5889{
5890 struct proc_dir_entry *ent;
5891
5892 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5893 if (mpt_proc_root_dir == NULL)
5894 return -ENOTDIR;
5895
5896 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5897 if (ent)
5898 ent->read_proc = procmpt_summary_read;
5899
5900 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5901 if (ent)
5902 ent->read_proc = procmpt_version_read;
5903
5904 return 0;
5905}
5906
5907/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005908/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5910 *
5911 * Returns 0 for success, non-zero for failure.
5912 */
5913static void
5914procmpt_destroy(void)
5915{
5916 remove_proc_entry("version", mpt_proc_root_dir);
5917 remove_proc_entry("summary", mpt_proc_root_dir);
5918 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5919}
5920
5921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005922/**
5923 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 * @buf: Pointer to area to write information
5925 * @start: Pointer to start pointer
5926 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005927 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 * @eof: Pointer to EOF integer
5929 * @data: Pointer
5930 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005931 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 * Returns number of characters written to process performing the read.
5933 */
5934static int
5935procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5936{
5937 MPT_ADAPTER *ioc;
5938 char *out = buf;
5939 int len;
5940
5941 if (data) {
5942 int more = 0;
5943
5944 ioc = data;
5945 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5946
5947 out += more;
5948 } else {
5949 list_for_each_entry(ioc, &ioc_list, list) {
5950 int more = 0;
5951
5952 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5953
5954 out += more;
5955 if ((out-buf) >= request)
5956 break;
5957 }
5958 }
5959
5960 len = out - buf;
5961
5962 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5963}
5964
5965/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005966/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 * procmpt_version_read - Handle read request from /proc/mpt/version.
5968 * @buf: Pointer to area to write information
5969 * @start: Pointer to start pointer
5970 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005971 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 * @eof: Pointer to EOF integer
5973 * @data: Pointer
5974 *
5975 * Returns number of characters written to process performing the read.
5976 */
5977static int
5978procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5979{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305980 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005981 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 char *drvname;
5983 int len;
5984
5985 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5986 len += sprintf(buf+len, " Fusion MPT base driver\n");
5987
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005988 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06005989 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305991 if (MptCallbacks[cb_idx]) {
5992 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005993 case MPTSPI_DRIVER:
5994 if (!scsi++) drvname = "SPI host";
5995 break;
5996 case MPTFC_DRIVER:
5997 if (!fc++) drvname = "FC host";
5998 break;
5999 case MPTSAS_DRIVER:
6000 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 break;
6002 case MPTLAN_DRIVER:
6003 if (!lan++) drvname = "LAN";
6004 break;
6005 case MPTSTM_DRIVER:
6006 if (!targ++) drvname = "SCSI target";
6007 break;
6008 case MPTCTL_DRIVER:
6009 if (!ctl++) drvname = "ioctl";
6010 break;
6011 }
6012
6013 if (drvname)
6014 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6015 }
6016 }
6017
6018 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6019}
6020
6021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006022/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6024 * @buf: Pointer to area to write information
6025 * @start: Pointer to start pointer
6026 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006027 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 * @eof: Pointer to EOF integer
6029 * @data: Pointer
6030 *
6031 * Returns number of characters written to process performing the read.
6032 */
6033static int
6034procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6035{
6036 MPT_ADAPTER *ioc = data;
6037 int len;
6038 char expVer[32];
6039 int sz;
6040 int p;
6041
6042 mpt_get_fw_exp_ver(expVer, ioc);
6043
6044 len = sprintf(buf, "%s:", ioc->name);
6045 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6046 len += sprintf(buf+len, " (f/w download boot flag set)");
6047// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6048// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6049
6050 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6051 ioc->facts.ProductID,
6052 ioc->prod_name);
6053 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6054 if (ioc->facts.FWImageSize)
6055 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6056 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6057 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6058 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6059
6060 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6061 ioc->facts.CurrentHostMfaHighAddr);
6062 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6063 ioc->facts.CurrentSenseBufferHighAddr);
6064
6065 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6066 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6067
6068 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6069 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6070 /*
6071 * Rounding UP to nearest 4-kB boundary here...
6072 */
6073 sz = (ioc->req_sz * ioc->req_depth) + 128;
6074 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6075 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6076 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6077 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6078 4*ioc->facts.RequestFrameSize,
6079 ioc->facts.GlobalCredits);
6080
6081 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6082 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6083 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6084 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6085 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6086 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6087 ioc->facts.CurReplyFrameSize,
6088 ioc->facts.ReplyQueueDepth);
6089
6090 len += sprintf(buf+len, " MaxDevices = %d\n",
6091 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6092 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6093
6094 /* per-port info */
6095 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6096 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6097 p+1,
6098 ioc->facts.NumberOfPorts);
6099 if (ioc->bus_type == FC) {
6100 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6101 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6102 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6103 a[5], a[4], a[3], a[2], a[1], a[0]);
6104 }
6105 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6106 ioc->fc_port_page0[p].WWNN.High,
6107 ioc->fc_port_page0[p].WWNN.Low,
6108 ioc->fc_port_page0[p].WWPN.High,
6109 ioc->fc_port_page0[p].WWPN.Low);
6110 }
6111 }
6112
6113 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6114}
6115
6116#endif /* CONFIG_PROC_FS } */
6117
6118/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6119static void
6120mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6121{
6122 buf[0] ='\0';
6123 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6124 sprintf(buf, " (Exp %02d%02d)",
6125 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6126 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6127
6128 /* insider hack! */
6129 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6130 strcat(buf, " [MDBG]");
6131 }
6132}
6133
6134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6135/**
6136 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6137 * @ioc: Pointer to MPT_ADAPTER structure
6138 * @buffer: Pointer to buffer where IOC summary info should be written
6139 * @size: Pointer to number of bytes we wrote (set by this routine)
6140 * @len: Offset at which to start writing in buffer
6141 * @showlan: Display LAN stuff?
6142 *
6143 * This routine writes (english readable) ASCII text, which represents
6144 * a summary of IOC information, to a buffer.
6145 */
6146void
6147mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6148{
6149 char expVer[32];
6150 int y;
6151
6152 mpt_get_fw_exp_ver(expVer, ioc);
6153
6154 /*
6155 * Shorter summary of attached ioc's...
6156 */
6157 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6158 ioc->name,
6159 ioc->prod_name,
6160 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6161 ioc->facts.FWVersion.Word,
6162 expVer,
6163 ioc->facts.NumberOfPorts,
6164 ioc->req_depth);
6165
6166 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6167 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6168 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6169 a[5], a[4], a[3], a[2], a[1], a[0]);
6170 }
6171
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173
6174 if (!ioc->active)
6175 y += sprintf(buffer+len+y, " (disabled)");
6176
6177 y += sprintf(buffer+len+y, "\n");
6178
6179 *size = y;
6180}
6181
6182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6183/*
6184 * Reset Handling
6185 */
6186/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6187/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006188 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 * @ioc: Pointer to MPT_ADAPTER structure
6190 * @sleepFlag: Indicates if sleep or schedule must be called.
6191 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006192 * Issues SCSI Task Management call based on input arg values.
6193 * If TaskMgmt fails, returns associated SCSI request.
6194 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6196 * or a non-interrupt thread. In the former, must not call schedule().
6197 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006198 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 * FW reload/initialization failed.
6200 *
6201 * Returns 0 for SUCCESS or -1 if FAILED.
6202 */
6203int
6204mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6205{
6206 int rc;
6207 unsigned long flags;
6208
Prakash, Sathya436ace72007-07-24 15:42:08 +05306209 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210#ifdef MFCNT
6211 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6212 printk("MF count 0x%x !\n", ioc->mfcnt);
6213#endif
6214
6215 /* Reset the adapter. Prevent more than 1 call to
6216 * mpt_do_ioc_recovery at any instant in time.
6217 */
6218 spin_lock_irqsave(&ioc->diagLock, flags);
6219 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6220 spin_unlock_irqrestore(&ioc->diagLock, flags);
6221 return 0;
6222 } else {
6223 ioc->diagPending = 1;
6224 }
6225 spin_unlock_irqrestore(&ioc->diagLock, flags);
6226
6227 /* FIXME: If do_ioc_recovery fails, repeat....
6228 */
6229
6230 /* The SCSI driver needs to adjust timeouts on all current
6231 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006232 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 * For all other protocol drivers, this is a no-op.
6234 */
6235 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306236 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 int r = 0;
6238
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306239 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6240 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306241 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306242 ioc->name, cb_idx));
6243 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306245 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306246 ioc->name, ioc->alt_ioc->name, cb_idx));
6247 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 }
6249 }
6250 }
6251 }
6252
6253 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006254 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 }
6256 ioc->reload_fw = 0;
6257 if (ioc->alt_ioc)
6258 ioc->alt_ioc->reload_fw = 0;
6259
6260 spin_lock_irqsave(&ioc->diagLock, flags);
6261 ioc->diagPending = 0;
6262 if (ioc->alt_ioc)
6263 ioc->alt_ioc->diagPending = 0;
6264 spin_unlock_irqrestore(&ioc->diagLock, flags);
6265
Prakash, Sathya436ace72007-07-24 15:42:08 +05306266 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267
6268 return rc;
6269}
6270
6271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006272static void
6273EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274{
Eric Moore509e5e52006-04-26 13:22:37 -06006275 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
6277 switch(event) {
6278 case MPI_EVENT_NONE:
6279 ds = "None";
6280 break;
6281 case MPI_EVENT_LOG_DATA:
6282 ds = "Log Data";
6283 break;
6284 case MPI_EVENT_STATE_CHANGE:
6285 ds = "State Change";
6286 break;
6287 case MPI_EVENT_UNIT_ATTENTION:
6288 ds = "Unit Attention";
6289 break;
6290 case MPI_EVENT_IOC_BUS_RESET:
6291 ds = "IOC Bus Reset";
6292 break;
6293 case MPI_EVENT_EXT_BUS_RESET:
6294 ds = "External Bus Reset";
6295 break;
6296 case MPI_EVENT_RESCAN:
6297 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298 break;
6299 case MPI_EVENT_LINK_STATUS_CHANGE:
6300 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6301 ds = "Link Status(FAILURE) Change";
6302 else
6303 ds = "Link Status(ACTIVE) Change";
6304 break;
6305 case MPI_EVENT_LOOP_STATE_CHANGE:
6306 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6307 ds = "Loop State(LIP) Change";
6308 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006309 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 else
Eric Moore509e5e52006-04-26 13:22:37 -06006311 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 break;
6313 case MPI_EVENT_LOGOUT:
6314 ds = "Logout";
6315 break;
6316 case MPI_EVENT_EVENT_CHANGE:
6317 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006318 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006320 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 break;
6322 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006323 {
6324 u8 ReasonCode = (u8)(evData0 >> 16);
6325 switch (ReasonCode) {
6326 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6327 ds = "Integrated Raid: Volume Created";
6328 break;
6329 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6330 ds = "Integrated Raid: Volume Deleted";
6331 break;
6332 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6333 ds = "Integrated Raid: Volume Settings Changed";
6334 break;
6335 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6336 ds = "Integrated Raid: Volume Status Changed";
6337 break;
6338 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6339 ds = "Integrated Raid: Volume Physdisk Changed";
6340 break;
6341 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6342 ds = "Integrated Raid: Physdisk Created";
6343 break;
6344 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6345 ds = "Integrated Raid: Physdisk Deleted";
6346 break;
6347 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6348 ds = "Integrated Raid: Physdisk Settings Changed";
6349 break;
6350 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6351 ds = "Integrated Raid: Physdisk Status Changed";
6352 break;
6353 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6354 ds = "Integrated Raid: Domain Validation Needed";
6355 break;
6356 case MPI_EVENT_RAID_RC_SMART_DATA :
6357 ds = "Integrated Raid; Smart Data";
6358 break;
6359 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6360 ds = "Integrated Raid: Replace Action Started";
6361 break;
6362 default:
6363 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006365 }
6366 break;
6367 }
6368 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6369 ds = "SCSI Device Status Change";
6370 break;
6371 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6372 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006373 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006374 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006375 u8 ReasonCode = (u8)(evData0 >> 16);
6376 switch (ReasonCode) {
6377 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006378 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006379 "SAS Device Status Change: Added: "
6380 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006381 break;
6382 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006383 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006384 "SAS Device Status Change: Deleted: "
6385 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006386 break;
6387 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006388 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006389 "SAS Device Status Change: SMART Data: "
6390 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006391 break;
6392 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006393 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006394 "SAS Device Status Change: No Persistancy: "
6395 "id=%d channel=%d", id, channel);
6396 break;
6397 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6398 snprintf(evStr, EVENT_DESCR_STR_SZ,
6399 "SAS Device Status Change: Unsupported Device "
6400 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006401 break;
6402 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6403 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006404 "SAS Device Status Change: Internal Device "
6405 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006406 break;
6407 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6408 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006409 "SAS Device Status Change: Internal Task "
6410 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006411 break;
6412 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6413 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006414 "SAS Device Status Change: Internal Abort "
6415 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006416 break;
6417 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6418 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006419 "SAS Device Status Change: Internal Clear "
6420 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006421 break;
6422 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6423 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006424 "SAS Device Status Change: Internal Query "
6425 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006426 break;
6427 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006428 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006429 "SAS Device Status Change: Unknown: "
6430 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006431 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006432 }
6433 break;
6434 }
6435 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6436 ds = "Bus Timer Expired";
6437 break;
6438 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006439 {
6440 u16 curr_depth = (u16)(evData0 >> 16);
6441 u8 channel = (u8)(evData0 >> 8);
6442 u8 id = (u8)(evData0);
6443
6444 snprintf(evStr, EVENT_DESCR_STR_SZ,
6445 "Queue Full: channel=%d id=%d depth=%d",
6446 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006447 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006448 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006449 case MPI_EVENT_SAS_SES:
6450 ds = "SAS SES Event";
6451 break;
6452 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6453 ds = "Persistent Table Full";
6454 break;
6455 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006456 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006457 u8 LinkRates = (u8)(evData0 >> 8);
6458 u8 PhyNumber = (u8)(evData0);
6459 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6460 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6461 switch (LinkRates) {
6462 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006463 snprintf(evStr, EVENT_DESCR_STR_SZ,
6464 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006465 " Rate Unknown",PhyNumber);
6466 break;
6467 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006468 snprintf(evStr, EVENT_DESCR_STR_SZ,
6469 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006470 " Phy Disabled",PhyNumber);
6471 break;
6472 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006473 snprintf(evStr, EVENT_DESCR_STR_SZ,
6474 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006475 " Failed Speed Nego",PhyNumber);
6476 break;
6477 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006478 snprintf(evStr, EVENT_DESCR_STR_SZ,
6479 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006480 " Sata OOB Completed",PhyNumber);
6481 break;
6482 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006483 snprintf(evStr, EVENT_DESCR_STR_SZ,
6484 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006485 " Rate 1.5 Gbps",PhyNumber);
6486 break;
6487 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006488 snprintf(evStr, EVENT_DESCR_STR_SZ,
6489 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006490 " Rate 3.0 Gpbs",PhyNumber);
6491 break;
6492 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006493 snprintf(evStr, EVENT_DESCR_STR_SZ,
6494 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006495 break;
6496 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006497 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006498 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006499 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6500 ds = "SAS Discovery Error";
6501 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006502 case MPI_EVENT_IR_RESYNC_UPDATE:
6503 {
6504 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006505 snprintf(evStr, EVENT_DESCR_STR_SZ,
6506 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006507 break;
6508 }
6509 case MPI_EVENT_IR2:
6510 {
6511 u8 ReasonCode = (u8)(evData0 >> 16);
6512 switch (ReasonCode) {
6513 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6514 ds = "IR2: LD State Changed";
6515 break;
6516 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6517 ds = "IR2: PD State Changed";
6518 break;
6519 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6520 ds = "IR2: Bad Block Table Full";
6521 break;
6522 case MPI_EVENT_IR2_RC_PD_INSERTED:
6523 ds = "IR2: PD Inserted";
6524 break;
6525 case MPI_EVENT_IR2_RC_PD_REMOVED:
6526 ds = "IR2: PD Removed";
6527 break;
6528 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6529 ds = "IR2: Foreign CFG Detected";
6530 break;
6531 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6532 ds = "IR2: Rebuild Medium Error";
6533 break;
6534 default:
6535 ds = "IR2";
6536 break;
6537 }
6538 break;
6539 }
6540 case MPI_EVENT_SAS_DISCOVERY:
6541 {
6542 if (evData0)
6543 ds = "SAS Discovery: Start";
6544 else
6545 ds = "SAS Discovery: Stop";
6546 break;
6547 }
6548 case MPI_EVENT_LOG_ENTRY_ADDED:
6549 ds = "SAS Log Entry Added";
6550 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006551
Eric Moorec6c727a2007-01-29 09:44:54 -07006552 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6553 {
6554 u8 phy_num = (u8)(evData0);
6555 u8 port_num = (u8)(evData0 >> 8);
6556 u8 port_width = (u8)(evData0 >> 16);
6557 u8 primative = (u8)(evData0 >> 24);
6558 snprintf(evStr, EVENT_DESCR_STR_SZ,
6559 "SAS Broadcase Primative: phy=%d port=%d "
6560 "width=%d primative=0x%02x",
6561 phy_num, port_num, port_width, primative);
6562 break;
6563 }
6564
6565 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6566 {
6567 u8 reason = (u8)(evData0);
6568 u8 port_num = (u8)(evData0 >> 8);
6569 u16 handle = le16_to_cpu(evData0 >> 16);
6570
6571 snprintf(evStr, EVENT_DESCR_STR_SZ,
6572 "SAS Initiator Device Status Change: reason=0x%02x "
6573 "port=%d handle=0x%04x",
6574 reason, port_num, handle);
6575 break;
6576 }
6577
6578 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6579 {
6580 u8 max_init = (u8)(evData0);
6581 u8 current_init = (u8)(evData0 >> 8);
6582
6583 snprintf(evStr, EVENT_DESCR_STR_SZ,
6584 "SAS Initiator Device Table Overflow: max initiators=%02d "
6585 "current initators=%02d",
6586 max_init, current_init);
6587 break;
6588 }
6589 case MPI_EVENT_SAS_SMP_ERROR:
6590 {
6591 u8 status = (u8)(evData0);
6592 u8 port_num = (u8)(evData0 >> 8);
6593 u8 result = (u8)(evData0 >> 16);
6594
6595 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6596 snprintf(evStr, EVENT_DESCR_STR_SZ,
6597 "SAS SMP Error: port=%d result=0x%02x",
6598 port_num, result);
6599 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6600 snprintf(evStr, EVENT_DESCR_STR_SZ,
6601 "SAS SMP Error: port=%d : CRC Error",
6602 port_num);
6603 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6604 snprintf(evStr, EVENT_DESCR_STR_SZ,
6605 "SAS SMP Error: port=%d : Timeout",
6606 port_num);
6607 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6608 snprintf(evStr, EVENT_DESCR_STR_SZ,
6609 "SAS SMP Error: port=%d : No Destination",
6610 port_num);
6611 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6612 snprintf(evStr, EVENT_DESCR_STR_SZ,
6613 "SAS SMP Error: port=%d : Bad Destination",
6614 port_num);
6615 else
6616 snprintf(evStr, EVENT_DESCR_STR_SZ,
6617 "SAS SMP Error: port=%d : status=0x%02x",
6618 port_num, status);
6619 break;
6620 }
6621
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622 /*
6623 * MPT base "custom" events may be added here...
6624 */
6625 default:
6626 ds = "Unknown";
6627 break;
6628 }
Eric Moore509e5e52006-04-26 13:22:37 -06006629 if (ds)
6630 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631}
6632
6633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006634/**
6635 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636 * @ioc: Pointer to MPT_ADAPTER structure
6637 * @pEventReply: Pointer to EventNotification reply frame
6638 * @evHandlers: Pointer to integer, number of event handlers
6639 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006640 * Routes a received EventNotificationReply to all currently registered
6641 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642 * Returns sum of event handlers return values.
6643 */
6644static int
6645ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6646{
6647 u16 evDataLen;
6648 u32 evData0 = 0;
6649// u32 evCtx;
6650 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306651 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652 int r = 0;
6653 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006654 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655 u8 event;
6656
6657 /*
6658 * Do platform normalization of values
6659 */
6660 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6661// evCtx = le32_to_cpu(pEventReply->EventContext);
6662 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6663 if (evDataLen) {
6664 evData0 = le32_to_cpu(pEventReply->Data[0]);
6665 }
6666
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006667 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306668 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006670 event,
6671 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672
Prakash, Sathya436ace72007-07-24 15:42:08 +05306673#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006674 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6675 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306677 devtverboseprintk(ioc, printk(" %08x",
6678 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006679 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680#endif
6681
6682 /*
6683 * Do general / base driver event processing
6684 */
6685 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6687 if (evDataLen) {
6688 u8 evState = evData0 & 0xFF;
6689
6690 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6691
6692 /* Update EventState field in cached IocFacts */
6693 if (ioc->facts.Function) {
6694 ioc->facts.EventState = evState;
6695 }
6696 }
6697 break;
Moore, Ericece50912006-01-16 18:53:19 -07006698 case MPI_EVENT_INTEGRATED_RAID:
6699 mptbase_raid_process_event_data(ioc,
6700 (MpiEventDataRaid_t *)pEventReply->Data);
6701 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006702 default:
6703 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704 }
6705
6706 /*
6707 * Should this event be logged? Events are written sequentially.
6708 * When buffer is full, start again at the top.
6709 */
6710 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6711 int idx;
6712
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006713 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714
6715 ioc->events[idx].event = event;
6716 ioc->events[idx].eventContext = ioc->eventContext;
6717
6718 for (ii = 0; ii < 2; ii++) {
6719 if (ii < evDataLen)
6720 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6721 else
6722 ioc->events[idx].data[ii] = 0;
6723 }
6724
6725 ioc->eventContext++;
6726 }
6727
6728
6729 /*
6730 * Call each currently registered protocol event handler.
6731 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006732 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306733 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306734 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306735 ioc->name, cb_idx));
6736 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737 handlers++;
6738 }
6739 }
6740 /* FIXME? Examine results here? */
6741
6742 /*
6743 * If needed, send (a single) EventAck.
6744 */
6745 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306746 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006747 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306749 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750 ioc->name, ii));
6751 }
6752 }
6753
6754 *evHandlers = handlers;
6755 return r;
6756}
6757
6758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006759/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6761 * @ioc: Pointer to MPT_ADAPTER structure
6762 * @log_info: U32 LogInfo reply word from the IOC
6763 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006764 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765 */
6766static void
6767mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6768{
Eric Moore7c431e52007-06-13 16:34:36 -06006769 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006770
Eric Moore7c431e52007-06-13 16:34:36 -06006771 switch (log_info & 0xFF000000) {
6772 case MPI_IOCLOGINFO_FC_INIT_BASE:
6773 desc = "FCP Initiator";
6774 break;
6775 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6776 desc = "FCP Target";
6777 break;
6778 case MPI_IOCLOGINFO_FC_LAN_BASE:
6779 desc = "LAN";
6780 break;
6781 case MPI_IOCLOGINFO_FC_MSG_BASE:
6782 desc = "MPI Message Layer";
6783 break;
6784 case MPI_IOCLOGINFO_FC_LINK_BASE:
6785 desc = "FC Link";
6786 break;
6787 case MPI_IOCLOGINFO_FC_CTX_BASE:
6788 desc = "Context Manager";
6789 break;
6790 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6791 desc = "Invalid Field Offset";
6792 break;
6793 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6794 desc = "State Change Info";
6795 break;
6796 }
6797
6798 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6799 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800}
6801
6802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006803/**
Moore, Eric335a9412006-01-17 17:06:23 -07006804 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805 * @ioc: Pointer to MPT_ADAPTER structure
6806 * @mr: Pointer to MPT reply frame
6807 * @log_info: U32 LogInfo word from the IOC
6808 *
6809 * Refer to lsi/sp_log.h.
6810 */
6811static void
Moore, Eric335a9412006-01-17 17:06:23 -07006812mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813{
6814 u32 info = log_info & 0x00FF0000;
6815 char *desc = "unknown";
6816
6817 switch (info) {
6818 case 0x00010000:
6819 desc = "bug! MID not found";
6820 if (ioc->reload_fw == 0)
6821 ioc->reload_fw++;
6822 break;
6823
6824 case 0x00020000:
6825 desc = "Parity Error";
6826 break;
6827
6828 case 0x00030000:
6829 desc = "ASYNC Outbound Overrun";
6830 break;
6831
6832 case 0x00040000:
6833 desc = "SYNC Offset Error";
6834 break;
6835
6836 case 0x00050000:
6837 desc = "BM Change";
6838 break;
6839
6840 case 0x00060000:
6841 desc = "Msg In Overflow";
6842 break;
6843
6844 case 0x00070000:
6845 desc = "DMA Error";
6846 break;
6847
6848 case 0x00080000:
6849 desc = "Outbound DMA Overrun";
6850 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006851
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852 case 0x00090000:
6853 desc = "Task Management";
6854 break;
6855
6856 case 0x000A0000:
6857 desc = "Device Problem";
6858 break;
6859
6860 case 0x000B0000:
6861 desc = "Invalid Phase Change";
6862 break;
6863
6864 case 0x000C0000:
6865 desc = "Untagged Table Size";
6866 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006867
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868 }
6869
6870 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6871}
6872
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006873/* strings for sas loginfo */
6874 static char *originator_str[] = {
6875 "IOP", /* 00h */
6876 "PL", /* 01h */
6877 "IR" /* 02h */
6878 };
6879 static char *iop_code_str[] = {
6880 NULL, /* 00h */
6881 "Invalid SAS Address", /* 01h */
6882 NULL, /* 02h */
6883 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006884 "Diag Message Error", /* 04h */
6885 "Task Terminated", /* 05h */
6886 "Enclosure Management", /* 06h */
6887 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006888 };
6889 static char *pl_code_str[] = {
6890 NULL, /* 00h */
6891 "Open Failure", /* 01h */
6892 "Invalid Scatter Gather List", /* 02h */
6893 "Wrong Relative Offset or Frame Length", /* 03h */
6894 "Frame Transfer Error", /* 04h */
6895 "Transmit Frame Connected Low", /* 05h */
6896 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6897 "SATA Read Log Receive Data Error", /* 07h */
6898 "SATA NCQ Fail All Commands After Error", /* 08h */
6899 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6900 "Receive Frame Invalid Message", /* 0Ah */
6901 "Receive Context Message Valid Error", /* 0Bh */
6902 "Receive Frame Current Frame Error", /* 0Ch */
6903 "SATA Link Down", /* 0Dh */
6904 "Discovery SATA Init W IOS", /* 0Eh */
6905 "Config Invalid Page", /* 0Fh */
6906 "Discovery SATA Init Timeout", /* 10h */
6907 "Reset", /* 11h */
6908 "Abort", /* 12h */
6909 "IO Not Yet Executed", /* 13h */
6910 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006911 "Persistent Reservation Out Not Affiliation "
6912 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006913 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006914 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006915 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006916 NULL, /* 19h */
6917 NULL, /* 1Ah */
6918 NULL, /* 1Bh */
6919 NULL, /* 1Ch */
6920 NULL, /* 1Dh */
6921 NULL, /* 1Eh */
6922 NULL, /* 1Fh */
6923 "Enclosure Management" /* 20h */
6924 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006925 static char *ir_code_str[] = {
6926 "Raid Action Error", /* 00h */
6927 NULL, /* 00h */
6928 NULL, /* 01h */
6929 NULL, /* 02h */
6930 NULL, /* 03h */
6931 NULL, /* 04h */
6932 NULL, /* 05h */
6933 NULL, /* 06h */
6934 NULL /* 07h */
6935 };
6936 static char *raid_sub_code_str[] = {
6937 NULL, /* 00h */
6938 "Volume Creation Failed: Data Passed too "
6939 "Large", /* 01h */
6940 "Volume Creation Failed: Duplicate Volumes "
6941 "Attempted", /* 02h */
6942 "Volume Creation Failed: Max Number "
6943 "Supported Volumes Exceeded", /* 03h */
6944 "Volume Creation Failed: DMA Error", /* 04h */
6945 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6946 "Volume Creation Failed: Error Reading "
6947 "MFG Page 4", /* 06h */
6948 "Volume Creation Failed: Creating Internal "
6949 "Structures", /* 07h */
6950 NULL, /* 08h */
6951 NULL, /* 09h */
6952 NULL, /* 0Ah */
6953 NULL, /* 0Bh */
6954 NULL, /* 0Ch */
6955 NULL, /* 0Dh */
6956 NULL, /* 0Eh */
6957 NULL, /* 0Fh */
6958 "Activation failed: Already Active Volume", /* 10h */
6959 "Activation failed: Unsupported Volume Type", /* 11h */
6960 "Activation failed: Too Many Active Volumes", /* 12h */
6961 "Activation failed: Volume ID in Use", /* 13h */
6962 "Activation failed: Reported Failure", /* 14h */
6963 "Activation failed: Importing a Volume", /* 15h */
6964 NULL, /* 16h */
6965 NULL, /* 17h */
6966 NULL, /* 18h */
6967 NULL, /* 19h */
6968 NULL, /* 1Ah */
6969 NULL, /* 1Bh */
6970 NULL, /* 1Ch */
6971 NULL, /* 1Dh */
6972 NULL, /* 1Eh */
6973 NULL, /* 1Fh */
6974 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6975 "Phys Disk failed: Data Passed too Large", /* 21h */
6976 "Phys Disk failed: DMA Error", /* 22h */
6977 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6978 "Phys Disk failed: Creating Phys Disk Config "
6979 "Page", /* 24h */
6980 NULL, /* 25h */
6981 NULL, /* 26h */
6982 NULL, /* 27h */
6983 NULL, /* 28h */
6984 NULL, /* 29h */
6985 NULL, /* 2Ah */
6986 NULL, /* 2Bh */
6987 NULL, /* 2Ch */
6988 NULL, /* 2Dh */
6989 NULL, /* 2Eh */
6990 NULL, /* 2Fh */
6991 "Compatibility Error: IR Disabled", /* 30h */
6992 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6993 "Compatibility Error: Device not Direct Access "
6994 "Device ", /* 32h */
6995 "Compatibility Error: Removable Device Found", /* 33h */
6996 "Compatibility Error: Device SCSI Version not "
6997 "2 or Higher", /* 34h */
6998 "Compatibility Error: SATA Device, 48 BIT LBA "
6999 "not Supported", /* 35h */
7000 "Compatibility Error: Device doesn't have "
7001 "512 Byte Block Sizes", /* 36h */
7002 "Compatibility Error: Volume Type Check Failed", /* 37h */
7003 "Compatibility Error: Volume Type is "
7004 "Unsupported by FW", /* 38h */
7005 "Compatibility Error: Disk Drive too Small for "
7006 "use in Volume", /* 39h */
7007 "Compatibility Error: Phys Disk for Create "
7008 "Volume not Found", /* 3Ah */
7009 "Compatibility Error: Too Many or too Few "
7010 "Disks for Volume Type", /* 3Bh */
7011 "Compatibility Error: Disk stripe Sizes "
7012 "Must be 64KB", /* 3Ch */
7013 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7014 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007015
7016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007017/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007018 * mpt_sas_log_info - Log information returned from SAS IOC.
7019 * @ioc: Pointer to MPT_ADAPTER structure
7020 * @log_info: U32 LogInfo reply word from the IOC
7021 *
7022 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007023 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007024static void
7025mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7026{
7027union loginfo_type {
7028 u32 loginfo;
7029 struct {
7030 u32 subcode:16;
7031 u32 code:8;
7032 u32 originator:4;
7033 u32 bus_type:4;
7034 }dw;
7035};
7036 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007037 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007038 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007039 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007040
7041 sas_loginfo.loginfo = log_info;
7042 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7043 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7044 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007045
7046 originator_desc = originator_str[sas_loginfo.dw.originator];
7047
7048 switch (sas_loginfo.dw.originator) {
7049
7050 case 0: /* IOP */
7051 if (sas_loginfo.dw.code <
7052 sizeof(iop_code_str)/sizeof(char*))
7053 code_desc = iop_code_str[sas_loginfo.dw.code];
7054 break;
7055 case 1: /* PL */
7056 if (sas_loginfo.dw.code <
7057 sizeof(pl_code_str)/sizeof(char*))
7058 code_desc = pl_code_str[sas_loginfo.dw.code];
7059 break;
7060 case 2: /* IR */
7061 if (sas_loginfo.dw.code >=
7062 sizeof(ir_code_str)/sizeof(char*))
7063 break;
7064 code_desc = ir_code_str[sas_loginfo.dw.code];
7065 if (sas_loginfo.dw.subcode >=
7066 sizeof(raid_sub_code_str)/sizeof(char*))
7067 break;
7068 if (sas_loginfo.dw.code == 0)
7069 sub_code_desc =
7070 raid_sub_code_str[sas_loginfo.dw.subcode];
7071 break;
7072 default:
7073 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007074 }
7075
Eric Moorec6c727a2007-01-29 09:44:54 -07007076 if (sub_code_desc != NULL)
7077 printk(MYIOC_s_INFO_FMT
7078 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7079 " SubCode={%s}\n",
7080 ioc->name, log_info, originator_desc, code_desc,
7081 sub_code_desc);
7082 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007083 printk(MYIOC_s_INFO_FMT
7084 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7085 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007086 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007087 sas_loginfo.dw.subcode);
7088 else
7089 printk(MYIOC_s_INFO_FMT
7090 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7091 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007092 ioc->name, log_info, originator_desc,
7093 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007094}
7095
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007097/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007098 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7099 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007100 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007101 * @mf: Pointer to MPT request frame
7102 *
7103 * Refer to lsi/mpi.h.
7104 **/
7105static void
7106mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7107{
7108 Config_t *pReq = (Config_t *)mf;
7109 char extend_desc[EVENT_DESCR_STR_SZ];
7110 char *desc = NULL;
7111 u32 form;
7112 u8 page_type;
7113
7114 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7115 page_type = pReq->ExtPageType;
7116 else
7117 page_type = pReq->Header.PageType;
7118
7119 /*
7120 * ignore invalid page messages for GET_NEXT_HANDLE
7121 */
7122 form = le32_to_cpu(pReq->PageAddress);
7123 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7124 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7125 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7126 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7127 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7128 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7129 return;
7130 }
7131 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7132 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7133 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7134 return;
7135 }
7136
7137 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7138 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7139 page_type, pReq->Header.PageNumber, pReq->Action, form);
7140
7141 switch (ioc_status) {
7142
7143 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7144 desc = "Config Page Invalid Action";
7145 break;
7146
7147 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7148 desc = "Config Page Invalid Type";
7149 break;
7150
7151 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7152 desc = "Config Page Invalid Page";
7153 break;
7154
7155 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7156 desc = "Config Page Invalid Data";
7157 break;
7158
7159 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7160 desc = "Config Page No Defaults";
7161 break;
7162
7163 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7164 desc = "Config Page Can't Commit";
7165 break;
7166 }
7167
7168 if (!desc)
7169 return;
7170
Eric Moore29dd3602007-09-14 18:46:51 -06007171 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7172 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007173}
7174
7175/**
7176 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007177 * @ioc: Pointer to MPT_ADAPTER structure
7178 * @ioc_status: U32 IOCStatus word from IOC
7179 * @mf: Pointer to MPT request frame
7180 *
7181 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007182 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007184mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185{
7186 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007187 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188
7189 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007190
7191/****************************************************************************/
7192/* Common IOCStatus values for all replies */
7193/****************************************************************************/
7194
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7196 desc = "Invalid Function";
7197 break;
7198
7199 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7200 desc = "Busy";
7201 break;
7202
7203 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7204 desc = "Invalid SGL";
7205 break;
7206
7207 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7208 desc = "Internal Error";
7209 break;
7210
7211 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7212 desc = "Reserved";
7213 break;
7214
7215 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7216 desc = "Insufficient Resources";
7217 break;
7218
7219 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7220 desc = "Invalid Field";
7221 break;
7222
7223 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7224 desc = "Invalid State";
7225 break;
7226
Eric Moorec6c727a2007-01-29 09:44:54 -07007227/****************************************************************************/
7228/* Config IOCStatus values */
7229/****************************************************************************/
7230
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7232 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7233 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7234 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7235 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7236 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007237 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238 break;
7239
Eric Moorec6c727a2007-01-29 09:44:54 -07007240/****************************************************************************/
7241/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7242/* */
7243/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7244/* */
7245/****************************************************************************/
7246
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007249 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7250 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7251 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7252 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007255 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007256 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007257 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007259 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260 break;
7261
Eric Moorec6c727a2007-01-29 09:44:54 -07007262/****************************************************************************/
7263/* SCSI Target values */
7264/****************************************************************************/
7265
7266 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7267 desc = "Target: Priority IO";
7268 break;
7269
7270 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7271 desc = "Target: Invalid Port";
7272 break;
7273
7274 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7275 desc = "Target Invalid IO Index:";
7276 break;
7277
7278 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7279 desc = "Target: Aborted";
7280 break;
7281
7282 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7283 desc = "Target: No Conn Retryable";
7284 break;
7285
7286 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7287 desc = "Target: No Connection";
7288 break;
7289
7290 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7291 desc = "Target: Transfer Count Mismatch";
7292 break;
7293
7294 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7295 desc = "Target: STS Data not Sent";
7296 break;
7297
7298 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7299 desc = "Target: Data Offset Error";
7300 break;
7301
7302 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7303 desc = "Target: Too Much Write Data";
7304 break;
7305
7306 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7307 desc = "Target: IU Too Short";
7308 break;
7309
7310 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7311 desc = "Target: ACK NAK Timeout";
7312 break;
7313
7314 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7315 desc = "Target: Nak Received";
7316 break;
7317
7318/****************************************************************************/
7319/* Fibre Channel Direct Access values */
7320/****************************************************************************/
7321
7322 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7323 desc = "FC: Aborted";
7324 break;
7325
7326 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7327 desc = "FC: RX ID Invalid";
7328 break;
7329
7330 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7331 desc = "FC: DID Invalid";
7332 break;
7333
7334 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7335 desc = "FC: Node Logged Out";
7336 break;
7337
7338 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7339 desc = "FC: Exchange Canceled";
7340 break;
7341
7342/****************************************************************************/
7343/* LAN values */
7344/****************************************************************************/
7345
7346 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7347 desc = "LAN: Device not Found";
7348 break;
7349
7350 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7351 desc = "LAN: Device Failure";
7352 break;
7353
7354 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7355 desc = "LAN: Transmit Error";
7356 break;
7357
7358 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7359 desc = "LAN: Transmit Aborted";
7360 break;
7361
7362 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7363 desc = "LAN: Receive Error";
7364 break;
7365
7366 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7367 desc = "LAN: Receive Aborted";
7368 break;
7369
7370 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7371 desc = "LAN: Partial Packet";
7372 break;
7373
7374 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7375 desc = "LAN: Canceled";
7376 break;
7377
7378/****************************************************************************/
7379/* Serial Attached SCSI values */
7380/****************************************************************************/
7381
7382 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7383 desc = "SAS: SMP Request Failed";
7384 break;
7385
7386 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7387 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388 break;
7389
7390 default:
7391 desc = "Others";
7392 break;
7393 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007394
7395 if (!desc)
7396 return;
7397
Eric Moore29dd3602007-09-14 18:46:51 -06007398 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7399 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400}
7401
7402/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007403EXPORT_SYMBOL(mpt_attach);
7404EXPORT_SYMBOL(mpt_detach);
7405#ifdef CONFIG_PM
7406EXPORT_SYMBOL(mpt_resume);
7407EXPORT_SYMBOL(mpt_suspend);
7408#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007409EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007410EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411EXPORT_SYMBOL(mpt_register);
7412EXPORT_SYMBOL(mpt_deregister);
7413EXPORT_SYMBOL(mpt_event_register);
7414EXPORT_SYMBOL(mpt_event_deregister);
7415EXPORT_SYMBOL(mpt_reset_register);
7416EXPORT_SYMBOL(mpt_reset_deregister);
7417EXPORT_SYMBOL(mpt_device_driver_register);
7418EXPORT_SYMBOL(mpt_device_driver_deregister);
7419EXPORT_SYMBOL(mpt_get_msg_frame);
7420EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307421EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007422EXPORT_SYMBOL(mpt_free_msg_frame);
7423EXPORT_SYMBOL(mpt_add_sge);
7424EXPORT_SYMBOL(mpt_send_handshake_request);
7425EXPORT_SYMBOL(mpt_verify_adapter);
7426EXPORT_SYMBOL(mpt_GetIocState);
7427EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428EXPORT_SYMBOL(mpt_HardResetHandler);
7429EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007430EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007431EXPORT_SYMBOL(mpt_alloc_fw_memory);
7432EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007433EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007434EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Linus Torvalds1da177e2005-04-16 15:20:36 -07007436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007437/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007438 * fusion_init - Fusion MPT base driver initialization routine.
7439 *
7440 * Returns 0 for success, non-zero for failure.
7441 */
7442static int __init
7443fusion_init(void)
7444{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307445 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446
7447 show_mptmod_ver(my_NAME, my_VERSION);
7448 printk(KERN_INFO COPYRIGHT "\n");
7449
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307450 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7451 MptCallbacks[cb_idx] = NULL;
7452 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7453 MptEvHandlers[cb_idx] = NULL;
7454 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455 }
7456
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007457 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458 * EventNotification handling.
7459 */
7460 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7461
7462 /* Register for hard reset handling callbacks.
7463 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307464 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465
7466#ifdef CONFIG_PROC_FS
7467 (void) procmpt_create();
7468#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007469 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470}
7471
7472/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007473/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474 * fusion_exit - Perform driver unload cleanup.
7475 *
7476 * This routine frees all resources associated with each MPT adapter
7477 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7478 */
7479static void __exit
7480fusion_exit(void)
7481{
7482
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483 mpt_reset_deregister(mpt_base_index);
7484
7485#ifdef CONFIG_PROC_FS
7486 procmpt_destroy();
7487#endif
7488}
7489
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490module_init(fusion_init);
7491module_exit(fusion_exit);