blob: d40d6d15ae20f62d158d5456f857689e051cdf5a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05308 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Prakash, Sathya23a274c2008-03-07 15:53:21 +053082static int mpt_msi_enable = -1;
Christoph Hellwig4ddce142006-01-17 13:44:29 +000083module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600256/*
257 * Process turbo (context) reply...
258 */
259static void
260mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
261{
262 MPT_FRAME_HDR *mf = NULL;
263 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264 u16 req_idx = 0;
265 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600266
Prakash, Sathya436ace72007-07-24 15:42:08 +0530267 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600268 ioc->name, pa));
269
270 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
271 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
272 req_idx = pa & 0x0000FFFF;
273 cb_idx = (pa & 0x00FF0000) >> 16;
274 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
275 break;
276 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530277 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600278 /*
279 * Blind set of mf to NULL here was fatal
280 * after lan_reply says "freeme"
281 * Fix sort of combined with an optimization here;
282 * added explicit check for case where lan_reply
283 * was just returning 1 and doing nothing else.
284 * For this case skip the callback, but set up
285 * proper mf value first here:-)
286 */
287 if ((pa & 0x58000000) == 0x58000000) {
288 req_idx = pa & 0x0000FFFF;
289 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
290 mpt_free_msg_frame(ioc, mf);
291 mb();
292 return;
293 break;
294 }
295 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
296 break;
297 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530298 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600299 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
300 break;
301 default:
302 cb_idx = 0;
303 BUG();
304 }
305
306 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530307 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600308 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600309 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
310 __FUNCTION__, ioc->name, cb_idx);
311 goto out;
312 }
313
314 if (MptCallbacks[cb_idx](ioc, mf, mr))
315 mpt_free_msg_frame(ioc, mf);
316 out:
317 mb();
318}
319
320static void
321mpt_reply(MPT_ADAPTER *ioc, u32 pa)
322{
323 MPT_FRAME_HDR *mf;
324 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530325 u16 req_idx;
326 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 int freeme;
328
329 u32 reply_dma_low;
330 u16 ioc_stat;
331
332 /* non-TURBO reply! Hmmm, something may be up...
333 * Newest turbo reply mechanism; get address
334 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
335 */
336
337 /* Map DMA address of reply header to cpu address.
338 * pa is 32 bits - but the dma address may be 32 or 64 bits
339 * get offset based only only the low addresses
340 */
341
342 reply_dma_low = (pa <<= 1);
343 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
344 (reply_dma_low - ioc->reply_frames_low_dma));
345
346 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
347 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
348 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
349
Prakash, Sathya436ace72007-07-24 15:42:08 +0530350 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600351 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600352 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600353
354 /* Check/log IOC log info
355 */
356 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
357 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
358 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
359 if (ioc->bus_type == FC)
360 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700361 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700362 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600363 else if (ioc->bus_type == SAS)
364 mpt_sas_log_info(ioc, log_info);
365 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600366
Eric Moorec6c727a2007-01-29 09:44:54 -0700367 if (ioc_stat & MPI_IOCSTATUS_MASK)
368 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600369
370 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530371 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600372 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
374 __FUNCTION__, ioc->name, cb_idx);
375 freeme = 0;
376 goto out;
377 }
378
379 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
380
381 out:
382 /* Flush (non-TURBO) reply with a WRITE! */
383 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
384
385 if (freeme)
386 mpt_free_msg_frame(ioc, mf);
387 mb();
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
393 * @irq: irq number (not used)
394 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 *
396 * This routine is registered via the request_irq() kernel API call,
397 * and handles all interrupts generated from a specific MPT adapter
398 * (also referred to as a IO Controller or IOC).
399 * This routine must clear the interrupt from the adapter and does
400 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 *
403 * This routine handles register-level access of the adapter but
404 * dispatches (calls) a protocol-specific callback routine to handle
405 * the protocol-specific details of the MPT request completion.
406 */
407static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100408mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600410 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600411 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
412
413 if (pa == 0xFFFFFFFF)
414 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 /*
417 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600419 do {
420 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600421 mpt_reply(ioc, pa);
422 else
423 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600424 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
425 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 return IRQ_HANDLED;
428}
429
430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800431/**
432 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 * @ioc: Pointer to MPT_ADAPTER structure
434 * @mf: Pointer to original MPT request frame
435 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
436 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800437 * MPT base driver's callback routine; all base driver
438 * "internal" request/reply processing is routed here.
439 * Currently used for EventNotification and EventAck handling.
440 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 * should be freed, or 0 if it shouldn't.
443 */
444static int
445mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
446{
447 int freereq = 1;
448 u8 func;
449
Prakash, Sathya436ace72007-07-24 15:42:08 +0530450 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
451#ifdef CONFIG_FUSION_LOGGING
452 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
453 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
455 ioc->name, mf));
456 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530461 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 ioc->name, func));
463
464 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
465 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
466 int evHandlers = 0;
467 int results;
468
469 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
470 if (results != evHandlers) {
471 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530472 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 ioc->name, evHandlers, results));
474 }
475
476 /*
477 * Hmmm... It seems that EventNotificationReply is an exception
478 * to the rule of one reply per request.
479 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200480 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200482 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530483 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200484 ioc->name, pEvReply));
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487#ifdef CONFIG_PROC_FS
488// LogEvent(ioc, pEvReply);
489#endif
490
491 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530492 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700494 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 CONFIGPARMS *pCfg;
496 unsigned long flags;
497
Prakash, Sathya436ace72007-07-24 15:42:08 +0530498 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ioc->name, mf, reply));
500
501 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
502
503 if (pCfg) {
504 /* disable timer and remove from linked list */
505 del_timer(&pCfg->timer);
506
507 spin_lock_irqsave(&ioc->FreeQlock, flags);
508 list_del(&pCfg->linkage);
509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
510
511 /*
512 * If IOC Status is SUCCESS, save the header
513 * and set the status code to GOOD.
514 */
515 pCfg->status = MPT_CONFIG_ERROR;
516 if (reply) {
517 ConfigReply_t *pReply = (ConfigReply_t *)reply;
518 u16 status;
519
520 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600521 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
522 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 pCfg->status = status;
525 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200526 if ((pReply->Header.PageType &
527 MPI_CONFIG_PAGETYPE_MASK) ==
528 MPI_CONFIG_PAGETYPE_EXTENDED) {
529 pCfg->cfghdr.ehdr->ExtPageLength =
530 le16_to_cpu(pReply->ExtPageLength);
531 pCfg->cfghdr.ehdr->ExtPageType =
532 pReply->ExtPageType;
533 }
534 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
535
536 /* If this is a regular header, save PageLength. */
537 /* LMP Do this better so not using a reserved field! */
538 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
539 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
540 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542 }
543
544 /*
545 * Wake up the original calling thread
546 */
547 pCfg->wait_done = 1;
548 wake_up(&mpt_waitq);
549 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200550 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
551 /* we should be always getting a reply frame */
552 memcpy(ioc->persist_reply_frame, reply,
553 min(MPT_DEFAULT_FRAME_SIZE,
554 4*reply->u.reply.MsgLength));
555 del_timer(&ioc->persist_timer);
556 ioc->persist_wait_done = 1;
557 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
559 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
560 ioc->name, func);
561 }
562
563 /*
564 * Conditionally tell caller to free the original
565 * EventNotification/EventAck/unexpected request frame!
566 */
567 return freereq;
568}
569
570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
571/**
572 * mpt_register - Register protocol-specific main callback handler.
573 * @cbfunc: callback function pointer
574 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
575 *
576 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800577 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 * protocol-specific driver must do this before it will be able to
579 * use any IOC resources, such as obtaining request frames.
580 *
581 * NOTES: The SCSI protocol driver currently calls this routine thrice
582 * in order to register separate callbacks; one for "normal" SCSI IO;
583 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
584 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530585 * Returns u8 valued "handle" in the range (and S.O.D. order)
586 * {N,...,7,6,5,...,1} if successful.
587 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
588 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530590u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
592{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530593 u8 cb_idx;
594 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /*
597 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
598 * (slot/handle 0 is reserved!)
599 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530600 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
601 if (MptCallbacks[cb_idx] == NULL) {
602 MptCallbacks[cb_idx] = cbfunc;
603 MptDriverClass[cb_idx] = dclass;
604 MptEvHandlers[cb_idx] = NULL;
605 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 break;
607 }
608 }
609
610 return last_drv_idx;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
614/**
615 * mpt_deregister - Deregister a protocol drivers resources.
616 * @cb_idx: previously registered callback handle
617 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800618 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 * module is unloaded.
620 */
621void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530622mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600624 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 MptCallbacks[cb_idx] = NULL;
626 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
627 MptEvHandlers[cb_idx] = NULL;
628
629 last_drv_idx++;
630 }
631}
632
633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
634/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800635 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 * @cb_idx: previously registered (via mpt_register) callback handle
637 * @ev_cbfunc: callback function
638 *
639 * This routine can be called by one or more protocol-specific drivers
640 * if/when they choose to be notified of MPT events.
641 *
642 * Returns 0 for success.
643 */
644int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530645mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600647 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 return -1;
649
650 MptEvHandlers[cb_idx] = ev_cbfunc;
651 return 0;
652}
653
654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
655/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800656 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 * @cb_idx: previously registered callback handle
658 *
659 * Each protocol-specific driver should call this routine
660 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800661 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 */
663void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530664mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600666 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return;
668
669 MptEvHandlers[cb_idx] = NULL;
670}
671
672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
673/**
674 * mpt_reset_register - Register protocol-specific IOC reset handler.
675 * @cb_idx: previously registered (via mpt_register) callback handle
676 * @reset_func: reset function
677 *
678 * This routine can be called by one or more protocol-specific drivers
679 * if/when they choose to be notified of IOC resets.
680 *
681 * Returns 0 for success.
682 */
683int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530684mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 return -1;
688
689 MptResetHandlers[cb_idx] = reset_func;
690 return 0;
691}
692
693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
694/**
695 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
696 * @cb_idx: previously registered callback handle
697 *
698 * Each protocol-specific driver should call this routine
699 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800700 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 */
702void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530703mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530705 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
708 MptResetHandlers[cb_idx] = NULL;
709}
710
711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
712/**
713 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800714 * @dd_cbfunc: driver callbacks struct
715 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 */
717int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530718mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600721 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Eric Moore8d6d83e2007-09-14 18:47:40 -0600723 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400724 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
727
728 /* call per pci device probe entry point */
729 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600730 id = ioc->pcidev->driver ?
731 ioc->pcidev->driver->id_table : NULL;
732 if (dd_cbfunc->probe)
733 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
740/**
741 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800742 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 */
744void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530745mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 struct mpt_pci_driver *dd_cbfunc;
748 MPT_ADAPTER *ioc;
749
Eric Moore8d6d83e2007-09-14 18:47:40 -0600750 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return;
752
753 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
754
755 list_for_each_entry(ioc, &ioc_list, list) {
756 if (dd_cbfunc->remove)
757 dd_cbfunc->remove(ioc->pcidev);
758 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 MptDeviceDriverHandlers[cb_idx] = NULL;
761}
762
763
764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
765/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800766 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530767 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 * @ioc: Pointer to MPT adapter structure
769 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800770 * Obtain an MPT request frame from the pool (of 1024) that are
771 * allocated per MPT adapter.
772 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 * Returns pointer to a MPT request frame or %NULL if none are available
774 * or IOC is not active.
775 */
776MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 MPT_FRAME_HDR *mf;
780 unsigned long flags;
781 u16 req_idx; /* Request index */
782
783 /* validate handle and ioc identifier */
784
785#ifdef MFCNT
786 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600787 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
788 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789#endif
790
791 /* If interrupts are not attached, do not return a request frame */
792 if (!ioc->active)
793 return NULL;
794
795 spin_lock_irqsave(&ioc->FreeQlock, flags);
796 if (!list_empty(&ioc->FreeQ)) {
797 int req_offset;
798
799 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
800 u.frame.linkage.list);
801 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200802 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530803 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
805 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500806 req_idx = req_offset / ioc->req_sz;
807 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 /* Default, will be changed if necessary in SG generation */
810 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811#ifdef MFCNT
812 ioc->mfcnt++;
813#endif
814 }
815 else
816 mf = NULL;
817 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
818
819#ifdef MFCNT
820 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600821 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
822 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
823 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 mfcounter++;
825 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600826 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
827 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828#endif
829
Eric Moore29dd3602007-09-14 18:46:51 -0600830 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
831 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return mf;
833}
834
835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
836/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800837 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530838 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 * @ioc: Pointer to MPT adapter structure
840 * @mf: Pointer to MPT request frame
841 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800842 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 * specific MPT adapter.
844 */
845void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530846mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 u32 mf_dma_addr;
849 int req_offset;
850 u16 req_idx; /* Request index */
851
852 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530853 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
855 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500856 req_idx = req_offset / ioc->req_sz;
857 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
859
Prakash, Sathya436ace72007-07-24 15:42:08 +0530860 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200862 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600863 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
864 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
865 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
867}
868
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530869/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800870 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530871 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530872 * @ioc: Pointer to MPT adapter structure
873 * @mf: Pointer to MPT request frame
874 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800875 * Send a protocol-specific MPT request frame to an IOC using
876 * hi-priority request queue.
877 *
878 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530879 * specific MPT adapter.
880 **/
881void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530882mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530883{
884 u32 mf_dma_addr;
885 int req_offset;
886 u16 req_idx; /* Request index */
887
888 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530889 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530890 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
891 req_idx = req_offset / ioc->req_sz;
892 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
893 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
894
895 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
896
897 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
898 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
899 ioc->name, mf_dma_addr, req_idx));
900 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
901}
902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
904/**
905 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
906 * @handle: Handle of registered MPT protocol driver
907 * @ioc: Pointer to MPT adapter structure
908 * @mf: Pointer to MPT request frame
909 *
910 * This routine places a MPT request frame back on the MPT adapter's
911 * FreeQ.
912 */
913void
914mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
915{
916 unsigned long flags;
917
918 /* Put Request back on FreeQ! */
919 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200920 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
922#ifdef MFCNT
923 ioc->mfcnt--;
924#endif
925 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
926}
927
928/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
929/**
930 * mpt_add_sge - Place a simple SGE at address pAddr.
931 * @pAddr: virtual address for SGE
932 * @flagslength: SGE flags and data transfer length
933 * @dma_addr: Physical address
934 *
935 * This routine places a MPT request frame back on the MPT adapter's
936 * FreeQ.
937 */
938void
939mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
940{
941 if (sizeof(dma_addr_t) == sizeof(u64)) {
942 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
943 u32 tmp = dma_addr & 0xFFFFFFFF;
944
945 pSge->FlagsLength = cpu_to_le32(flagslength);
946 pSge->Address.Low = cpu_to_le32(tmp);
947 tmp = (u32) ((u64)dma_addr >> 32);
948 pSge->Address.High = cpu_to_le32(tmp);
949
950 } else {
951 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
952 pSge->FlagsLength = cpu_to_le32(flagslength);
953 pSge->Address = cpu_to_le32(dma_addr);
954 }
955}
956
957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
958/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800959 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530960 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * @ioc: Pointer to MPT adapter structure
962 * @reqBytes: Size of the request in bytes
963 * @req: Pointer to MPT request frame
964 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
965 *
966 * This routine is used exclusively to send MptScsiTaskMgmt
967 * requests since they are required to be sent via doorbell handshake.
968 *
969 * NOTE: It is the callers responsibility to byte-swap fields in the
970 * request which are greater than 1 byte in size.
971 *
972 * Returns 0 for success, non-zero for failure.
973 */
974int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530975mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
Eric Moorecd2c6192007-01-29 09:47:47 -0700977 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 u8 *req_as_bytes;
979 int ii;
980
981 /* State is known to be good upon entering
982 * this function so issue the bus reset
983 * request.
984 */
985
986 /*
987 * Emulate what mpt_put_msg_frame() does /wrt to sanity
988 * setting cb_idx/req_idx. But ONLY if this request
989 * is in proper (pre-alloc'd) request buffer range...
990 */
991 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
992 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
993 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
994 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530995 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 }
997
998 /* Make sure there are no doorbells */
999 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1002 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1003 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1004
1005 /* Wait for IOC doorbell int */
1006 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1007 return ii;
1008 }
1009
1010 /* Read doorbell and check for active bit */
1011 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1012 return -5;
1013
Eric Moore29dd3602007-09-14 18:46:51 -06001014 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001015 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1018
1019 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1020 return -2;
1021 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* Send request via doorbell handshake */
1024 req_as_bytes = (u8 *) req;
1025 for (ii = 0; ii < reqBytes/4; ii++) {
1026 u32 word;
1027
1028 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1029 (req_as_bytes[(ii*4) + 1] << 8) |
1030 (req_as_bytes[(ii*4) + 2] << 16) |
1031 (req_as_bytes[(ii*4) + 3] << 24));
1032 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1033 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1034 r = -3;
1035 break;
1036 }
1037 }
1038
1039 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1040 r = 0;
1041 else
1042 r = -4;
1043
1044 /* Make sure there are no doorbells */
1045 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return r;
1048}
1049
1050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1051/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001052 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001053 * @ioc: Pointer to MPT adapter structure
1054 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001055 * @sleepFlag: Specifies whether the process can sleep
1056 *
1057 * Provides mechanism for the host driver to control the IOC's
1058 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001059 *
1060 * Access Control Value - bits[15:12]
1061 * 0h Reserved
1062 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1063 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1064 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1065 *
1066 * Returns 0 for success, non-zero for failure.
1067 */
1068
1069static int
1070mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1071{
1072 int r = 0;
1073
1074 /* return if in use */
1075 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1076 & MPI_DOORBELL_ACTIVE)
1077 return -1;
1078
1079 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1080
1081 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1082 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1083 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1084 (access_control_value<<12)));
1085
1086 /* Wait for IOC to clear Doorbell Status bit */
1087 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1088 return -2;
1089 }else
1090 return 0;
1091}
1092
1093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1094/**
1095 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001096 * @ioc: Pointer to pointer to IOC adapter
1097 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001098 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001099 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001100 * Returns 0 for success, non-zero for failure.
1101 */
1102static int
1103mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1104{
1105 char *psge;
1106 int flags_length;
1107 u32 host_page_buffer_sz=0;
1108
1109 if(!ioc->HostPageBuffer) {
1110
1111 host_page_buffer_sz =
1112 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1113
1114 if(!host_page_buffer_sz)
1115 return 0; /* fw doesn't need any host buffers */
1116
1117 /* spin till we get enough memory */
1118 while(host_page_buffer_sz > 0) {
1119
1120 if((ioc->HostPageBuffer = pci_alloc_consistent(
1121 ioc->pcidev,
1122 host_page_buffer_sz,
1123 &ioc->HostPageBuffer_dma)) != NULL) {
1124
Prakash, Sathya436ace72007-07-24 15:42:08 +05301125 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001126 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001127 ioc->name, ioc->HostPageBuffer,
1128 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001129 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001130 ioc->alloc_total += host_page_buffer_sz;
1131 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1132 break;
1133 }
1134
1135 host_page_buffer_sz -= (4*1024);
1136 }
1137 }
1138
1139 if(!ioc->HostPageBuffer) {
1140 printk(MYIOC_s_ERR_FMT
1141 "Failed to alloc memory for host_page_buffer!\n",
1142 ioc->name);
1143 return -999;
1144 }
1145
1146 psge = (char *)&ioc_init->HostPageBufferSGE;
1147 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1148 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1149 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1150 MPI_SGE_FLAGS_HOST_TO_IOC |
1151 MPI_SGE_FLAGS_END_OF_BUFFER;
1152 if (sizeof(dma_addr_t) == sizeof(u64)) {
1153 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1154 }
1155 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1156 flags_length |= ioc->HostPageBuffer_sz;
1157 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1158 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1159
1160return 0;
1161}
1162
1163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1164/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001165 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 * @iocid: IOC unique identifier (integer)
1167 * @iocpp: Pointer to pointer to IOC adapter
1168 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001169 * Given a unique IOC identifier, set pointer to the associated MPT
1170 * adapter structure.
1171 *
1172 * Returns iocid and sets iocpp if iocid is found.
1173 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 */
1175int
1176mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1177{
1178 MPT_ADAPTER *ioc;
1179
1180 list_for_each_entry(ioc,&ioc_list,list) {
1181 if (ioc->id == iocid) {
1182 *iocpp =ioc;
1183 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 *iocpp = NULL;
1188 return -1;
1189}
1190
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301191/**
1192 * mpt_get_product_name - returns product string
1193 * @vendor: pci vendor id
1194 * @device: pci device id
1195 * @revision: pci revision id
1196 * @prod_name: string returned
1197 *
1198 * Returns product string displayed when driver loads,
1199 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1200 *
1201 **/
1202static void
1203mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1204{
1205 char *product_str = NULL;
1206
1207 if (vendor == PCI_VENDOR_ID_BROCADE) {
1208 switch (device)
1209 {
1210 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1211 switch (revision)
1212 {
1213 case 0x00:
1214 product_str = "BRE040 A0";
1215 break;
1216 case 0x01:
1217 product_str = "BRE040 A1";
1218 break;
1219 default:
1220 product_str = "BRE040";
1221 break;
1222 }
1223 break;
1224 }
1225 goto out;
1226 }
1227
1228 switch (device)
1229 {
1230 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1231 product_str = "LSIFC909 B1";
1232 break;
1233 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1234 product_str = "LSIFC919 B0";
1235 break;
1236 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1237 product_str = "LSIFC929 B0";
1238 break;
1239 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1240 if (revision < 0x80)
1241 product_str = "LSIFC919X A0";
1242 else
1243 product_str = "LSIFC919XL A1";
1244 break;
1245 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1246 if (revision < 0x80)
1247 product_str = "LSIFC929X A0";
1248 else
1249 product_str = "LSIFC929XL A1";
1250 break;
1251 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1252 product_str = "LSIFC939X A1";
1253 break;
1254 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1255 product_str = "LSIFC949X A1";
1256 break;
1257 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1258 switch (revision)
1259 {
1260 case 0x00:
1261 product_str = "LSIFC949E A0";
1262 break;
1263 case 0x01:
1264 product_str = "LSIFC949E A1";
1265 break;
1266 default:
1267 product_str = "LSIFC949E";
1268 break;
1269 }
1270 break;
1271 case MPI_MANUFACTPAGE_DEVID_53C1030:
1272 switch (revision)
1273 {
1274 case 0x00:
1275 product_str = "LSI53C1030 A0";
1276 break;
1277 case 0x01:
1278 product_str = "LSI53C1030 B0";
1279 break;
1280 case 0x03:
1281 product_str = "LSI53C1030 B1";
1282 break;
1283 case 0x07:
1284 product_str = "LSI53C1030 B2";
1285 break;
1286 case 0x08:
1287 product_str = "LSI53C1030 C0";
1288 break;
1289 case 0x80:
1290 product_str = "LSI53C1030T A0";
1291 break;
1292 case 0x83:
1293 product_str = "LSI53C1030T A2";
1294 break;
1295 case 0x87:
1296 product_str = "LSI53C1030T A3";
1297 break;
1298 case 0xc1:
1299 product_str = "LSI53C1020A A1";
1300 break;
1301 default:
1302 product_str = "LSI53C1030";
1303 break;
1304 }
1305 break;
1306 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1307 switch (revision)
1308 {
1309 case 0x03:
1310 product_str = "LSI53C1035 A2";
1311 break;
1312 case 0x04:
1313 product_str = "LSI53C1035 B0";
1314 break;
1315 default:
1316 product_str = "LSI53C1035";
1317 break;
1318 }
1319 break;
1320 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1321 switch (revision)
1322 {
1323 case 0x00:
1324 product_str = "LSISAS1064 A1";
1325 break;
1326 case 0x01:
1327 product_str = "LSISAS1064 A2";
1328 break;
1329 case 0x02:
1330 product_str = "LSISAS1064 A3";
1331 break;
1332 case 0x03:
1333 product_str = "LSISAS1064 A4";
1334 break;
1335 default:
1336 product_str = "LSISAS1064";
1337 break;
1338 }
1339 break;
1340 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1341 switch (revision)
1342 {
1343 case 0x00:
1344 product_str = "LSISAS1064E A0";
1345 break;
1346 case 0x01:
1347 product_str = "LSISAS1064E B0";
1348 break;
1349 case 0x02:
1350 product_str = "LSISAS1064E B1";
1351 break;
1352 case 0x04:
1353 product_str = "LSISAS1064E B2";
1354 break;
1355 case 0x08:
1356 product_str = "LSISAS1064E B3";
1357 break;
1358 default:
1359 product_str = "LSISAS1064E";
1360 break;
1361 }
1362 break;
1363 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1364 switch (revision)
1365 {
1366 case 0x00:
1367 product_str = "LSISAS1068 A0";
1368 break;
1369 case 0x01:
1370 product_str = "LSISAS1068 B0";
1371 break;
1372 case 0x02:
1373 product_str = "LSISAS1068 B1";
1374 break;
1375 default:
1376 product_str = "LSISAS1068";
1377 break;
1378 }
1379 break;
1380 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1381 switch (revision)
1382 {
1383 case 0x00:
1384 product_str = "LSISAS1068E A0";
1385 break;
1386 case 0x01:
1387 product_str = "LSISAS1068E B0";
1388 break;
1389 case 0x02:
1390 product_str = "LSISAS1068E B1";
1391 break;
1392 case 0x04:
1393 product_str = "LSISAS1068E B2";
1394 break;
1395 case 0x08:
1396 product_str = "LSISAS1068E B3";
1397 break;
1398 default:
1399 product_str = "LSISAS1068E";
1400 break;
1401 }
1402 break;
1403 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1404 switch (revision)
1405 {
1406 case 0x00:
1407 product_str = "LSISAS1078 A0";
1408 break;
1409 case 0x01:
1410 product_str = "LSISAS1078 B0";
1411 break;
1412 case 0x02:
1413 product_str = "LSISAS1078 C0";
1414 break;
1415 case 0x03:
1416 product_str = "LSISAS1078 C1";
1417 break;
1418 case 0x04:
1419 product_str = "LSISAS1078 C2";
1420 break;
1421 default:
1422 product_str = "LSISAS1078";
1423 break;
1424 }
1425 break;
1426 }
1427
1428 out:
1429 if (product_str)
1430 sprintf(prod_name, "%s", product_str);
1431}
1432
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301433/**
1434 * mpt_mapresources - map in memory mapped io
1435 * @ioc: Pointer to pointer to IOC adapter
1436 *
1437 **/
1438static int
1439mpt_mapresources(MPT_ADAPTER *ioc)
1440{
1441 u8 __iomem *mem;
1442 int ii;
1443 unsigned long mem_phys;
1444 unsigned long port;
1445 u32 msize;
1446 u32 psize;
1447 u8 revision;
1448 int r = -ENODEV;
1449 struct pci_dev *pdev;
1450
1451 pdev = ioc->pcidev;
1452 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1453 if (pci_enable_device_mem(pdev)) {
1454 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1455 "failed\n", ioc->name);
1456 return r;
1457 }
1458 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1459 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1460 "MEM failed\n", ioc->name);
1461 return r;
1462 }
1463
1464 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1465
1466 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
1467 && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
1468 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1469 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1470 ioc->name));
1471 } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)
1472 && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
1473 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1474 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1475 ioc->name));
1476 } else {
1477 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1478 ioc->name, pci_name(pdev));
1479 pci_release_selected_regions(pdev, ioc->bars);
1480 return r;
1481 }
1482
1483 mem_phys = msize = 0;
1484 port = psize = 0;
1485 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1486 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1487 if (psize)
1488 continue;
1489 /* Get I/O space! */
1490 port = pci_resource_start(pdev, ii);
1491 psize = pci_resource_len(pdev, ii);
1492 } else {
1493 if (msize)
1494 continue;
1495 /* Get memmap */
1496 mem_phys = pci_resource_start(pdev, ii);
1497 msize = pci_resource_len(pdev, ii);
1498 }
1499 }
1500 ioc->mem_size = msize;
1501
1502 mem = NULL;
1503 /* Get logical ptr for PciMem0 space */
1504 /*mem = ioremap(mem_phys, msize);*/
1505 mem = ioremap(mem_phys, msize);
1506 if (mem == NULL) {
1507 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1508 " memory!\n", ioc->name);
1509 return -EINVAL;
1510 }
1511 ioc->memmap = mem;
1512 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1513 ioc->name, mem, mem_phys));
1514
1515 ioc->mem_phys = mem_phys;
1516 ioc->chip = (SYSIF_REGS __iomem *)mem;
1517
1518 /* Save Port IO values in case we need to do downloadboot */
1519 ioc->pio_mem_phys = port;
1520 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1521
1522 return 0;
1523}
1524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001526/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001527 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001529 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 *
1531 * This routine performs all the steps necessary to bring the IOC of
1532 * a MPT adapter to a OPERATIONAL state. This includes registering
1533 * memory regions, registering the interrupt, and allocating request
1534 * and reply memory pools.
1535 *
1536 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1537 * MPT adapter.
1538 *
1539 * Returns 0 for success, non-zero for failure.
1540 *
1541 * TODO: Add support for polled controllers
1542 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001543int
1544mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301547 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 u8 revision;
1550 u8 pcixcmd;
1551 static int mpt_ids = 0;
1552#ifdef CONFIG_PROC_FS
1553 struct proc_dir_entry *dent, *ent;
1554#endif
1555
Jesper Juhl56876192007-08-10 14:50:51 -07001556 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1557 if (ioc == NULL) {
1558 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1559 return -ENOMEM;
1560 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301561
Eric Moore29dd3602007-09-14 18:46:51 -06001562 ioc->id = mpt_ids++;
1563 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001564
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301565 /*
1566 * set initial debug level
1567 * (refer to mptdebug.h)
1568 *
1569 */
1570 ioc->debug_level = mpt_debug_level;
1571 if (mpt_debug_level)
1572 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301573
Eric Moore29dd3602007-09-14 18:46:51 -06001574 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001575
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301576 ioc->pcidev = pdev;
1577 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001578 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return r;
1580 }
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 ioc->alloc_total = sizeof(MPT_ADAPTER);
1583 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1584 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 ioc->pcidev = pdev;
1587 ioc->diagPending = 0;
1588 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001589 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 /* Initialize the event logging.
1592 */
1593 ioc->eventTypes = 0; /* None */
1594 ioc->eventContext = 0;
1595 ioc->eventLogSize = 0;
1596 ioc->events = NULL;
1597
1598#ifdef MFCNT
1599 ioc->mfcnt = 0;
1600#endif
1601
1602 ioc->cached_fw = NULL;
1603
1604 /* Initilize SCSI Config Data structure
1605 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001606 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 /* Initialize the running configQ head.
1609 */
1610 INIT_LIST_HEAD(&ioc->configQ);
1611
Michael Reed05e8ec12006-01-13 14:31:54 -06001612 /* Initialize the fc rport list head.
1613 */
1614 INIT_LIST_HEAD(&ioc->fc_rports);
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* Find lookup slot. */
1617 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001618
Eric Moore29dd3602007-09-14 18:46:51 -06001619 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1620 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301622 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1623 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1624
1625 switch (pdev->device)
1626 {
1627 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1628 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1629 ioc->errata_flag_1064 = 1;
1630 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1631 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1632 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1633 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301635 break;
1636
1637 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 /* 929X Chip Fix. Set Split transactions level
1640 * for PCIX. Set MOST bits to zero.
1641 */
1642 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1643 pcixcmd &= 0x8F;
1644 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1645 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 /* 929XL Chip Fix. Set MMRBC to 0x08.
1647 */
1648 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1649 pcixcmd |= 0x08;
1650 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301653 break;
1654
1655 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 /* 919X Chip Fix. Set Split transactions level
1657 * for PCIX. Set MOST bits to zero.
1658 */
1659 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1660 pcixcmd &= 0x8F;
1661 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001662 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301663 break;
1664
1665 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 /* 1030 Chip Fix. Disable Split transactions
1667 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1668 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (revision < C0_1030) {
1670 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1671 pcixcmd &= 0x8F;
1672 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1673 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301674
1675 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001676 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301677 break;
1678
1679 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1680 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001681 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301682
1683 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1684 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1685 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001686 ioc->bus_type = SAS;
1687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
James Bottomley27898982008-07-10 22:10:55 -05001689 if (mpt_msi_enable == -1) {
1690 /* Enable on SAS, disable on FC and SPI */
1691 if (ioc->bus_type == SAS)
1692 ioc->msi_enable = 1;
1693 else
1694 ioc->msi_enable = 0;
1695 } else
1696 /* follow flag: 0 - disable; 1 - enable */
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301697 ioc->msi_enable = mpt_msi_enable;
1698
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001699 if (ioc->errata_flag_1064)
1700 pci_disable_io_access(pdev);
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 spin_lock_init(&ioc->FreeQlock);
1703
1704 /* Disable all! */
1705 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1706 ioc->active = 0;
1707 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1708
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301709 /* Set IOC ptr in the pcidev's driver data. */
1710 pci_set_drvdata(ioc->pcidev, ioc);
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 /* Set lookup ptr. */
1713 list_add_tail(&ioc->list, &ioc_list);
1714
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001715 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 */
1717 mpt_detect_bound_ports(ioc, pdev);
1718
James Bottomleyc92f2222006-03-01 09:02:49 -06001719 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1720 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001721 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1722 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001725 if (ioc->alt_ioc)
1726 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301727 iounmap(ioc->memmap);
1728 if (r != -5)
1729 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 kfree(ioc);
1731 pci_set_drvdata(pdev, NULL);
1732 return r;
1733 }
1734
1735 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001736 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301737 if(MptDeviceDriverHandlers[cb_idx] &&
1738 MptDeviceDriverHandlers[cb_idx]->probe) {
1739 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 }
1741 }
1742
1743#ifdef CONFIG_PROC_FS
1744 /*
1745 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1746 */
1747 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1748 if (dent) {
1749 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1750 if (ent) {
1751 ent->read_proc = procmpt_iocinfo_read;
1752 ent->data = ioc;
1753 }
1754 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1755 if (ent) {
1756 ent->read_proc = procmpt_summary_read;
1757 ent->data = ioc;
1758 }
1759 }
1760#endif
1761
1762 return 0;
1763}
1764
1765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001766/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001767 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 */
1770
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001771void
1772mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773{
1774 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1775 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301776 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1779 remove_proc_entry(pname, NULL);
1780 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1781 remove_proc_entry(pname, NULL);
1782 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1783 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001786 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301787 if(MptDeviceDriverHandlers[cb_idx] &&
1788 MptDeviceDriverHandlers[cb_idx]->remove) {
1789 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 }
1791 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 /* Disable interrupts! */
1794 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1795
1796 ioc->active = 0;
1797 synchronize_irq(pdev->irq);
1798
1799 /* Clear any lingering interrupt */
1800 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1801
1802 CHIPREG_READ32(&ioc->chip->IntStatus);
1803
1804 mpt_adapter_dispose(ioc);
1805
1806 pci_set_drvdata(pdev, NULL);
1807}
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809/**************************************************************************
1810 * Power Management
1811 */
1812#ifdef CONFIG_PM
1813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001814/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001815 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001816 * @pdev: Pointer to pci_dev structure
1817 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001819int
1820mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 u32 device_state;
1823 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301825 device_state = pci_choose_state(pdev, state);
1826 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
1827 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1828 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
1830 /* put ioc into READY_STATE */
1831 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1832 printk(MYIOC_s_ERR_FMT
1833 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1834 }
1835
1836 /* disable interrupts */
1837 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1838 ioc->active = 0;
1839
1840 /* Clear any lingering interrupt */
1841 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1842
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301843 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05001844 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301845 pci_disable_msi(ioc->pcidev);
1846 ioc->pci_irq = -1;
1847 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301849 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 return 0;
1852}
1853
1854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001855/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001856 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001857 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001859int
1860mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861{
1862 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1863 u32 device_state = pdev->current_state;
1864 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301865 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001866
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301867 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
1868 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
1869 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301871 pci_set_power_state(pdev, PCI_D0);
1872 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301874 ioc->pcidev = pdev;
1875 err = mpt_mapresources(ioc);
1876 if (err)
1877 return err;
1878
1879 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1880 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1881 CHIPREG_READ32(&ioc->chip->Doorbell));
1882
1883 /*
1884 * Errata workaround for SAS pci express:
1885 * Upon returning to the D0 state, the contents of the doorbell will be
1886 * stale data, and this will incorrectly signal to the host driver that
1887 * the firmware is ready to process mpt commands. The workaround is
1888 * to issue a diagnostic reset.
1889 */
1890 if (ioc->bus_type == SAS && (pdev->device ==
1891 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
1892 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
1893 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
1894 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
1895 ioc->name);
1896 goto out;
1897 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301901 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
1902 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1903 CAN_SLEEP);
1904 if (recovery_state != 0)
1905 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
1906 "error:[%x]\n", ioc->name, recovery_state);
1907 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301909 "pci-resume: success\n", ioc->name);
1910 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301912
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913}
1914#endif
1915
James Bottomley4ff42a62006-05-17 18:06:52 -05001916static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301917mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001918{
1919 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1920 ioc->bus_type != SPI) ||
1921 (MptDriverClass[index] == MPTFC_DRIVER &&
1922 ioc->bus_type != FC) ||
1923 (MptDriverClass[index] == MPTSAS_DRIVER &&
1924 ioc->bus_type != SAS))
1925 /* make sure we only call the relevant reset handler
1926 * for the bus */
1927 return 0;
1928 return (MptResetHandlers[index])(ioc, reset_phase);
1929}
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001932/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1934 * @ioc: Pointer to MPT adapter structure
1935 * @reason: Event word / reason
1936 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1937 *
1938 * This routine performs all the steps necessary to bring the IOC
1939 * to a OPERATIONAL state.
1940 *
1941 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1942 * MPT adapter.
1943 *
1944 * Returns:
1945 * 0 for success
1946 * -1 if failed to get board READY
1947 * -2 if READY but IOCFacts Failed
1948 * -3 if READY but PrimeIOCFifos Failed
1949 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301950 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301951 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 */
1953static int
1954mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1955{
1956 int hard_reset_done = 0;
1957 int alt_ioc_ready = 0;
1958 int hard;
1959 int rc=0;
1960 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301961 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 int handlers;
1963 int ret = 0;
1964 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001965 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301966 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Eric Moore29dd3602007-09-14 18:46:51 -06001968 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1969 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 /* Disable reply interrupts (also blocks FreeQ) */
1972 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1973 ioc->active = 0;
1974
1975 if (ioc->alt_ioc) {
1976 if (ioc->alt_ioc->active)
1977 reset_alt_ioc_active = 1;
1978
1979 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1980 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1981 ioc->alt_ioc->active = 0;
1982 }
1983
1984 hard = 1;
1985 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1986 hard = 0;
1987
1988 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1989 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001990 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1991 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993 if (reset_alt_ioc_active && ioc->alt_ioc) {
1994 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001995 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1996 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001997 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 ioc->alt_ioc->active = 1;
1999 }
2000
2001 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002002 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
2004 return -1;
2005 }
2006
2007 /* hard_reset_done = 0 if a soft reset was performed
2008 * and 1 if a hard reset was performed.
2009 */
2010 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2011 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2012 alt_ioc_ready = 1;
2013 else
Eric Moore29dd3602007-09-14 18:46:51 -06002014 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 }
2016
2017 for (ii=0; ii<5; ii++) {
2018 /* Get IOC facts! Allow 5 retries */
2019 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2020 break;
2021 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002025 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2026 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 ret = -2;
2028 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2029 MptDisplayIocCapabilities(ioc);
2030 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002031
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (alt_ioc_ready) {
2033 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302034 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002035 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 /* Retry - alt IOC was initialized once
2037 */
2038 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2039 }
2040 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302041 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002042 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 alt_ioc_ready = 0;
2044 reset_alt_ioc_active = 0;
2045 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2046 MptDisplayIocCapabilities(ioc->alt_ioc);
2047 }
2048 }
2049
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302050 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2051 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2052 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2053 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2054 IORESOURCE_IO);
2055 if (pci_enable_device(ioc->pcidev))
2056 return -5;
2057 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2058 "mpt"))
2059 return -5;
2060 }
2061
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002062 /*
2063 * Device is reset now. It must have de-asserted the interrupt line
2064 * (if it was asserted) and it should be safe to register for the
2065 * interrupt now.
2066 */
2067 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2068 ioc->pci_irq = -1;
2069 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302070 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002071 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002072 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302073 else
2074 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002075 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002076 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002077 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002078 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002079 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302080 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002081 pci_disable_msi(ioc->pcidev);
2082 return -EBUSY;
2083 }
2084 irq_allocated = 1;
2085 ioc->pci_irq = ioc->pcidev->irq;
2086 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002087 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2088 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002089 }
2090 }
2091
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 /* Prime reply & request queues!
2093 * (mucho alloc's) Must be done prior to
2094 * init as upper addresses are needed for init.
2095 * If fails, continue with alt-ioc processing
2096 */
2097 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2098 ret = -3;
2099
2100 /* May need to check/upload firmware & data here!
2101 * If fails, continue with alt-ioc processing
2102 */
2103 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2104 ret = -4;
2105// NEW!
2106 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002107 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2108 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 alt_ioc_ready = 0;
2110 reset_alt_ioc_active = 0;
2111 }
2112
2113 if (alt_ioc_ready) {
2114 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2115 alt_ioc_ready = 0;
2116 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002117 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2118 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120 }
2121
2122 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2123 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302124 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002125 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127 /* Controller is not operational, cannot do upload
2128 */
2129 if (ret == 0) {
2130 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002131 if (rc == 0) {
2132 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2133 /*
2134 * Maintain only one pointer to FW memory
2135 * so there will not be two attempt to
2136 * downloadboot onboard dual function
2137 * chips (mpt_adapter_disable,
2138 * mpt_diag_reset)
2139 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302140 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002141 "mpt_upload: alt_%s has cached_fw=%p \n",
2142 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302143 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002144 }
2145 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002146 printk(MYIOC_s_WARN_FMT
2147 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302148 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 }
2151 }
2152 }
2153
2154 if (ret == 0) {
2155 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002156 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 ioc->active = 1;
2158 }
2159
2160 if (reset_alt_ioc_active && ioc->alt_ioc) {
2161 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002162 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2163 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002164 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 ioc->alt_ioc->active = 1;
2166 }
2167
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002168 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 * and EventAck handling.
2170 */
2171 if ((ret == 0) && (!ioc->facts.EventState))
2172 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2173
2174 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2175 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2176
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002177 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2179 * recursive scenario; GetLanConfigPages times out, timer expired
2180 * routine calls HardResetHandler, which calls into here again,
2181 * and we try GetLanConfigPages again...
2182 */
2183 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002184
2185 /*
2186 * Initalize link list for inactive raid volumes.
2187 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002188 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002189 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2190
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002191 if (ioc->bus_type == SAS) {
2192
2193 /* clear persistency table */
2194 if(ioc->facts.IOCExceptions &
2195 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2196 ret = mptbase_sas_persist_operation(ioc,
2197 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2198 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002199 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002200 }
2201
2202 /* Find IM volumes
2203 */
2204 mpt_findImVolumes(ioc);
2205
2206 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2208 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2209 /*
2210 * Pre-fetch the ports LAN MAC address!
2211 * (LANPage1_t stuff)
2212 */
2213 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302214 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2215 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002216 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2217 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 }
2220 } else {
2221 /* Get NVRAM and adapter maximums from SPP 0 and 2
2222 */
2223 mpt_GetScsiPortSettings(ioc, 0);
2224
2225 /* Get version and length of SDP 1
2226 */
2227 mpt_readScsiDevicePageHeaders(ioc, 0);
2228
2229 /* Find IM volumes
2230 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002231 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 mpt_findImVolumes(ioc);
2233
2234 /* Check, and possibly reset, the coalescing value
2235 */
2236 mpt_read_ioc_pg_1(ioc);
2237
2238 mpt_read_ioc_pg_4(ioc);
2239 }
2240
2241 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302242 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244
2245 /*
2246 * Call each currently registered protocol IOC reset handler
2247 * with post-reset indication.
2248 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2249 * MptResetHandlers[] registered yet.
2250 */
2251 if (hard_reset_done) {
2252 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302253 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2254 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302255 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002256 "Calling IOC post_reset handler #%d\n",
2257 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302258 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 handlers++;
2260 }
2261
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302262 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302263 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002264 "Calling IOC post_reset handler #%d\n",
2265 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302266 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 handlers++;
2268 }
2269 }
2270 /* FIXME? Examine results here? */
2271 }
2272
Eric Moore0ccdb002006-07-11 17:33:13 -06002273 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002274 if ((ret != 0) && irq_allocated) {
2275 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302276 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002277 pci_disable_msi(ioc->pcidev);
2278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 return ret;
2280}
2281
2282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002283/**
2284 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 * @ioc: Pointer to MPT adapter structure
2286 * @pdev: Pointer to (struct pci_dev) structure
2287 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002288 * Search for PCI bus/dev_function which matches
2289 * PCI bus/dev_function (+/-1) for newly discovered 929,
2290 * 929X, 1030 or 1035.
2291 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2293 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2294 */
2295static void
2296mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2297{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002298 struct pci_dev *peer=NULL;
2299 unsigned int slot = PCI_SLOT(pdev->devfn);
2300 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 MPT_ADAPTER *ioc_srch;
2302
Prakash, Sathya436ace72007-07-24 15:42:08 +05302303 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002304 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002305 ioc->name, pci_name(pdev), pdev->bus->number,
2306 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002307
2308 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2309 if (!peer) {
2310 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2311 if (!peer)
2312 return;
2313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 list_for_each_entry(ioc_srch, &ioc_list, list) {
2316 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002317 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 /* Paranoia checks */
2319 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002320 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002321 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 break;
2323 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002324 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002325 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 break;
2327 }
Eric Moore29dd3602007-09-14 18:46:51 -06002328 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002329 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 ioc_srch->alt_ioc = ioc;
2331 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
2333 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002334 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335}
2336
2337/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002338/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002340 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 */
2342static void
2343mpt_adapter_disable(MPT_ADAPTER *ioc)
2344{
2345 int sz;
2346 int ret;
2347
2348 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302349 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2350 "adapter\n", __FUNCTION__, ioc->name));
2351 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2352 ioc->cached_fw, CAN_SLEEP)) < 0) {
2353 printk(MYIOC_s_WARN_FMT
2354 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002355 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 }
2357 }
2358
2359 /* Disable adapter interrupts! */
2360 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2361 ioc->active = 0;
2362 /* Clear any lingering interrupt */
2363 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2364
2365 if (ioc->alloc != NULL) {
2366 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002367 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2368 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 pci_free_consistent(ioc->pcidev, sz,
2370 ioc->alloc, ioc->alloc_dma);
2371 ioc->reply_frames = NULL;
2372 ioc->req_frames = NULL;
2373 ioc->alloc = NULL;
2374 ioc->alloc_total -= sz;
2375 }
2376
2377 if (ioc->sense_buf_pool != NULL) {
2378 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2379 pci_free_consistent(ioc->pcidev, sz,
2380 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2381 ioc->sense_buf_pool = NULL;
2382 ioc->alloc_total -= sz;
2383 }
2384
2385 if (ioc->events != NULL){
2386 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2387 kfree(ioc->events);
2388 ioc->events = NULL;
2389 ioc->alloc_total -= sz;
2390 }
2391
Prakash, Sathya984621b2008-01-11 14:42:17 +05302392 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002394 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002395 mpt_inactive_raid_list_free(ioc);
2396 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002397 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002398 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002399 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 if (ioc->spi_data.pIocPg4 != NULL) {
2402 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302403 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 ioc->spi_data.pIocPg4,
2405 ioc->spi_data.IocPg4_dma);
2406 ioc->spi_data.pIocPg4 = NULL;
2407 ioc->alloc_total -= sz;
2408 }
2409
2410 if (ioc->ReqToChain != NULL) {
2411 kfree(ioc->ReqToChain);
2412 kfree(ioc->RequestNB);
2413 ioc->ReqToChain = NULL;
2414 }
2415
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002416 kfree(ioc->ChainToChain);
2417 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002418
2419 if (ioc->HostPageBuffer != NULL) {
2420 if((ret = mpt_host_page_access_control(ioc,
2421 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002422 printk(MYIOC_s_ERR_FMT
2423 "host page buffers free failed (%d)!\n",
2424 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002425 }
Eric Moore29dd3602007-09-14 18:46:51 -06002426 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002427 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2428 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002429 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002430 ioc->HostPageBuffer = NULL;
2431 ioc->HostPageBuffer_sz = 0;
2432 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434}
2435
2436/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002437/**
2438 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 * @ioc: Pointer to MPT adapter structure
2440 *
2441 * This routine unregisters h/w resources and frees all alloc'd memory
2442 * associated with a MPT adapter structure.
2443 */
2444static void
2445mpt_adapter_dispose(MPT_ADAPTER *ioc)
2446{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002447 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002449 if (ioc == NULL)
2450 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002452 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002454 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002456 if (ioc->pci_irq != -1) {
2457 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302458 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002459 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002460 ioc->pci_irq = -1;
2461 }
2462
2463 if (ioc->memmap != NULL) {
2464 iounmap(ioc->memmap);
2465 ioc->memmap = NULL;
2466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302468 pci_disable_device(ioc->pcidev);
2469 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2470
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002472 if (ioc->mtrr_reg > 0) {
2473 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002474 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476#endif
2477
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002478 /* Zap the adapter lookup ptr! */
2479 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002481 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002482 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2483 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002484
2485 if (ioc->alt_ioc)
2486 ioc->alt_ioc->alt_ioc = NULL;
2487
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002488 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489}
2490
2491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002492/**
2493 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 * @ioc: Pointer to MPT adapter structure
2495 */
2496static void
2497MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2498{
2499 int i = 0;
2500
2501 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302502 if (ioc->prod_name)
2503 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 printk("Capabilities={");
2505
2506 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2507 printk("Initiator");
2508 i++;
2509 }
2510
2511 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2512 printk("%sTarget", i ? "," : "");
2513 i++;
2514 }
2515
2516 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2517 printk("%sLAN", i ? "," : "");
2518 i++;
2519 }
2520
2521#if 0
2522 /*
2523 * This would probably evoke more questions than it's worth
2524 */
2525 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2526 printk("%sLogBusAddr", i ? "," : "");
2527 i++;
2528 }
2529#endif
2530
2531 printk("}\n");
2532}
2533
2534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002535/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2537 * @ioc: Pointer to MPT_ADAPTER structure
2538 * @force: Force hard KickStart of IOC
2539 * @sleepFlag: Specifies whether the process can sleep
2540 *
2541 * Returns:
2542 * 1 - DIAG reset and READY
2543 * 0 - READY initially OR soft reset and READY
2544 * -1 - Any failure on KickStart
2545 * -2 - Msg Unit Reset Failed
2546 * -3 - IO Unit Reset Failed
2547 * -4 - IOC owned by a PEER
2548 */
2549static int
2550MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2551{
2552 u32 ioc_state;
2553 int statefault = 0;
2554 int cntdn;
2555 int hard_reset_done = 0;
2556 int r;
2557 int ii;
2558 int whoinit;
2559
2560 /* Get current [raw] IOC state */
2561 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002562 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
2564 /*
2565 * Check to see if IOC got left/stuck in doorbell handshake
2566 * grip of death. If so, hard reset the IOC.
2567 */
2568 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2569 statefault = 1;
2570 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2571 ioc->name);
2572 }
2573
2574 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002575 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 return 0;
2577
2578 /*
2579 * Check to see if IOC is in FAULT state.
2580 */
2581 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2582 statefault = 2;
2583 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002584 ioc->name);
2585 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2586 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
2588
2589 /*
2590 * Hmmm... Did it get left operational?
2591 */
2592 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302593 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 ioc->name));
2595
2596 /* Check WhoInit.
2597 * If PCI Peer, exit.
2598 * Else, if no fault conditions are present, issue a MessageUnitReset
2599 * Else, fall through to KickStart case
2600 */
2601 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002602 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2603 "whoinit 0x%x statefault %d force %d\n",
2604 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 if (whoinit == MPI_WHOINIT_PCI_PEER)
2606 return -4;
2607 else {
2608 if ((statefault == 0 ) && (force == 0)) {
2609 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2610 return 0;
2611 }
2612 statefault = 3;
2613 }
2614 }
2615
2616 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2617 if (hard_reset_done < 0)
2618 return -1;
2619
2620 /*
2621 * Loop here waiting for IOC to come READY.
2622 */
2623 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002624 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2627 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2628 /*
2629 * BIOS or previous driver load left IOC in OP state.
2630 * Reset messaging FIFOs.
2631 */
2632 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2633 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2634 return -2;
2635 }
2636 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2637 /*
2638 * Something is wrong. Try to get IOC back
2639 * to a known state.
2640 */
2641 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2642 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2643 return -3;
2644 }
2645 }
2646
2647 ii++; cntdn--;
2648 if (!cntdn) {
2649 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2650 ioc->name, (int)((ii+5)/HZ));
2651 return -ETIME;
2652 }
2653
2654 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002655 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 } else {
2657 mdelay (1); /* 1 msec delay */
2658 }
2659
2660 }
2661
2662 if (statefault < 3) {
2663 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2664 ioc->name,
2665 statefault==1 ? "stuck handshake" : "IOC FAULT");
2666 }
2667
2668 return hard_reset_done;
2669}
2670
2671/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002672/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 * mpt_GetIocState - Get the current state of a MPT adapter.
2674 * @ioc: Pointer to MPT_ADAPTER structure
2675 * @cooked: Request raw or cooked IOC state
2676 *
2677 * Returns all IOC Doorbell register bits if cooked==0, else just the
2678 * Doorbell bits in MPI_IOC_STATE_MASK.
2679 */
2680u32
2681mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2682{
2683 u32 s, sc;
2684
2685 /* Get! */
2686 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 sc = s & MPI_IOC_STATE_MASK;
2688
2689 /* Save! */
2690 ioc->last_state = sc;
2691
2692 return cooked ? sc : s;
2693}
2694
2695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002696/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 * GetIocFacts - Send IOCFacts request to MPT adapter.
2698 * @ioc: Pointer to MPT_ADAPTER structure
2699 * @sleepFlag: Specifies whether the process can sleep
2700 * @reason: If recovery, only update facts.
2701 *
2702 * Returns 0 for success, non-zero for failure.
2703 */
2704static int
2705GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2706{
2707 IOCFacts_t get_facts;
2708 IOCFactsReply_t *facts;
2709 int r;
2710 int req_sz;
2711 int reply_sz;
2712 int sz;
2713 u32 status, vv;
2714 u8 shiftFactor=1;
2715
2716 /* IOC *must* NOT be in RESET state! */
2717 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002718 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2719 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 return -44;
2721 }
2722
2723 facts = &ioc->facts;
2724
2725 /* Destination (reply area)... */
2726 reply_sz = sizeof(*facts);
2727 memset(facts, 0, reply_sz);
2728
2729 /* Request area (get_facts on the stack right now!) */
2730 req_sz = sizeof(get_facts);
2731 memset(&get_facts, 0, req_sz);
2732
2733 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2734 /* Assert: All other get_facts fields are zero! */
2735
Prakash, Sathya436ace72007-07-24 15:42:08 +05302736 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002737 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 ioc->name, req_sz, reply_sz));
2739
2740 /* No non-zero fields in the get_facts request are greater than
2741 * 1 byte in size, so we can just fire it off as is.
2742 */
2743 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2744 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2745 if (r != 0)
2746 return r;
2747
2748 /*
2749 * Now byte swap (GRRR) the necessary fields before any further
2750 * inspection of reply contents.
2751 *
2752 * But need to do some sanity checks on MsgLength (byte) field
2753 * to make sure we don't zero IOC's req_sz!
2754 */
2755 /* Did we get a valid reply? */
2756 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2757 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2758 /*
2759 * If not been here, done that, save off first WhoInit value
2760 */
2761 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2762 ioc->FirstWhoInit = facts->WhoInit;
2763 }
2764
2765 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2766 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2767 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2768 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2769 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002770 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 /* CHECKME! IOCStatus, IOCLogInfo */
2772
2773 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2774 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2775
2776 /*
2777 * FC f/w version changed between 1.1 and 1.2
2778 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2779 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2780 */
2781 if (facts->MsgVersion < 0x0102) {
2782 /*
2783 * Handle old FC f/w style, convert to new...
2784 */
2785 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2786 facts->FWVersion.Word =
2787 ((oldv<<12) & 0xFF000000) |
2788 ((oldv<<8) & 0x000FFF00);
2789 } else
2790 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2791
2792 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002793 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2794 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2795 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 facts->CurrentHostMfaHighAddr =
2797 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2798 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2799 facts->CurrentSenseBufferHighAddr =
2800 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2801 facts->CurReplyFrameSize =
2802 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002803 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805 /*
2806 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2807 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2808 * to 14 in MPI-1.01.0x.
2809 */
2810 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2811 facts->MsgVersion > 0x0100) {
2812 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2813 }
2814
2815 sz = facts->FWImageSize;
2816 if ( sz & 0x01 )
2817 sz += 1;
2818 if ( sz & 0x02 )
2819 sz += 2;
2820 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002821
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 if (!facts->RequestFrameSize) {
2823 /* Something is wrong! */
2824 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2825 ioc->name);
2826 return -55;
2827 }
2828
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002829 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 vv = ((63 / (sz * 4)) + 1) & 0x03;
2831 ioc->NB_for_64_byte_frame = vv;
2832 while ( sz )
2833 {
2834 shiftFactor++;
2835 sz = sz >> 1;
2836 }
2837 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302838 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002839 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2840 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002841
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2843 /*
2844 * Set values for this IOC's request & reply frame sizes,
2845 * and request & reply queue depths...
2846 */
2847 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2848 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2849 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2850 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2851
Prakash, Sathya436ace72007-07-24 15:42:08 +05302852 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302854 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 ioc->name, ioc->req_sz, ioc->req_depth));
2856
2857 /* Get port facts! */
2858 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2859 return r;
2860 }
2861 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002862 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2864 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2865 RequestFrameSize)/sizeof(u32)));
2866 return -66;
2867 }
2868
2869 return 0;
2870}
2871
2872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002873/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 * GetPortFacts - Send PortFacts request to MPT adapter.
2875 * @ioc: Pointer to MPT_ADAPTER structure
2876 * @portnum: Port number
2877 * @sleepFlag: Specifies whether the process can sleep
2878 *
2879 * Returns 0 for success, non-zero for failure.
2880 */
2881static int
2882GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2883{
2884 PortFacts_t get_pfacts;
2885 PortFactsReply_t *pfacts;
2886 int ii;
2887 int req_sz;
2888 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002889 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
2891 /* IOC *must* NOT be in RESET state! */
2892 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002893 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2894 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 return -4;
2896 }
2897
2898 pfacts = &ioc->pfacts[portnum];
2899
2900 /* Destination (reply area)... */
2901 reply_sz = sizeof(*pfacts);
2902 memset(pfacts, 0, reply_sz);
2903
2904 /* Request area (get_pfacts on the stack right now!) */
2905 req_sz = sizeof(get_pfacts);
2906 memset(&get_pfacts, 0, req_sz);
2907
2908 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2909 get_pfacts.PortNumber = portnum;
2910 /* Assert: All other get_pfacts fields are zero! */
2911
Prakash, Sathya436ace72007-07-24 15:42:08 +05302912 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 ioc->name, portnum));
2914
2915 /* No non-zero fields in the get_pfacts request are greater than
2916 * 1 byte in size, so we can just fire it off as is.
2917 */
2918 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2919 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2920 if (ii != 0)
2921 return ii;
2922
2923 /* Did we get a valid reply? */
2924
2925 /* Now byte swap the necessary fields in the response. */
2926 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2927 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2928 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2929 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2930 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2931 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2932 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2933 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2934 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2935
Eric Moore793955f2007-01-29 09:42:20 -07002936 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2937 pfacts->MaxDevices;
2938 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2939 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2940
2941 /*
2942 * Place all the devices on channels
2943 *
2944 * (for debuging)
2945 */
2946 if (mpt_channel_mapping) {
2947 ioc->devices_per_bus = 1;
2948 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2949 }
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 return 0;
2952}
2953
2954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002955/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 * SendIocInit - Send IOCInit request to MPT adapter.
2957 * @ioc: Pointer to MPT_ADAPTER structure
2958 * @sleepFlag: Specifies whether the process can sleep
2959 *
2960 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2961 *
2962 * Returns 0 for success, non-zero for failure.
2963 */
2964static int
2965SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2966{
2967 IOCInit_t ioc_init;
2968 MPIDefaultReply_t init_reply;
2969 u32 state;
2970 int r;
2971 int count;
2972 int cntdn;
2973
2974 memset(&ioc_init, 0, sizeof(ioc_init));
2975 memset(&init_reply, 0, sizeof(init_reply));
2976
2977 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2978 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2979
2980 /* If we are in a recovery mode and we uploaded the FW image,
2981 * then this pointer is not NULL. Skip the upload a second time.
2982 * Set this flag if cached_fw set for either IOC.
2983 */
2984 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2985 ioc->upload_fw = 1;
2986 else
2987 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302988 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2990
Eric Moore793955f2007-01-29 09:42:20 -07002991 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2992 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302993 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002994 ioc->name, ioc->facts.MsgVersion));
2995 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2996 // set MsgVersion and HeaderVersion host driver was built with
2997 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2998 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003000 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3001 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3002 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3003 return -99;
3004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3006
3007 if (sizeof(dma_addr_t) == sizeof(u64)) {
3008 /* Save the upper 32-bits of the request
3009 * (reply) and sense buffers.
3010 */
3011 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3012 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3013 } else {
3014 /* Force 32-bit addressing */
3015 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3016 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3017 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003018
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3020 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003021 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3022 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Prakash, Sathya436ace72007-07-24 15:42:08 +05303024 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 ioc->name, &ioc_init));
3026
3027 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3028 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003029 if (r != 0) {
3030 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003035 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 */
3037
Prakash, Sathya436ace72007-07-24 15:42:08 +05303038 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003040
3041 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3042 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
3046 /* YIKES! SUPER IMPORTANT!!!
3047 * Poll IocState until _OPERATIONAL while IOC is doing
3048 * LoopInit and TargetDiscovery!
3049 */
3050 count = 0;
3051 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3052 state = mpt_GetIocState(ioc, 1);
3053 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3054 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003055 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 } else {
3057 mdelay(1);
3058 }
3059
3060 if (!cntdn) {
3061 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3062 ioc->name, (int)((count+5)/HZ));
3063 return -9;
3064 }
3065
3066 state = mpt_GetIocState(ioc, 1);
3067 count++;
3068 }
Eric Moore29dd3602007-09-14 18:46:51 -06003069 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 ioc->name, count));
3071
Eric Mooreba856d32006-07-11 17:34:01 -06003072 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 return r;
3074}
3075
3076/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003077/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 * SendPortEnable - Send PortEnable request to MPT adapter port.
3079 * @ioc: Pointer to MPT_ADAPTER structure
3080 * @portnum: Port number to enable
3081 * @sleepFlag: Specifies whether the process can sleep
3082 *
3083 * Send PortEnable to bring IOC to OPERATIONAL state.
3084 *
3085 * Returns 0 for success, non-zero for failure.
3086 */
3087static int
3088SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3089{
3090 PortEnable_t port_enable;
3091 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003092 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 int req_sz;
3094 int reply_sz;
3095
3096 /* Destination... */
3097 reply_sz = sizeof(MPIDefaultReply_t);
3098 memset(&reply_buf, 0, reply_sz);
3099
3100 req_sz = sizeof(PortEnable_t);
3101 memset(&port_enable, 0, req_sz);
3102
3103 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3104 port_enable.PortNumber = portnum;
3105/* port_enable.ChainOffset = 0; */
3106/* port_enable.MsgFlags = 0; */
3107/* port_enable.MsgContext = 0; */
3108
Prakash, Sathya436ace72007-07-24 15:42:08 +05303109 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 ioc->name, portnum, &port_enable));
3111
3112 /* RAID FW may take a long time to enable
3113 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003114 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003115 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3116 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3117 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003118 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003119 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3120 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3121 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003123 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124}
3125
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003126/**
3127 * mpt_alloc_fw_memory - allocate firmware memory
3128 * @ioc: Pointer to MPT_ADAPTER structure
3129 * @size: total FW bytes
3130 *
3131 * If memory has already been allocated, the same (cached) value
3132 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303133 *
3134 * Return 0 if successfull, or non-zero for failure
3135 **/
3136int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3138{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303139 int rc;
3140
3141 if (ioc->cached_fw) {
3142 rc = 0; /* use already allocated memory */
3143 goto out;
3144 }
3145 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3147 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303148 rc = 0;
3149 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303151 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3152 if (!ioc->cached_fw) {
3153 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3154 ioc->name);
3155 rc = -1;
3156 } else {
3157 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3158 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3159 ioc->alloc_total += size;
3160 rc = 0;
3161 }
3162 out:
3163 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303165
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003166/**
3167 * mpt_free_fw_memory - free firmware memory
3168 * @ioc: Pointer to MPT_ADAPTER structure
3169 *
3170 * If alt_img is NULL, delete from ioc structure.
3171 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303172 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173void
3174mpt_free_fw_memory(MPT_ADAPTER *ioc)
3175{
3176 int sz;
3177
Prakash, Sathya984621b2008-01-11 14:42:17 +05303178 if (!ioc->cached_fw)
3179 return;
3180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303182 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3183 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003184 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303185 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187}
3188
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003190/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3192 * @ioc: Pointer to MPT_ADAPTER structure
3193 * @sleepFlag: Specifies whether the process can sleep
3194 *
3195 * Returns 0 for success, >0 for handshake failure
3196 * <0 for fw upload failure.
3197 *
3198 * Remark: If bound IOC and a successful FWUpload was performed
3199 * on the bound IOC, the second image is discarded
3200 * and memory is free'd. Both channels must upload to prevent
3201 * IOC from running in degraded mode.
3202 */
3203static int
3204mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3205{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 u8 reply[sizeof(FWUploadReply_t)];
3207 FWUpload_t *prequest;
3208 FWUploadReply_t *preply;
3209 FWUploadTCSGE_t *ptcsge;
3210 int sgeoffset;
3211 u32 flagsLength;
3212 int ii, sz, reply_sz;
3213 int cmdStatus;
3214
3215 /* If the image size is 0, we are done.
3216 */
3217 if ((sz = ioc->facts.FWImageSize) == 0)
3218 return 0;
3219
Prakash, Sathya984621b2008-01-11 14:42:17 +05303220 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3221 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
Eric Moore29dd3602007-09-14 18:46:51 -06003223 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3224 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003225
Eric Moorebc6e0892007-09-29 10:16:28 -06003226 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3227 kzalloc(ioc->req_sz, GFP_KERNEL);
3228 if (!prequest) {
3229 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3230 "while allocating memory \n", ioc->name));
3231 mpt_free_fw_memory(ioc);
3232 return -ENOMEM;
3233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
Eric Moorebc6e0892007-09-29 10:16:28 -06003235 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
3237 reply_sz = sizeof(reply);
3238 memset(preply, 0, reply_sz);
3239
3240 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3241 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3242
3243 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3244 ptcsge->DetailsLength = 12;
3245 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3246 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003247 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
3249 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3250
3251 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003252 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
3254 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003255 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3256 ioc->name, prequest, sgeoffset));
3257 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3260 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3261
Eric Moore29dd3602007-09-14 18:46:51 -06003262 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
3264 cmdStatus = -EFAULT;
3265 if (ii == 0) {
3266 /* Handshake transfer was complete and successful.
3267 * Check the Reply Frame.
3268 */
3269 int status, transfer_sz;
3270 status = le16_to_cpu(preply->IOCStatus);
3271 if (status == MPI_IOCSTATUS_SUCCESS) {
3272 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3273 if (transfer_sz == sz)
3274 cmdStatus = 0;
3275 }
3276 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 ioc->name, cmdStatus));
3279
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003280
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 if (cmdStatus) {
3282
Prakash, Sathya436ace72007-07-24 15:42:08 +05303283 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 ioc->name));
3285 mpt_free_fw_memory(ioc);
3286 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003287 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
3289 return cmdStatus;
3290}
3291
3292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003293/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 * mpt_downloadboot - DownloadBoot code
3295 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003296 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 * @sleepFlag: Specifies whether the process can sleep
3298 *
3299 * FwDownloadBoot requires Programmed IO access.
3300 *
3301 * Returns 0 for success
3302 * -1 FW Image size is 0
3303 * -2 No valid cached_fw Pointer
3304 * <0 for fw upload failure.
3305 */
3306static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003307mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 MpiExtImageHeader_t *pExtImage;
3310 u32 fwSize;
3311 u32 diag0val;
3312 int count;
3313 u32 *ptrFw;
3314 u32 diagRwData;
3315 u32 nextImage;
3316 u32 load_addr;
3317 u32 ioc_state=0;
3318
Prakash, Sathya436ace72007-07-24 15:42:08 +05303319 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003320 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003321
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3323 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3324 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3325 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3326 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3327 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3328
3329 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3330
3331 /* wait 1 msec */
3332 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003333 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 } else {
3335 mdelay (1);
3336 }
3337
3338 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3339 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3340
3341 for (count = 0; count < 30; count ++) {
3342 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3343 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303344 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 ioc->name, count));
3346 break;
3347 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003348 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003350 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003352 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 }
3354 }
3355
3356 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303357 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003358 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 ioc->name, diag0val));
3360 return -3;
3361 }
3362
3363 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3364 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3365 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3366 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3367 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3368 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3369
3370 /* Set the DiagRwEn and Disable ARM bits */
3371 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3372
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 fwSize = (pFwHeader->ImageSize + 3)/4;
3374 ptrFw = (u32 *) pFwHeader;
3375
3376 /* Write the LoadStartAddress to the DiagRw Address Register
3377 * using Programmed IO
3378 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003379 if (ioc->errata_flag_1064)
3380 pci_enable_io_access(ioc->pcidev);
3381
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303383 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 ioc->name, pFwHeader->LoadStartAddress));
3385
Prakash, Sathya436ace72007-07-24 15:42:08 +05303386 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 ioc->name, fwSize*4, ptrFw));
3388 while (fwSize--) {
3389 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3390 }
3391
3392 nextImage = pFwHeader->NextImageHeaderOffset;
3393 while (nextImage) {
3394 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3395
3396 load_addr = pExtImage->LoadStartAddress;
3397
3398 fwSize = (pExtImage->ImageSize + 3) >> 2;
3399 ptrFw = (u32 *)pExtImage;
3400
Prakash, Sathya436ace72007-07-24 15:42:08 +05303401 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 +02003402 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3404
3405 while (fwSize--) {
3406 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3407 }
3408 nextImage = pExtImage->NextImageHeaderOffset;
3409 }
3410
3411 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303412 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3414
3415 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303416 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3418
3419 /* Clear the internal flash bad bit - autoincrementing register,
3420 * so must do two writes.
3421 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003422 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003423 /*
3424 * 1030 and 1035 H/W errata, workaround to access
3425 * the ClearFlashBadSignatureBit
3426 */
3427 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3428 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3429 diagRwData |= 0x40000000;
3430 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3431 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3432
3433 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3434 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3435 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3436 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3437
3438 /* wait 1 msec */
3439 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003440 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003441 } else {
3442 mdelay (1);
3443 }
3444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003446 if (ioc->errata_flag_1064)
3447 pci_disable_io_access(ioc->pcidev);
3448
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303450 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003451 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003453 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303454 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 ioc->name, diag0val));
3456 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3457
3458 /* Write 0xFF to reset the sequencer */
3459 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3460
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003461 if (ioc->bus_type == SAS) {
3462 ioc_state = mpt_GetIocState(ioc, 0);
3463 if ( (GetIocFacts(ioc, sleepFlag,
3464 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303465 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003466 ioc->name, ioc_state));
3467 return -EFAULT;
3468 }
3469 }
3470
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 for (count=0; count<HZ*20; count++) {
3472 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303473 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3474 "downloadboot successful! (count=%d) IocState=%x\n",
3475 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003476 if (ioc->bus_type == SAS) {
3477 return 0;
3478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303480 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3481 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 ioc->name));
3483 return -EFAULT;
3484 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303485 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3486 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 ioc->name));
3488 return 0;
3489 }
3490 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003491 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 } else {
3493 mdelay (10);
3494 }
3495 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303496 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3497 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 return -EFAULT;
3499}
3500
3501/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003502/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 * KickStart - Perform hard reset of MPT adapter.
3504 * @ioc: Pointer to MPT_ADAPTER structure
3505 * @force: Force hard reset
3506 * @sleepFlag: Specifies whether the process can sleep
3507 *
3508 * This routine places MPT adapter in diagnostic mode via the
3509 * WriteSequence register, and then performs a hard reset of adapter
3510 * via the Diagnostic register.
3511 *
3512 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3513 * or NO_SLEEP (interrupt thread, use mdelay)
3514 * force - 1 if doorbell active, board fault state
3515 * board operational, IOC_RECOVERY or
3516 * IOC_BRINGUP and there is an alt_ioc.
3517 * 0 else
3518 *
3519 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003520 * 1 - hard reset, READY
3521 * 0 - no reset due to History bit, READY
3522 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 * OR reset but failed to come READY
3524 * -2 - no reset, could not enter DIAG mode
3525 * -3 - reset but bad FW bit
3526 */
3527static int
3528KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3529{
3530 int hard_reset_done = 0;
3531 u32 ioc_state=0;
3532 int cnt,cntdn;
3533
Eric Moore29dd3602007-09-14 18:46:51 -06003534 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003535 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 /* Always issue a Msg Unit Reset first. This will clear some
3537 * SCSI bus hang conditions.
3538 */
3539 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3540
3541 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003542 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 } else {
3544 mdelay (1000);
3545 }
3546 }
3547
3548 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3549 if (hard_reset_done < 0)
3550 return hard_reset_done;
3551
Prakash, Sathya436ace72007-07-24 15:42:08 +05303552 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003553 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
3555 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3556 for (cnt=0; cnt<cntdn; cnt++) {
3557 ioc_state = mpt_GetIocState(ioc, 1);
3558 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303559 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 ioc->name, cnt));
3561 return hard_reset_done;
3562 }
3563 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003564 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 } else {
3566 mdelay (10);
3567 }
3568 }
3569
Eric Moore29dd3602007-09-14 18:46:51 -06003570 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3571 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 return -1;
3573}
3574
3575/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003576/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 * mpt_diag_reset - Perform hard reset of the adapter.
3578 * @ioc: Pointer to MPT_ADAPTER structure
3579 * @ignore: Set if to honor and clear to ignore
3580 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003581 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 * else set to NO_SLEEP (use mdelay instead)
3583 *
3584 * This routine places the adapter in diagnostic mode via the
3585 * WriteSequence register and then performs a hard reset of adapter
3586 * via the Diagnostic register. Adapter should be in ready state
3587 * upon successful completion.
3588 *
3589 * Returns: 1 hard reset successful
3590 * 0 no reset performed because reset history bit set
3591 * -2 enabling diagnostic mode failed
3592 * -3 diagnostic reset failed
3593 */
3594static int
3595mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3596{
3597 u32 diag0val;
3598 u32 doorbell;
3599 int hard_reset_done = 0;
3600 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303602 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Eric Moorecd2c6192007-01-29 09:47:47 -07003604 /* Clear any existing interrupts */
3605 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3606
Eric Moore87cf8982006-06-27 16:09:26 -06003607 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303608 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003609 "address=%p\n", ioc->name, __FUNCTION__,
3610 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3611 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3612 if (sleepFlag == CAN_SLEEP)
3613 msleep(1);
3614 else
3615 mdelay(1);
3616
3617 for (count = 0; count < 60; count ++) {
3618 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3619 doorbell &= MPI_IOC_STATE_MASK;
3620
Prakash, Sathya436ace72007-07-24 15:42:08 +05303621 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003622 "looking for READY STATE: doorbell=%x"
3623 " count=%d\n",
3624 ioc->name, doorbell, count));
3625 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003626 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003627 }
3628
3629 /* wait 1 sec */
3630 if (sleepFlag == CAN_SLEEP)
3631 msleep(1000);
3632 else
3633 mdelay(1000);
3634 }
3635 return -1;
3636 }
3637
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 /* Use "Diagnostic reset" method! (only thing available!) */
3639 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3640
Prakash, Sathya436ace72007-07-24 15:42:08 +05303641 if (ioc->debug_level & MPT_DEBUG) {
3642 if (ioc->alt_ioc)
3643 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3644 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648 /* Do the reset if we are told to ignore the reset history
3649 * or if the reset history is 0
3650 */
3651 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3652 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3653 /* Write magic sequence to WriteSequence register
3654 * Loop until in diagnostic mode
3655 */
3656 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3657 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3658 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3659 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3660 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3661 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3662
3663 /* wait 100 msec */
3664 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003665 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 } else {
3667 mdelay (100);
3668 }
3669
3670 count++;
3671 if (count > 20) {
3672 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3673 ioc->name, diag0val);
3674 return -2;
3675
3676 }
3677
3678 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3679
Prakash, Sathya436ace72007-07-24 15:42:08 +05303680 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 ioc->name, diag0val));
3682 }
3683
Prakash, Sathya436ace72007-07-24 15:42:08 +05303684 if (ioc->debug_level & MPT_DEBUG) {
3685 if (ioc->alt_ioc)
3686 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3687 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 /*
3691 * Disable the ARM (Bug fix)
3692 *
3693 */
3694 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003695 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
3697 /*
3698 * Now hit the reset bit in the Diagnostic register
3699 * (THE BIG HAMMER!) (Clears DRWE bit).
3700 */
3701 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3702 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303703 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 ioc->name));
3705
3706 /*
3707 * Call each currently registered protocol IOC reset handler
3708 * with pre-reset indication.
3709 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3710 * MptResetHandlers[] registered yet.
3711 */
3712 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303713 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 int r = 0;
3715
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303716 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3717 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303718 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3719 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303720 ioc->name, cb_idx));
3721 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303723 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3724 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303725 ioc->name, ioc->alt_ioc->name, cb_idx));
3726 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 }
3728 }
3729 }
3730 /* FIXME? Examine results here? */
3731 }
3732
Eric Moore0ccdb002006-07-11 17:33:13 -06003733 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303734 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003735 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303736 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3737 else
3738 cached_fw = NULL;
3739 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 /* If the DownloadBoot operation fails, the
3741 * IOC will be left unusable. This is a fatal error
3742 * case. _diag_reset will return < 0
3743 */
3744 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303745 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3747 break;
3748 }
3749
Prakash, Sathya436ace72007-07-24 15:42:08 +05303750 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303751 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 /* wait 1 sec */
3753 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003754 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 } else {
3756 mdelay (1000);
3757 }
3758 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303759 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003760 printk(MYIOC_s_WARN_FMT
3761 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 }
3763
3764 } else {
3765 /* Wait for FW to reload and for board
3766 * to go to the READY state.
3767 * Maximum wait is 60 seconds.
3768 * If fail, no error will check again
3769 * with calling program.
3770 */
3771 for (count = 0; count < 60; count ++) {
3772 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3773 doorbell &= MPI_IOC_STATE_MASK;
3774
3775 if (doorbell == MPI_IOC_STATE_READY) {
3776 break;
3777 }
3778
3779 /* wait 1 sec */
3780 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003781 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 } else {
3783 mdelay (1000);
3784 }
3785 }
3786 }
3787 }
3788
3789 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303790 if (ioc->debug_level & MPT_DEBUG) {
3791 if (ioc->alt_ioc)
3792 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3793 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3794 ioc->name, diag0val, diag1val));
3795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796
3797 /* Clear RESET_HISTORY bit! Place board in the
3798 * diagnostic mode to update the diag register.
3799 */
3800 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3801 count = 0;
3802 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3803 /* Write magic sequence to WriteSequence register
3804 * Loop until in diagnostic mode
3805 */
3806 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3807 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3808 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3809 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3810 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3811 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3812
3813 /* wait 100 msec */
3814 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003815 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 } else {
3817 mdelay (100);
3818 }
3819
3820 count++;
3821 if (count > 20) {
3822 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3823 ioc->name, diag0val);
3824 break;
3825 }
3826 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3827 }
3828 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3829 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3830 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3831 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3832 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3833 ioc->name);
3834 }
3835
3836 /* Disable Diagnostic Mode
3837 */
3838 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3839
3840 /* Check FW reload status flags.
3841 */
3842 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3843 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3844 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3845 ioc->name, diag0val);
3846 return -3;
3847 }
3848
Prakash, Sathya436ace72007-07-24 15:42:08 +05303849 if (ioc->debug_level & MPT_DEBUG) {
3850 if (ioc->alt_ioc)
3851 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3852 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
3856 /*
3857 * Reset flag that says we've enabled event notification
3858 */
3859 ioc->facts.EventState = 0;
3860
3861 if (ioc->alt_ioc)
3862 ioc->alt_ioc->facts.EventState = 0;
3863
3864 return hard_reset_done;
3865}
3866
3867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003868/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 * SendIocReset - Send IOCReset request to MPT adapter.
3870 * @ioc: Pointer to MPT_ADAPTER structure
3871 * @reset_type: reset type, expected values are
3872 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003873 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 *
3875 * Send IOCReset request to the MPT adapter.
3876 *
3877 * Returns 0 for success, non-zero for failure.
3878 */
3879static int
3880SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3881{
3882 int r;
3883 u32 state;
3884 int cntdn, count;
3885
Prakash, Sathya436ace72007-07-24 15:42:08 +05303886 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 ioc->name, reset_type));
3888 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3889 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3890 return r;
3891
3892 /* FW ACK'd request, wait for READY state
3893 */
3894 count = 0;
3895 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3896
3897 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3898 cntdn--;
3899 count++;
3900 if (!cntdn) {
3901 if (sleepFlag != CAN_SLEEP)
3902 count *= 10;
3903
Eric Moore29dd3602007-09-14 18:46:51 -06003904 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3905 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 return -ETIME;
3907 }
3908
3909 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003910 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 } else {
3912 mdelay (1); /* 1 msec delay */
3913 }
3914 }
3915
3916 /* TODO!
3917 * Cleanup all event stuff for this IOC; re-issue EventNotification
3918 * request if needed.
3919 */
3920 if (ioc->facts.Function)
3921 ioc->facts.EventState = 0;
3922
3923 return 0;
3924}
3925
3926/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003927/**
3928 * initChainBuffers - Allocate memory for and initialize chain buffers
3929 * @ioc: Pointer to MPT_ADAPTER structure
3930 *
3931 * Allocates memory for and initializes chain buffers,
3932 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 */
3934static int
3935initChainBuffers(MPT_ADAPTER *ioc)
3936{
3937 u8 *mem;
3938 int sz, ii, num_chain;
3939 int scale, num_sge, numSGE;
3940
3941 /* ReqToChain size must equal the req_depth
3942 * index = req_idx
3943 */
3944 if (ioc->ReqToChain == NULL) {
3945 sz = ioc->req_depth * sizeof(int);
3946 mem = kmalloc(sz, GFP_ATOMIC);
3947 if (mem == NULL)
3948 return -1;
3949
3950 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303951 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 ioc->name, mem, sz));
3953 mem = kmalloc(sz, GFP_ATOMIC);
3954 if (mem == NULL)
3955 return -1;
3956
3957 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303958 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 ioc->name, mem, sz));
3960 }
3961 for (ii = 0; ii < ioc->req_depth; ii++) {
3962 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3963 }
3964
3965 /* ChainToChain size must equal the total number
3966 * of chain buffers to be allocated.
3967 * index = chain_idx
3968 *
3969 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003970 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 *
3972 * num_sge = num sge in request frame + last chain buffer
3973 * scale = num sge per chain buffer if no chain element
3974 */
3975 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3976 if (sizeof(dma_addr_t) == sizeof(u64))
3977 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3978 else
3979 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3980
3981 if (sizeof(dma_addr_t) == sizeof(u64)) {
3982 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3983 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3984 } else {
3985 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3986 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3987 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303988 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 ioc->name, num_sge, numSGE));
3990
3991 if ( numSGE > MPT_SCSI_SG_DEPTH )
3992 numSGE = MPT_SCSI_SG_DEPTH;
3993
3994 num_chain = 1;
3995 while (numSGE - num_sge > 0) {
3996 num_chain++;
3997 num_sge += (scale - 1);
3998 }
3999 num_chain++;
4000
Prakash, Sathya436ace72007-07-24 15:42:08 +05304001 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 ioc->name, numSGE, num_sge, num_chain));
4003
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004004 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 num_chain *= MPT_SCSI_CAN_QUEUE;
4006 else
4007 num_chain *= MPT_FC_CAN_QUEUE;
4008
4009 ioc->num_chain = num_chain;
4010
4011 sz = num_chain * sizeof(int);
4012 if (ioc->ChainToChain == NULL) {
4013 mem = kmalloc(sz, GFP_ATOMIC);
4014 if (mem == NULL)
4015 return -1;
4016
4017 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 ioc->name, mem, sz));
4020 } else {
4021 mem = (u8 *) ioc->ChainToChain;
4022 }
4023 memset(mem, 0xFF, sz);
4024 return num_chain;
4025}
4026
4027/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004028/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4030 * @ioc: Pointer to MPT_ADAPTER structure
4031 *
4032 * This routine allocates memory for the MPT reply and request frame
4033 * pools (if necessary), and primes the IOC reply FIFO with
4034 * reply frames.
4035 *
4036 * Returns 0 for success, non-zero for failure.
4037 */
4038static int
4039PrimeIocFifos(MPT_ADAPTER *ioc)
4040{
4041 MPT_FRAME_HDR *mf;
4042 unsigned long flags;
4043 dma_addr_t alloc_dma;
4044 u8 *mem;
4045 int i, reply_sz, sz, total_size, num_chain;
4046
4047 /* Prime reply FIFO... */
4048
4049 if (ioc->reply_frames == NULL) {
4050 if ( (num_chain = initChainBuffers(ioc)) < 0)
4051 return -1;
4052
4053 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304054 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304056 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 ioc->name, reply_sz, reply_sz));
4058
4059 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304060 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 ioc->name, sz, sz));
4064 total_size += sz;
4065
4066 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304067 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304069 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 ioc->name, sz, sz, num_chain));
4071
4072 total_size += sz;
4073 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4074 if (mem == NULL) {
4075 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4076 ioc->name);
4077 goto out_fail;
4078 }
4079
Prakash, Sathya436ace72007-07-24 15:42:08 +05304080 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4082
4083 memset(mem, 0, total_size);
4084 ioc->alloc_total += total_size;
4085 ioc->alloc = mem;
4086 ioc->alloc_dma = alloc_dma;
4087 ioc->alloc_sz = total_size;
4088 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4089 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4090
Prakash, Sathya436ace72007-07-24 15:42:08 +05304091 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004092 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4093
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 alloc_dma += reply_sz;
4095 mem += reply_sz;
4096
4097 /* Request FIFO - WE manage this! */
4098
4099 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4100 ioc->req_frames_dma = alloc_dma;
4101
Prakash, Sathya436ace72007-07-24 15:42:08 +05304102 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 ioc->name, mem, (void *)(ulong)alloc_dma));
4104
4105 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4106
4107#if defined(CONFIG_MTRR) && 0
4108 /*
4109 * Enable Write Combining MTRR for IOC's memory region.
4110 * (at least as much as we can; "size and base must be
4111 * multiples of 4 kiB"
4112 */
4113 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4114 sz,
4115 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304116 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 ioc->name, ioc->req_frames_dma, sz));
4118#endif
4119
4120 for (i = 0; i < ioc->req_depth; i++) {
4121 alloc_dma += ioc->req_sz;
4122 mem += ioc->req_sz;
4123 }
4124
4125 ioc->ChainBuffer = mem;
4126 ioc->ChainBufferDMA = alloc_dma;
4127
Prakash, Sathya436ace72007-07-24 15:42:08 +05304128 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4130
4131 /* Initialize the free chain Q.
4132 */
4133
4134 INIT_LIST_HEAD(&ioc->FreeChainQ);
4135
4136 /* Post the chain buffers to the FreeChainQ.
4137 */
4138 mem = (u8 *)ioc->ChainBuffer;
4139 for (i=0; i < num_chain; i++) {
4140 mf = (MPT_FRAME_HDR *) mem;
4141 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4142 mem += ioc->req_sz;
4143 }
4144
4145 /* Initialize Request frames linked list
4146 */
4147 alloc_dma = ioc->req_frames_dma;
4148 mem = (u8 *) ioc->req_frames;
4149
4150 spin_lock_irqsave(&ioc->FreeQlock, flags);
4151 INIT_LIST_HEAD(&ioc->FreeQ);
4152 for (i = 0; i < ioc->req_depth; i++) {
4153 mf = (MPT_FRAME_HDR *) mem;
4154
4155 /* Queue REQUESTs *internally*! */
4156 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4157
4158 mem += ioc->req_sz;
4159 }
4160 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4161
4162 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4163 ioc->sense_buf_pool =
4164 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4165 if (ioc->sense_buf_pool == NULL) {
4166 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4167 ioc->name);
4168 goto out_fail;
4169 }
4170
4171 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4172 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304173 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4175
4176 }
4177
4178 /* Post Reply frames to FIFO
4179 */
4180 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304181 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4183
4184 for (i = 0; i < ioc->reply_depth; i++) {
4185 /* Write each address to the IOC! */
4186 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4187 alloc_dma += ioc->reply_sz;
4188 }
4189
4190 return 0;
4191
4192out_fail:
4193 if (ioc->alloc != NULL) {
4194 sz = ioc->alloc_sz;
4195 pci_free_consistent(ioc->pcidev,
4196 sz,
4197 ioc->alloc, ioc->alloc_dma);
4198 ioc->reply_frames = NULL;
4199 ioc->req_frames = NULL;
4200 ioc->alloc_total -= sz;
4201 }
4202 if (ioc->sense_buf_pool != NULL) {
4203 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4204 pci_free_consistent(ioc->pcidev,
4205 sz,
4206 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4207 ioc->sense_buf_pool = NULL;
4208 }
4209 return -1;
4210}
4211
4212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4213/**
4214 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4215 * from IOC via doorbell handshake method.
4216 * @ioc: Pointer to MPT_ADAPTER structure
4217 * @reqBytes: Size of the request in bytes
4218 * @req: Pointer to MPT request frame
4219 * @replyBytes: Expected size of the reply in bytes
4220 * @u16reply: Pointer to area where reply should be written
4221 * @maxwait: Max wait time for a reply (in seconds)
4222 * @sleepFlag: Specifies whether the process can sleep
4223 *
4224 * NOTES: It is the callers responsibility to byte-swap fields in the
4225 * request which are greater than 1 byte in size. It is also the
4226 * callers responsibility to byte-swap response fields which are
4227 * greater than 1 byte in size.
4228 *
4229 * Returns 0 for success, non-zero for failure.
4230 */
4231static int
4232mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004233 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234{
4235 MPIDefaultReply_t *mptReply;
4236 int failcnt = 0;
4237 int t;
4238
4239 /*
4240 * Get ready to cache a handshake reply
4241 */
4242 ioc->hs_reply_idx = 0;
4243 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4244 mptReply->MsgLength = 0;
4245
4246 /*
4247 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4248 * then tell IOC that we want to handshake a request of N words.
4249 * (WRITE u32val to Doorbell reg).
4250 */
4251 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4252 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4253 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4254 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4255
4256 /*
4257 * Wait for IOC's doorbell handshake int
4258 */
4259 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4260 failcnt++;
4261
Prakash, Sathya436ace72007-07-24 15:42:08 +05304262 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4264
4265 /* Read doorbell and check for active bit */
4266 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4267 return -1;
4268
4269 /*
4270 * Clear doorbell int (WRITE 0 to IntStatus reg),
4271 * then wait for IOC to ACKnowledge that it's ready for
4272 * our handshake request.
4273 */
4274 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4275 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4276 failcnt++;
4277
4278 if (!failcnt) {
4279 int ii;
4280 u8 *req_as_bytes = (u8 *) req;
4281
4282 /*
4283 * Stuff request words via doorbell handshake,
4284 * with ACK from IOC for each.
4285 */
4286 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4287 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4288 (req_as_bytes[(ii*4) + 1] << 8) |
4289 (req_as_bytes[(ii*4) + 2] << 16) |
4290 (req_as_bytes[(ii*4) + 3] << 24));
4291
4292 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4293 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4294 failcnt++;
4295 }
4296
Prakash, Sathya436ace72007-07-24 15:42:08 +05304297 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004298 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Prakash, Sathya436ace72007-07-24 15:42:08 +05304300 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4302
4303 /*
4304 * Wait for completion of doorbell handshake reply from the IOC
4305 */
4306 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4307 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004308
Prakash, Sathya436ace72007-07-24 15:42:08 +05304309 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4311
4312 /*
4313 * Copy out the cached reply...
4314 */
4315 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4316 u16reply[ii] = ioc->hs_reply[ii];
4317 } else {
4318 return -99;
4319 }
4320
4321 return -failcnt;
4322}
4323
4324/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004325/**
4326 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 * @ioc: Pointer to MPT_ADAPTER structure
4328 * @howlong: How long to wait (in seconds)
4329 * @sleepFlag: Specifies whether the process can sleep
4330 *
4331 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004332 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4333 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 *
4335 * Returns a negative value on failure, else wait loop count.
4336 */
4337static int
4338WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4339{
4340 int cntdn;
4341 int count = 0;
4342 u32 intstat=0;
4343
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004344 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
4346 if (sleepFlag == CAN_SLEEP) {
4347 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004348 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4350 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4351 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 count++;
4353 }
4354 } else {
4355 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004356 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4358 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4359 break;
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 ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 ioc->name, count));
4367 return count;
4368 }
4369
4370 printk(MYIOC_s_ERR_FMT "Doorbell ACK 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 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
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 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004382 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4383 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 *
4385 * Returns a negative value on failure, else wait loop count.
4386 */
4387static int
4388WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4389{
4390 int cntdn;
4391 int count = 0;
4392 u32 intstat=0;
4393
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004394 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 if (sleepFlag == CAN_SLEEP) {
4396 while (--cntdn) {
4397 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4398 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4399 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004400 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 count++;
4402 }
4403 } else {
4404 while (--cntdn) {
4405 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4406 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4407 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004408 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 count++;
4410 }
4411 }
4412
4413 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304414 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 ioc->name, count, howlong));
4416 return count;
4417 }
4418
4419 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4420 ioc->name, count, intstat);
4421 return -1;
4422}
4423
4424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004425/**
4426 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 * @ioc: Pointer to MPT_ADAPTER structure
4428 * @howlong: How long to wait (in seconds)
4429 * @sleepFlag: Specifies whether the process can sleep
4430 *
4431 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4432 * Reply is cached to IOC private area large enough to hold a maximum
4433 * of 128 bytes of reply data.
4434 *
4435 * Returns a negative value on failure, else size of reply in WORDS.
4436 */
4437static int
4438WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4439{
4440 int u16cnt = 0;
4441 int failcnt = 0;
4442 int t;
4443 u16 *hs_reply = ioc->hs_reply;
4444 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4445 u16 hword;
4446
4447 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4448
4449 /*
4450 * Get first two u16's so we can look at IOC's intended reply MsgLength
4451 */
4452 u16cnt=0;
4453 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4454 failcnt++;
4455 } else {
4456 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4457 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4458 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4459 failcnt++;
4460 else {
4461 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4462 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4463 }
4464 }
4465
Prakash, Sathya436ace72007-07-24 15:42:08 +05304466 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004467 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4469
4470 /*
4471 * If no error (and IOC said MsgLength is > 0), piece together
4472 * reply 16 bits at a time.
4473 */
4474 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4475 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4476 failcnt++;
4477 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4478 /* don't overflow our IOC hs_reply[] buffer! */
4479 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4480 hs_reply[u16cnt] = hword;
4481 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4482 }
4483
4484 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4485 failcnt++;
4486 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4487
4488 if (failcnt) {
4489 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4490 ioc->name);
4491 return -failcnt;
4492 }
4493#if 0
4494 else if (u16cnt != (2 * mptReply->MsgLength)) {
4495 return -101;
4496 }
4497 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4498 return -102;
4499 }
4500#endif
4501
Prakash, Sathya436ace72007-07-24 15:42:08 +05304502 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004503 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504
Prakash, Sathya436ace72007-07-24 15:42:08 +05304505 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 ioc->name, t, u16cnt/2));
4507 return u16cnt/2;
4508}
4509
4510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004511/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 * GetLanConfigPages - Fetch LANConfig pages.
4513 * @ioc: Pointer to MPT_ADAPTER structure
4514 *
4515 * Return: 0 for success
4516 * -ENOMEM if no memory available
4517 * -EPERM if not allowed due to ISR context
4518 * -EAGAIN if no msg frames currently available
4519 * -EFAULT for non-successful reply or no reply (timeout)
4520 */
4521static int
4522GetLanConfigPages(MPT_ADAPTER *ioc)
4523{
4524 ConfigPageHeader_t hdr;
4525 CONFIGPARMS cfg;
4526 LANPage0_t *ppage0_alloc;
4527 dma_addr_t page0_dma;
4528 LANPage1_t *ppage1_alloc;
4529 dma_addr_t page1_dma;
4530 int rc = 0;
4531 int data_sz;
4532 int copy_sz;
4533
4534 /* Get LAN Page 0 header */
4535 hdr.PageVersion = 0;
4536 hdr.PageLength = 0;
4537 hdr.PageNumber = 0;
4538 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004539 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 cfg.physAddr = -1;
4541 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4542 cfg.dir = 0;
4543 cfg.pageAddr = 0;
4544 cfg.timeout = 0;
4545
4546 if ((rc = mpt_config(ioc, &cfg)) != 0)
4547 return rc;
4548
4549 if (hdr.PageLength > 0) {
4550 data_sz = hdr.PageLength * 4;
4551 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4552 rc = -ENOMEM;
4553 if (ppage0_alloc) {
4554 memset((u8 *)ppage0_alloc, 0, data_sz);
4555 cfg.physAddr = page0_dma;
4556 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4557
4558 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4559 /* save the data */
4560 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4561 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4562
4563 }
4564
4565 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4566
4567 /* FIXME!
4568 * Normalize endianness of structure data,
4569 * by byte-swapping all > 1 byte fields!
4570 */
4571
4572 }
4573
4574 if (rc)
4575 return rc;
4576 }
4577
4578 /* Get LAN Page 1 header */
4579 hdr.PageVersion = 0;
4580 hdr.PageLength = 0;
4581 hdr.PageNumber = 1;
4582 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004583 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 cfg.physAddr = -1;
4585 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4586 cfg.dir = 0;
4587 cfg.pageAddr = 0;
4588
4589 if ((rc = mpt_config(ioc, &cfg)) != 0)
4590 return rc;
4591
4592 if (hdr.PageLength == 0)
4593 return 0;
4594
4595 data_sz = hdr.PageLength * 4;
4596 rc = -ENOMEM;
4597 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4598 if (ppage1_alloc) {
4599 memset((u8 *)ppage1_alloc, 0, data_sz);
4600 cfg.physAddr = page1_dma;
4601 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4602
4603 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4604 /* save the data */
4605 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4606 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4607 }
4608
4609 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4610
4611 /* FIXME!
4612 * Normalize endianness of structure data,
4613 * by byte-swapping all > 1 byte fields!
4614 */
4615
4616 }
4617
4618 return rc;
4619}
4620
4621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004622/**
4623 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004624 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004625 * @persist_opcode: see below
4626 *
4627 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4628 * devices not currently present.
4629 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4630 *
4631 * NOTE: Don't use not this function during interrupt time.
4632 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004633 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004634 */
4635
4636/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4637int
4638mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4639{
4640 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4641 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4642 MPT_FRAME_HDR *mf = NULL;
4643 MPIHeader_t *mpi_hdr;
4644
4645
4646 /* insure garbage is not sent to fw */
4647 switch(persist_opcode) {
4648
4649 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4650 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4651 break;
4652
4653 default:
4654 return -1;
4655 break;
4656 }
4657
4658 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4659
4660 /* Get a MF for this command.
4661 */
4662 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4663 printk("%s: no msg frames!\n",__FUNCTION__);
4664 return -1;
4665 }
4666
4667 mpi_hdr = (MPIHeader_t *) mf;
4668 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4669 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4670 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4671 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4672 sasIoUnitCntrReq->Operation = persist_opcode;
4673
4674 init_timer(&ioc->persist_timer);
4675 ioc->persist_timer.data = (unsigned long) ioc;
4676 ioc->persist_timer.function = mpt_timer_expired;
4677 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4678 ioc->persist_wait_done=0;
4679 add_timer(&ioc->persist_timer);
4680 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4681 wait_event(mpt_waitq, ioc->persist_wait_done);
4682
4683 sasIoUnitCntrReply =
4684 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4685 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4686 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4687 __FUNCTION__,
4688 sasIoUnitCntrReply->IOCStatus,
4689 sasIoUnitCntrReply->IOCLogInfo);
4690 return -1;
4691 }
4692
4693 printk("%s: success\n",__FUNCTION__);
4694 return 0;
4695}
4696
4697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004698
4699static void
4700mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4701 MpiEventDataRaid_t * pRaidEventData)
4702{
4703 int volume;
4704 int reason;
4705 int disk;
4706 int status;
4707 int flags;
4708 int state;
4709
4710 volume = pRaidEventData->VolumeID;
4711 reason = pRaidEventData->ReasonCode;
4712 disk = pRaidEventData->PhysDiskNum;
4713 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4714 flags = (status >> 0) & 0xff;
4715 state = (status >> 8) & 0xff;
4716
4717 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4718 return;
4719 }
4720
4721 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4722 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4723 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004724 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4725 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004726 } else {
4727 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4728 ioc->name, volume);
4729 }
4730
4731 switch(reason) {
4732 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4733 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4734 ioc->name);
4735 break;
4736
4737 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4738
4739 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4740 ioc->name);
4741 break;
4742
4743 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4744 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4745 ioc->name);
4746 break;
4747
4748 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4749 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4750 ioc->name,
4751 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4752 ? "optimal"
4753 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4754 ? "degraded"
4755 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4756 ? "failed"
4757 : "state unknown",
4758 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4759 ? ", enabled" : "",
4760 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4761 ? ", quiesced" : "",
4762 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4763 ? ", resync in progress" : "" );
4764 break;
4765
4766 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4767 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4768 ioc->name, disk);
4769 break;
4770
4771 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4772 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4773 ioc->name);
4774 break;
4775
4776 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4777 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4778 ioc->name);
4779 break;
4780
4781 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4782 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4783 ioc->name);
4784 break;
4785
4786 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4787 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4788 ioc->name,
4789 state == MPI_PHYSDISK0_STATUS_ONLINE
4790 ? "online"
4791 : state == MPI_PHYSDISK0_STATUS_MISSING
4792 ? "missing"
4793 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4794 ? "not compatible"
4795 : state == MPI_PHYSDISK0_STATUS_FAILED
4796 ? "failed"
4797 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4798 ? "initializing"
4799 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4800 ? "offline requested"
4801 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4802 ? "failed requested"
4803 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4804 ? "offline"
4805 : "state unknown",
4806 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4807 ? ", out of sync" : "",
4808 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4809 ? ", quiesced" : "" );
4810 break;
4811
4812 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4813 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4814 ioc->name, disk);
4815 break;
4816
4817 case MPI_EVENT_RAID_RC_SMART_DATA:
4818 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4819 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4820 break;
4821
4822 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4823 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4824 ioc->name, disk);
4825 break;
4826 }
4827}
4828
4829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004830/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4832 * @ioc: Pointer to MPT_ADAPTER structure
4833 *
4834 * Returns: 0 for success
4835 * -ENOMEM if no memory available
4836 * -EPERM if not allowed due to ISR context
4837 * -EAGAIN if no msg frames currently available
4838 * -EFAULT for non-successful reply or no reply (timeout)
4839 */
4840static int
4841GetIoUnitPage2(MPT_ADAPTER *ioc)
4842{
4843 ConfigPageHeader_t hdr;
4844 CONFIGPARMS cfg;
4845 IOUnitPage2_t *ppage_alloc;
4846 dma_addr_t page_dma;
4847 int data_sz;
4848 int rc;
4849
4850 /* Get the page header */
4851 hdr.PageVersion = 0;
4852 hdr.PageLength = 0;
4853 hdr.PageNumber = 2;
4854 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004855 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 cfg.physAddr = -1;
4857 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4858 cfg.dir = 0;
4859 cfg.pageAddr = 0;
4860 cfg.timeout = 0;
4861
4862 if ((rc = mpt_config(ioc, &cfg)) != 0)
4863 return rc;
4864
4865 if (hdr.PageLength == 0)
4866 return 0;
4867
4868 /* Read the config page */
4869 data_sz = hdr.PageLength * 4;
4870 rc = -ENOMEM;
4871 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4872 if (ppage_alloc) {
4873 memset((u8 *)ppage_alloc, 0, data_sz);
4874 cfg.physAddr = page_dma;
4875 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4876
4877 /* If Good, save data */
4878 if ((rc = mpt_config(ioc, &cfg)) == 0)
4879 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4880
4881 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4882 }
4883
4884 return rc;
4885}
4886
4887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004888/**
4889 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 * @ioc: Pointer to a Adapter Strucutre
4891 * @portnum: IOC port number
4892 *
4893 * Return: -EFAULT if read of config page header fails
4894 * or if no nvram
4895 * If read of SCSI Port Page 0 fails,
4896 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4897 * Adapter settings: async, narrow
4898 * Return 1
4899 * If read of SCSI Port Page 2 fails,
4900 * Adapter settings valid
4901 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4902 * Return 1
4903 * Else
4904 * Both valid
4905 * Return 0
4906 * CHECK - what type of locking mechanisms should be used????
4907 */
4908static int
4909mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4910{
4911 u8 *pbuf;
4912 dma_addr_t buf_dma;
4913 CONFIGPARMS cfg;
4914 ConfigPageHeader_t header;
4915 int ii;
4916 int data, rc = 0;
4917
4918 /* Allocate memory
4919 */
4920 if (!ioc->spi_data.nvram) {
4921 int sz;
4922 u8 *mem;
4923 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4924 mem = kmalloc(sz, GFP_ATOMIC);
4925 if (mem == NULL)
4926 return -EFAULT;
4927
4928 ioc->spi_data.nvram = (int *) mem;
4929
Prakash, Sathya436ace72007-07-24 15:42:08 +05304930 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 ioc->name, ioc->spi_data.nvram, sz));
4932 }
4933
4934 /* Invalidate NVRAM information
4935 */
4936 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4937 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4938 }
4939
4940 /* Read SPP0 header, allocate memory, then read page.
4941 */
4942 header.PageVersion = 0;
4943 header.PageLength = 0;
4944 header.PageNumber = 0;
4945 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004946 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 cfg.physAddr = -1;
4948 cfg.pageAddr = portnum;
4949 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4950 cfg.dir = 0;
4951 cfg.timeout = 0; /* use default */
4952 if (mpt_config(ioc, &cfg) != 0)
4953 return -EFAULT;
4954
4955 if (header.PageLength > 0) {
4956 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4957 if (pbuf) {
4958 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4959 cfg.physAddr = buf_dma;
4960 if (mpt_config(ioc, &cfg) != 0) {
4961 ioc->spi_data.maxBusWidth = MPT_NARROW;
4962 ioc->spi_data.maxSyncOffset = 0;
4963 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4964 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4965 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304966 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4967 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004968 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 } else {
4970 /* Save the Port Page 0 data
4971 */
4972 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4973 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4974 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4975
4976 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4977 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004978 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4979 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 ioc->name, pPP0->Capabilities));
4981 }
4982 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4983 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4984 if (data) {
4985 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4986 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4987 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304988 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4989 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004990 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 } else {
4992 ioc->spi_data.maxSyncOffset = 0;
4993 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4994 }
4995
4996 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4997
4998 /* Update the minSyncFactor based on bus type.
4999 */
5000 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5001 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5002
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005003 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305005 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5006 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005007 ioc->name, ioc->spi_data.minSyncFactor));
5008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 }
5010 }
5011 if (pbuf) {
5012 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5013 }
5014 }
5015 }
5016
5017 /* SCSI Port Page 2 - Read the header then the page.
5018 */
5019 header.PageVersion = 0;
5020 header.PageLength = 0;
5021 header.PageNumber = 2;
5022 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005023 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 cfg.physAddr = -1;
5025 cfg.pageAddr = portnum;
5026 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5027 cfg.dir = 0;
5028 if (mpt_config(ioc, &cfg) != 0)
5029 return -EFAULT;
5030
5031 if (header.PageLength > 0) {
5032 /* Allocate memory and read SCSI Port Page 2
5033 */
5034 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5035 if (pbuf) {
5036 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5037 cfg.physAddr = buf_dma;
5038 if (mpt_config(ioc, &cfg) != 0) {
5039 /* Nvram data is left with INVALID mark
5040 */
5041 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005042 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5043
5044 /* This is an ATTO adapter, read Page2 accordingly
5045 */
5046 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5047 ATTODeviceInfo_t *pdevice = NULL;
5048 u16 ATTOFlags;
5049
5050 /* Save the Port Page 2 data
5051 * (reformat into a 32bit quantity)
5052 */
5053 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5054 pdevice = &pPP2->DeviceSettings[ii];
5055 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5056 data = 0;
5057
5058 /* Translate ATTO device flags to LSI format
5059 */
5060 if (ATTOFlags & ATTOFLAG_DISC)
5061 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5062 if (ATTOFlags & ATTOFLAG_ID_ENB)
5063 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5064 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5065 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5066 if (ATTOFlags & ATTOFLAG_TAGGED)
5067 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5068 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5069 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5070
5071 data = (data << 16) | (pdevice->Period << 8) | 10;
5072 ioc->spi_data.nvram[ii] = data;
5073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 } else {
5075 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5076 MpiDeviceInfo_t *pdevice = NULL;
5077
Moore, Ericd8e925d2006-01-16 18:53:06 -07005078 /*
5079 * Save "Set to Avoid SCSI Bus Resets" flag
5080 */
5081 ioc->spi_data.bus_reset =
5082 (le32_to_cpu(pPP2->PortFlags) &
5083 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5084 0 : 1 ;
5085
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 /* Save the Port Page 2 data
5087 * (reformat into a 32bit quantity)
5088 */
5089 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5090 ioc->spi_data.PortFlags = data;
5091 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5092 pdevice = &pPP2->DeviceSettings[ii];
5093 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5094 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5095 ioc->spi_data.nvram[ii] = data;
5096 }
5097 }
5098
5099 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5100 }
5101 }
5102
5103 /* Update Adapter limits with those from NVRAM
5104 * Comment: Don't need to do this. Target performance
5105 * parameters will never exceed the adapters limits.
5106 */
5107
5108 return rc;
5109}
5110
5111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005112/**
5113 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 * @ioc: Pointer to a Adapter Strucutre
5115 * @portnum: IOC port number
5116 *
5117 * Return: -EFAULT if read of config page header fails
5118 * or 0 if success.
5119 */
5120static int
5121mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5122{
5123 CONFIGPARMS cfg;
5124 ConfigPageHeader_t header;
5125
5126 /* Read the SCSI Device Page 1 header
5127 */
5128 header.PageVersion = 0;
5129 header.PageLength = 0;
5130 header.PageNumber = 1;
5131 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005132 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 cfg.physAddr = -1;
5134 cfg.pageAddr = portnum;
5135 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5136 cfg.dir = 0;
5137 cfg.timeout = 0;
5138 if (mpt_config(ioc, &cfg) != 0)
5139 return -EFAULT;
5140
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005141 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5142 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
5144 header.PageVersion = 0;
5145 header.PageLength = 0;
5146 header.PageNumber = 0;
5147 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5148 if (mpt_config(ioc, &cfg) != 0)
5149 return -EFAULT;
5150
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005151 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5152 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153
Prakash, Sathya436ace72007-07-24 15:42:08 +05305154 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5156
Prakash, Sathya436ace72007-07-24 15:42:08 +05305157 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5159 return 0;
5160}
5161
Eric Mooreb506ade2007-01-29 09:45:37 -07005162/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005163 * mpt_inactive_raid_list_free - This clears this link list.
5164 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005165 **/
5166static void
5167mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5168{
5169 struct inactive_raid_component_info *component_info, *pNext;
5170
5171 if (list_empty(&ioc->raid_data.inactive_list))
5172 return;
5173
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005174 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005175 list_for_each_entry_safe(component_info, pNext,
5176 &ioc->raid_data.inactive_list, list) {
5177 list_del(&component_info->list);
5178 kfree(component_info);
5179 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005180 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005181}
5182
5183/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005184 * 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 -07005185 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005186 * @ioc : pointer to per adapter structure
5187 * @channel : volume channel
5188 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005189 **/
5190static void
5191mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5192{
5193 CONFIGPARMS cfg;
5194 ConfigPageHeader_t hdr;
5195 dma_addr_t dma_handle;
5196 pRaidVolumePage0_t buffer = NULL;
5197 int i;
5198 RaidPhysDiskPage0_t phys_disk;
5199 struct inactive_raid_component_info *component_info;
5200 int handle_inactive_volumes;
5201
5202 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5203 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5204 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5205 cfg.pageAddr = (channel << 8) + id;
5206 cfg.cfghdr.hdr = &hdr;
5207 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5208
5209 if (mpt_config(ioc, &cfg) != 0)
5210 goto out;
5211
5212 if (!hdr.PageLength)
5213 goto out;
5214
5215 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5216 &dma_handle);
5217
5218 if (!buffer)
5219 goto out;
5220
5221 cfg.physAddr = dma_handle;
5222 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5223
5224 if (mpt_config(ioc, &cfg) != 0)
5225 goto out;
5226
5227 if (!buffer->NumPhysDisks)
5228 goto out;
5229
5230 handle_inactive_volumes =
5231 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5232 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5233 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5234 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5235
5236 if (!handle_inactive_volumes)
5237 goto out;
5238
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005239 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005240 for (i = 0; i < buffer->NumPhysDisks; i++) {
5241 if(mpt_raid_phys_disk_pg0(ioc,
5242 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5243 continue;
5244
5245 if ((component_info = kmalloc(sizeof (*component_info),
5246 GFP_KERNEL)) == NULL)
5247 continue;
5248
5249 component_info->volumeID = id;
5250 component_info->volumeBus = channel;
5251 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5252 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5253 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5254 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5255
5256 list_add_tail(&component_info->list,
5257 &ioc->raid_data.inactive_list);
5258 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005259 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005260
5261 out:
5262 if (buffer)
5263 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5264 dma_handle);
5265}
5266
5267/**
5268 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5269 * @ioc: Pointer to a Adapter Structure
5270 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5271 * @phys_disk: requested payload data returned
5272 *
5273 * Return:
5274 * 0 on success
5275 * -EFAULT if read of config page header fails or data pointer not NULL
5276 * -ENOMEM if pci_alloc failed
5277 **/
5278int
5279mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5280{
5281 CONFIGPARMS cfg;
5282 ConfigPageHeader_t hdr;
5283 dma_addr_t dma_handle;
5284 pRaidPhysDiskPage0_t buffer = NULL;
5285 int rc;
5286
5287 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5288 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5289
5290 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5291 cfg.cfghdr.hdr = &hdr;
5292 cfg.physAddr = -1;
5293 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5294
5295 if (mpt_config(ioc, &cfg) != 0) {
5296 rc = -EFAULT;
5297 goto out;
5298 }
5299
5300 if (!hdr.PageLength) {
5301 rc = -EFAULT;
5302 goto out;
5303 }
5304
5305 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5306 &dma_handle);
5307
5308 if (!buffer) {
5309 rc = -ENOMEM;
5310 goto out;
5311 }
5312
5313 cfg.physAddr = dma_handle;
5314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5315 cfg.pageAddr = phys_disk_num;
5316
5317 if (mpt_config(ioc, &cfg) != 0) {
5318 rc = -EFAULT;
5319 goto out;
5320 }
5321
5322 rc = 0;
5323 memcpy(phys_disk, buffer, sizeof(*buffer));
5324 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5325
5326 out:
5327
5328 if (buffer)
5329 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5330 dma_handle);
5331
5332 return rc;
5333}
5334
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335/**
5336 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5337 * @ioc: Pointer to a Adapter Strucutre
5338 * @portnum: IOC port number
5339 *
5340 * Return:
5341 * 0 on success
5342 * -EFAULT if read of config page header fails or data pointer not NULL
5343 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005344 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345int
5346mpt_findImVolumes(MPT_ADAPTER *ioc)
5347{
5348 IOCPage2_t *pIoc2;
5349 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 dma_addr_t ioc2_dma;
5351 CONFIGPARMS cfg;
5352 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 int rc = 0;
5354 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005355 int i;
5356
5357 if (!ioc->ir_firmware)
5358 return 0;
5359
5360 /* Free the old page
5361 */
5362 kfree(ioc->raid_data.pIocPg2);
5363 ioc->raid_data.pIocPg2 = NULL;
5364 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
5366 /* Read IOCP2 header then the page.
5367 */
5368 header.PageVersion = 0;
5369 header.PageLength = 0;
5370 header.PageNumber = 2;
5371 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005372 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 cfg.physAddr = -1;
5374 cfg.pageAddr = 0;
5375 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5376 cfg.dir = 0;
5377 cfg.timeout = 0;
5378 if (mpt_config(ioc, &cfg) != 0)
5379 return -EFAULT;
5380
5381 if (header.PageLength == 0)
5382 return -EFAULT;
5383
5384 iocpage2sz = header.PageLength * 4;
5385 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5386 if (!pIoc2)
5387 return -ENOMEM;
5388
5389 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5390 cfg.physAddr = ioc2_dma;
5391 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005392 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393
Eric Mooreb506ade2007-01-29 09:45:37 -07005394 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5395 if (!mem)
5396 goto out;
5397
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005399 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
Eric Mooreb506ade2007-01-29 09:45:37 -07005401 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
Eric Mooreb506ade2007-01-29 09:45:37 -07005403 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5404 mpt_inactive_raid_volumes(ioc,
5405 pIoc2->RaidVolume[i].VolumeBus,
5406 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
Eric Mooreb506ade2007-01-29 09:45:37 -07005408 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5410
5411 return rc;
5412}
5413
Moore, Ericc972c702006-03-14 09:14:06 -07005414static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5416{
5417 IOCPage3_t *pIoc3;
5418 u8 *mem;
5419 CONFIGPARMS cfg;
5420 ConfigPageHeader_t header;
5421 dma_addr_t ioc3_dma;
5422 int iocpage3sz = 0;
5423
5424 /* Free the old page
5425 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005426 kfree(ioc->raid_data.pIocPg3);
5427 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428
5429 /* There is at least one physical disk.
5430 * Read and save IOC Page 3
5431 */
5432 header.PageVersion = 0;
5433 header.PageLength = 0;
5434 header.PageNumber = 3;
5435 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005436 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 cfg.physAddr = -1;
5438 cfg.pageAddr = 0;
5439 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5440 cfg.dir = 0;
5441 cfg.timeout = 0;
5442 if (mpt_config(ioc, &cfg) != 0)
5443 return 0;
5444
5445 if (header.PageLength == 0)
5446 return 0;
5447
5448 /* Read Header good, alloc memory
5449 */
5450 iocpage3sz = header.PageLength * 4;
5451 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5452 if (!pIoc3)
5453 return 0;
5454
5455 /* Read the Page and save the data
5456 * into malloc'd memory.
5457 */
5458 cfg.physAddr = ioc3_dma;
5459 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5460 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005461 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 if (mem) {
5463 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005464 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 }
5466 }
5467
5468 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5469
5470 return 0;
5471}
5472
5473static void
5474mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5475{
5476 IOCPage4_t *pIoc4;
5477 CONFIGPARMS cfg;
5478 ConfigPageHeader_t header;
5479 dma_addr_t ioc4_dma;
5480 int iocpage4sz;
5481
5482 /* Read and save IOC Page 4
5483 */
5484 header.PageVersion = 0;
5485 header.PageLength = 0;
5486 header.PageNumber = 4;
5487 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005488 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 cfg.physAddr = -1;
5490 cfg.pageAddr = 0;
5491 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5492 cfg.dir = 0;
5493 cfg.timeout = 0;
5494 if (mpt_config(ioc, &cfg) != 0)
5495 return;
5496
5497 if (header.PageLength == 0)
5498 return;
5499
5500 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5501 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5502 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5503 if (!pIoc4)
5504 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005505 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 } else {
5507 ioc4_dma = ioc->spi_data.IocPg4_dma;
5508 iocpage4sz = ioc->spi_data.IocPg4Sz;
5509 }
5510
5511 /* Read the Page into dma memory.
5512 */
5513 cfg.physAddr = ioc4_dma;
5514 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5515 if (mpt_config(ioc, &cfg) == 0) {
5516 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5517 ioc->spi_data.IocPg4_dma = ioc4_dma;
5518 ioc->spi_data.IocPg4Sz = iocpage4sz;
5519 } else {
5520 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5521 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005522 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 }
5524}
5525
5526static void
5527mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5528{
5529 IOCPage1_t *pIoc1;
5530 CONFIGPARMS cfg;
5531 ConfigPageHeader_t header;
5532 dma_addr_t ioc1_dma;
5533 int iocpage1sz = 0;
5534 u32 tmp;
5535
5536 /* Check the Coalescing Timeout in IOC Page 1
5537 */
5538 header.PageVersion = 0;
5539 header.PageLength = 0;
5540 header.PageNumber = 1;
5541 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005542 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 cfg.physAddr = -1;
5544 cfg.pageAddr = 0;
5545 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5546 cfg.dir = 0;
5547 cfg.timeout = 0;
5548 if (mpt_config(ioc, &cfg) != 0)
5549 return;
5550
5551 if (header.PageLength == 0)
5552 return;
5553
5554 /* Read Header good, alloc memory
5555 */
5556 iocpage1sz = header.PageLength * 4;
5557 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5558 if (!pIoc1)
5559 return;
5560
5561 /* Read the Page and check coalescing timeout
5562 */
5563 cfg.physAddr = ioc1_dma;
5564 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5565 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305566
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5568 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5569 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5570
Prakash, Sathya436ace72007-07-24 15:42:08 +05305571 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 ioc->name, tmp));
5573
5574 if (tmp > MPT_COALESCING_TIMEOUT) {
5575 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5576
5577 /* Write NVRAM and current
5578 */
5579 cfg.dir = 1;
5580 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5581 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305582 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 ioc->name, MPT_COALESCING_TIMEOUT));
5584
5585 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5586 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305587 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5588 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 ioc->name, MPT_COALESCING_TIMEOUT));
5590 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305591 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5592 "Reset NVRAM Coalescing Timeout Failed\n",
5593 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 }
5595
5596 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305597 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5598 "Reset of Current Coalescing Timeout Failed!\n",
5599 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 }
5601 }
5602
5603 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305604 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 }
5606 }
5607
5608 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5609
5610 return;
5611}
5612
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305613static void
5614mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5615{
5616 CONFIGPARMS cfg;
5617 ConfigPageHeader_t hdr;
5618 dma_addr_t buf_dma;
5619 ManufacturingPage0_t *pbuf = NULL;
5620
5621 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5622 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5623
5624 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5625 cfg.cfghdr.hdr = &hdr;
5626 cfg.physAddr = -1;
5627 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5628 cfg.timeout = 10;
5629
5630 if (mpt_config(ioc, &cfg) != 0)
5631 goto out;
5632
5633 if (!cfg.cfghdr.hdr->PageLength)
5634 goto out;
5635
5636 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5637 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5638 if (!pbuf)
5639 goto out;
5640
5641 cfg.physAddr = buf_dma;
5642
5643 if (mpt_config(ioc, &cfg) != 0)
5644 goto out;
5645
5646 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5647 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5648 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5649
5650 out:
5651
5652 if (pbuf)
5653 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5654}
5655
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005657/**
5658 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 * @ioc: Pointer to MPT_ADAPTER structure
5660 * @EvSwitch: Event switch flags
5661 */
5662static int
5663SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5664{
5665 EventNotification_t *evnp;
5666
5667 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5668 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305669 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 ioc->name));
5671 return 0;
5672 }
5673 memset(evnp, 0, sizeof(*evnp));
5674
Prakash, Sathya436ace72007-07-24 15:42:08 +05305675 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
5677 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5678 evnp->ChainOffset = 0;
5679 evnp->MsgFlags = 0;
5680 evnp->Switch = EvSwitch;
5681
5682 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5683
5684 return 0;
5685}
5686
5687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5688/**
5689 * SendEventAck - Send EventAck request to MPT adapter.
5690 * @ioc: Pointer to MPT_ADAPTER structure
5691 * @evnp: Pointer to original EventNotification request
5692 */
5693static int
5694SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5695{
5696 EventAck_t *pAck;
5697
5698 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305699 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005700 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 return -1;
5702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
Prakash, Sathya436ace72007-07-24 15:42:08 +05305704 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705
5706 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5707 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005708 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005710 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 pAck->Event = evnp->Event;
5712 pAck->EventContext = evnp->EventContext;
5713
5714 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5715
5716 return 0;
5717}
5718
5719/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5720/**
5721 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005722 * @ioc: Pointer to an adapter structure
5723 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 * action, page address, direction, physical address
5725 * and pointer to a configuration page header
5726 * Page header is updated.
5727 *
5728 * Returns 0 for success
5729 * -EPERM if not allowed due to ISR context
5730 * -EAGAIN if no msg frames currently available
5731 * -EFAULT for non-successful reply or no reply (timeout)
5732 */
5733int
5734mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5735{
5736 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005737 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 MPT_FRAME_HDR *mf;
5739 unsigned long flags;
5740 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005741 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 int in_isr;
5743
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005744 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 * to be in ISR context, because that is fatal!
5746 */
5747 in_isr = in_interrupt();
5748 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305749 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 ioc->name));
5751 return -EPERM;
5752 }
5753
5754 /* Get and Populate a free Frame
5755 */
5756 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305757 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 ioc->name));
5759 return -EAGAIN;
5760 }
5761 pReq = (Config_t *)mf;
5762 pReq->Action = pCfg->action;
5763 pReq->Reserved = 0;
5764 pReq->ChainOffset = 0;
5765 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005766
5767 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 pReq->ExtPageLength = 0;
5769 pReq->ExtPageType = 0;
5770 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005771
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 for (ii=0; ii < 8; ii++)
5773 pReq->Reserved2[ii] = 0;
5774
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005775 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5776 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5777 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5778 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5779
5780 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5781 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5782 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5783 pReq->ExtPageType = pExtHdr->ExtPageType;
5784 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5785
5786 /* Page Length must be treated as a reserved field for the extended header. */
5787 pReq->Header.PageLength = 0;
5788 }
5789
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5791
5792 /* Add a SGE to the config request.
5793 */
5794 if (pCfg->dir)
5795 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5796 else
5797 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5798
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005799 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5800 flagsLength |= pExtHdr->ExtPageLength * 4;
5801
Prakash, Sathya436ace72007-07-24 15:42:08 +05305802 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 +02005803 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5804 }
5805 else {
5806 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5807
Prakash, Sathya436ace72007-07-24 15:42:08 +05305808 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 +02005809 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811
5812 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5813
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814 /* Append pCfg pointer to end of mf
5815 */
5816 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5817
5818 /* Initalize the timer
5819 */
5820 init_timer(&pCfg->timer);
5821 pCfg->timer.data = (unsigned long) ioc;
5822 pCfg->timer.function = mpt_timer_expired;
5823 pCfg->wait_done = 0;
5824
5825 /* Set the timer; ensure 10 second minimum */
5826 if (pCfg->timeout < 10)
5827 pCfg->timer.expires = jiffies + HZ*10;
5828 else
5829 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5830
5831 /* Add to end of Q, set timer and then issue this command */
5832 spin_lock_irqsave(&ioc->FreeQlock, flags);
5833 list_add_tail(&pCfg->linkage, &ioc->configQ);
5834 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5835
5836 add_timer(&pCfg->timer);
5837 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5838 wait_event(mpt_waitq, pCfg->wait_done);
5839
5840 /* mf has been freed - do not access */
5841
5842 rc = pCfg->status;
5843
5844 return rc;
5845}
5846
5847/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005848/**
5849 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850 * Used only internal config functionality.
5851 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5852 */
5853static void
5854mpt_timer_expired(unsigned long data)
5855{
5856 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5857
Prakash, Sathya436ace72007-07-24 15:42:08 +05305858 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859
5860 /* Perform a FW reload */
5861 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5862 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5863
5864 /* No more processing.
5865 * Hard reset clean-up will wake up
5866 * process and free all resources.
5867 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305868 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
5870 return;
5871}
5872
5873/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005874/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 * mpt_ioc_reset - Base cleanup for hard reset
5876 * @ioc: Pointer to the adapter structure
5877 * @reset_phase: Indicates pre- or post-reset functionality
5878 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005879 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 */
5881static int
5882mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5883{
5884 CONFIGPARMS *pCfg;
5885 unsigned long flags;
5886
Eric Moore29dd3602007-09-14 18:46:51 -06005887 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5888 ": IOC %s_reset routed to MPT base driver!\n",
5889 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5890 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891
5892 if (reset_phase == MPT_IOC_SETUP_RESET) {
5893 ;
5894 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5895 /* If the internal config Q is not empty -
5896 * delete timer. MF resources will be freed when
5897 * the FIFO's are primed.
5898 */
5899 spin_lock_irqsave(&ioc->FreeQlock, flags);
5900 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5901 del_timer(&pCfg->timer);
5902 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5903
5904 } else {
5905 CONFIGPARMS *pNext;
5906
5907 /* Search the configQ for internal commands.
5908 * Flush the Q, and wake up all suspended threads.
5909 */
5910 spin_lock_irqsave(&ioc->FreeQlock, flags);
5911 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5912 list_del(&pCfg->linkage);
5913
5914 pCfg->status = MPT_CONFIG_ERROR;
5915 pCfg->wait_done = 1;
5916 wake_up(&mpt_waitq);
5917 }
5918 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5919 }
5920
5921 return 1; /* currently means nothing really */
5922}
5923
5924
5925#ifdef CONFIG_PROC_FS /* { */
5926/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5927/*
5928 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5929 */
5930/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005931/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5933 *
5934 * Returns 0 for success, non-zero for failure.
5935 */
5936static int
5937procmpt_create(void)
5938{
5939 struct proc_dir_entry *ent;
5940
5941 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5942 if (mpt_proc_root_dir == NULL)
5943 return -ENOTDIR;
5944
5945 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5946 if (ent)
5947 ent->read_proc = procmpt_summary_read;
5948
5949 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5950 if (ent)
5951 ent->read_proc = procmpt_version_read;
5952
5953 return 0;
5954}
5955
5956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005957/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5959 *
5960 * Returns 0 for success, non-zero for failure.
5961 */
5962static void
5963procmpt_destroy(void)
5964{
5965 remove_proc_entry("version", mpt_proc_root_dir);
5966 remove_proc_entry("summary", mpt_proc_root_dir);
5967 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5968}
5969
5970/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005971/**
5972 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 * @buf: Pointer to area to write information
5974 * @start: Pointer to start pointer
5975 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005976 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 * @eof: Pointer to EOF integer
5978 * @data: Pointer
5979 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005980 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 * Returns number of characters written to process performing the read.
5982 */
5983static int
5984procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5985{
5986 MPT_ADAPTER *ioc;
5987 char *out = buf;
5988 int len;
5989
5990 if (data) {
5991 int more = 0;
5992
5993 ioc = data;
5994 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5995
5996 out += more;
5997 } else {
5998 list_for_each_entry(ioc, &ioc_list, list) {
5999 int more = 0;
6000
6001 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6002
6003 out += more;
6004 if ((out-buf) >= request)
6005 break;
6006 }
6007 }
6008
6009 len = out - buf;
6010
6011 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6012}
6013
6014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006015/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 * procmpt_version_read - Handle read request from /proc/mpt/version.
6017 * @buf: Pointer to area to write information
6018 * @start: Pointer to start pointer
6019 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006020 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 * @eof: Pointer to EOF integer
6022 * @data: Pointer
6023 *
6024 * Returns number of characters written to process performing the read.
6025 */
6026static int
6027procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6028{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306029 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006030 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 char *drvname;
6032 int len;
6033
6034 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6035 len += sprintf(buf+len, " Fusion MPT base driver\n");
6036
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006037 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006038 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306040 if (MptCallbacks[cb_idx]) {
6041 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006042 case MPTSPI_DRIVER:
6043 if (!scsi++) drvname = "SPI host";
6044 break;
6045 case MPTFC_DRIVER:
6046 if (!fc++) drvname = "FC host";
6047 break;
6048 case MPTSAS_DRIVER:
6049 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 break;
6051 case MPTLAN_DRIVER:
6052 if (!lan++) drvname = "LAN";
6053 break;
6054 case MPTSTM_DRIVER:
6055 if (!targ++) drvname = "SCSI target";
6056 break;
6057 case MPTCTL_DRIVER:
6058 if (!ctl++) drvname = "ioctl";
6059 break;
6060 }
6061
6062 if (drvname)
6063 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6064 }
6065 }
6066
6067 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6068}
6069
6070/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006071/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6073 * @buf: Pointer to area to write information
6074 * @start: Pointer to start pointer
6075 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006076 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 * @eof: Pointer to EOF integer
6078 * @data: Pointer
6079 *
6080 * Returns number of characters written to process performing the read.
6081 */
6082static int
6083procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6084{
6085 MPT_ADAPTER *ioc = data;
6086 int len;
6087 char expVer[32];
6088 int sz;
6089 int p;
6090
6091 mpt_get_fw_exp_ver(expVer, ioc);
6092
6093 len = sprintf(buf, "%s:", ioc->name);
6094 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6095 len += sprintf(buf+len, " (f/w download boot flag set)");
6096// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6097// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6098
6099 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6100 ioc->facts.ProductID,
6101 ioc->prod_name);
6102 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6103 if (ioc->facts.FWImageSize)
6104 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6105 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6106 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6107 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6108
6109 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6110 ioc->facts.CurrentHostMfaHighAddr);
6111 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6112 ioc->facts.CurrentSenseBufferHighAddr);
6113
6114 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6115 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6116
6117 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6118 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6119 /*
6120 * Rounding UP to nearest 4-kB boundary here...
6121 */
6122 sz = (ioc->req_sz * ioc->req_depth) + 128;
6123 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6124 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6125 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6126 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6127 4*ioc->facts.RequestFrameSize,
6128 ioc->facts.GlobalCredits);
6129
6130 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6131 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6132 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6133 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6134 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6135 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6136 ioc->facts.CurReplyFrameSize,
6137 ioc->facts.ReplyQueueDepth);
6138
6139 len += sprintf(buf+len, " MaxDevices = %d\n",
6140 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6141 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6142
6143 /* per-port info */
6144 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6145 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6146 p+1,
6147 ioc->facts.NumberOfPorts);
6148 if (ioc->bus_type == FC) {
6149 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6150 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6151 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6152 a[5], a[4], a[3], a[2], a[1], a[0]);
6153 }
6154 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6155 ioc->fc_port_page0[p].WWNN.High,
6156 ioc->fc_port_page0[p].WWNN.Low,
6157 ioc->fc_port_page0[p].WWPN.High,
6158 ioc->fc_port_page0[p].WWPN.Low);
6159 }
6160 }
6161
6162 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6163}
6164
6165#endif /* CONFIG_PROC_FS } */
6166
6167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6168static void
6169mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6170{
6171 buf[0] ='\0';
6172 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6173 sprintf(buf, " (Exp %02d%02d)",
6174 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6175 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6176
6177 /* insider hack! */
6178 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6179 strcat(buf, " [MDBG]");
6180 }
6181}
6182
6183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6184/**
6185 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6186 * @ioc: Pointer to MPT_ADAPTER structure
6187 * @buffer: Pointer to buffer where IOC summary info should be written
6188 * @size: Pointer to number of bytes we wrote (set by this routine)
6189 * @len: Offset at which to start writing in buffer
6190 * @showlan: Display LAN stuff?
6191 *
6192 * This routine writes (english readable) ASCII text, which represents
6193 * a summary of IOC information, to a buffer.
6194 */
6195void
6196mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6197{
6198 char expVer[32];
6199 int y;
6200
6201 mpt_get_fw_exp_ver(expVer, ioc);
6202
6203 /*
6204 * Shorter summary of attached ioc's...
6205 */
6206 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6207 ioc->name,
6208 ioc->prod_name,
6209 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6210 ioc->facts.FWVersion.Word,
6211 expVer,
6212 ioc->facts.NumberOfPorts,
6213 ioc->req_depth);
6214
6215 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6216 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6217 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6218 a[5], a[4], a[3], a[2], a[1], a[0]);
6219 }
6220
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222
6223 if (!ioc->active)
6224 y += sprintf(buffer+len+y, " (disabled)");
6225
6226 y += sprintf(buffer+len+y, "\n");
6227
6228 *size = y;
6229}
6230
6231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6232/*
6233 * Reset Handling
6234 */
6235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6236/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006237 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 * @ioc: Pointer to MPT_ADAPTER structure
6239 * @sleepFlag: Indicates if sleep or schedule must be called.
6240 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006241 * Issues SCSI Task Management call based on input arg values.
6242 * If TaskMgmt fails, returns associated SCSI request.
6243 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6245 * or a non-interrupt thread. In the former, must not call schedule().
6246 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006247 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 * FW reload/initialization failed.
6249 *
6250 * Returns 0 for SUCCESS or -1 if FAILED.
6251 */
6252int
6253mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6254{
6255 int rc;
6256 unsigned long flags;
6257
Prakash, Sathya436ace72007-07-24 15:42:08 +05306258 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259#ifdef MFCNT
6260 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6261 printk("MF count 0x%x !\n", ioc->mfcnt);
6262#endif
6263
6264 /* Reset the adapter. Prevent more than 1 call to
6265 * mpt_do_ioc_recovery at any instant in time.
6266 */
6267 spin_lock_irqsave(&ioc->diagLock, flags);
6268 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6269 spin_unlock_irqrestore(&ioc->diagLock, flags);
6270 return 0;
6271 } else {
6272 ioc->diagPending = 1;
6273 }
6274 spin_unlock_irqrestore(&ioc->diagLock, flags);
6275
6276 /* FIXME: If do_ioc_recovery fails, repeat....
6277 */
6278
6279 /* The SCSI driver needs to adjust timeouts on all current
6280 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006281 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 * For all other protocol drivers, this is a no-op.
6283 */
6284 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306285 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 int r = 0;
6287
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306288 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6289 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306290 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306291 ioc->name, cb_idx));
6292 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306294 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306295 ioc->name, ioc->alt_ioc->name, cb_idx));
6296 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297 }
6298 }
6299 }
6300 }
6301
6302 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006303 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 }
6305 ioc->reload_fw = 0;
6306 if (ioc->alt_ioc)
6307 ioc->alt_ioc->reload_fw = 0;
6308
6309 spin_lock_irqsave(&ioc->diagLock, flags);
6310 ioc->diagPending = 0;
6311 if (ioc->alt_ioc)
6312 ioc->alt_ioc->diagPending = 0;
6313 spin_unlock_irqrestore(&ioc->diagLock, flags);
6314
Prakash, Sathya436ace72007-07-24 15:42:08 +05306315 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316
6317 return rc;
6318}
6319
6320/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006321static void
6322EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323{
Eric Moore509e5e52006-04-26 13:22:37 -06006324 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
6326 switch(event) {
6327 case MPI_EVENT_NONE:
6328 ds = "None";
6329 break;
6330 case MPI_EVENT_LOG_DATA:
6331 ds = "Log Data";
6332 break;
6333 case MPI_EVENT_STATE_CHANGE:
6334 ds = "State Change";
6335 break;
6336 case MPI_EVENT_UNIT_ATTENTION:
6337 ds = "Unit Attention";
6338 break;
6339 case MPI_EVENT_IOC_BUS_RESET:
6340 ds = "IOC Bus Reset";
6341 break;
6342 case MPI_EVENT_EXT_BUS_RESET:
6343 ds = "External Bus Reset";
6344 break;
6345 case MPI_EVENT_RESCAN:
6346 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 break;
6348 case MPI_EVENT_LINK_STATUS_CHANGE:
6349 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6350 ds = "Link Status(FAILURE) Change";
6351 else
6352 ds = "Link Status(ACTIVE) Change";
6353 break;
6354 case MPI_EVENT_LOOP_STATE_CHANGE:
6355 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6356 ds = "Loop State(LIP) Change";
6357 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006358 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 else
Eric Moore509e5e52006-04-26 13:22:37 -06006360 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361 break;
6362 case MPI_EVENT_LOGOUT:
6363 ds = "Logout";
6364 break;
6365 case MPI_EVENT_EVENT_CHANGE:
6366 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006367 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006369 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370 break;
6371 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006372 {
6373 u8 ReasonCode = (u8)(evData0 >> 16);
6374 switch (ReasonCode) {
6375 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6376 ds = "Integrated Raid: Volume Created";
6377 break;
6378 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6379 ds = "Integrated Raid: Volume Deleted";
6380 break;
6381 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6382 ds = "Integrated Raid: Volume Settings Changed";
6383 break;
6384 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6385 ds = "Integrated Raid: Volume Status Changed";
6386 break;
6387 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6388 ds = "Integrated Raid: Volume Physdisk Changed";
6389 break;
6390 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6391 ds = "Integrated Raid: Physdisk Created";
6392 break;
6393 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6394 ds = "Integrated Raid: Physdisk Deleted";
6395 break;
6396 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6397 ds = "Integrated Raid: Physdisk Settings Changed";
6398 break;
6399 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6400 ds = "Integrated Raid: Physdisk Status Changed";
6401 break;
6402 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6403 ds = "Integrated Raid: Domain Validation Needed";
6404 break;
6405 case MPI_EVENT_RAID_RC_SMART_DATA :
6406 ds = "Integrated Raid; Smart Data";
6407 break;
6408 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6409 ds = "Integrated Raid: Replace Action Started";
6410 break;
6411 default:
6412 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006414 }
6415 break;
6416 }
6417 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6418 ds = "SCSI Device Status Change";
6419 break;
6420 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6421 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006422 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006423 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006424 u8 ReasonCode = (u8)(evData0 >> 16);
6425 switch (ReasonCode) {
6426 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006427 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006428 "SAS Device Status Change: Added: "
6429 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006430 break;
6431 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006432 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006433 "SAS Device Status Change: Deleted: "
6434 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006435 break;
6436 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006437 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006438 "SAS Device Status Change: SMART Data: "
6439 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006440 break;
6441 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006442 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006443 "SAS Device Status Change: No Persistancy: "
6444 "id=%d channel=%d", id, channel);
6445 break;
6446 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6447 snprintf(evStr, EVENT_DESCR_STR_SZ,
6448 "SAS Device Status Change: Unsupported Device "
6449 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006450 break;
6451 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6452 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006453 "SAS Device Status Change: Internal Device "
6454 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006455 break;
6456 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6457 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006458 "SAS Device Status Change: Internal Task "
6459 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006460 break;
6461 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6462 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006463 "SAS Device Status Change: Internal Abort "
6464 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006465 break;
6466 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6467 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006468 "SAS Device Status Change: Internal Clear "
6469 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006470 break;
6471 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6472 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006473 "SAS Device Status Change: Internal Query "
6474 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006475 break;
6476 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006477 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006478 "SAS Device Status Change: Unknown: "
6479 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006480 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006481 }
6482 break;
6483 }
6484 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6485 ds = "Bus Timer Expired";
6486 break;
6487 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006488 {
6489 u16 curr_depth = (u16)(evData0 >> 16);
6490 u8 channel = (u8)(evData0 >> 8);
6491 u8 id = (u8)(evData0);
6492
6493 snprintf(evStr, EVENT_DESCR_STR_SZ,
6494 "Queue Full: channel=%d id=%d depth=%d",
6495 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006496 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006497 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006498 case MPI_EVENT_SAS_SES:
6499 ds = "SAS SES Event";
6500 break;
6501 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6502 ds = "Persistent Table Full";
6503 break;
6504 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006505 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006506 u8 LinkRates = (u8)(evData0 >> 8);
6507 u8 PhyNumber = (u8)(evData0);
6508 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6509 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6510 switch (LinkRates) {
6511 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006512 snprintf(evStr, EVENT_DESCR_STR_SZ,
6513 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006514 " Rate Unknown",PhyNumber);
6515 break;
6516 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006517 snprintf(evStr, EVENT_DESCR_STR_SZ,
6518 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006519 " Phy Disabled",PhyNumber);
6520 break;
6521 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006522 snprintf(evStr, EVENT_DESCR_STR_SZ,
6523 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006524 " Failed Speed Nego",PhyNumber);
6525 break;
6526 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006527 snprintf(evStr, EVENT_DESCR_STR_SZ,
6528 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006529 " Sata OOB Completed",PhyNumber);
6530 break;
6531 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006532 snprintf(evStr, EVENT_DESCR_STR_SZ,
6533 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006534 " Rate 1.5 Gbps",PhyNumber);
6535 break;
6536 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006537 snprintf(evStr, EVENT_DESCR_STR_SZ,
6538 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006539 " Rate 3.0 Gpbs",PhyNumber);
6540 break;
6541 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006542 snprintf(evStr, EVENT_DESCR_STR_SZ,
6543 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006544 break;
6545 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006546 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006547 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006548 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6549 ds = "SAS Discovery Error";
6550 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006551 case MPI_EVENT_IR_RESYNC_UPDATE:
6552 {
6553 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006554 snprintf(evStr, EVENT_DESCR_STR_SZ,
6555 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006556 break;
6557 }
6558 case MPI_EVENT_IR2:
6559 {
6560 u8 ReasonCode = (u8)(evData0 >> 16);
6561 switch (ReasonCode) {
6562 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6563 ds = "IR2: LD State Changed";
6564 break;
6565 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6566 ds = "IR2: PD State Changed";
6567 break;
6568 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6569 ds = "IR2: Bad Block Table Full";
6570 break;
6571 case MPI_EVENT_IR2_RC_PD_INSERTED:
6572 ds = "IR2: PD Inserted";
6573 break;
6574 case MPI_EVENT_IR2_RC_PD_REMOVED:
6575 ds = "IR2: PD Removed";
6576 break;
6577 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6578 ds = "IR2: Foreign CFG Detected";
6579 break;
6580 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6581 ds = "IR2: Rebuild Medium Error";
6582 break;
6583 default:
6584 ds = "IR2";
6585 break;
6586 }
6587 break;
6588 }
6589 case MPI_EVENT_SAS_DISCOVERY:
6590 {
6591 if (evData0)
6592 ds = "SAS Discovery: Start";
6593 else
6594 ds = "SAS Discovery: Stop";
6595 break;
6596 }
6597 case MPI_EVENT_LOG_ENTRY_ADDED:
6598 ds = "SAS Log Entry Added";
6599 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006600
Eric Moorec6c727a2007-01-29 09:44:54 -07006601 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6602 {
6603 u8 phy_num = (u8)(evData0);
6604 u8 port_num = (u8)(evData0 >> 8);
6605 u8 port_width = (u8)(evData0 >> 16);
6606 u8 primative = (u8)(evData0 >> 24);
6607 snprintf(evStr, EVENT_DESCR_STR_SZ,
6608 "SAS Broadcase Primative: phy=%d port=%d "
6609 "width=%d primative=0x%02x",
6610 phy_num, port_num, port_width, primative);
6611 break;
6612 }
6613
6614 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6615 {
6616 u8 reason = (u8)(evData0);
6617 u8 port_num = (u8)(evData0 >> 8);
6618 u16 handle = le16_to_cpu(evData0 >> 16);
6619
6620 snprintf(evStr, EVENT_DESCR_STR_SZ,
6621 "SAS Initiator Device Status Change: reason=0x%02x "
6622 "port=%d handle=0x%04x",
6623 reason, port_num, handle);
6624 break;
6625 }
6626
6627 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6628 {
6629 u8 max_init = (u8)(evData0);
6630 u8 current_init = (u8)(evData0 >> 8);
6631
6632 snprintf(evStr, EVENT_DESCR_STR_SZ,
6633 "SAS Initiator Device Table Overflow: max initiators=%02d "
6634 "current initators=%02d",
6635 max_init, current_init);
6636 break;
6637 }
6638 case MPI_EVENT_SAS_SMP_ERROR:
6639 {
6640 u8 status = (u8)(evData0);
6641 u8 port_num = (u8)(evData0 >> 8);
6642 u8 result = (u8)(evData0 >> 16);
6643
6644 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6645 snprintf(evStr, EVENT_DESCR_STR_SZ,
6646 "SAS SMP Error: port=%d result=0x%02x",
6647 port_num, result);
6648 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6649 snprintf(evStr, EVENT_DESCR_STR_SZ,
6650 "SAS SMP Error: port=%d : CRC Error",
6651 port_num);
6652 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6653 snprintf(evStr, EVENT_DESCR_STR_SZ,
6654 "SAS SMP Error: port=%d : Timeout",
6655 port_num);
6656 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6657 snprintf(evStr, EVENT_DESCR_STR_SZ,
6658 "SAS SMP Error: port=%d : No Destination",
6659 port_num);
6660 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6661 snprintf(evStr, EVENT_DESCR_STR_SZ,
6662 "SAS SMP Error: port=%d : Bad Destination",
6663 port_num);
6664 else
6665 snprintf(evStr, EVENT_DESCR_STR_SZ,
6666 "SAS SMP Error: port=%d : status=0x%02x",
6667 port_num, status);
6668 break;
6669 }
6670
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671 /*
6672 * MPT base "custom" events may be added here...
6673 */
6674 default:
6675 ds = "Unknown";
6676 break;
6677 }
Eric Moore509e5e52006-04-26 13:22:37 -06006678 if (ds)
6679 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680}
6681
6682/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006683/**
6684 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685 * @ioc: Pointer to MPT_ADAPTER structure
6686 * @pEventReply: Pointer to EventNotification reply frame
6687 * @evHandlers: Pointer to integer, number of event handlers
6688 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006689 * Routes a received EventNotificationReply to all currently registered
6690 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691 * Returns sum of event handlers return values.
6692 */
6693static int
6694ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6695{
6696 u16 evDataLen;
6697 u32 evData0 = 0;
6698// u32 evCtx;
6699 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306700 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 int r = 0;
6702 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006703 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704 u8 event;
6705
6706 /*
6707 * Do platform normalization of values
6708 */
6709 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6710// evCtx = le32_to_cpu(pEventReply->EventContext);
6711 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6712 if (evDataLen) {
6713 evData0 = le32_to_cpu(pEventReply->Data[0]);
6714 }
6715
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006716 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306717 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006719 event,
6720 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721
Prakash, Sathya436ace72007-07-24 15:42:08 +05306722#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006723 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6724 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306726 devtverboseprintk(ioc, printk(" %08x",
6727 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006728 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729#endif
6730
6731 /*
6732 * Do general / base driver event processing
6733 */
6734 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6736 if (evDataLen) {
6737 u8 evState = evData0 & 0xFF;
6738
6739 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6740
6741 /* Update EventState field in cached IocFacts */
6742 if (ioc->facts.Function) {
6743 ioc->facts.EventState = evState;
6744 }
6745 }
6746 break;
Moore, Ericece50912006-01-16 18:53:19 -07006747 case MPI_EVENT_INTEGRATED_RAID:
6748 mptbase_raid_process_event_data(ioc,
6749 (MpiEventDataRaid_t *)pEventReply->Data);
6750 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006751 default:
6752 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753 }
6754
6755 /*
6756 * Should this event be logged? Events are written sequentially.
6757 * When buffer is full, start again at the top.
6758 */
6759 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6760 int idx;
6761
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006762 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763
6764 ioc->events[idx].event = event;
6765 ioc->events[idx].eventContext = ioc->eventContext;
6766
6767 for (ii = 0; ii < 2; ii++) {
6768 if (ii < evDataLen)
6769 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6770 else
6771 ioc->events[idx].data[ii] = 0;
6772 }
6773
6774 ioc->eventContext++;
6775 }
6776
6777
6778 /*
6779 * Call each currently registered protocol event handler.
6780 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006781 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306782 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306783 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306784 ioc->name, cb_idx));
6785 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786 handlers++;
6787 }
6788 }
6789 /* FIXME? Examine results here? */
6790
6791 /*
6792 * If needed, send (a single) EventAck.
6793 */
6794 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306795 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006796 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306798 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799 ioc->name, ii));
6800 }
6801 }
6802
6803 *evHandlers = handlers;
6804 return r;
6805}
6806
6807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006808/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6810 * @ioc: Pointer to MPT_ADAPTER structure
6811 * @log_info: U32 LogInfo reply word from the IOC
6812 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006813 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814 */
6815static void
6816mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6817{
Eric Moore7c431e52007-06-13 16:34:36 -06006818 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819
Eric Moore7c431e52007-06-13 16:34:36 -06006820 switch (log_info & 0xFF000000) {
6821 case MPI_IOCLOGINFO_FC_INIT_BASE:
6822 desc = "FCP Initiator";
6823 break;
6824 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6825 desc = "FCP Target";
6826 break;
6827 case MPI_IOCLOGINFO_FC_LAN_BASE:
6828 desc = "LAN";
6829 break;
6830 case MPI_IOCLOGINFO_FC_MSG_BASE:
6831 desc = "MPI Message Layer";
6832 break;
6833 case MPI_IOCLOGINFO_FC_LINK_BASE:
6834 desc = "FC Link";
6835 break;
6836 case MPI_IOCLOGINFO_FC_CTX_BASE:
6837 desc = "Context Manager";
6838 break;
6839 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6840 desc = "Invalid Field Offset";
6841 break;
6842 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6843 desc = "State Change Info";
6844 break;
6845 }
6846
6847 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6848 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849}
6850
6851/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006852/**
Moore, Eric335a9412006-01-17 17:06:23 -07006853 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006854 * @ioc: Pointer to MPT_ADAPTER structure
6855 * @mr: Pointer to MPT reply frame
6856 * @log_info: U32 LogInfo word from the IOC
6857 *
6858 * Refer to lsi/sp_log.h.
6859 */
6860static void
Moore, Eric335a9412006-01-17 17:06:23 -07006861mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006862{
6863 u32 info = log_info & 0x00FF0000;
6864 char *desc = "unknown";
6865
6866 switch (info) {
6867 case 0x00010000:
6868 desc = "bug! MID not found";
6869 if (ioc->reload_fw == 0)
6870 ioc->reload_fw++;
6871 break;
6872
6873 case 0x00020000:
6874 desc = "Parity Error";
6875 break;
6876
6877 case 0x00030000:
6878 desc = "ASYNC Outbound Overrun";
6879 break;
6880
6881 case 0x00040000:
6882 desc = "SYNC Offset Error";
6883 break;
6884
6885 case 0x00050000:
6886 desc = "BM Change";
6887 break;
6888
6889 case 0x00060000:
6890 desc = "Msg In Overflow";
6891 break;
6892
6893 case 0x00070000:
6894 desc = "DMA Error";
6895 break;
6896
6897 case 0x00080000:
6898 desc = "Outbound DMA Overrun";
6899 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006900
Linus Torvalds1da177e2005-04-16 15:20:36 -07006901 case 0x00090000:
6902 desc = "Task Management";
6903 break;
6904
6905 case 0x000A0000:
6906 desc = "Device Problem";
6907 break;
6908
6909 case 0x000B0000:
6910 desc = "Invalid Phase Change";
6911 break;
6912
6913 case 0x000C0000:
6914 desc = "Untagged Table Size";
6915 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006916
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917 }
6918
6919 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6920}
6921
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006922/* strings for sas loginfo */
6923 static char *originator_str[] = {
6924 "IOP", /* 00h */
6925 "PL", /* 01h */
6926 "IR" /* 02h */
6927 };
6928 static char *iop_code_str[] = {
6929 NULL, /* 00h */
6930 "Invalid SAS Address", /* 01h */
6931 NULL, /* 02h */
6932 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006933 "Diag Message Error", /* 04h */
6934 "Task Terminated", /* 05h */
6935 "Enclosure Management", /* 06h */
6936 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006937 };
6938 static char *pl_code_str[] = {
6939 NULL, /* 00h */
6940 "Open Failure", /* 01h */
6941 "Invalid Scatter Gather List", /* 02h */
6942 "Wrong Relative Offset or Frame Length", /* 03h */
6943 "Frame Transfer Error", /* 04h */
6944 "Transmit Frame Connected Low", /* 05h */
6945 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6946 "SATA Read Log Receive Data Error", /* 07h */
6947 "SATA NCQ Fail All Commands After Error", /* 08h */
6948 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6949 "Receive Frame Invalid Message", /* 0Ah */
6950 "Receive Context Message Valid Error", /* 0Bh */
6951 "Receive Frame Current Frame Error", /* 0Ch */
6952 "SATA Link Down", /* 0Dh */
6953 "Discovery SATA Init W IOS", /* 0Eh */
6954 "Config Invalid Page", /* 0Fh */
6955 "Discovery SATA Init Timeout", /* 10h */
6956 "Reset", /* 11h */
6957 "Abort", /* 12h */
6958 "IO Not Yet Executed", /* 13h */
6959 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006960 "Persistent Reservation Out Not Affiliation "
6961 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006962 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006963 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006964 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006965 NULL, /* 19h */
6966 NULL, /* 1Ah */
6967 NULL, /* 1Bh */
6968 NULL, /* 1Ch */
6969 NULL, /* 1Dh */
6970 NULL, /* 1Eh */
6971 NULL, /* 1Fh */
6972 "Enclosure Management" /* 20h */
6973 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006974 static char *ir_code_str[] = {
6975 "Raid Action Error", /* 00h */
6976 NULL, /* 00h */
6977 NULL, /* 01h */
6978 NULL, /* 02h */
6979 NULL, /* 03h */
6980 NULL, /* 04h */
6981 NULL, /* 05h */
6982 NULL, /* 06h */
6983 NULL /* 07h */
6984 };
6985 static char *raid_sub_code_str[] = {
6986 NULL, /* 00h */
6987 "Volume Creation Failed: Data Passed too "
6988 "Large", /* 01h */
6989 "Volume Creation Failed: Duplicate Volumes "
6990 "Attempted", /* 02h */
6991 "Volume Creation Failed: Max Number "
6992 "Supported Volumes Exceeded", /* 03h */
6993 "Volume Creation Failed: DMA Error", /* 04h */
6994 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6995 "Volume Creation Failed: Error Reading "
6996 "MFG Page 4", /* 06h */
6997 "Volume Creation Failed: Creating Internal "
6998 "Structures", /* 07h */
6999 NULL, /* 08h */
7000 NULL, /* 09h */
7001 NULL, /* 0Ah */
7002 NULL, /* 0Bh */
7003 NULL, /* 0Ch */
7004 NULL, /* 0Dh */
7005 NULL, /* 0Eh */
7006 NULL, /* 0Fh */
7007 "Activation failed: Already Active Volume", /* 10h */
7008 "Activation failed: Unsupported Volume Type", /* 11h */
7009 "Activation failed: Too Many Active Volumes", /* 12h */
7010 "Activation failed: Volume ID in Use", /* 13h */
7011 "Activation failed: Reported Failure", /* 14h */
7012 "Activation failed: Importing a Volume", /* 15h */
7013 NULL, /* 16h */
7014 NULL, /* 17h */
7015 NULL, /* 18h */
7016 NULL, /* 19h */
7017 NULL, /* 1Ah */
7018 NULL, /* 1Bh */
7019 NULL, /* 1Ch */
7020 NULL, /* 1Dh */
7021 NULL, /* 1Eh */
7022 NULL, /* 1Fh */
7023 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7024 "Phys Disk failed: Data Passed too Large", /* 21h */
7025 "Phys Disk failed: DMA Error", /* 22h */
7026 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7027 "Phys Disk failed: Creating Phys Disk Config "
7028 "Page", /* 24h */
7029 NULL, /* 25h */
7030 NULL, /* 26h */
7031 NULL, /* 27h */
7032 NULL, /* 28h */
7033 NULL, /* 29h */
7034 NULL, /* 2Ah */
7035 NULL, /* 2Bh */
7036 NULL, /* 2Ch */
7037 NULL, /* 2Dh */
7038 NULL, /* 2Eh */
7039 NULL, /* 2Fh */
7040 "Compatibility Error: IR Disabled", /* 30h */
7041 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7042 "Compatibility Error: Device not Direct Access "
7043 "Device ", /* 32h */
7044 "Compatibility Error: Removable Device Found", /* 33h */
7045 "Compatibility Error: Device SCSI Version not "
7046 "2 or Higher", /* 34h */
7047 "Compatibility Error: SATA Device, 48 BIT LBA "
7048 "not Supported", /* 35h */
7049 "Compatibility Error: Device doesn't have "
7050 "512 Byte Block Sizes", /* 36h */
7051 "Compatibility Error: Volume Type Check Failed", /* 37h */
7052 "Compatibility Error: Volume Type is "
7053 "Unsupported by FW", /* 38h */
7054 "Compatibility Error: Disk Drive too Small for "
7055 "use in Volume", /* 39h */
7056 "Compatibility Error: Phys Disk for Create "
7057 "Volume not Found", /* 3Ah */
7058 "Compatibility Error: Too Many or too Few "
7059 "Disks for Volume Type", /* 3Bh */
7060 "Compatibility Error: Disk stripe Sizes "
7061 "Must be 64KB", /* 3Ch */
7062 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7063 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007064
7065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007066/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007067 * mpt_sas_log_info - Log information returned from SAS IOC.
7068 * @ioc: Pointer to MPT_ADAPTER structure
7069 * @log_info: U32 LogInfo reply word from the IOC
7070 *
7071 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007072 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007073static void
7074mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7075{
7076union loginfo_type {
7077 u32 loginfo;
7078 struct {
7079 u32 subcode:16;
7080 u32 code:8;
7081 u32 originator:4;
7082 u32 bus_type:4;
7083 }dw;
7084};
7085 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007086 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007087 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007088 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007089
7090 sas_loginfo.loginfo = log_info;
7091 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7092 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7093 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007094
7095 originator_desc = originator_str[sas_loginfo.dw.originator];
7096
7097 switch (sas_loginfo.dw.originator) {
7098
7099 case 0: /* IOP */
7100 if (sas_loginfo.dw.code <
7101 sizeof(iop_code_str)/sizeof(char*))
7102 code_desc = iop_code_str[sas_loginfo.dw.code];
7103 break;
7104 case 1: /* PL */
7105 if (sas_loginfo.dw.code <
7106 sizeof(pl_code_str)/sizeof(char*))
7107 code_desc = pl_code_str[sas_loginfo.dw.code];
7108 break;
7109 case 2: /* IR */
7110 if (sas_loginfo.dw.code >=
7111 sizeof(ir_code_str)/sizeof(char*))
7112 break;
7113 code_desc = ir_code_str[sas_loginfo.dw.code];
7114 if (sas_loginfo.dw.subcode >=
7115 sizeof(raid_sub_code_str)/sizeof(char*))
7116 break;
7117 if (sas_loginfo.dw.code == 0)
7118 sub_code_desc =
7119 raid_sub_code_str[sas_loginfo.dw.subcode];
7120 break;
7121 default:
7122 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007123 }
7124
Eric Moorec6c727a2007-01-29 09:44:54 -07007125 if (sub_code_desc != NULL)
7126 printk(MYIOC_s_INFO_FMT
7127 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7128 " SubCode={%s}\n",
7129 ioc->name, log_info, originator_desc, code_desc,
7130 sub_code_desc);
7131 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007132 printk(MYIOC_s_INFO_FMT
7133 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7134 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007135 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007136 sas_loginfo.dw.subcode);
7137 else
7138 printk(MYIOC_s_INFO_FMT
7139 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7140 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007141 ioc->name, log_info, originator_desc,
7142 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007143}
7144
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007146/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007147 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7148 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007149 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007150 * @mf: Pointer to MPT request frame
7151 *
7152 * Refer to lsi/mpi.h.
7153 **/
7154static void
7155mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7156{
7157 Config_t *pReq = (Config_t *)mf;
7158 char extend_desc[EVENT_DESCR_STR_SZ];
7159 char *desc = NULL;
7160 u32 form;
7161 u8 page_type;
7162
7163 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7164 page_type = pReq->ExtPageType;
7165 else
7166 page_type = pReq->Header.PageType;
7167
7168 /*
7169 * ignore invalid page messages for GET_NEXT_HANDLE
7170 */
7171 form = le32_to_cpu(pReq->PageAddress);
7172 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7173 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7174 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7175 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7176 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7177 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7178 return;
7179 }
7180 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7181 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7182 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7183 return;
7184 }
7185
7186 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7187 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7188 page_type, pReq->Header.PageNumber, pReq->Action, form);
7189
7190 switch (ioc_status) {
7191
7192 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7193 desc = "Config Page Invalid Action";
7194 break;
7195
7196 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7197 desc = "Config Page Invalid Type";
7198 break;
7199
7200 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7201 desc = "Config Page Invalid Page";
7202 break;
7203
7204 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7205 desc = "Config Page Invalid Data";
7206 break;
7207
7208 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7209 desc = "Config Page No Defaults";
7210 break;
7211
7212 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7213 desc = "Config Page Can't Commit";
7214 break;
7215 }
7216
7217 if (!desc)
7218 return;
7219
Eric Moore29dd3602007-09-14 18:46:51 -06007220 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7221 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007222}
7223
7224/**
7225 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226 * @ioc: Pointer to MPT_ADAPTER structure
7227 * @ioc_status: U32 IOCStatus word from IOC
7228 * @mf: Pointer to MPT request frame
7229 *
7230 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007231 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007233mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007234{
7235 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007236 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237
7238 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007239
7240/****************************************************************************/
7241/* Common IOCStatus values for all replies */
7242/****************************************************************************/
7243
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7245 desc = "Invalid Function";
7246 break;
7247
7248 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7249 desc = "Busy";
7250 break;
7251
7252 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7253 desc = "Invalid SGL";
7254 break;
7255
7256 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7257 desc = "Internal Error";
7258 break;
7259
7260 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7261 desc = "Reserved";
7262 break;
7263
7264 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7265 desc = "Insufficient Resources";
7266 break;
7267
7268 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7269 desc = "Invalid Field";
7270 break;
7271
7272 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7273 desc = "Invalid State";
7274 break;
7275
Eric Moorec6c727a2007-01-29 09:44:54 -07007276/****************************************************************************/
7277/* Config IOCStatus values */
7278/****************************************************************************/
7279
Linus Torvalds1da177e2005-04-16 15:20:36 -07007280 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7281 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7282 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7283 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7284 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7285 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007286 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007287 break;
7288
Eric Moorec6c727a2007-01-29 09:44:54 -07007289/****************************************************************************/
7290/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7291/* */
7292/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7293/* */
7294/****************************************************************************/
7295
Linus Torvalds1da177e2005-04-16 15:20:36 -07007296 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007298 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7299 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7300 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7301 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007302 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007308 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309 break;
7310
Eric Moorec6c727a2007-01-29 09:44:54 -07007311/****************************************************************************/
7312/* SCSI Target values */
7313/****************************************************************************/
7314
7315 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7316 desc = "Target: Priority IO";
7317 break;
7318
7319 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7320 desc = "Target: Invalid Port";
7321 break;
7322
7323 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7324 desc = "Target Invalid IO Index:";
7325 break;
7326
7327 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7328 desc = "Target: Aborted";
7329 break;
7330
7331 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7332 desc = "Target: No Conn Retryable";
7333 break;
7334
7335 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7336 desc = "Target: No Connection";
7337 break;
7338
7339 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7340 desc = "Target: Transfer Count Mismatch";
7341 break;
7342
7343 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7344 desc = "Target: STS Data not Sent";
7345 break;
7346
7347 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7348 desc = "Target: Data Offset Error";
7349 break;
7350
7351 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7352 desc = "Target: Too Much Write Data";
7353 break;
7354
7355 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7356 desc = "Target: IU Too Short";
7357 break;
7358
7359 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7360 desc = "Target: ACK NAK Timeout";
7361 break;
7362
7363 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7364 desc = "Target: Nak Received";
7365 break;
7366
7367/****************************************************************************/
7368/* Fibre Channel Direct Access values */
7369/****************************************************************************/
7370
7371 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7372 desc = "FC: Aborted";
7373 break;
7374
7375 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7376 desc = "FC: RX ID Invalid";
7377 break;
7378
7379 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7380 desc = "FC: DID Invalid";
7381 break;
7382
7383 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7384 desc = "FC: Node Logged Out";
7385 break;
7386
7387 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7388 desc = "FC: Exchange Canceled";
7389 break;
7390
7391/****************************************************************************/
7392/* LAN values */
7393/****************************************************************************/
7394
7395 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7396 desc = "LAN: Device not Found";
7397 break;
7398
7399 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7400 desc = "LAN: Device Failure";
7401 break;
7402
7403 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7404 desc = "LAN: Transmit Error";
7405 break;
7406
7407 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7408 desc = "LAN: Transmit Aborted";
7409 break;
7410
7411 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7412 desc = "LAN: Receive Error";
7413 break;
7414
7415 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7416 desc = "LAN: Receive Aborted";
7417 break;
7418
7419 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7420 desc = "LAN: Partial Packet";
7421 break;
7422
7423 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7424 desc = "LAN: Canceled";
7425 break;
7426
7427/****************************************************************************/
7428/* Serial Attached SCSI values */
7429/****************************************************************************/
7430
7431 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7432 desc = "SAS: SMP Request Failed";
7433 break;
7434
7435 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7436 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437 break;
7438
7439 default:
7440 desc = "Others";
7441 break;
7442 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007443
7444 if (!desc)
7445 return;
7446
Eric Moore29dd3602007-09-14 18:46:51 -06007447 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7448 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449}
7450
7451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007452EXPORT_SYMBOL(mpt_attach);
7453EXPORT_SYMBOL(mpt_detach);
7454#ifdef CONFIG_PM
7455EXPORT_SYMBOL(mpt_resume);
7456EXPORT_SYMBOL(mpt_suspend);
7457#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007459EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007460EXPORT_SYMBOL(mpt_register);
7461EXPORT_SYMBOL(mpt_deregister);
7462EXPORT_SYMBOL(mpt_event_register);
7463EXPORT_SYMBOL(mpt_event_deregister);
7464EXPORT_SYMBOL(mpt_reset_register);
7465EXPORT_SYMBOL(mpt_reset_deregister);
7466EXPORT_SYMBOL(mpt_device_driver_register);
7467EXPORT_SYMBOL(mpt_device_driver_deregister);
7468EXPORT_SYMBOL(mpt_get_msg_frame);
7469EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307470EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007471EXPORT_SYMBOL(mpt_free_msg_frame);
7472EXPORT_SYMBOL(mpt_add_sge);
7473EXPORT_SYMBOL(mpt_send_handshake_request);
7474EXPORT_SYMBOL(mpt_verify_adapter);
7475EXPORT_SYMBOL(mpt_GetIocState);
7476EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007477EXPORT_SYMBOL(mpt_HardResetHandler);
7478EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007479EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007480EXPORT_SYMBOL(mpt_alloc_fw_memory);
7481EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007482EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007483EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007484
Linus Torvalds1da177e2005-04-16 15:20:36 -07007485/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007486/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007487 * fusion_init - Fusion MPT base driver initialization routine.
7488 *
7489 * Returns 0 for success, non-zero for failure.
7490 */
7491static int __init
7492fusion_init(void)
7493{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307494 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495
7496 show_mptmod_ver(my_NAME, my_VERSION);
7497 printk(KERN_INFO COPYRIGHT "\n");
7498
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307499 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7500 MptCallbacks[cb_idx] = NULL;
7501 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7502 MptEvHandlers[cb_idx] = NULL;
7503 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007504 }
7505
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007506 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007507 * EventNotification handling.
7508 */
7509 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7510
7511 /* Register for hard reset handling callbacks.
7512 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307513 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514
7515#ifdef CONFIG_PROC_FS
7516 (void) procmpt_create();
7517#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007518 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007519}
7520
7521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007522/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523 * fusion_exit - Perform driver unload cleanup.
7524 *
7525 * This routine frees all resources associated with each MPT adapter
7526 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7527 */
7528static void __exit
7529fusion_exit(void)
7530{
7531
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532 mpt_reset_deregister(mpt_base_index);
7533
7534#ifdef CONFIG_PROC_FS
7535 procmpt_destroy();
7536#endif
7537}
7538
Linus Torvalds1da177e2005-04-16 15:20:36 -07007539module_init(fusion_init);
7540module_exit(fusion_exit);