blob: 52fb216dfe7448ee0c5dbdfdac3db24c4787db2f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05308 * Copyright (c) 1999-2007 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Christoph Hellwig4ddce142006-01-17 13:44:29 +000082static int mpt_msi_enable;
83module_param(mpt_msi_enable, int, 0);
84MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086static int mpt_channel_mapping;
87module_param(mpt_channel_mapping, int, 0);
88MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
89
Prakash, Sathya436ace72007-07-24 15:42:08 +053090static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -040091static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
92module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
93 &mpt_debug_level, 0600);
Prakash, Sathya436ace72007-07-24 15:42:08 +053094MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#ifdef MFCNT
97static int mfcounter = 0;
98#define PRINT_MF_COUNT 20000
99#endif
100
101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
102/*
103 * Public data...
104 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Linus Torvaldsf7473072005-11-29 14:21:57 -0800106struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108#define WHOINIT_UNKNOWN 0xAA
109
110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
111/*
112 * Private data...
113 */
114 /* Adapter link list */
115LIST_HEAD(ioc_list);
116 /* Callback lookup table */
117static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
118 /* Protocol driver class lookup table */
119static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
120 /* Event handler lookup table */
121static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
122 /* Reset handler lookup table */
123static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
124static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
127
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530128/*
129 * Driver Callback Index's
130 */
131static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
132static u8 last_drv_idx;
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
135/*
136 * Forward protos...
137 */
David Howells7d12e782006-10-05 14:55:46 +0100138static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
140static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
141 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
142 int sleepFlag);
143static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
144static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
145static void mpt_adapter_disable(MPT_ADAPTER *ioc);
146static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
147
148static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
149static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
151static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
152static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
153static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
154static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200155static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
157static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
158static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
159static int PrimeIocFifos(MPT_ADAPTER *ioc);
160static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
161static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
162static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
163static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200165int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
167static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
168static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
169static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
170static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530171static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
173static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200174static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
175static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#ifdef CONFIG_PROC_FS
178static int procmpt_summary_read(char *buf, char **start, off_t offset,
179 int request, int *eof, void *data);
180static int procmpt_version_read(char *buf, char **start, off_t offset,
181 int request, int *eof, void *data);
182static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
183 int request, int *eof, void *data);
184#endif
185static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
186
187//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
188static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700189static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700191static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600192static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700193static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700194static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int __init fusion_init (void);
198static void __exit fusion_exit (void);
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define CHIPREG_READ32(addr) readl_relaxed(addr)
201#define CHIPREG_READ32_dmasync(addr) readl(addr)
202#define CHIPREG_WRITE32(addr,val) writel(val, addr)
203#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
204#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
205
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600206static void
207pci_disable_io_access(struct pci_dev *pdev)
208{
209 u16 command_reg;
210
211 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
212 command_reg &= ~1;
213 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
214}
215
216static void
217pci_enable_io_access(struct pci_dev *pdev)
218{
219 u16 command_reg;
220
221 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
222 command_reg |= 1;
223 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
224}
225
James Bottomleydb47c2d2007-07-28 13:40:21 -0400226static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
227{
228 int ret = param_set_int(val, kp);
229 MPT_ADAPTER *ioc;
230
231 if (ret)
232 return ret;
233
234 list_for_each_entry(ioc, &ioc_list, list)
235 ioc->debug_level = mpt_debug_level;
236 return 0;
237}
238
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530239/**
240 * mpt_get_cb_idx - obtain cb_idx for registered driver
241 * @dclass: class driver enum
242 *
243 * Returns cb_idx, or zero means it wasn't found
244 **/
245static u8
246mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
247{
248 u8 cb_idx;
249
250 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
251 if (MptDriverClass[cb_idx] == dclass)
252 return cb_idx;
253 return 0;
254}
255
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600256/*
257 * Process turbo (context) reply...
258 */
259static void
260mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
261{
262 MPT_FRAME_HDR *mf = NULL;
263 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264 u16 req_idx = 0;
265 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600266
Prakash, Sathya436ace72007-07-24 15:42:08 +0530267 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600268 ioc->name, pa));
269
270 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
271 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
272 req_idx = pa & 0x0000FFFF;
273 cb_idx = (pa & 0x00FF0000) >> 16;
274 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
275 break;
276 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530277 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600278 /*
279 * Blind set of mf to NULL here was fatal
280 * after lan_reply says "freeme"
281 * Fix sort of combined with an optimization here;
282 * added explicit check for case where lan_reply
283 * was just returning 1 and doing nothing else.
284 * For this case skip the callback, but set up
285 * proper mf value first here:-)
286 */
287 if ((pa & 0x58000000) == 0x58000000) {
288 req_idx = pa & 0x0000FFFF;
289 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
290 mpt_free_msg_frame(ioc, mf);
291 mb();
292 return;
293 break;
294 }
295 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
296 break;
297 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530298 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600299 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
300 break;
301 default:
302 cb_idx = 0;
303 BUG();
304 }
305
306 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530307 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600308 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600309 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
310 __FUNCTION__, ioc->name, cb_idx);
311 goto out;
312 }
313
314 if (MptCallbacks[cb_idx](ioc, mf, mr))
315 mpt_free_msg_frame(ioc, mf);
316 out:
317 mb();
318}
319
320static void
321mpt_reply(MPT_ADAPTER *ioc, u32 pa)
322{
323 MPT_FRAME_HDR *mf;
324 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530325 u16 req_idx;
326 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600327 int freeme;
328
329 u32 reply_dma_low;
330 u16 ioc_stat;
331
332 /* non-TURBO reply! Hmmm, something may be up...
333 * Newest turbo reply mechanism; get address
334 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
335 */
336
337 /* Map DMA address of reply header to cpu address.
338 * pa is 32 bits - but the dma address may be 32 or 64 bits
339 * get offset based only only the low addresses
340 */
341
342 reply_dma_low = (pa <<= 1);
343 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
344 (reply_dma_low - ioc->reply_frames_low_dma));
345
346 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
347 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
348 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
349
Prakash, Sathya436ace72007-07-24 15:42:08 +0530350 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600351 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600352 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600353
354 /* Check/log IOC log info
355 */
356 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
357 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
358 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
359 if (ioc->bus_type == FC)
360 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700361 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700362 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600363 else if (ioc->bus_type == SAS)
364 mpt_sas_log_info(ioc, log_info);
365 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600366
Eric Moorec6c727a2007-01-29 09:44:54 -0700367 if (ioc_stat & MPI_IOCSTATUS_MASK)
368 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600369
370 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530371 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600372 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600373 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
374 __FUNCTION__, ioc->name, cb_idx);
375 freeme = 0;
376 goto out;
377 }
378
379 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
380
381 out:
382 /* Flush (non-TURBO) reply with a WRITE! */
383 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
384
385 if (freeme)
386 mpt_free_msg_frame(ioc, mf);
387 mb();
388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
393 * @irq: irq number (not used)
394 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 *
396 * This routine is registered via the request_irq() kernel API call,
397 * and handles all interrupts generated from a specific MPT adapter
398 * (also referred to as a IO Controller or IOC).
399 * This routine must clear the interrupt from the adapter and does
400 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200401 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 *
403 * This routine handles register-level access of the adapter but
404 * dispatches (calls) a protocol-specific callback routine to handle
405 * the protocol-specific details of the MPT request completion.
406 */
407static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100408mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600410 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600411 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
412
413 if (pa == 0xFFFFFFFF)
414 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 /*
417 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600419 do {
420 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600421 mpt_reply(ioc, pa);
422 else
423 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600424 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
425 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 return IRQ_HANDLED;
428}
429
430/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800431/**
432 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 * @ioc: Pointer to MPT_ADAPTER structure
434 * @mf: Pointer to original MPT request frame
435 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
436 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800437 * MPT base driver's callback routine; all base driver
438 * "internal" request/reply processing is routed here.
439 * Currently used for EventNotification and EventAck handling.
440 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200441 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 * should be freed, or 0 if it shouldn't.
443 */
444static int
445mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
446{
447 int freereq = 1;
448 u8 func;
449
Prakash, Sathya436ace72007-07-24 15:42:08 +0530450 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
451#ifdef CONFIG_FUSION_LOGGING
452 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
453 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
455 ioc->name, mf));
456 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530461 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 ioc->name, func));
463
464 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
465 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
466 int evHandlers = 0;
467 int results;
468
469 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
470 if (results != evHandlers) {
471 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530472 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 ioc->name, evHandlers, results));
474 }
475
476 /*
477 * Hmmm... It seems that EventNotificationReply is an exception
478 * to the rule of one reply per request.
479 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200480 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200482 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530483 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200484 ioc->name, pEvReply));
485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
487#ifdef CONFIG_PROC_FS
488// LogEvent(ioc, pEvReply);
489#endif
490
491 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530492 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700494 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 CONFIGPARMS *pCfg;
496 unsigned long flags;
497
Prakash, Sathya436ace72007-07-24 15:42:08 +0530498 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ioc->name, mf, reply));
500
501 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
502
503 if (pCfg) {
504 /* disable timer and remove from linked list */
505 del_timer(&pCfg->timer);
506
507 spin_lock_irqsave(&ioc->FreeQlock, flags);
508 list_del(&pCfg->linkage);
509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
510
511 /*
512 * If IOC Status is SUCCESS, save the header
513 * and set the status code to GOOD.
514 */
515 pCfg->status = MPT_CONFIG_ERROR;
516 if (reply) {
517 ConfigReply_t *pReply = (ConfigReply_t *)reply;
518 u16 status;
519
520 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600521 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
522 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524 pCfg->status = status;
525 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200526 if ((pReply->Header.PageType &
527 MPI_CONFIG_PAGETYPE_MASK) ==
528 MPI_CONFIG_PAGETYPE_EXTENDED) {
529 pCfg->cfghdr.ehdr->ExtPageLength =
530 le16_to_cpu(pReply->ExtPageLength);
531 pCfg->cfghdr.ehdr->ExtPageType =
532 pReply->ExtPageType;
533 }
534 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
535
536 /* If this is a regular header, save PageLength. */
537 /* LMP Do this better so not using a reserved field! */
538 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
539 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
540 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 }
542 }
543
544 /*
545 * Wake up the original calling thread
546 */
547 pCfg->wait_done = 1;
548 wake_up(&mpt_waitq);
549 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200550 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
551 /* we should be always getting a reply frame */
552 memcpy(ioc->persist_reply_frame, reply,
553 min(MPT_DEFAULT_FRAME_SIZE,
554 4*reply->u.reply.MsgLength));
555 del_timer(&ioc->persist_timer);
556 ioc->persist_wait_done = 1;
557 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
559 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
560 ioc->name, func);
561 }
562
563 /*
564 * Conditionally tell caller to free the original
565 * EventNotification/EventAck/unexpected request frame!
566 */
567 return freereq;
568}
569
570/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
571/**
572 * mpt_register - Register protocol-specific main callback handler.
573 * @cbfunc: callback function pointer
574 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
575 *
576 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800577 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 * protocol-specific driver must do this before it will be able to
579 * use any IOC resources, such as obtaining request frames.
580 *
581 * NOTES: The SCSI protocol driver currently calls this routine thrice
582 * in order to register separate callbacks; one for "normal" SCSI IO;
583 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
584 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530585 * Returns u8 valued "handle" in the range (and S.O.D. order)
586 * {N,...,7,6,5,...,1} if successful.
587 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
588 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530590u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
592{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530593 u8 cb_idx;
594 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 /*
597 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
598 * (slot/handle 0 is reserved!)
599 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530600 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
601 if (MptCallbacks[cb_idx] == NULL) {
602 MptCallbacks[cb_idx] = cbfunc;
603 MptDriverClass[cb_idx] = dclass;
604 MptEvHandlers[cb_idx] = NULL;
605 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 break;
607 }
608 }
609
610 return last_drv_idx;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
614/**
615 * mpt_deregister - Deregister a protocol drivers resources.
616 * @cb_idx: previously registered callback handle
617 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800618 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 * module is unloaded.
620 */
621void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530622mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600624 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 MptCallbacks[cb_idx] = NULL;
626 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
627 MptEvHandlers[cb_idx] = NULL;
628
629 last_drv_idx++;
630 }
631}
632
633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
634/**
635 * mpt_event_register - Register protocol-specific event callback
636 * handler.
637 * @cb_idx: previously registered (via mpt_register) callback handle
638 * @ev_cbfunc: callback function
639 *
640 * This routine can be called by one or more protocol-specific drivers
641 * if/when they choose to be notified of MPT events.
642 *
643 * Returns 0 for success.
644 */
645int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600648 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 return -1;
650
651 MptEvHandlers[cb_idx] = ev_cbfunc;
652 return 0;
653}
654
655/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
656/**
657 * mpt_event_deregister - Deregister protocol-specific event callback
658 * handler.
659 * @cb_idx: previously registered callback handle
660 *
661 * Each protocol-specific driver should call this routine
662 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800663 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 */
665void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530666mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600668 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return;
670
671 MptEvHandlers[cb_idx] = NULL;
672}
673
674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
675/**
676 * mpt_reset_register - Register protocol-specific IOC reset handler.
677 * @cb_idx: previously registered (via mpt_register) callback handle
678 * @reset_func: reset function
679 *
680 * This routine can be called by one or more protocol-specific drivers
681 * if/when they choose to be notified of IOC resets.
682 *
683 * Returns 0 for success.
684 */
685int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530686mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530688 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return -1;
690
691 MptResetHandlers[cb_idx] = reset_func;
692 return 0;
693}
694
695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
696/**
697 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
698 * @cb_idx: previously registered callback handle
699 *
700 * Each protocol-specific driver should call this routine
701 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800702 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 */
704void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530705mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530707 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
710 MptResetHandlers[cb_idx] = NULL;
711}
712
713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
714/**
715 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * @dd_cbfunc: driver callbacks struct
717 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600723 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Eric Moore8d6d83e2007-09-14 18:47:40 -0600725 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400726 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
729
730 /* call per pci device probe entry point */
731 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600732 id = ioc->pcidev->driver ?
733 ioc->pcidev->driver->id_table : NULL;
734 if (dd_cbfunc->probe)
735 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400738 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739}
740
741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
742/**
743 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800744 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 */
746void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530747mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 struct mpt_pci_driver *dd_cbfunc;
750 MPT_ADAPTER *ioc;
751
Eric Moore8d6d83e2007-09-14 18:47:40 -0600752 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 return;
754
755 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
756
757 list_for_each_entry(ioc, &ioc_list, list) {
758 if (dd_cbfunc->remove)
759 dd_cbfunc->remove(ioc->pcidev);
760 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 MptDeviceDriverHandlers[cb_idx] = NULL;
763}
764
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
769 * allocated per MPT adapter.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530770 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 * @ioc: Pointer to MPT adapter structure
772 *
773 * Returns pointer to a MPT request frame or %NULL if none are available
774 * or IOC is not active.
775 */
776MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 MPT_FRAME_HDR *mf;
780 unsigned long flags;
781 u16 req_idx; /* Request index */
782
783 /* validate handle and ioc identifier */
784
785#ifdef MFCNT
786 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600787 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
788 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789#endif
790
791 /* If interrupts are not attached, do not return a request frame */
792 if (!ioc->active)
793 return NULL;
794
795 spin_lock_irqsave(&ioc->FreeQlock, flags);
796 if (!list_empty(&ioc->FreeQ)) {
797 int req_offset;
798
799 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
800 u.frame.linkage.list);
801 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200802 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530803 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
805 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500806 req_idx = req_offset / ioc->req_sz;
807 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600809 /* Default, will be changed if necessary in SG generation */
810 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811#ifdef MFCNT
812 ioc->mfcnt++;
813#endif
814 }
815 else
816 mf = NULL;
817 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
818
819#ifdef MFCNT
820 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600821 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
822 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
823 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 mfcounter++;
825 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600826 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
827 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828#endif
829
Eric Moore29dd3602007-09-14 18:46:51 -0600830 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
831 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return mf;
833}
834
835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
836/**
837 * mpt_put_msg_frame - Send a protocol specific MPT request frame
838 * to a IOC.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530839 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 * @ioc: Pointer to MPT adapter structure
841 * @mf: Pointer to MPT request frame
842 *
843 * This routine posts a MPT request frame to the request post FIFO of a
844 * specific MPT adapter.
845 */
846void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530847mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
849 u32 mf_dma_addr;
850 int req_offset;
851 u16 req_idx; /* Request index */
852
853 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530854 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
856 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500857 req_idx = req_offset / ioc->req_sz;
858 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
860
Prakash, Sathya436ace72007-07-24 15:42:08 +0530861 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200863 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600864 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
865 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
866 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
868}
869
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530870/**
871 * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
872 * to a IOC using hi priority request queue.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530873 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530874 * @ioc: Pointer to MPT adapter structure
875 * @mf: Pointer to MPT request frame
876 *
877 * This routine posts a MPT request frame to the request post FIFO of a
878 * specific MPT adapter.
879 **/
880void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530881mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530882{
883 u32 mf_dma_addr;
884 int req_offset;
885 u16 req_idx; /* Request index */
886
887 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530888 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530889 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
890 req_idx = req_offset / ioc->req_sz;
891 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
892 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
893
894 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
895
896 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
897 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
898 ioc->name, mf_dma_addr, req_idx));
899 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
900}
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
903/**
904 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
905 * @handle: Handle of registered MPT protocol driver
906 * @ioc: Pointer to MPT adapter structure
907 * @mf: Pointer to MPT request frame
908 *
909 * This routine places a MPT request frame back on the MPT adapter's
910 * FreeQ.
911 */
912void
913mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
914{
915 unsigned long flags;
916
917 /* Put Request back on FreeQ! */
918 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200919 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
921#ifdef MFCNT
922 ioc->mfcnt--;
923#endif
924 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
925}
926
927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
928/**
929 * mpt_add_sge - Place a simple SGE at address pAddr.
930 * @pAddr: virtual address for SGE
931 * @flagslength: SGE flags and data transfer length
932 * @dma_addr: Physical address
933 *
934 * This routine places a MPT request frame back on the MPT adapter's
935 * FreeQ.
936 */
937void
938mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
939{
940 if (sizeof(dma_addr_t) == sizeof(u64)) {
941 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
942 u32 tmp = dma_addr & 0xFFFFFFFF;
943
944 pSge->FlagsLength = cpu_to_le32(flagslength);
945 pSge->Address.Low = cpu_to_le32(tmp);
946 tmp = (u32) ((u64)dma_addr >> 32);
947 pSge->Address.High = cpu_to_le32(tmp);
948
949 } else {
950 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
951 pSge->FlagsLength = cpu_to_le32(flagslength);
952 pSge->Address = cpu_to_le32(dma_addr);
953 }
954}
955
956/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
957/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800958 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530959 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 * @ioc: Pointer to MPT adapter structure
961 * @reqBytes: Size of the request in bytes
962 * @req: Pointer to MPT request frame
963 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
964 *
965 * This routine is used exclusively to send MptScsiTaskMgmt
966 * requests since they are required to be sent via doorbell handshake.
967 *
968 * NOTE: It is the callers responsibility to byte-swap fields in the
969 * request which are greater than 1 byte in size.
970 *
971 * Returns 0 for success, non-zero for failure.
972 */
973int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530974mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Eric Moorecd2c6192007-01-29 09:47:47 -0700976 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 u8 *req_as_bytes;
978 int ii;
979
980 /* State is known to be good upon entering
981 * this function so issue the bus reset
982 * request.
983 */
984
985 /*
986 * Emulate what mpt_put_msg_frame() does /wrt to sanity
987 * setting cb_idx/req_idx. But ONLY if this request
988 * is in proper (pre-alloc'd) request buffer range...
989 */
990 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
991 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
992 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
993 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530994 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
996
997 /* Make sure there are no doorbells */
998 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1001 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1002 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1003
1004 /* Wait for IOC doorbell int */
1005 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1006 return ii;
1007 }
1008
1009 /* Read doorbell and check for active bit */
1010 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1011 return -5;
1012
Eric Moore29dd3602007-09-14 18:46:51 -06001013 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001014 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1017
1018 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1019 return -2;
1020 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 /* Send request via doorbell handshake */
1023 req_as_bytes = (u8 *) req;
1024 for (ii = 0; ii < reqBytes/4; ii++) {
1025 u32 word;
1026
1027 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1028 (req_as_bytes[(ii*4) + 1] << 8) |
1029 (req_as_bytes[(ii*4) + 2] << 16) |
1030 (req_as_bytes[(ii*4) + 3] << 24));
1031 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1032 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1033 r = -3;
1034 break;
1035 }
1036 }
1037
1038 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1039 r = 0;
1040 else
1041 r = -4;
1042
1043 /* Make sure there are no doorbells */
1044 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return r;
1047}
1048
1049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1050/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001051 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001052 * @ioc: Pointer to MPT adapter structure
1053 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001054 * @sleepFlag: Specifies whether the process can sleep
1055 *
1056 * Provides mechanism for the host driver to control the IOC's
1057 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001058 *
1059 * Access Control Value - bits[15:12]
1060 * 0h Reserved
1061 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1062 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1063 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1064 *
1065 * Returns 0 for success, non-zero for failure.
1066 */
1067
1068static int
1069mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1070{
1071 int r = 0;
1072
1073 /* return if in use */
1074 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1075 & MPI_DOORBELL_ACTIVE)
1076 return -1;
1077
1078 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1079
1080 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1081 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1082 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1083 (access_control_value<<12)));
1084
1085 /* Wait for IOC to clear Doorbell Status bit */
1086 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1087 return -2;
1088 }else
1089 return 0;
1090}
1091
1092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1093/**
1094 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001095 * @ioc: Pointer to pointer to IOC adapter
1096 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001098 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001099 * Returns 0 for success, non-zero for failure.
1100 */
1101static int
1102mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1103{
1104 char *psge;
1105 int flags_length;
1106 u32 host_page_buffer_sz=0;
1107
1108 if(!ioc->HostPageBuffer) {
1109
1110 host_page_buffer_sz =
1111 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1112
1113 if(!host_page_buffer_sz)
1114 return 0; /* fw doesn't need any host buffers */
1115
1116 /* spin till we get enough memory */
1117 while(host_page_buffer_sz > 0) {
1118
1119 if((ioc->HostPageBuffer = pci_alloc_consistent(
1120 ioc->pcidev,
1121 host_page_buffer_sz,
1122 &ioc->HostPageBuffer_dma)) != NULL) {
1123
Prakash, Sathya436ace72007-07-24 15:42:08 +05301124 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001125 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001126 ioc->name, ioc->HostPageBuffer,
1127 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001128 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001129 ioc->alloc_total += host_page_buffer_sz;
1130 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1131 break;
1132 }
1133
1134 host_page_buffer_sz -= (4*1024);
1135 }
1136 }
1137
1138 if(!ioc->HostPageBuffer) {
1139 printk(MYIOC_s_ERR_FMT
1140 "Failed to alloc memory for host_page_buffer!\n",
1141 ioc->name);
1142 return -999;
1143 }
1144
1145 psge = (char *)&ioc_init->HostPageBufferSGE;
1146 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1147 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1148 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1149 MPI_SGE_FLAGS_HOST_TO_IOC |
1150 MPI_SGE_FLAGS_END_OF_BUFFER;
1151 if (sizeof(dma_addr_t) == sizeof(u64)) {
1152 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1153 }
1154 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1155 flags_length |= ioc->HostPageBuffer_sz;
1156 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1157 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1158
1159return 0;
1160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001164 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 * @iocid: IOC unique identifier (integer)
1166 * @iocpp: Pointer to pointer to IOC adapter
1167 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001168 * Given a unique IOC identifier, set pointer to the associated MPT
1169 * adapter structure.
1170 *
1171 * Returns iocid and sets iocpp if iocid is found.
1172 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 */
1174int
1175mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1176{
1177 MPT_ADAPTER *ioc;
1178
1179 list_for_each_entry(ioc,&ioc_list,list) {
1180 if (ioc->id == iocid) {
1181 *iocpp =ioc;
1182 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 *iocpp = NULL;
1187 return -1;
1188}
1189
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301190/**
1191 * mpt_get_product_name - returns product string
1192 * @vendor: pci vendor id
1193 * @device: pci device id
1194 * @revision: pci revision id
1195 * @prod_name: string returned
1196 *
1197 * Returns product string displayed when driver loads,
1198 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1199 *
1200 **/
1201static void
1202mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1203{
1204 char *product_str = NULL;
1205
1206 if (vendor == PCI_VENDOR_ID_BROCADE) {
1207 switch (device)
1208 {
1209 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1210 switch (revision)
1211 {
1212 case 0x00:
1213 product_str = "BRE040 A0";
1214 break;
1215 case 0x01:
1216 product_str = "BRE040 A1";
1217 break;
1218 default:
1219 product_str = "BRE040";
1220 break;
1221 }
1222 break;
1223 }
1224 goto out;
1225 }
1226
1227 switch (device)
1228 {
1229 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1230 product_str = "LSIFC909 B1";
1231 break;
1232 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1233 product_str = "LSIFC919 B0";
1234 break;
1235 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1236 product_str = "LSIFC929 B0";
1237 break;
1238 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1239 if (revision < 0x80)
1240 product_str = "LSIFC919X A0";
1241 else
1242 product_str = "LSIFC919XL A1";
1243 break;
1244 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1245 if (revision < 0x80)
1246 product_str = "LSIFC929X A0";
1247 else
1248 product_str = "LSIFC929XL A1";
1249 break;
1250 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1251 product_str = "LSIFC939X A1";
1252 break;
1253 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1254 product_str = "LSIFC949X A1";
1255 break;
1256 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1257 switch (revision)
1258 {
1259 case 0x00:
1260 product_str = "LSIFC949E A0";
1261 break;
1262 case 0x01:
1263 product_str = "LSIFC949E A1";
1264 break;
1265 default:
1266 product_str = "LSIFC949E";
1267 break;
1268 }
1269 break;
1270 case MPI_MANUFACTPAGE_DEVID_53C1030:
1271 switch (revision)
1272 {
1273 case 0x00:
1274 product_str = "LSI53C1030 A0";
1275 break;
1276 case 0x01:
1277 product_str = "LSI53C1030 B0";
1278 break;
1279 case 0x03:
1280 product_str = "LSI53C1030 B1";
1281 break;
1282 case 0x07:
1283 product_str = "LSI53C1030 B2";
1284 break;
1285 case 0x08:
1286 product_str = "LSI53C1030 C0";
1287 break;
1288 case 0x80:
1289 product_str = "LSI53C1030T A0";
1290 break;
1291 case 0x83:
1292 product_str = "LSI53C1030T A2";
1293 break;
1294 case 0x87:
1295 product_str = "LSI53C1030T A3";
1296 break;
1297 case 0xc1:
1298 product_str = "LSI53C1020A A1";
1299 break;
1300 default:
1301 product_str = "LSI53C1030";
1302 break;
1303 }
1304 break;
1305 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1306 switch (revision)
1307 {
1308 case 0x03:
1309 product_str = "LSI53C1035 A2";
1310 break;
1311 case 0x04:
1312 product_str = "LSI53C1035 B0";
1313 break;
1314 default:
1315 product_str = "LSI53C1035";
1316 break;
1317 }
1318 break;
1319 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1320 switch (revision)
1321 {
1322 case 0x00:
1323 product_str = "LSISAS1064 A1";
1324 break;
1325 case 0x01:
1326 product_str = "LSISAS1064 A2";
1327 break;
1328 case 0x02:
1329 product_str = "LSISAS1064 A3";
1330 break;
1331 case 0x03:
1332 product_str = "LSISAS1064 A4";
1333 break;
1334 default:
1335 product_str = "LSISAS1064";
1336 break;
1337 }
1338 break;
1339 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1340 switch (revision)
1341 {
1342 case 0x00:
1343 product_str = "LSISAS1064E A0";
1344 break;
1345 case 0x01:
1346 product_str = "LSISAS1064E B0";
1347 break;
1348 case 0x02:
1349 product_str = "LSISAS1064E B1";
1350 break;
1351 case 0x04:
1352 product_str = "LSISAS1064E B2";
1353 break;
1354 case 0x08:
1355 product_str = "LSISAS1064E B3";
1356 break;
1357 default:
1358 product_str = "LSISAS1064E";
1359 break;
1360 }
1361 break;
1362 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "LSISAS1068 A0";
1367 break;
1368 case 0x01:
1369 product_str = "LSISAS1068 B0";
1370 break;
1371 case 0x02:
1372 product_str = "LSISAS1068 B1";
1373 break;
1374 default:
1375 product_str = "LSISAS1068";
1376 break;
1377 }
1378 break;
1379 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1380 switch (revision)
1381 {
1382 case 0x00:
1383 product_str = "LSISAS1068E A0";
1384 break;
1385 case 0x01:
1386 product_str = "LSISAS1068E B0";
1387 break;
1388 case 0x02:
1389 product_str = "LSISAS1068E B1";
1390 break;
1391 case 0x04:
1392 product_str = "LSISAS1068E B2";
1393 break;
1394 case 0x08:
1395 product_str = "LSISAS1068E B3";
1396 break;
1397 default:
1398 product_str = "LSISAS1068E";
1399 break;
1400 }
1401 break;
1402 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1403 switch (revision)
1404 {
1405 case 0x00:
1406 product_str = "LSISAS1078 A0";
1407 break;
1408 case 0x01:
1409 product_str = "LSISAS1078 B0";
1410 break;
1411 case 0x02:
1412 product_str = "LSISAS1078 C0";
1413 break;
1414 case 0x03:
1415 product_str = "LSISAS1078 C1";
1416 break;
1417 case 0x04:
1418 product_str = "LSISAS1078 C2";
1419 break;
1420 default:
1421 product_str = "LSISAS1078";
1422 break;
1423 }
1424 break;
1425 }
1426
1427 out:
1428 if (product_str)
1429 sprintf(prod_name, "%s", product_str);
1430}
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001433/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001434 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *
1438 * This routine performs all the steps necessary to bring the IOC of
1439 * a MPT adapter to a OPERATIONAL state. This includes registering
1440 * memory regions, registering the interrupt, and allocating request
1441 * and reply memory pools.
1442 *
1443 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1444 * MPT adapter.
1445 *
1446 * Returns 0 for success, non-zero for failure.
1447 *
1448 * TODO: Add support for polled controllers
1449 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001450int
1451mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 MPT_ADAPTER *ioc;
1454 u8 __iomem *mem;
Eric Moorebc6e0892007-09-29 10:16:28 -06001455 u8 __iomem *pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long mem_phys;
1457 unsigned long port;
1458 u32 msize;
1459 u32 psize;
1460 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301461 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 u8 revision;
1464 u8 pcixcmd;
1465 static int mpt_ids = 0;
1466#ifdef CONFIG_PROC_FS
1467 struct proc_dir_entry *dent, *ent;
1468#endif
1469
Prakash, Sathya436ace72007-07-24 15:42:08 +05301470 if (mpt_debug_level)
1471 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (pci_enable_device(pdev))
1474 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001475
Jesper Juhl56876192007-08-10 14:50:51 -07001476 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1477 if (ioc == NULL) {
1478 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1479 return -ENOMEM;
1480 }
1481 ioc->debug_level = mpt_debug_level;
Eric Moore29dd3602007-09-14 18:46:51 -06001482 ioc->id = mpt_ids++;
1483 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001484
Eric Moore29dd3602007-09-14 18:46:51 -06001485 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001486
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001487 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001488 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1489 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001490 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001491 printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
1492 ioc->name);
Jesper Juhl56876192007-08-10 14:50:51 -07001493 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 return r;
1495 }
1496
Prakash, Sathya436ace72007-07-24 15:42:08 +05301497 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001498 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1499 ": Using 64 bit consistent mask\n", ioc->name));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301500 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001501 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1502 ": Not using 64 bit consistent mask\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 ioc->alloc_total = sizeof(MPT_ADAPTER);
1506 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1507 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 ioc->pcidev = pdev;
1510 ioc->diagPending = 0;
1511 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001512 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 /* Initialize the event logging.
1515 */
1516 ioc->eventTypes = 0; /* None */
1517 ioc->eventContext = 0;
1518 ioc->eventLogSize = 0;
1519 ioc->events = NULL;
1520
1521#ifdef MFCNT
1522 ioc->mfcnt = 0;
1523#endif
1524
1525 ioc->cached_fw = NULL;
1526
1527 /* Initilize SCSI Config Data structure
1528 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001529 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 /* Initialize the running configQ head.
1532 */
1533 INIT_LIST_HEAD(&ioc->configQ);
1534
Michael Reed05e8ec12006-01-13 14:31:54 -06001535 /* Initialize the fc rport list head.
1536 */
1537 INIT_LIST_HEAD(&ioc->fc_rports);
1538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 /* Find lookup slot. */
1540 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 mem_phys = msize = 0;
1543 port = psize = 0;
1544 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1545 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001546 if (psize)
1547 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 /* Get I/O space! */
1549 port = pci_resource_start(pdev, ii);
1550 psize = pci_resource_len(pdev,ii);
1551 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001552 if (msize)
1553 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* Get memmap */
1555 mem_phys = pci_resource_start(pdev, ii);
1556 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 }
1559 ioc->mem_size = msize;
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 mem = NULL;
1562 /* Get logical ptr for PciMem0 space */
1563 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001564 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (mem == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001566 printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 kfree(ioc);
1568 return -EINVAL;
1569 }
1570 ioc->memmap = mem;
Eric Moore29dd3602007-09-14 18:46:51 -06001571 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Eric Moore29dd3602007-09-14 18:46:51 -06001573 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1574 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 ioc->mem_phys = mem_phys;
1577 ioc->chip = (SYSIF_REGS __iomem *)mem;
1578
1579 /* Save Port IO values in case we need to do downloadboot */
Eric Moorebc6e0892007-09-29 10:16:28 -06001580 ioc->pio_mem_phys = port;
1581 pmem = (u8 __iomem *)port;
1582 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301584 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1585 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1586
1587 switch (pdev->device)
1588 {
1589 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1590 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1591 ioc->errata_flag_1064 = 1;
1592 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1593 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1594 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1595 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301597 break;
1598
1599 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* 929X Chip Fix. Set Split transactions level
1602 * for PCIX. Set MOST bits to zero.
1603 */
1604 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1605 pcixcmd &= 0x8F;
1606 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1607 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* 929XL Chip Fix. Set MMRBC to 0x08.
1609 */
1610 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1611 pcixcmd |= 0x08;
1612 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301615 break;
1616
1617 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* 919X Chip Fix. Set Split transactions level
1619 * for PCIX. Set MOST bits to zero.
1620 */
1621 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1622 pcixcmd &= 0x8F;
1623 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001624 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301625 break;
1626
1627 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* 1030 Chip Fix. Disable Split transactions
1629 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1630 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (revision < C0_1030) {
1632 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1633 pcixcmd &= 0x8F;
1634 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1635 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301636
1637 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001638 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301639 break;
1640
1641 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1642 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001643 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301644
1645 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1646 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1647 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001648 ioc->bus_type = SAS;
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001651 if (ioc->errata_flag_1064)
1652 pci_disable_io_access(pdev);
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 spin_lock_init(&ioc->FreeQlock);
1655
1656 /* Disable all! */
1657 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1658 ioc->active = 0;
1659 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1660
1661 /* Set lookup ptr. */
1662 list_add_tail(&ioc->list, &ioc_list);
1663
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001664 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 */
1666 mpt_detect_bound_ports(ioc, pdev);
1667
James Bottomleyc92f2222006-03-01 09:02:49 -06001668 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1669 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001670 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1671 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001674 if (ioc->alt_ioc)
1675 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 iounmap(mem);
1677 kfree(ioc);
1678 pci_set_drvdata(pdev, NULL);
1679 return r;
1680 }
1681
1682 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001683 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301684 if(MptDeviceDriverHandlers[cb_idx] &&
1685 MptDeviceDriverHandlers[cb_idx]->probe) {
1686 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 }
1688 }
1689
1690#ifdef CONFIG_PROC_FS
1691 /*
1692 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1693 */
1694 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1695 if (dent) {
1696 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1697 if (ent) {
1698 ent->read_proc = procmpt_iocinfo_read;
1699 ent->data = ioc;
1700 }
1701 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1702 if (ent) {
1703 ent->read_proc = procmpt_summary_read;
1704 ent->data = ioc;
1705 }
1706 }
1707#endif
1708
1709 return 0;
1710}
1711
1712/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001713/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001714 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 */
1717
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001718void
1719mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1722 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301723 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1726 remove_proc_entry(pname, NULL);
1727 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1728 remove_proc_entry(pname, NULL);
1729 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1730 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001733 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301734 if(MptDeviceDriverHandlers[cb_idx] &&
1735 MptDeviceDriverHandlers[cb_idx]->remove) {
1736 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 }
1738 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 /* Disable interrupts! */
1741 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1742
1743 ioc->active = 0;
1744 synchronize_irq(pdev->irq);
1745
1746 /* Clear any lingering interrupt */
1747 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1748
1749 CHIPREG_READ32(&ioc->chip->IntStatus);
1750
1751 mpt_adapter_dispose(ioc);
1752
1753 pci_set_drvdata(pdev, NULL);
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756/**************************************************************************
1757 * Power Management
1758 */
1759#ifdef CONFIG_PM
1760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001761/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001762 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001763 * @pdev: Pointer to pci_dev structure
1764 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001766int
1767mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 u32 device_state;
1770 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Pavel Machek2a569572005-07-07 17:56:40 -07001772 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 printk(MYIOC_s_INFO_FMT
1775 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1776 ioc->name, pdev, pci_name(pdev), device_state);
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pci_save_state(pdev);
1779
1780 /* put ioc into READY_STATE */
1781 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1782 printk(MYIOC_s_ERR_FMT
1783 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1784 }
1785
1786 /* disable interrupts */
1787 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1788 ioc->active = 0;
1789
1790 /* Clear any lingering interrupt */
1791 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1792
1793 pci_disable_device(pdev);
1794 pci_set_power_state(pdev, device_state);
1795
1796 return 0;
1797}
1798
1799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001800/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001801 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001802 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001804int
1805mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
1807 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1808 u32 device_state = pdev->current_state;
1809 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001810 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 printk(MYIOC_s_INFO_FMT
1813 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1814 ioc->name, pdev, pci_name(pdev), device_state);
1815
1816 pci_set_power_state(pdev, 0);
1817 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001818 err = pci_enable_device(pdev);
1819 if (err)
1820 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001823 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 ioc->active = 1;
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 printk(MYIOC_s_INFO_FMT
1827 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1828 ioc->name,
1829 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1830 CHIPREG_READ32(&ioc->chip->Doorbell));
1831
1832 /* bring ioc to operational state */
1833 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1834 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1835 printk(MYIOC_s_INFO_FMT
1836 "pci-resume: Cannot recover, error:[%x]\n",
1837 ioc->name, recovery_state);
1838 } else {
1839 printk(MYIOC_s_INFO_FMT
1840 "pci-resume: success\n", ioc->name);
1841 }
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 return 0;
1844}
1845#endif
1846
James Bottomley4ff42a62006-05-17 18:06:52 -05001847static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301848mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001849{
1850 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1851 ioc->bus_type != SPI) ||
1852 (MptDriverClass[index] == MPTFC_DRIVER &&
1853 ioc->bus_type != FC) ||
1854 (MptDriverClass[index] == MPTSAS_DRIVER &&
1855 ioc->bus_type != SAS))
1856 /* make sure we only call the relevant reset handler
1857 * for the bus */
1858 return 0;
1859 return (MptResetHandlers[index])(ioc, reset_phase);
1860}
1861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001863/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1865 * @ioc: Pointer to MPT adapter structure
1866 * @reason: Event word / reason
1867 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1868 *
1869 * This routine performs all the steps necessary to bring the IOC
1870 * to a OPERATIONAL state.
1871 *
1872 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1873 * MPT adapter.
1874 *
1875 * Returns:
1876 * 0 for success
1877 * -1 if failed to get board READY
1878 * -2 if READY but IOCFacts Failed
1879 * -3 if READY but PrimeIOCFifos Failed
1880 * -4 if READY but IOCInit Failed
1881 */
1882static int
1883mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1884{
1885 int hard_reset_done = 0;
1886 int alt_ioc_ready = 0;
1887 int hard;
1888 int rc=0;
1889 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301890 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 int handlers;
1892 int ret = 0;
1893 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001894 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301895 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Eric Moore29dd3602007-09-14 18:46:51 -06001897 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1898 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* Disable reply interrupts (also blocks FreeQ) */
1901 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1902 ioc->active = 0;
1903
1904 if (ioc->alt_ioc) {
1905 if (ioc->alt_ioc->active)
1906 reset_alt_ioc_active = 1;
1907
1908 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1909 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1910 ioc->alt_ioc->active = 0;
1911 }
1912
1913 hard = 1;
1914 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1915 hard = 0;
1916
1917 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1918 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001919 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1920 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 if (reset_alt_ioc_active && ioc->alt_ioc) {
1923 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001924 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1925 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001926 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 ioc->alt_ioc->active = 1;
1928 }
1929
1930 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001931 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
1933 return -1;
1934 }
1935
1936 /* hard_reset_done = 0 if a soft reset was performed
1937 * and 1 if a hard reset was performed.
1938 */
1939 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1940 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1941 alt_ioc_ready = 1;
1942 else
Eric Moore29dd3602007-09-14 18:46:51 -06001943 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
1945
1946 for (ii=0; ii<5; ii++) {
1947 /* Get IOC facts! Allow 5 retries */
1948 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1949 break;
1950 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
1953 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06001954 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1955 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 ret = -2;
1957 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1958 MptDisplayIocCapabilities(ioc);
1959 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (alt_ioc_ready) {
1962 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301963 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001964 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 /* Retry - alt IOC was initialized once
1966 */
1967 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1968 }
1969 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301970 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001971 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 alt_ioc_ready = 0;
1973 reset_alt_ioc_active = 0;
1974 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1975 MptDisplayIocCapabilities(ioc->alt_ioc);
1976 }
1977 }
1978
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001979 /*
1980 * Device is reset now. It must have de-asserted the interrupt line
1981 * (if it was asserted) and it should be safe to register for the
1982 * interrupt now.
1983 */
1984 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1985 ioc->pci_irq = -1;
1986 if (ioc->pcidev->irq) {
1987 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1988 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001989 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001990 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06001991 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001992 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001993 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06001994 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001995 if (mpt_msi_enable)
1996 pci_disable_msi(ioc->pcidev);
1997 return -EBUSY;
1998 }
1999 irq_allocated = 1;
2000 ioc->pci_irq = ioc->pcidev->irq;
2001 pci_set_master(ioc->pcidev); /* ?? */
2002 pci_set_drvdata(ioc->pcidev, ioc);
Eric Moore29dd3602007-09-14 18:46:51 -06002003 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2004 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002005 }
2006 }
2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 /* Prime reply & request queues!
2009 * (mucho alloc's) Must be done prior to
2010 * init as upper addresses are needed for init.
2011 * If fails, continue with alt-ioc processing
2012 */
2013 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2014 ret = -3;
2015
2016 /* May need to check/upload firmware & data here!
2017 * If fails, continue with alt-ioc processing
2018 */
2019 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2020 ret = -4;
2021// NEW!
2022 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002023 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2024 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 alt_ioc_ready = 0;
2026 reset_alt_ioc_active = 0;
2027 }
2028
2029 if (alt_ioc_ready) {
2030 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2031 alt_ioc_ready = 0;
2032 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002033 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2034 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 }
2036 }
2037
2038 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2039 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302040 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002041 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
2043 /* Controller is not operational, cannot do upload
2044 */
2045 if (ret == 0) {
2046 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002047 if (rc == 0) {
2048 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2049 /*
2050 * Maintain only one pointer to FW memory
2051 * so there will not be two attempt to
2052 * downloadboot onboard dual function
2053 * chips (mpt_adapter_disable,
2054 * mpt_diag_reset)
2055 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302056 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002057 "mpt_upload: alt_%s has cached_fw=%p \n",
2058 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002059 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002060 }
2061 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002062 printk(MYIOC_s_WARN_FMT
2063 "firmware upload failure!\n", ioc->name);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002064 ret = -5;
2065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 }
2067 }
2068 }
2069
2070 if (ret == 0) {
2071 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002072 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 ioc->active = 1;
2074 }
2075
2076 if (reset_alt_ioc_active && ioc->alt_ioc) {
2077 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002078 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2079 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002080 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 ioc->alt_ioc->active = 1;
2082 }
2083
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002084 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 * and EventAck handling.
2086 */
2087 if ((ret == 0) && (!ioc->facts.EventState))
2088 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2089
2090 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2091 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2092
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002093 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2095 * recursive scenario; GetLanConfigPages times out, timer expired
2096 * routine calls HardResetHandler, which calls into here again,
2097 * and we try GetLanConfigPages again...
2098 */
2099 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002100
2101 /*
2102 * Initalize link list for inactive raid volumes.
2103 */
2104 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2105 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2106
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002107 if (ioc->bus_type == SAS) {
2108
2109 /* clear persistency table */
2110 if(ioc->facts.IOCExceptions &
2111 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2112 ret = mptbase_sas_persist_operation(ioc,
2113 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2114 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002115 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002116 }
2117
2118 /* Find IM volumes
2119 */
2120 mpt_findImVolumes(ioc);
2121
2122 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2124 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2125 /*
2126 * Pre-fetch the ports LAN MAC address!
2127 * (LANPage1_t stuff)
2128 */
2129 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302130 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2131 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002132 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2133 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 }
2136 } else {
2137 /* Get NVRAM and adapter maximums from SPP 0 and 2
2138 */
2139 mpt_GetScsiPortSettings(ioc, 0);
2140
2141 /* Get version and length of SDP 1
2142 */
2143 mpt_readScsiDevicePageHeaders(ioc, 0);
2144
2145 /* Find IM volumes
2146 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002147 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 mpt_findImVolumes(ioc);
2149
2150 /* Check, and possibly reset, the coalescing value
2151 */
2152 mpt_read_ioc_pg_1(ioc);
2153
2154 mpt_read_ioc_pg_4(ioc);
2155 }
2156
2157 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302158 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160
2161 /*
2162 * Call each currently registered protocol IOC reset handler
2163 * with post-reset indication.
2164 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2165 * MptResetHandlers[] registered yet.
2166 */
2167 if (hard_reset_done) {
2168 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302169 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2170 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002172 "Calling IOC post_reset handler #%d\n",
2173 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302174 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 handlers++;
2176 }
2177
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302178 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302179 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002180 "Calling IOC post_reset handler #%d\n",
2181 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302182 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 handlers++;
2184 }
2185 }
2186 /* FIXME? Examine results here? */
2187 }
2188
Eric Moore0ccdb002006-07-11 17:33:13 -06002189 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002190 if ((ret != 0) && irq_allocated) {
2191 free_irq(ioc->pci_irq, ioc);
2192 if (mpt_msi_enable)
2193 pci_disable_msi(ioc->pcidev);
2194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 return ret;
2196}
2197
2198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002199/**
2200 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 * @ioc: Pointer to MPT adapter structure
2202 * @pdev: Pointer to (struct pci_dev) structure
2203 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002204 * Search for PCI bus/dev_function which matches
2205 * PCI bus/dev_function (+/-1) for newly discovered 929,
2206 * 929X, 1030 or 1035.
2207 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2209 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2210 */
2211static void
2212mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2213{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002214 struct pci_dev *peer=NULL;
2215 unsigned int slot = PCI_SLOT(pdev->devfn);
2216 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 MPT_ADAPTER *ioc_srch;
2218
Prakash, Sathya436ace72007-07-24 15:42:08 +05302219 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002220 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002221 ioc->name, pci_name(pdev), pdev->bus->number,
2222 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002223
2224 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2225 if (!peer) {
2226 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2227 if (!peer)
2228 return;
2229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 list_for_each_entry(ioc_srch, &ioc_list, list) {
2232 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002233 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 /* Paranoia checks */
2235 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002236 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002237 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 break;
2239 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002240 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002241 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 break;
2243 }
Eric Moore29dd3602007-09-14 18:46:51 -06002244 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002245 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ioc_srch->alt_ioc = ioc;
2247 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002250 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251}
2252
2253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002254/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002256 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 */
2258static void
2259mpt_adapter_disable(MPT_ADAPTER *ioc)
2260{
2261 int sz;
2262 int ret;
2263
2264 if (ioc->cached_fw != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002265 ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
2266 "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002267 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002268 printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
2269 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 }
2271 }
2272
2273 /* Disable adapter interrupts! */
2274 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2275 ioc->active = 0;
2276 /* Clear any lingering interrupt */
2277 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2278
2279 if (ioc->alloc != NULL) {
2280 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002281 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2282 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 pci_free_consistent(ioc->pcidev, sz,
2284 ioc->alloc, ioc->alloc_dma);
2285 ioc->reply_frames = NULL;
2286 ioc->req_frames = NULL;
2287 ioc->alloc = NULL;
2288 ioc->alloc_total -= sz;
2289 }
2290
2291 if (ioc->sense_buf_pool != NULL) {
2292 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2293 pci_free_consistent(ioc->pcidev, sz,
2294 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2295 ioc->sense_buf_pool = NULL;
2296 ioc->alloc_total -= sz;
2297 }
2298
2299 if (ioc->events != NULL){
2300 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2301 kfree(ioc->events);
2302 ioc->events = NULL;
2303 ioc->alloc_total -= sz;
2304 }
2305
2306 if (ioc->cached_fw != NULL) {
2307 sz = ioc->facts.FWImageSize;
2308 pci_free_consistent(ioc->pcidev, sz,
2309 ioc->cached_fw, ioc->cached_fw_dma);
2310 ioc->cached_fw = NULL;
2311 ioc->alloc_total -= sz;
2312 }
2313
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002314 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002315 mpt_inactive_raid_list_free(ioc);
2316 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002317 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002318 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002319 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
2321 if (ioc->spi_data.pIocPg4 != NULL) {
2322 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302323 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 ioc->spi_data.pIocPg4,
2325 ioc->spi_data.IocPg4_dma);
2326 ioc->spi_data.pIocPg4 = NULL;
2327 ioc->alloc_total -= sz;
2328 }
2329
2330 if (ioc->ReqToChain != NULL) {
2331 kfree(ioc->ReqToChain);
2332 kfree(ioc->RequestNB);
2333 ioc->ReqToChain = NULL;
2334 }
2335
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002336 kfree(ioc->ChainToChain);
2337 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002338
2339 if (ioc->HostPageBuffer != NULL) {
2340 if((ret = mpt_host_page_access_control(ioc,
2341 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002342 printk(MYIOC_s_ERR_FMT
2343 "host page buffers free failed (%d)!\n",
2344 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002345 }
Eric Moore29dd3602007-09-14 18:46:51 -06002346 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002347 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2348 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002349 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002350 ioc->HostPageBuffer = NULL;
2351 ioc->HostPageBuffer_sz = 0;
2352 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354}
2355
2356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002357/**
2358 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 * @ioc: Pointer to MPT adapter structure
2360 *
2361 * This routine unregisters h/w resources and frees all alloc'd memory
2362 * associated with a MPT adapter structure.
2363 */
2364static void
2365mpt_adapter_dispose(MPT_ADAPTER *ioc)
2366{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002367 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002369 if (ioc == NULL)
2370 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002374 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002376 if (ioc->pci_irq != -1) {
2377 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002378 if (mpt_msi_enable)
2379 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002380 ioc->pci_irq = -1;
2381 }
2382
2383 if (ioc->memmap != NULL) {
2384 iounmap(ioc->memmap);
2385 ioc->memmap = NULL;
2386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002389 if (ioc->mtrr_reg > 0) {
2390 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002391 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393#endif
2394
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002395 /* Zap the adapter lookup ptr! */
2396 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002398 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002399 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2400 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002401
2402 if (ioc->alt_ioc)
2403 ioc->alt_ioc->alt_ioc = NULL;
2404
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002405 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406}
2407
2408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002409/**
2410 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 * @ioc: Pointer to MPT adapter structure
2412 */
2413static void
2414MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2415{
2416 int i = 0;
2417
2418 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302419 if (ioc->prod_name)
2420 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 printk("Capabilities={");
2422
2423 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2424 printk("Initiator");
2425 i++;
2426 }
2427
2428 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2429 printk("%sTarget", i ? "," : "");
2430 i++;
2431 }
2432
2433 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2434 printk("%sLAN", i ? "," : "");
2435 i++;
2436 }
2437
2438#if 0
2439 /*
2440 * This would probably evoke more questions than it's worth
2441 */
2442 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2443 printk("%sLogBusAddr", i ? "," : "");
2444 i++;
2445 }
2446#endif
2447
2448 printk("}\n");
2449}
2450
2451/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002452/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2454 * @ioc: Pointer to MPT_ADAPTER structure
2455 * @force: Force hard KickStart of IOC
2456 * @sleepFlag: Specifies whether the process can sleep
2457 *
2458 * Returns:
2459 * 1 - DIAG reset and READY
2460 * 0 - READY initially OR soft reset and READY
2461 * -1 - Any failure on KickStart
2462 * -2 - Msg Unit Reset Failed
2463 * -3 - IO Unit Reset Failed
2464 * -4 - IOC owned by a PEER
2465 */
2466static int
2467MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2468{
2469 u32 ioc_state;
2470 int statefault = 0;
2471 int cntdn;
2472 int hard_reset_done = 0;
2473 int r;
2474 int ii;
2475 int whoinit;
2476
2477 /* Get current [raw] IOC state */
2478 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002479 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
2481 /*
2482 * Check to see if IOC got left/stuck in doorbell handshake
2483 * grip of death. If so, hard reset the IOC.
2484 */
2485 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2486 statefault = 1;
2487 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2488 ioc->name);
2489 }
2490
2491 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002492 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 return 0;
2494
2495 /*
2496 * Check to see if IOC is in FAULT state.
2497 */
2498 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2499 statefault = 2;
2500 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002501 ioc->name);
2502 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2503 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 }
2505
2506 /*
2507 * Hmmm... Did it get left operational?
2508 */
2509 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302510 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 ioc->name));
2512
2513 /* Check WhoInit.
2514 * If PCI Peer, exit.
2515 * Else, if no fault conditions are present, issue a MessageUnitReset
2516 * Else, fall through to KickStart case
2517 */
2518 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002519 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2520 "whoinit 0x%x statefault %d force %d\n",
2521 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 if (whoinit == MPI_WHOINIT_PCI_PEER)
2523 return -4;
2524 else {
2525 if ((statefault == 0 ) && (force == 0)) {
2526 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2527 return 0;
2528 }
2529 statefault = 3;
2530 }
2531 }
2532
2533 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2534 if (hard_reset_done < 0)
2535 return -1;
2536
2537 /*
2538 * Loop here waiting for IOC to come READY.
2539 */
2540 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002541 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2544 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2545 /*
2546 * BIOS or previous driver load left IOC in OP state.
2547 * Reset messaging FIFOs.
2548 */
2549 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2550 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2551 return -2;
2552 }
2553 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2554 /*
2555 * Something is wrong. Try to get IOC back
2556 * to a known state.
2557 */
2558 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2559 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2560 return -3;
2561 }
2562 }
2563
2564 ii++; cntdn--;
2565 if (!cntdn) {
2566 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2567 ioc->name, (int)((ii+5)/HZ));
2568 return -ETIME;
2569 }
2570
2571 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002572 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 } else {
2574 mdelay (1); /* 1 msec delay */
2575 }
2576
2577 }
2578
2579 if (statefault < 3) {
2580 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2581 ioc->name,
2582 statefault==1 ? "stuck handshake" : "IOC FAULT");
2583 }
2584
2585 return hard_reset_done;
2586}
2587
2588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002589/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 * mpt_GetIocState - Get the current state of a MPT adapter.
2591 * @ioc: Pointer to MPT_ADAPTER structure
2592 * @cooked: Request raw or cooked IOC state
2593 *
2594 * Returns all IOC Doorbell register bits if cooked==0, else just the
2595 * Doorbell bits in MPI_IOC_STATE_MASK.
2596 */
2597u32
2598mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2599{
2600 u32 s, sc;
2601
2602 /* Get! */
2603 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 sc = s & MPI_IOC_STATE_MASK;
2605
2606 /* Save! */
2607 ioc->last_state = sc;
2608
2609 return cooked ? sc : s;
2610}
2611
2612/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002613/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 * GetIocFacts - Send IOCFacts request to MPT adapter.
2615 * @ioc: Pointer to MPT_ADAPTER structure
2616 * @sleepFlag: Specifies whether the process can sleep
2617 * @reason: If recovery, only update facts.
2618 *
2619 * Returns 0 for success, non-zero for failure.
2620 */
2621static int
2622GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2623{
2624 IOCFacts_t get_facts;
2625 IOCFactsReply_t *facts;
2626 int r;
2627 int req_sz;
2628 int reply_sz;
2629 int sz;
2630 u32 status, vv;
2631 u8 shiftFactor=1;
2632
2633 /* IOC *must* NOT be in RESET state! */
2634 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002635 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2636 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 return -44;
2638 }
2639
2640 facts = &ioc->facts;
2641
2642 /* Destination (reply area)... */
2643 reply_sz = sizeof(*facts);
2644 memset(facts, 0, reply_sz);
2645
2646 /* Request area (get_facts on the stack right now!) */
2647 req_sz = sizeof(get_facts);
2648 memset(&get_facts, 0, req_sz);
2649
2650 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2651 /* Assert: All other get_facts fields are zero! */
2652
Prakash, Sathya436ace72007-07-24 15:42:08 +05302653 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002654 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 ioc->name, req_sz, reply_sz));
2656
2657 /* No non-zero fields in the get_facts request are greater than
2658 * 1 byte in size, so we can just fire it off as is.
2659 */
2660 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2661 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2662 if (r != 0)
2663 return r;
2664
2665 /*
2666 * Now byte swap (GRRR) the necessary fields before any further
2667 * inspection of reply contents.
2668 *
2669 * But need to do some sanity checks on MsgLength (byte) field
2670 * to make sure we don't zero IOC's req_sz!
2671 */
2672 /* Did we get a valid reply? */
2673 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2674 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2675 /*
2676 * If not been here, done that, save off first WhoInit value
2677 */
2678 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2679 ioc->FirstWhoInit = facts->WhoInit;
2680 }
2681
2682 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2683 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2684 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2685 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2686 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002687 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 /* CHECKME! IOCStatus, IOCLogInfo */
2689
2690 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2691 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2692
2693 /*
2694 * FC f/w version changed between 1.1 and 1.2
2695 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2696 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2697 */
2698 if (facts->MsgVersion < 0x0102) {
2699 /*
2700 * Handle old FC f/w style, convert to new...
2701 */
2702 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2703 facts->FWVersion.Word =
2704 ((oldv<<12) & 0xFF000000) |
2705 ((oldv<<8) & 0x000FFF00);
2706 } else
2707 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2708
2709 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002710 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2711 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2712 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 facts->CurrentHostMfaHighAddr =
2714 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2715 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2716 facts->CurrentSenseBufferHighAddr =
2717 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2718 facts->CurReplyFrameSize =
2719 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002720 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
2722 /*
2723 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2724 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2725 * to 14 in MPI-1.01.0x.
2726 */
2727 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2728 facts->MsgVersion > 0x0100) {
2729 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2730 }
2731
2732 sz = facts->FWImageSize;
2733 if ( sz & 0x01 )
2734 sz += 1;
2735 if ( sz & 0x02 )
2736 sz += 2;
2737 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002738
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 if (!facts->RequestFrameSize) {
2740 /* Something is wrong! */
2741 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2742 ioc->name);
2743 return -55;
2744 }
2745
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002746 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 vv = ((63 / (sz * 4)) + 1) & 0x03;
2748 ioc->NB_for_64_byte_frame = vv;
2749 while ( sz )
2750 {
2751 shiftFactor++;
2752 sz = sz >> 1;
2753 }
2754 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302755 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002756 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2757 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002758
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2760 /*
2761 * Set values for this IOC's request & reply frame sizes,
2762 * and request & reply queue depths...
2763 */
2764 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2765 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2766 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2767 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2768
Prakash, Sathya436ace72007-07-24 15:42:08 +05302769 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302771 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 ioc->name, ioc->req_sz, ioc->req_depth));
2773
2774 /* Get port facts! */
2775 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2776 return r;
2777 }
2778 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002779 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2781 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2782 RequestFrameSize)/sizeof(u32)));
2783 return -66;
2784 }
2785
2786 return 0;
2787}
2788
2789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002790/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 * GetPortFacts - Send PortFacts request to MPT adapter.
2792 * @ioc: Pointer to MPT_ADAPTER structure
2793 * @portnum: Port number
2794 * @sleepFlag: Specifies whether the process can sleep
2795 *
2796 * Returns 0 for success, non-zero for failure.
2797 */
2798static int
2799GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2800{
2801 PortFacts_t get_pfacts;
2802 PortFactsReply_t *pfacts;
2803 int ii;
2804 int req_sz;
2805 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002806 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 /* IOC *must* NOT be in RESET state! */
2809 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002810 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2811 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 return -4;
2813 }
2814
2815 pfacts = &ioc->pfacts[portnum];
2816
2817 /* Destination (reply area)... */
2818 reply_sz = sizeof(*pfacts);
2819 memset(pfacts, 0, reply_sz);
2820
2821 /* Request area (get_pfacts on the stack right now!) */
2822 req_sz = sizeof(get_pfacts);
2823 memset(&get_pfacts, 0, req_sz);
2824
2825 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2826 get_pfacts.PortNumber = portnum;
2827 /* Assert: All other get_pfacts fields are zero! */
2828
Prakash, Sathya436ace72007-07-24 15:42:08 +05302829 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 ioc->name, portnum));
2831
2832 /* No non-zero fields in the get_pfacts request are greater than
2833 * 1 byte in size, so we can just fire it off as is.
2834 */
2835 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2836 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2837 if (ii != 0)
2838 return ii;
2839
2840 /* Did we get a valid reply? */
2841
2842 /* Now byte swap the necessary fields in the response. */
2843 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2844 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2845 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2846 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2847 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2848 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2849 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2850 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2851 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2852
Eric Moore793955f2007-01-29 09:42:20 -07002853 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2854 pfacts->MaxDevices;
2855 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2856 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2857
2858 /*
2859 * Place all the devices on channels
2860 *
2861 * (for debuging)
2862 */
2863 if (mpt_channel_mapping) {
2864 ioc->devices_per_bus = 1;
2865 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2866 }
2867
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 return 0;
2869}
2870
2871/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002872/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 * SendIocInit - Send IOCInit request to MPT adapter.
2874 * @ioc: Pointer to MPT_ADAPTER structure
2875 * @sleepFlag: Specifies whether the process can sleep
2876 *
2877 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2878 *
2879 * Returns 0 for success, non-zero for failure.
2880 */
2881static int
2882SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2883{
2884 IOCInit_t ioc_init;
2885 MPIDefaultReply_t init_reply;
2886 u32 state;
2887 int r;
2888 int count;
2889 int cntdn;
2890
2891 memset(&ioc_init, 0, sizeof(ioc_init));
2892 memset(&init_reply, 0, sizeof(init_reply));
2893
2894 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2895 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2896
2897 /* If we are in a recovery mode and we uploaded the FW image,
2898 * then this pointer is not NULL. Skip the upload a second time.
2899 * Set this flag if cached_fw set for either IOC.
2900 */
2901 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2902 ioc->upload_fw = 1;
2903 else
2904 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302905 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2907
Eric Moore793955f2007-01-29 09:42:20 -07002908 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2909 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302910 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002911 ioc->name, ioc->facts.MsgVersion));
2912 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2913 // set MsgVersion and HeaderVersion host driver was built with
2914 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2915 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002917 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2918 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2919 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2920 return -99;
2921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2923
2924 if (sizeof(dma_addr_t) == sizeof(u64)) {
2925 /* Save the upper 32-bits of the request
2926 * (reply) and sense buffers.
2927 */
2928 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2929 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2930 } else {
2931 /* Force 32-bit addressing */
2932 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2933 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2934 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2937 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002938 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2939 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
Prakash, Sathya436ace72007-07-24 15:42:08 +05302941 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 ioc->name, &ioc_init));
2943
2944 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2945 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002946 if (r != 0) {
2947 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002952 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 */
2954
Prakash, Sathya436ace72007-07-24 15:42:08 +05302955 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002957
2958 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2959 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963 /* YIKES! SUPER IMPORTANT!!!
2964 * Poll IocState until _OPERATIONAL while IOC is doing
2965 * LoopInit and TargetDiscovery!
2966 */
2967 count = 0;
2968 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2969 state = mpt_GetIocState(ioc, 1);
2970 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2971 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002972 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 } else {
2974 mdelay(1);
2975 }
2976
2977 if (!cntdn) {
2978 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2979 ioc->name, (int)((count+5)/HZ));
2980 return -9;
2981 }
2982
2983 state = mpt_GetIocState(ioc, 1);
2984 count++;
2985 }
Eric Moore29dd3602007-09-14 18:46:51 -06002986 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 ioc->name, count));
2988
Eric Mooreba856d32006-07-11 17:34:01 -06002989 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 return r;
2991}
2992
2993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002994/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 * SendPortEnable - Send PortEnable request to MPT adapter port.
2996 * @ioc: Pointer to MPT_ADAPTER structure
2997 * @portnum: Port number to enable
2998 * @sleepFlag: Specifies whether the process can sleep
2999 *
3000 * Send PortEnable to bring IOC to OPERATIONAL state.
3001 *
3002 * Returns 0 for success, non-zero for failure.
3003 */
3004static int
3005SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3006{
3007 PortEnable_t port_enable;
3008 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003009 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 int req_sz;
3011 int reply_sz;
3012
3013 /* Destination... */
3014 reply_sz = sizeof(MPIDefaultReply_t);
3015 memset(&reply_buf, 0, reply_sz);
3016
3017 req_sz = sizeof(PortEnable_t);
3018 memset(&port_enable, 0, req_sz);
3019
3020 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3021 port_enable.PortNumber = portnum;
3022/* port_enable.ChainOffset = 0; */
3023/* port_enable.MsgFlags = 0; */
3024/* port_enable.MsgContext = 0; */
3025
Prakash, Sathya436ace72007-07-24 15:42:08 +05303026 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 ioc->name, portnum, &port_enable));
3028
3029 /* RAID FW may take a long time to enable
3030 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003031 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003032 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3033 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3034 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003035 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003036 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3037 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3038 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003040 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041}
3042
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003043/**
3044 * mpt_alloc_fw_memory - allocate firmware memory
3045 * @ioc: Pointer to MPT_ADAPTER structure
3046 * @size: total FW bytes
3047 *
3048 * If memory has already been allocated, the same (cached) value
3049 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 */
3051void
3052mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3053{
3054 if (ioc->cached_fw)
3055 return; /* use already allocated memory */
3056 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3057 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3058 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003059 ioc->alloc_total += size;
3060 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 } else {
3062 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3063 ioc->alloc_total += size;
3064 }
3065}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003066/**
3067 * mpt_free_fw_memory - free firmware memory
3068 * @ioc: Pointer to MPT_ADAPTER structure
3069 *
3070 * If alt_img is NULL, delete from ioc structure.
3071 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 */
3073void
3074mpt_free_fw_memory(MPT_ADAPTER *ioc)
3075{
3076 int sz;
3077
3078 sz = ioc->facts.FWImageSize;
Eric Moore29dd3602007-09-14 18:46:51 -06003079 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3080 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3081 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 ioc->cached_fw = NULL;
3083
3084 return;
3085}
3086
3087
3088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003089/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3091 * @ioc: Pointer to MPT_ADAPTER structure
3092 * @sleepFlag: Specifies whether the process can sleep
3093 *
3094 * Returns 0 for success, >0 for handshake failure
3095 * <0 for fw upload failure.
3096 *
3097 * Remark: If bound IOC and a successful FWUpload was performed
3098 * on the bound IOC, the second image is discarded
3099 * and memory is free'd. Both channels must upload to prevent
3100 * IOC from running in degraded mode.
3101 */
3102static int
3103mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3104{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 u8 reply[sizeof(FWUploadReply_t)];
3106 FWUpload_t *prequest;
3107 FWUploadReply_t *preply;
3108 FWUploadTCSGE_t *ptcsge;
3109 int sgeoffset;
3110 u32 flagsLength;
3111 int ii, sz, reply_sz;
3112 int cmdStatus;
3113
3114 /* If the image size is 0, we are done.
3115 */
3116 if ((sz = ioc->facts.FWImageSize) == 0)
3117 return 0;
3118
3119 mpt_alloc_fw_memory(ioc, sz);
3120
Eric Moore29dd3602007-09-14 18:46:51 -06003121 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3122 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003123
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 if (ioc->cached_fw == NULL) {
3125 /* Major Failure.
3126 */
3127 return -ENOMEM;
3128 }
3129
Eric Moorebc6e0892007-09-29 10:16:28 -06003130 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3131 kzalloc(ioc->req_sz, GFP_KERNEL);
3132 if (!prequest) {
3133 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3134 "while allocating memory \n", ioc->name));
3135 mpt_free_fw_memory(ioc);
3136 return -ENOMEM;
3137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
Eric Moorebc6e0892007-09-29 10:16:28 -06003139 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
3141 reply_sz = sizeof(reply);
3142 memset(preply, 0, reply_sz);
3143
3144 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3145 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3146
3147 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3148 ptcsge->DetailsLength = 12;
3149 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3150 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003151 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152
3153 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3154
3155 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003156 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157
3158 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003159 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3160 ioc->name, prequest, sgeoffset));
3161 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3164 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3165
Eric Moore29dd3602007-09-14 18:46:51 -06003166 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
3168 cmdStatus = -EFAULT;
3169 if (ii == 0) {
3170 /* Handshake transfer was complete and successful.
3171 * Check the Reply Frame.
3172 */
3173 int status, transfer_sz;
3174 status = le16_to_cpu(preply->IOCStatus);
3175 if (status == MPI_IOCSTATUS_SUCCESS) {
3176 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3177 if (transfer_sz == sz)
3178 cmdStatus = 0;
3179 }
3180 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303181 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 ioc->name, cmdStatus));
3183
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 if (cmdStatus) {
3186
Prakash, Sathya436ace72007-07-24 15:42:08 +05303187 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 ioc->name));
3189 mpt_free_fw_memory(ioc);
3190 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003191 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 return cmdStatus;
3194}
3195
3196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003197/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 * mpt_downloadboot - DownloadBoot code
3199 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003200 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 * @sleepFlag: Specifies whether the process can sleep
3202 *
3203 * FwDownloadBoot requires Programmed IO access.
3204 *
3205 * Returns 0 for success
3206 * -1 FW Image size is 0
3207 * -2 No valid cached_fw Pointer
3208 * <0 for fw upload failure.
3209 */
3210static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003211mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 MpiExtImageHeader_t *pExtImage;
3214 u32 fwSize;
3215 u32 diag0val;
3216 int count;
3217 u32 *ptrFw;
3218 u32 diagRwData;
3219 u32 nextImage;
3220 u32 load_addr;
3221 u32 ioc_state=0;
3222
Prakash, Sathya436ace72007-07-24 15:42:08 +05303223 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003224 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003225
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3227 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3228 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3229 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3230 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3231 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3232
3233 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3234
3235 /* wait 1 msec */
3236 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003237 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 } else {
3239 mdelay (1);
3240 }
3241
3242 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3243 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3244
3245 for (count = 0; count < 30; count ++) {
3246 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3247 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303248 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 ioc->name, count));
3250 break;
3251 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003252 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003254 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003256 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 }
3258 }
3259
3260 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303261 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003262 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 ioc->name, diag0val));
3264 return -3;
3265 }
3266
3267 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3268 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3269 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3270 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3271 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3272 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3273
3274 /* Set the DiagRwEn and Disable ARM bits */
3275 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3276
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 fwSize = (pFwHeader->ImageSize + 3)/4;
3278 ptrFw = (u32 *) pFwHeader;
3279
3280 /* Write the LoadStartAddress to the DiagRw Address Register
3281 * using Programmed IO
3282 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003283 if (ioc->errata_flag_1064)
3284 pci_enable_io_access(ioc->pcidev);
3285
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303287 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 ioc->name, pFwHeader->LoadStartAddress));
3289
Prakash, Sathya436ace72007-07-24 15:42:08 +05303290 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 ioc->name, fwSize*4, ptrFw));
3292 while (fwSize--) {
3293 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3294 }
3295
3296 nextImage = pFwHeader->NextImageHeaderOffset;
3297 while (nextImage) {
3298 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3299
3300 load_addr = pExtImage->LoadStartAddress;
3301
3302 fwSize = (pExtImage->ImageSize + 3) >> 2;
3303 ptrFw = (u32 *)pExtImage;
3304
Prakash, Sathya436ace72007-07-24 15:42:08 +05303305 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 +02003306 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3308
3309 while (fwSize--) {
3310 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3311 }
3312 nextImage = pExtImage->NextImageHeaderOffset;
3313 }
3314
3315 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303316 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3318
3319 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303320 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3322
3323 /* Clear the internal flash bad bit - autoincrementing register,
3324 * so must do two writes.
3325 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003326 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003327 /*
3328 * 1030 and 1035 H/W errata, workaround to access
3329 * the ClearFlashBadSignatureBit
3330 */
3331 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3332 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3333 diagRwData |= 0x40000000;
3334 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3335 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3336
3337 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3338 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3339 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3340 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3341
3342 /* wait 1 msec */
3343 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003344 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003345 } else {
3346 mdelay (1);
3347 }
3348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003350 if (ioc->errata_flag_1064)
3351 pci_disable_io_access(ioc->pcidev);
3352
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303354 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003355 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003357 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303358 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 ioc->name, diag0val));
3360 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3361
3362 /* Write 0xFF to reset the sequencer */
3363 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3364
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003365 if (ioc->bus_type == SAS) {
3366 ioc_state = mpt_GetIocState(ioc, 0);
3367 if ( (GetIocFacts(ioc, sleepFlag,
3368 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303369 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003370 ioc->name, ioc_state));
3371 return -EFAULT;
3372 }
3373 }
3374
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 for (count=0; count<HZ*20; count++) {
3376 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303377 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3378 "downloadboot successful! (count=%d) IocState=%x\n",
3379 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003380 if (ioc->bus_type == SAS) {
3381 return 0;
3382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303384 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3385 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 ioc->name));
3387 return -EFAULT;
3388 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303389 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3390 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 ioc->name));
3392 return 0;
3393 }
3394 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003395 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 } else {
3397 mdelay (10);
3398 }
3399 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303400 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3401 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 return -EFAULT;
3403}
3404
3405/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003406/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 * KickStart - Perform hard reset of MPT adapter.
3408 * @ioc: Pointer to MPT_ADAPTER structure
3409 * @force: Force hard reset
3410 * @sleepFlag: Specifies whether the process can sleep
3411 *
3412 * This routine places MPT adapter in diagnostic mode via the
3413 * WriteSequence register, and then performs a hard reset of adapter
3414 * via the Diagnostic register.
3415 *
3416 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3417 * or NO_SLEEP (interrupt thread, use mdelay)
3418 * force - 1 if doorbell active, board fault state
3419 * board operational, IOC_RECOVERY or
3420 * IOC_BRINGUP and there is an alt_ioc.
3421 * 0 else
3422 *
3423 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003424 * 1 - hard reset, READY
3425 * 0 - no reset due to History bit, READY
3426 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 * OR reset but failed to come READY
3428 * -2 - no reset, could not enter DIAG mode
3429 * -3 - reset but bad FW bit
3430 */
3431static int
3432KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3433{
3434 int hard_reset_done = 0;
3435 u32 ioc_state=0;
3436 int cnt,cntdn;
3437
Eric Moore29dd3602007-09-14 18:46:51 -06003438 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003439 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 /* Always issue a Msg Unit Reset first. This will clear some
3441 * SCSI bus hang conditions.
3442 */
3443 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3444
3445 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003446 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 } else {
3448 mdelay (1000);
3449 }
3450 }
3451
3452 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3453 if (hard_reset_done < 0)
3454 return hard_reset_done;
3455
Prakash, Sathya436ace72007-07-24 15:42:08 +05303456 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003457 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
3459 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3460 for (cnt=0; cnt<cntdn; cnt++) {
3461 ioc_state = mpt_GetIocState(ioc, 1);
3462 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303463 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 ioc->name, cnt));
3465 return hard_reset_done;
3466 }
3467 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003468 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 } else {
3470 mdelay (10);
3471 }
3472 }
3473
Eric Moore29dd3602007-09-14 18:46:51 -06003474 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3475 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 return -1;
3477}
3478
3479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003480/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 * mpt_diag_reset - Perform hard reset of the adapter.
3482 * @ioc: Pointer to MPT_ADAPTER structure
3483 * @ignore: Set if to honor and clear to ignore
3484 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003485 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 * else set to NO_SLEEP (use mdelay instead)
3487 *
3488 * This routine places the adapter in diagnostic mode via the
3489 * WriteSequence register and then performs a hard reset of adapter
3490 * via the Diagnostic register. Adapter should be in ready state
3491 * upon successful completion.
3492 *
3493 * Returns: 1 hard reset successful
3494 * 0 no reset performed because reset history bit set
3495 * -2 enabling diagnostic mode failed
3496 * -3 diagnostic reset failed
3497 */
3498static int
3499mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3500{
Eric Moore0ccdb002006-07-11 17:33:13 -06003501 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 u32 diag0val;
3503 u32 doorbell;
3504 int hard_reset_done = 0;
3505 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507
Eric Moorecd2c6192007-01-29 09:47:47 -07003508 /* Clear any existing interrupts */
3509 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3510
Eric Moore87cf8982006-06-27 16:09:26 -06003511 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303512 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003513 "address=%p\n", ioc->name, __FUNCTION__,
3514 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3515 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3516 if (sleepFlag == CAN_SLEEP)
3517 msleep(1);
3518 else
3519 mdelay(1);
3520
3521 for (count = 0; count < 60; count ++) {
3522 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3523 doorbell &= MPI_IOC_STATE_MASK;
3524
Prakash, Sathya436ace72007-07-24 15:42:08 +05303525 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003526 "looking for READY STATE: doorbell=%x"
3527 " count=%d\n",
3528 ioc->name, doorbell, count));
3529 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003530 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003531 }
3532
3533 /* wait 1 sec */
3534 if (sleepFlag == CAN_SLEEP)
3535 msleep(1000);
3536 else
3537 mdelay(1000);
3538 }
3539 return -1;
3540 }
3541
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 /* Use "Diagnostic reset" method! (only thing available!) */
3543 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3544
Prakash, Sathya436ace72007-07-24 15:42:08 +05303545 if (ioc->debug_level & MPT_DEBUG) {
3546 if (ioc->alt_ioc)
3547 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3548 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
3552 /* Do the reset if we are told to ignore the reset history
3553 * or if the reset history is 0
3554 */
3555 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3556 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3557 /* Write magic sequence to WriteSequence register
3558 * Loop until in diagnostic mode
3559 */
3560 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3561 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3562 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3563 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3564 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3565 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3566
3567 /* wait 100 msec */
3568 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003569 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 } else {
3571 mdelay (100);
3572 }
3573
3574 count++;
3575 if (count > 20) {
3576 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3577 ioc->name, diag0val);
3578 return -2;
3579
3580 }
3581
3582 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3583
Prakash, Sathya436ace72007-07-24 15:42:08 +05303584 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 ioc->name, diag0val));
3586 }
3587
Prakash, Sathya436ace72007-07-24 15:42:08 +05303588 if (ioc->debug_level & MPT_DEBUG) {
3589 if (ioc->alt_ioc)
3590 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3591 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 /*
3595 * Disable the ARM (Bug fix)
3596 *
3597 */
3598 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003599 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600
3601 /*
3602 * Now hit the reset bit in the Diagnostic register
3603 * (THE BIG HAMMER!) (Clears DRWE bit).
3604 */
3605 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3606 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303607 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 ioc->name));
3609
3610 /*
3611 * Call each currently registered protocol IOC reset handler
3612 * with pre-reset indication.
3613 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3614 * MptResetHandlers[] registered yet.
3615 */
3616 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303617 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 int r = 0;
3619
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303620 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3621 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303622 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3623 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303624 ioc->name, cb_idx));
3625 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303627 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3628 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303629 ioc->name, ioc->alt_ioc->name, cb_idx));
3630 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 }
3632 }
3633 }
3634 /* FIXME? Examine results here? */
3635 }
3636
Eric Moore0ccdb002006-07-11 17:33:13 -06003637 if (ioc->cached_fw)
3638 iocp = ioc;
3639 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3640 iocp = ioc->alt_ioc;
3641 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 /* If the DownloadBoot operation fails, the
3643 * IOC will be left unusable. This is a fatal error
3644 * case. _diag_reset will return < 0
3645 */
3646 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003647 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3649 break;
3650 }
3651
Prakash, Sathya436ace72007-07-24 15:42:08 +05303652 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003653 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 /* wait 1 sec */
3655 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003656 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 } else {
3658 mdelay (1000);
3659 }
3660 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003661 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003662 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003663 printk(MYIOC_s_WARN_FMT
3664 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 }
3666
3667 } else {
3668 /* Wait for FW to reload and for board
3669 * to go to the READY state.
3670 * Maximum wait is 60 seconds.
3671 * If fail, no error will check again
3672 * with calling program.
3673 */
3674 for (count = 0; count < 60; count ++) {
3675 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3676 doorbell &= MPI_IOC_STATE_MASK;
3677
3678 if (doorbell == MPI_IOC_STATE_READY) {
3679 break;
3680 }
3681
3682 /* wait 1 sec */
3683 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003684 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 } else {
3686 mdelay (1000);
3687 }
3688 }
3689 }
3690 }
3691
3692 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303693 if (ioc->debug_level & MPT_DEBUG) {
3694 if (ioc->alt_ioc)
3695 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3696 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3697 ioc->name, diag0val, diag1val));
3698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
3700 /* Clear RESET_HISTORY bit! Place board in the
3701 * diagnostic mode to update the diag register.
3702 */
3703 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3704 count = 0;
3705 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3706 /* Write magic sequence to WriteSequence register
3707 * Loop until in diagnostic mode
3708 */
3709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3710 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3711 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3712 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3713 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3714 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3715
3716 /* wait 100 msec */
3717 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003718 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 } else {
3720 mdelay (100);
3721 }
3722
3723 count++;
3724 if (count > 20) {
3725 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3726 ioc->name, diag0val);
3727 break;
3728 }
3729 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3730 }
3731 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3732 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3733 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3734 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3735 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3736 ioc->name);
3737 }
3738
3739 /* Disable Diagnostic Mode
3740 */
3741 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3742
3743 /* Check FW reload status flags.
3744 */
3745 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3746 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3747 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3748 ioc->name, diag0val);
3749 return -3;
3750 }
3751
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 if (ioc->debug_level & MPT_DEBUG) {
3753 if (ioc->alt_ioc)
3754 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3755 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
3759 /*
3760 * Reset flag that says we've enabled event notification
3761 */
3762 ioc->facts.EventState = 0;
3763
3764 if (ioc->alt_ioc)
3765 ioc->alt_ioc->facts.EventState = 0;
3766
3767 return hard_reset_done;
3768}
3769
3770/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003771/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 * SendIocReset - Send IOCReset request to MPT adapter.
3773 * @ioc: Pointer to MPT_ADAPTER structure
3774 * @reset_type: reset type, expected values are
3775 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003776 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 *
3778 * Send IOCReset request to the MPT adapter.
3779 *
3780 * Returns 0 for success, non-zero for failure.
3781 */
3782static int
3783SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3784{
3785 int r;
3786 u32 state;
3787 int cntdn, count;
3788
Prakash, Sathya436ace72007-07-24 15:42:08 +05303789 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 ioc->name, reset_type));
3791 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3792 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3793 return r;
3794
3795 /* FW ACK'd request, wait for READY state
3796 */
3797 count = 0;
3798 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3799
3800 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3801 cntdn--;
3802 count++;
3803 if (!cntdn) {
3804 if (sleepFlag != CAN_SLEEP)
3805 count *= 10;
3806
Eric Moore29dd3602007-09-14 18:46:51 -06003807 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3808 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 return -ETIME;
3810 }
3811
3812 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003813 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 } else {
3815 mdelay (1); /* 1 msec delay */
3816 }
3817 }
3818
3819 /* TODO!
3820 * Cleanup all event stuff for this IOC; re-issue EventNotification
3821 * request if needed.
3822 */
3823 if (ioc->facts.Function)
3824 ioc->facts.EventState = 0;
3825
3826 return 0;
3827}
3828
3829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003830/**
3831 * initChainBuffers - Allocate memory for and initialize chain buffers
3832 * @ioc: Pointer to MPT_ADAPTER structure
3833 *
3834 * Allocates memory for and initializes chain buffers,
3835 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 */
3837static int
3838initChainBuffers(MPT_ADAPTER *ioc)
3839{
3840 u8 *mem;
3841 int sz, ii, num_chain;
3842 int scale, num_sge, numSGE;
3843
3844 /* ReqToChain size must equal the req_depth
3845 * index = req_idx
3846 */
3847 if (ioc->ReqToChain == NULL) {
3848 sz = ioc->req_depth * sizeof(int);
3849 mem = kmalloc(sz, GFP_ATOMIC);
3850 if (mem == NULL)
3851 return -1;
3852
3853 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303854 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 ioc->name, mem, sz));
3856 mem = kmalloc(sz, GFP_ATOMIC);
3857 if (mem == NULL)
3858 return -1;
3859
3860 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303861 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 ioc->name, mem, sz));
3863 }
3864 for (ii = 0; ii < ioc->req_depth; ii++) {
3865 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3866 }
3867
3868 /* ChainToChain size must equal the total number
3869 * of chain buffers to be allocated.
3870 * index = chain_idx
3871 *
3872 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003873 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 *
3875 * num_sge = num sge in request frame + last chain buffer
3876 * scale = num sge per chain buffer if no chain element
3877 */
3878 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3879 if (sizeof(dma_addr_t) == sizeof(u64))
3880 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3881 else
3882 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3883
3884 if (sizeof(dma_addr_t) == sizeof(u64)) {
3885 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3886 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3887 } else {
3888 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3889 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3890 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303891 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 ioc->name, num_sge, numSGE));
3893
3894 if ( numSGE > MPT_SCSI_SG_DEPTH )
3895 numSGE = MPT_SCSI_SG_DEPTH;
3896
3897 num_chain = 1;
3898 while (numSGE - num_sge > 0) {
3899 num_chain++;
3900 num_sge += (scale - 1);
3901 }
3902 num_chain++;
3903
Prakash, Sathya436ace72007-07-24 15:42:08 +05303904 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 ioc->name, numSGE, num_sge, num_chain));
3906
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003907 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 num_chain *= MPT_SCSI_CAN_QUEUE;
3909 else
3910 num_chain *= MPT_FC_CAN_QUEUE;
3911
3912 ioc->num_chain = num_chain;
3913
3914 sz = num_chain * sizeof(int);
3915 if (ioc->ChainToChain == NULL) {
3916 mem = kmalloc(sz, GFP_ATOMIC);
3917 if (mem == NULL)
3918 return -1;
3919
3920 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303921 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 ioc->name, mem, sz));
3923 } else {
3924 mem = (u8 *) ioc->ChainToChain;
3925 }
3926 memset(mem, 0xFF, sz);
3927 return num_chain;
3928}
3929
3930/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003931/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3933 * @ioc: Pointer to MPT_ADAPTER structure
3934 *
3935 * This routine allocates memory for the MPT reply and request frame
3936 * pools (if necessary), and primes the IOC reply FIFO with
3937 * reply frames.
3938 *
3939 * Returns 0 for success, non-zero for failure.
3940 */
3941static int
3942PrimeIocFifos(MPT_ADAPTER *ioc)
3943{
3944 MPT_FRAME_HDR *mf;
3945 unsigned long flags;
3946 dma_addr_t alloc_dma;
3947 u8 *mem;
3948 int i, reply_sz, sz, total_size, num_chain;
3949
3950 /* Prime reply FIFO... */
3951
3952 if (ioc->reply_frames == NULL) {
3953 if ( (num_chain = initChainBuffers(ioc)) < 0)
3954 return -1;
3955
3956 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303957 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303959 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 ioc->name, reply_sz, reply_sz));
3961
3962 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303963 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 ioc->name, sz, sz));
3967 total_size += sz;
3968
3969 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 ioc->name, sz, sz, num_chain));
3974
3975 total_size += sz;
3976 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3977 if (mem == NULL) {
3978 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3979 ioc->name);
3980 goto out_fail;
3981 }
3982
Prakash, Sathya436ace72007-07-24 15:42:08 +05303983 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3985
3986 memset(mem, 0, total_size);
3987 ioc->alloc_total += total_size;
3988 ioc->alloc = mem;
3989 ioc->alloc_dma = alloc_dma;
3990 ioc->alloc_sz = total_size;
3991 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3992 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3993
Prakash, Sathya436ace72007-07-24 15:42:08 +05303994 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003995 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3996
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 alloc_dma += reply_sz;
3998 mem += reply_sz;
3999
4000 /* Request FIFO - WE manage this! */
4001
4002 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4003 ioc->req_frames_dma = alloc_dma;
4004
Prakash, Sathya436ace72007-07-24 15:42:08 +05304005 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 ioc->name, mem, (void *)(ulong)alloc_dma));
4007
4008 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4009
4010#if defined(CONFIG_MTRR) && 0
4011 /*
4012 * Enable Write Combining MTRR for IOC's memory region.
4013 * (at least as much as we can; "size and base must be
4014 * multiples of 4 kiB"
4015 */
4016 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4017 sz,
4018 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304019 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 ioc->name, ioc->req_frames_dma, sz));
4021#endif
4022
4023 for (i = 0; i < ioc->req_depth; i++) {
4024 alloc_dma += ioc->req_sz;
4025 mem += ioc->req_sz;
4026 }
4027
4028 ioc->ChainBuffer = mem;
4029 ioc->ChainBufferDMA = alloc_dma;
4030
Prakash, Sathya436ace72007-07-24 15:42:08 +05304031 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4033
4034 /* Initialize the free chain Q.
4035 */
4036
4037 INIT_LIST_HEAD(&ioc->FreeChainQ);
4038
4039 /* Post the chain buffers to the FreeChainQ.
4040 */
4041 mem = (u8 *)ioc->ChainBuffer;
4042 for (i=0; i < num_chain; i++) {
4043 mf = (MPT_FRAME_HDR *) mem;
4044 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4045 mem += ioc->req_sz;
4046 }
4047
4048 /* Initialize Request frames linked list
4049 */
4050 alloc_dma = ioc->req_frames_dma;
4051 mem = (u8 *) ioc->req_frames;
4052
4053 spin_lock_irqsave(&ioc->FreeQlock, flags);
4054 INIT_LIST_HEAD(&ioc->FreeQ);
4055 for (i = 0; i < ioc->req_depth; i++) {
4056 mf = (MPT_FRAME_HDR *) mem;
4057
4058 /* Queue REQUESTs *internally*! */
4059 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4060
4061 mem += ioc->req_sz;
4062 }
4063 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4064
4065 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4066 ioc->sense_buf_pool =
4067 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4068 if (ioc->sense_buf_pool == NULL) {
4069 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4070 ioc->name);
4071 goto out_fail;
4072 }
4073
4074 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4075 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304076 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4078
4079 }
4080
4081 /* Post Reply frames to FIFO
4082 */
4083 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304084 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4086
4087 for (i = 0; i < ioc->reply_depth; i++) {
4088 /* Write each address to the IOC! */
4089 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4090 alloc_dma += ioc->reply_sz;
4091 }
4092
4093 return 0;
4094
4095out_fail:
4096 if (ioc->alloc != NULL) {
4097 sz = ioc->alloc_sz;
4098 pci_free_consistent(ioc->pcidev,
4099 sz,
4100 ioc->alloc, ioc->alloc_dma);
4101 ioc->reply_frames = NULL;
4102 ioc->req_frames = NULL;
4103 ioc->alloc_total -= sz;
4104 }
4105 if (ioc->sense_buf_pool != NULL) {
4106 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4107 pci_free_consistent(ioc->pcidev,
4108 sz,
4109 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4110 ioc->sense_buf_pool = NULL;
4111 }
4112 return -1;
4113}
4114
4115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4116/**
4117 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4118 * from IOC via doorbell handshake method.
4119 * @ioc: Pointer to MPT_ADAPTER structure
4120 * @reqBytes: Size of the request in bytes
4121 * @req: Pointer to MPT request frame
4122 * @replyBytes: Expected size of the reply in bytes
4123 * @u16reply: Pointer to area where reply should be written
4124 * @maxwait: Max wait time for a reply (in seconds)
4125 * @sleepFlag: Specifies whether the process can sleep
4126 *
4127 * NOTES: It is the callers responsibility to byte-swap fields in the
4128 * request which are greater than 1 byte in size. It is also the
4129 * callers responsibility to byte-swap response fields which are
4130 * greater than 1 byte in size.
4131 *
4132 * Returns 0 for success, non-zero for failure.
4133 */
4134static int
4135mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004136 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138 MPIDefaultReply_t *mptReply;
4139 int failcnt = 0;
4140 int t;
4141
4142 /*
4143 * Get ready to cache a handshake reply
4144 */
4145 ioc->hs_reply_idx = 0;
4146 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4147 mptReply->MsgLength = 0;
4148
4149 /*
4150 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4151 * then tell IOC that we want to handshake a request of N words.
4152 * (WRITE u32val to Doorbell reg).
4153 */
4154 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4155 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4156 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4157 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4158
4159 /*
4160 * Wait for IOC's doorbell handshake int
4161 */
4162 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4163 failcnt++;
4164
Prakash, Sathya436ace72007-07-24 15:42:08 +05304165 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4167
4168 /* Read doorbell and check for active bit */
4169 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4170 return -1;
4171
4172 /*
4173 * Clear doorbell int (WRITE 0 to IntStatus reg),
4174 * then wait for IOC to ACKnowledge that it's ready for
4175 * our handshake request.
4176 */
4177 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4178 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4179 failcnt++;
4180
4181 if (!failcnt) {
4182 int ii;
4183 u8 *req_as_bytes = (u8 *) req;
4184
4185 /*
4186 * Stuff request words via doorbell handshake,
4187 * with ACK from IOC for each.
4188 */
4189 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4190 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4191 (req_as_bytes[(ii*4) + 1] << 8) |
4192 (req_as_bytes[(ii*4) + 2] << 16) |
4193 (req_as_bytes[(ii*4) + 3] << 24));
4194
4195 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4196 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4197 failcnt++;
4198 }
4199
Prakash, Sathya436ace72007-07-24 15:42:08 +05304200 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004201 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202
Prakash, Sathya436ace72007-07-24 15:42:08 +05304203 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4205
4206 /*
4207 * Wait for completion of doorbell handshake reply from the IOC
4208 */
4209 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4210 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004211
Prakash, Sathya436ace72007-07-24 15:42:08 +05304212 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4214
4215 /*
4216 * Copy out the cached reply...
4217 */
4218 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4219 u16reply[ii] = ioc->hs_reply[ii];
4220 } else {
4221 return -99;
4222 }
4223
4224 return -failcnt;
4225}
4226
4227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004228/**
4229 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 * @ioc: Pointer to MPT_ADAPTER structure
4231 * @howlong: How long to wait (in seconds)
4232 * @sleepFlag: Specifies whether the process can sleep
4233 *
4234 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004235 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4236 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 *
4238 * Returns a negative value on failure, else wait loop count.
4239 */
4240static int
4241WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4242{
4243 int cntdn;
4244 int count = 0;
4245 u32 intstat=0;
4246
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004247 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
4249 if (sleepFlag == CAN_SLEEP) {
4250 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004251 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4253 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4254 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 count++;
4256 }
4257 } else {
4258 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004259 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4261 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4262 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 count++;
4264 }
4265 }
4266
4267 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304268 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 ioc->name, count));
4270 return count;
4271 }
4272
4273 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4274 ioc->name, count, intstat);
4275 return -1;
4276}
4277
4278/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004279/**
4280 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 * @ioc: Pointer to MPT_ADAPTER structure
4282 * @howlong: How long to wait (in seconds)
4283 * @sleepFlag: Specifies whether the process can sleep
4284 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004285 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4286 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 *
4288 * Returns a negative value on failure, else wait loop count.
4289 */
4290static int
4291WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4292{
4293 int cntdn;
4294 int count = 0;
4295 u32 intstat=0;
4296
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004297 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 if (sleepFlag == CAN_SLEEP) {
4299 while (--cntdn) {
4300 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4301 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4302 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004303 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 count++;
4305 }
4306 } else {
4307 while (--cntdn) {
4308 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4309 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4310 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004311 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 count++;
4313 }
4314 }
4315
4316 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304317 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 ioc->name, count, howlong));
4319 return count;
4320 }
4321
4322 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4323 ioc->name, count, intstat);
4324 return -1;
4325}
4326
4327/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004328/**
4329 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 * @ioc: Pointer to MPT_ADAPTER structure
4331 * @howlong: How long to wait (in seconds)
4332 * @sleepFlag: Specifies whether the process can sleep
4333 *
4334 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4335 * Reply is cached to IOC private area large enough to hold a maximum
4336 * of 128 bytes of reply data.
4337 *
4338 * Returns a negative value on failure, else size of reply in WORDS.
4339 */
4340static int
4341WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4342{
4343 int u16cnt = 0;
4344 int failcnt = 0;
4345 int t;
4346 u16 *hs_reply = ioc->hs_reply;
4347 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4348 u16 hword;
4349
4350 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4351
4352 /*
4353 * Get first two u16's so we can look at IOC's intended reply MsgLength
4354 */
4355 u16cnt=0;
4356 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4357 failcnt++;
4358 } else {
4359 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4360 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4361 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4362 failcnt++;
4363 else {
4364 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4365 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4366 }
4367 }
4368
Prakash, Sathya436ace72007-07-24 15:42:08 +05304369 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004370 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4372
4373 /*
4374 * If no error (and IOC said MsgLength is > 0), piece together
4375 * reply 16 bits at a time.
4376 */
4377 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4378 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4379 failcnt++;
4380 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4381 /* don't overflow our IOC hs_reply[] buffer! */
4382 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4383 hs_reply[u16cnt] = hword;
4384 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4385 }
4386
4387 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4388 failcnt++;
4389 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4390
4391 if (failcnt) {
4392 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4393 ioc->name);
4394 return -failcnt;
4395 }
4396#if 0
4397 else if (u16cnt != (2 * mptReply->MsgLength)) {
4398 return -101;
4399 }
4400 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4401 return -102;
4402 }
4403#endif
4404
Prakash, Sathya436ace72007-07-24 15:42:08 +05304405 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004406 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
Prakash, Sathya436ace72007-07-24 15:42:08 +05304408 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 ioc->name, t, u16cnt/2));
4410 return u16cnt/2;
4411}
4412
4413/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004414/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 * GetLanConfigPages - Fetch LANConfig pages.
4416 * @ioc: Pointer to MPT_ADAPTER structure
4417 *
4418 * Return: 0 for success
4419 * -ENOMEM if no memory available
4420 * -EPERM if not allowed due to ISR context
4421 * -EAGAIN if no msg frames currently available
4422 * -EFAULT for non-successful reply or no reply (timeout)
4423 */
4424static int
4425GetLanConfigPages(MPT_ADAPTER *ioc)
4426{
4427 ConfigPageHeader_t hdr;
4428 CONFIGPARMS cfg;
4429 LANPage0_t *ppage0_alloc;
4430 dma_addr_t page0_dma;
4431 LANPage1_t *ppage1_alloc;
4432 dma_addr_t page1_dma;
4433 int rc = 0;
4434 int data_sz;
4435 int copy_sz;
4436
4437 /* Get LAN Page 0 header */
4438 hdr.PageVersion = 0;
4439 hdr.PageLength = 0;
4440 hdr.PageNumber = 0;
4441 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004442 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 cfg.physAddr = -1;
4444 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4445 cfg.dir = 0;
4446 cfg.pageAddr = 0;
4447 cfg.timeout = 0;
4448
4449 if ((rc = mpt_config(ioc, &cfg)) != 0)
4450 return rc;
4451
4452 if (hdr.PageLength > 0) {
4453 data_sz = hdr.PageLength * 4;
4454 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4455 rc = -ENOMEM;
4456 if (ppage0_alloc) {
4457 memset((u8 *)ppage0_alloc, 0, data_sz);
4458 cfg.physAddr = page0_dma;
4459 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4460
4461 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4462 /* save the data */
4463 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4464 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4465
4466 }
4467
4468 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4469
4470 /* FIXME!
4471 * Normalize endianness of structure data,
4472 * by byte-swapping all > 1 byte fields!
4473 */
4474
4475 }
4476
4477 if (rc)
4478 return rc;
4479 }
4480
4481 /* Get LAN Page 1 header */
4482 hdr.PageVersion = 0;
4483 hdr.PageLength = 0;
4484 hdr.PageNumber = 1;
4485 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004486 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 cfg.physAddr = -1;
4488 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4489 cfg.dir = 0;
4490 cfg.pageAddr = 0;
4491
4492 if ((rc = mpt_config(ioc, &cfg)) != 0)
4493 return rc;
4494
4495 if (hdr.PageLength == 0)
4496 return 0;
4497
4498 data_sz = hdr.PageLength * 4;
4499 rc = -ENOMEM;
4500 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4501 if (ppage1_alloc) {
4502 memset((u8 *)ppage1_alloc, 0, data_sz);
4503 cfg.physAddr = page1_dma;
4504 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4505
4506 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4507 /* save the data */
4508 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4509 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4510 }
4511
4512 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4513
4514 /* FIXME!
4515 * Normalize endianness of structure data,
4516 * by byte-swapping all > 1 byte fields!
4517 */
4518
4519 }
4520
4521 return rc;
4522}
4523
4524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004525/**
4526 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004527 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004528 * @persist_opcode: see below
4529 *
4530 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4531 * devices not currently present.
4532 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4533 *
4534 * NOTE: Don't use not this function during interrupt time.
4535 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004536 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004537 */
4538
4539/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4540int
4541mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4542{
4543 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4544 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4545 MPT_FRAME_HDR *mf = NULL;
4546 MPIHeader_t *mpi_hdr;
4547
4548
4549 /* insure garbage is not sent to fw */
4550 switch(persist_opcode) {
4551
4552 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4553 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4554 break;
4555
4556 default:
4557 return -1;
4558 break;
4559 }
4560
4561 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4562
4563 /* Get a MF for this command.
4564 */
4565 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4566 printk("%s: no msg frames!\n",__FUNCTION__);
4567 return -1;
4568 }
4569
4570 mpi_hdr = (MPIHeader_t *) mf;
4571 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4572 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4573 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4574 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4575 sasIoUnitCntrReq->Operation = persist_opcode;
4576
4577 init_timer(&ioc->persist_timer);
4578 ioc->persist_timer.data = (unsigned long) ioc;
4579 ioc->persist_timer.function = mpt_timer_expired;
4580 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4581 ioc->persist_wait_done=0;
4582 add_timer(&ioc->persist_timer);
4583 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4584 wait_event(mpt_waitq, ioc->persist_wait_done);
4585
4586 sasIoUnitCntrReply =
4587 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4588 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4589 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4590 __FUNCTION__,
4591 sasIoUnitCntrReply->IOCStatus,
4592 sasIoUnitCntrReply->IOCLogInfo);
4593 return -1;
4594 }
4595
4596 printk("%s: success\n",__FUNCTION__);
4597 return 0;
4598}
4599
4600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004601
4602static void
4603mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4604 MpiEventDataRaid_t * pRaidEventData)
4605{
4606 int volume;
4607 int reason;
4608 int disk;
4609 int status;
4610 int flags;
4611 int state;
4612
4613 volume = pRaidEventData->VolumeID;
4614 reason = pRaidEventData->ReasonCode;
4615 disk = pRaidEventData->PhysDiskNum;
4616 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4617 flags = (status >> 0) & 0xff;
4618 state = (status >> 8) & 0xff;
4619
4620 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4621 return;
4622 }
4623
4624 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4625 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4626 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004627 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4628 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004629 } else {
4630 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4631 ioc->name, volume);
4632 }
4633
4634 switch(reason) {
4635 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4636 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4637 ioc->name);
4638 break;
4639
4640 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4641
4642 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4643 ioc->name);
4644 break;
4645
4646 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4647 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4648 ioc->name);
4649 break;
4650
4651 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4652 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4653 ioc->name,
4654 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4655 ? "optimal"
4656 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4657 ? "degraded"
4658 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4659 ? "failed"
4660 : "state unknown",
4661 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4662 ? ", enabled" : "",
4663 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4664 ? ", quiesced" : "",
4665 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4666 ? ", resync in progress" : "" );
4667 break;
4668
4669 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4670 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4671 ioc->name, disk);
4672 break;
4673
4674 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4675 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4676 ioc->name);
4677 break;
4678
4679 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4680 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4681 ioc->name);
4682 break;
4683
4684 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4685 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4686 ioc->name);
4687 break;
4688
4689 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4690 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4691 ioc->name,
4692 state == MPI_PHYSDISK0_STATUS_ONLINE
4693 ? "online"
4694 : state == MPI_PHYSDISK0_STATUS_MISSING
4695 ? "missing"
4696 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4697 ? "not compatible"
4698 : state == MPI_PHYSDISK0_STATUS_FAILED
4699 ? "failed"
4700 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4701 ? "initializing"
4702 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4703 ? "offline requested"
4704 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4705 ? "failed requested"
4706 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4707 ? "offline"
4708 : "state unknown",
4709 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4710 ? ", out of sync" : "",
4711 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4712 ? ", quiesced" : "" );
4713 break;
4714
4715 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4716 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4717 ioc->name, disk);
4718 break;
4719
4720 case MPI_EVENT_RAID_RC_SMART_DATA:
4721 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4722 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4723 break;
4724
4725 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4726 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4727 ioc->name, disk);
4728 break;
4729 }
4730}
4731
4732/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004733/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4735 * @ioc: Pointer to MPT_ADAPTER structure
4736 *
4737 * Returns: 0 for success
4738 * -ENOMEM if no memory available
4739 * -EPERM if not allowed due to ISR context
4740 * -EAGAIN if no msg frames currently available
4741 * -EFAULT for non-successful reply or no reply (timeout)
4742 */
4743static int
4744GetIoUnitPage2(MPT_ADAPTER *ioc)
4745{
4746 ConfigPageHeader_t hdr;
4747 CONFIGPARMS cfg;
4748 IOUnitPage2_t *ppage_alloc;
4749 dma_addr_t page_dma;
4750 int data_sz;
4751 int rc;
4752
4753 /* Get the page header */
4754 hdr.PageVersion = 0;
4755 hdr.PageLength = 0;
4756 hdr.PageNumber = 2;
4757 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004758 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 cfg.physAddr = -1;
4760 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4761 cfg.dir = 0;
4762 cfg.pageAddr = 0;
4763 cfg.timeout = 0;
4764
4765 if ((rc = mpt_config(ioc, &cfg)) != 0)
4766 return rc;
4767
4768 if (hdr.PageLength == 0)
4769 return 0;
4770
4771 /* Read the config page */
4772 data_sz = hdr.PageLength * 4;
4773 rc = -ENOMEM;
4774 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4775 if (ppage_alloc) {
4776 memset((u8 *)ppage_alloc, 0, data_sz);
4777 cfg.physAddr = page_dma;
4778 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4779
4780 /* If Good, save data */
4781 if ((rc = mpt_config(ioc, &cfg)) == 0)
4782 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4783
4784 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4785 }
4786
4787 return rc;
4788}
4789
4790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004791/**
4792 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 * @ioc: Pointer to a Adapter Strucutre
4794 * @portnum: IOC port number
4795 *
4796 * Return: -EFAULT if read of config page header fails
4797 * or if no nvram
4798 * If read of SCSI Port Page 0 fails,
4799 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4800 * Adapter settings: async, narrow
4801 * Return 1
4802 * If read of SCSI Port Page 2 fails,
4803 * Adapter settings valid
4804 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4805 * Return 1
4806 * Else
4807 * Both valid
4808 * Return 0
4809 * CHECK - what type of locking mechanisms should be used????
4810 */
4811static int
4812mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4813{
4814 u8 *pbuf;
4815 dma_addr_t buf_dma;
4816 CONFIGPARMS cfg;
4817 ConfigPageHeader_t header;
4818 int ii;
4819 int data, rc = 0;
4820
4821 /* Allocate memory
4822 */
4823 if (!ioc->spi_data.nvram) {
4824 int sz;
4825 u8 *mem;
4826 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4827 mem = kmalloc(sz, GFP_ATOMIC);
4828 if (mem == NULL)
4829 return -EFAULT;
4830
4831 ioc->spi_data.nvram = (int *) mem;
4832
Prakash, Sathya436ace72007-07-24 15:42:08 +05304833 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 ioc->name, ioc->spi_data.nvram, sz));
4835 }
4836
4837 /* Invalidate NVRAM information
4838 */
4839 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4840 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4841 }
4842
4843 /* Read SPP0 header, allocate memory, then read page.
4844 */
4845 header.PageVersion = 0;
4846 header.PageLength = 0;
4847 header.PageNumber = 0;
4848 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004849 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 cfg.physAddr = -1;
4851 cfg.pageAddr = portnum;
4852 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4853 cfg.dir = 0;
4854 cfg.timeout = 0; /* use default */
4855 if (mpt_config(ioc, &cfg) != 0)
4856 return -EFAULT;
4857
4858 if (header.PageLength > 0) {
4859 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4860 if (pbuf) {
4861 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4862 cfg.physAddr = buf_dma;
4863 if (mpt_config(ioc, &cfg) != 0) {
4864 ioc->spi_data.maxBusWidth = MPT_NARROW;
4865 ioc->spi_data.maxSyncOffset = 0;
4866 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4867 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4868 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304869 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4870 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004871 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 } else {
4873 /* Save the Port Page 0 data
4874 */
4875 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4876 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4877 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4878
4879 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4880 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004881 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4882 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 ioc->name, pPP0->Capabilities));
4884 }
4885 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4886 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4887 if (data) {
4888 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4889 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4890 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304891 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4892 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004893 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 } else {
4895 ioc->spi_data.maxSyncOffset = 0;
4896 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4897 }
4898
4899 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4900
4901 /* Update the minSyncFactor based on bus type.
4902 */
4903 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4904 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4905
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004906 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304908 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4909 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004910 ioc->name, ioc->spi_data.minSyncFactor));
4911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 }
4913 }
4914 if (pbuf) {
4915 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4916 }
4917 }
4918 }
4919
4920 /* SCSI Port Page 2 - Read the header then the page.
4921 */
4922 header.PageVersion = 0;
4923 header.PageLength = 0;
4924 header.PageNumber = 2;
4925 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004926 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 cfg.physAddr = -1;
4928 cfg.pageAddr = portnum;
4929 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4930 cfg.dir = 0;
4931 if (mpt_config(ioc, &cfg) != 0)
4932 return -EFAULT;
4933
4934 if (header.PageLength > 0) {
4935 /* Allocate memory and read SCSI Port Page 2
4936 */
4937 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4938 if (pbuf) {
4939 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4940 cfg.physAddr = buf_dma;
4941 if (mpt_config(ioc, &cfg) != 0) {
4942 /* Nvram data is left with INVALID mark
4943 */
4944 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004945 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4946
4947 /* This is an ATTO adapter, read Page2 accordingly
4948 */
4949 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4950 ATTODeviceInfo_t *pdevice = NULL;
4951 u16 ATTOFlags;
4952
4953 /* Save the Port Page 2 data
4954 * (reformat into a 32bit quantity)
4955 */
4956 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4957 pdevice = &pPP2->DeviceSettings[ii];
4958 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4959 data = 0;
4960
4961 /* Translate ATTO device flags to LSI format
4962 */
4963 if (ATTOFlags & ATTOFLAG_DISC)
4964 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4965 if (ATTOFlags & ATTOFLAG_ID_ENB)
4966 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4967 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4968 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4969 if (ATTOFlags & ATTOFLAG_TAGGED)
4970 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4971 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4972 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4973
4974 data = (data << 16) | (pdevice->Period << 8) | 10;
4975 ioc->spi_data.nvram[ii] = data;
4976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 } else {
4978 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4979 MpiDeviceInfo_t *pdevice = NULL;
4980
Moore, Ericd8e925d2006-01-16 18:53:06 -07004981 /*
4982 * Save "Set to Avoid SCSI Bus Resets" flag
4983 */
4984 ioc->spi_data.bus_reset =
4985 (le32_to_cpu(pPP2->PortFlags) &
4986 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4987 0 : 1 ;
4988
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989 /* Save the Port Page 2 data
4990 * (reformat into a 32bit quantity)
4991 */
4992 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4993 ioc->spi_data.PortFlags = data;
4994 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4995 pdevice = &pPP2->DeviceSettings[ii];
4996 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4997 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4998 ioc->spi_data.nvram[ii] = data;
4999 }
5000 }
5001
5002 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5003 }
5004 }
5005
5006 /* Update Adapter limits with those from NVRAM
5007 * Comment: Don't need to do this. Target performance
5008 * parameters will never exceed the adapters limits.
5009 */
5010
5011 return rc;
5012}
5013
5014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005015/**
5016 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 * @ioc: Pointer to a Adapter Strucutre
5018 * @portnum: IOC port number
5019 *
5020 * Return: -EFAULT if read of config page header fails
5021 * or 0 if success.
5022 */
5023static int
5024mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5025{
5026 CONFIGPARMS cfg;
5027 ConfigPageHeader_t header;
5028
5029 /* Read the SCSI Device Page 1 header
5030 */
5031 header.PageVersion = 0;
5032 header.PageLength = 0;
5033 header.PageNumber = 1;
5034 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005035 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 cfg.physAddr = -1;
5037 cfg.pageAddr = portnum;
5038 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5039 cfg.dir = 0;
5040 cfg.timeout = 0;
5041 if (mpt_config(ioc, &cfg) != 0)
5042 return -EFAULT;
5043
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005044 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5045 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046
5047 header.PageVersion = 0;
5048 header.PageLength = 0;
5049 header.PageNumber = 0;
5050 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5051 if (mpt_config(ioc, &cfg) != 0)
5052 return -EFAULT;
5053
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005054 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5055 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Prakash, Sathya436ace72007-07-24 15:42:08 +05305057 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5059
Prakash, Sathya436ace72007-07-24 15:42:08 +05305060 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5062 return 0;
5063}
5064
Eric Mooreb506ade2007-01-29 09:45:37 -07005065/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005066 * mpt_inactive_raid_list_free - This clears this link list.
5067 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005068 **/
5069static void
5070mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5071{
5072 struct inactive_raid_component_info *component_info, *pNext;
5073
5074 if (list_empty(&ioc->raid_data.inactive_list))
5075 return;
5076
5077 down(&ioc->raid_data.inactive_list_mutex);
5078 list_for_each_entry_safe(component_info, pNext,
5079 &ioc->raid_data.inactive_list, list) {
5080 list_del(&component_info->list);
5081 kfree(component_info);
5082 }
5083 up(&ioc->raid_data.inactive_list_mutex);
5084}
5085
5086/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005087 * 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 -07005088 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005089 * @ioc : pointer to per adapter structure
5090 * @channel : volume channel
5091 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005092 **/
5093static void
5094mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5095{
5096 CONFIGPARMS cfg;
5097 ConfigPageHeader_t hdr;
5098 dma_addr_t dma_handle;
5099 pRaidVolumePage0_t buffer = NULL;
5100 int i;
5101 RaidPhysDiskPage0_t phys_disk;
5102 struct inactive_raid_component_info *component_info;
5103 int handle_inactive_volumes;
5104
5105 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5106 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5107 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5108 cfg.pageAddr = (channel << 8) + id;
5109 cfg.cfghdr.hdr = &hdr;
5110 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5111
5112 if (mpt_config(ioc, &cfg) != 0)
5113 goto out;
5114
5115 if (!hdr.PageLength)
5116 goto out;
5117
5118 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5119 &dma_handle);
5120
5121 if (!buffer)
5122 goto out;
5123
5124 cfg.physAddr = dma_handle;
5125 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5126
5127 if (mpt_config(ioc, &cfg) != 0)
5128 goto out;
5129
5130 if (!buffer->NumPhysDisks)
5131 goto out;
5132
5133 handle_inactive_volumes =
5134 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5135 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5136 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5137 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5138
5139 if (!handle_inactive_volumes)
5140 goto out;
5141
5142 down(&ioc->raid_data.inactive_list_mutex);
5143 for (i = 0; i < buffer->NumPhysDisks; i++) {
5144 if(mpt_raid_phys_disk_pg0(ioc,
5145 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5146 continue;
5147
5148 if ((component_info = kmalloc(sizeof (*component_info),
5149 GFP_KERNEL)) == NULL)
5150 continue;
5151
5152 component_info->volumeID = id;
5153 component_info->volumeBus = channel;
5154 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5155 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5156 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5157 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5158
5159 list_add_tail(&component_info->list,
5160 &ioc->raid_data.inactive_list);
5161 }
5162 up(&ioc->raid_data.inactive_list_mutex);
5163
5164 out:
5165 if (buffer)
5166 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5167 dma_handle);
5168}
5169
5170/**
5171 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5172 * @ioc: Pointer to a Adapter Structure
5173 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5174 * @phys_disk: requested payload data returned
5175 *
5176 * Return:
5177 * 0 on success
5178 * -EFAULT if read of config page header fails or data pointer not NULL
5179 * -ENOMEM if pci_alloc failed
5180 **/
5181int
5182mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5183{
5184 CONFIGPARMS cfg;
5185 ConfigPageHeader_t hdr;
5186 dma_addr_t dma_handle;
5187 pRaidPhysDiskPage0_t buffer = NULL;
5188 int rc;
5189
5190 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5191 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5192
5193 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5194 cfg.cfghdr.hdr = &hdr;
5195 cfg.physAddr = -1;
5196 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5197
5198 if (mpt_config(ioc, &cfg) != 0) {
5199 rc = -EFAULT;
5200 goto out;
5201 }
5202
5203 if (!hdr.PageLength) {
5204 rc = -EFAULT;
5205 goto out;
5206 }
5207
5208 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5209 &dma_handle);
5210
5211 if (!buffer) {
5212 rc = -ENOMEM;
5213 goto out;
5214 }
5215
5216 cfg.physAddr = dma_handle;
5217 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5218 cfg.pageAddr = phys_disk_num;
5219
5220 if (mpt_config(ioc, &cfg) != 0) {
5221 rc = -EFAULT;
5222 goto out;
5223 }
5224
5225 rc = 0;
5226 memcpy(phys_disk, buffer, sizeof(*buffer));
5227 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5228
5229 out:
5230
5231 if (buffer)
5232 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5233 dma_handle);
5234
5235 return rc;
5236}
5237
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238/**
5239 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5240 * @ioc: Pointer to a Adapter Strucutre
5241 * @portnum: IOC port number
5242 *
5243 * Return:
5244 * 0 on success
5245 * -EFAULT if read of config page header fails or data pointer not NULL
5246 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005247 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248int
5249mpt_findImVolumes(MPT_ADAPTER *ioc)
5250{
5251 IOCPage2_t *pIoc2;
5252 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 dma_addr_t ioc2_dma;
5254 CONFIGPARMS cfg;
5255 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 int rc = 0;
5257 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005258 int i;
5259
5260 if (!ioc->ir_firmware)
5261 return 0;
5262
5263 /* Free the old page
5264 */
5265 kfree(ioc->raid_data.pIocPg2);
5266 ioc->raid_data.pIocPg2 = NULL;
5267 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
5269 /* Read IOCP2 header then the page.
5270 */
5271 header.PageVersion = 0;
5272 header.PageLength = 0;
5273 header.PageNumber = 2;
5274 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005275 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 cfg.physAddr = -1;
5277 cfg.pageAddr = 0;
5278 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5279 cfg.dir = 0;
5280 cfg.timeout = 0;
5281 if (mpt_config(ioc, &cfg) != 0)
5282 return -EFAULT;
5283
5284 if (header.PageLength == 0)
5285 return -EFAULT;
5286
5287 iocpage2sz = header.PageLength * 4;
5288 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5289 if (!pIoc2)
5290 return -ENOMEM;
5291
5292 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5293 cfg.physAddr = ioc2_dma;
5294 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005295 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296
Eric Mooreb506ade2007-01-29 09:45:37 -07005297 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5298 if (!mem)
5299 goto out;
5300
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005302 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
Eric Mooreb506ade2007-01-29 09:45:37 -07005304 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
Eric Mooreb506ade2007-01-29 09:45:37 -07005306 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5307 mpt_inactive_raid_volumes(ioc,
5308 pIoc2->RaidVolume[i].VolumeBus,
5309 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310
Eric Mooreb506ade2007-01-29 09:45:37 -07005311 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5313
5314 return rc;
5315}
5316
Moore, Ericc972c702006-03-14 09:14:06 -07005317static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5319{
5320 IOCPage3_t *pIoc3;
5321 u8 *mem;
5322 CONFIGPARMS cfg;
5323 ConfigPageHeader_t header;
5324 dma_addr_t ioc3_dma;
5325 int iocpage3sz = 0;
5326
5327 /* Free the old page
5328 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005329 kfree(ioc->raid_data.pIocPg3);
5330 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331
5332 /* There is at least one physical disk.
5333 * Read and save IOC Page 3
5334 */
5335 header.PageVersion = 0;
5336 header.PageLength = 0;
5337 header.PageNumber = 3;
5338 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005339 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 cfg.physAddr = -1;
5341 cfg.pageAddr = 0;
5342 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5343 cfg.dir = 0;
5344 cfg.timeout = 0;
5345 if (mpt_config(ioc, &cfg) != 0)
5346 return 0;
5347
5348 if (header.PageLength == 0)
5349 return 0;
5350
5351 /* Read Header good, alloc memory
5352 */
5353 iocpage3sz = header.PageLength * 4;
5354 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5355 if (!pIoc3)
5356 return 0;
5357
5358 /* Read the Page and save the data
5359 * into malloc'd memory.
5360 */
5361 cfg.physAddr = ioc3_dma;
5362 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5363 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005364 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 if (mem) {
5366 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005367 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368 }
5369 }
5370
5371 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5372
5373 return 0;
5374}
5375
5376static void
5377mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5378{
5379 IOCPage4_t *pIoc4;
5380 CONFIGPARMS cfg;
5381 ConfigPageHeader_t header;
5382 dma_addr_t ioc4_dma;
5383 int iocpage4sz;
5384
5385 /* Read and save IOC Page 4
5386 */
5387 header.PageVersion = 0;
5388 header.PageLength = 0;
5389 header.PageNumber = 4;
5390 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005391 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 cfg.physAddr = -1;
5393 cfg.pageAddr = 0;
5394 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5395 cfg.dir = 0;
5396 cfg.timeout = 0;
5397 if (mpt_config(ioc, &cfg) != 0)
5398 return;
5399
5400 if (header.PageLength == 0)
5401 return;
5402
5403 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5404 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5405 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5406 if (!pIoc4)
5407 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005408 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 } else {
5410 ioc4_dma = ioc->spi_data.IocPg4_dma;
5411 iocpage4sz = ioc->spi_data.IocPg4Sz;
5412 }
5413
5414 /* Read the Page into dma memory.
5415 */
5416 cfg.physAddr = ioc4_dma;
5417 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5418 if (mpt_config(ioc, &cfg) == 0) {
5419 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5420 ioc->spi_data.IocPg4_dma = ioc4_dma;
5421 ioc->spi_data.IocPg4Sz = iocpage4sz;
5422 } else {
5423 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5424 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005425 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 }
5427}
5428
5429static void
5430mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5431{
5432 IOCPage1_t *pIoc1;
5433 CONFIGPARMS cfg;
5434 ConfigPageHeader_t header;
5435 dma_addr_t ioc1_dma;
5436 int iocpage1sz = 0;
5437 u32 tmp;
5438
5439 /* Check the Coalescing Timeout in IOC Page 1
5440 */
5441 header.PageVersion = 0;
5442 header.PageLength = 0;
5443 header.PageNumber = 1;
5444 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005445 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 cfg.physAddr = -1;
5447 cfg.pageAddr = 0;
5448 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5449 cfg.dir = 0;
5450 cfg.timeout = 0;
5451 if (mpt_config(ioc, &cfg) != 0)
5452 return;
5453
5454 if (header.PageLength == 0)
5455 return;
5456
5457 /* Read Header good, alloc memory
5458 */
5459 iocpage1sz = header.PageLength * 4;
5460 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5461 if (!pIoc1)
5462 return;
5463
5464 /* Read the Page and check coalescing timeout
5465 */
5466 cfg.physAddr = ioc1_dma;
5467 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5468 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305469
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5471 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5472 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5473
Prakash, Sathya436ace72007-07-24 15:42:08 +05305474 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 ioc->name, tmp));
5476
5477 if (tmp > MPT_COALESCING_TIMEOUT) {
5478 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5479
5480 /* Write NVRAM and current
5481 */
5482 cfg.dir = 1;
5483 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5484 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305485 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 ioc->name, MPT_COALESCING_TIMEOUT));
5487
5488 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5489 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305490 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5491 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 ioc->name, MPT_COALESCING_TIMEOUT));
5493 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305494 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5495 "Reset NVRAM Coalescing Timeout Failed\n",
5496 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 }
5498
5499 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305500 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5501 "Reset of Current Coalescing Timeout Failed!\n",
5502 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 }
5504 }
5505
5506 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305507 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 }
5509 }
5510
5511 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5512
5513 return;
5514}
5515
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305516static void
5517mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5518{
5519 CONFIGPARMS cfg;
5520 ConfigPageHeader_t hdr;
5521 dma_addr_t buf_dma;
5522 ManufacturingPage0_t *pbuf = NULL;
5523
5524 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5525 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5526
5527 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5528 cfg.cfghdr.hdr = &hdr;
5529 cfg.physAddr = -1;
5530 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5531 cfg.timeout = 10;
5532
5533 if (mpt_config(ioc, &cfg) != 0)
5534 goto out;
5535
5536 if (!cfg.cfghdr.hdr->PageLength)
5537 goto out;
5538
5539 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5540 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5541 if (!pbuf)
5542 goto out;
5543
5544 cfg.physAddr = buf_dma;
5545
5546 if (mpt_config(ioc, &cfg) != 0)
5547 goto out;
5548
5549 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5550 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5551 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5552
5553 out:
5554
5555 if (pbuf)
5556 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5557}
5558
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005560/**
5561 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 * @ioc: Pointer to MPT_ADAPTER structure
5563 * @EvSwitch: Event switch flags
5564 */
5565static int
5566SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5567{
5568 EventNotification_t *evnp;
5569
5570 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5571 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305572 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 ioc->name));
5574 return 0;
5575 }
5576 memset(evnp, 0, sizeof(*evnp));
5577
Prakash, Sathya436ace72007-07-24 15:42:08 +05305578 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579
5580 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5581 evnp->ChainOffset = 0;
5582 evnp->MsgFlags = 0;
5583 evnp->Switch = EvSwitch;
5584
5585 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5586
5587 return 0;
5588}
5589
5590/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5591/**
5592 * SendEventAck - Send EventAck request to MPT adapter.
5593 * @ioc: Pointer to MPT_ADAPTER structure
5594 * @evnp: Pointer to original EventNotification request
5595 */
5596static int
5597SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5598{
5599 EventAck_t *pAck;
5600
5601 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305602 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005603 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 return -1;
5605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
Prakash, Sathya436ace72007-07-24 15:42:08 +05305607 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608
5609 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5610 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005611 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005613 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 pAck->Event = evnp->Event;
5615 pAck->EventContext = evnp->EventContext;
5616
5617 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5618
5619 return 0;
5620}
5621
5622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5623/**
5624 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005625 * @ioc: Pointer to an adapter structure
5626 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 * action, page address, direction, physical address
5628 * and pointer to a configuration page header
5629 * Page header is updated.
5630 *
5631 * Returns 0 for success
5632 * -EPERM if not allowed due to ISR context
5633 * -EAGAIN if no msg frames currently available
5634 * -EFAULT for non-successful reply or no reply (timeout)
5635 */
5636int
5637mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5638{
5639 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005640 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 MPT_FRAME_HDR *mf;
5642 unsigned long flags;
5643 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005644 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 int in_isr;
5646
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005647 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 * to be in ISR context, because that is fatal!
5649 */
5650 in_isr = in_interrupt();
5651 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305652 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 ioc->name));
5654 return -EPERM;
5655 }
5656
5657 /* Get and Populate a free Frame
5658 */
5659 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305660 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 ioc->name));
5662 return -EAGAIN;
5663 }
5664 pReq = (Config_t *)mf;
5665 pReq->Action = pCfg->action;
5666 pReq->Reserved = 0;
5667 pReq->ChainOffset = 0;
5668 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005669
5670 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 pReq->ExtPageLength = 0;
5672 pReq->ExtPageType = 0;
5673 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 for (ii=0; ii < 8; ii++)
5676 pReq->Reserved2[ii] = 0;
5677
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005678 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5679 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5680 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5681 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5682
5683 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5684 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5685 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5686 pReq->ExtPageType = pExtHdr->ExtPageType;
5687 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5688
5689 /* Page Length must be treated as a reserved field for the extended header. */
5690 pReq->Header.PageLength = 0;
5691 }
5692
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5694
5695 /* Add a SGE to the config request.
5696 */
5697 if (pCfg->dir)
5698 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5699 else
5700 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5701
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005702 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5703 flagsLength |= pExtHdr->ExtPageLength * 4;
5704
Prakash, Sathya436ace72007-07-24 15:42:08 +05305705 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 +02005706 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5707 }
5708 else {
5709 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5710
Prakash, Sathya436ace72007-07-24 15:42:08 +05305711 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 +02005712 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
5715 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5716
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 /* Append pCfg pointer to end of mf
5718 */
5719 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5720
5721 /* Initalize the timer
5722 */
5723 init_timer(&pCfg->timer);
5724 pCfg->timer.data = (unsigned long) ioc;
5725 pCfg->timer.function = mpt_timer_expired;
5726 pCfg->wait_done = 0;
5727
5728 /* Set the timer; ensure 10 second minimum */
5729 if (pCfg->timeout < 10)
5730 pCfg->timer.expires = jiffies + HZ*10;
5731 else
5732 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5733
5734 /* Add to end of Q, set timer and then issue this command */
5735 spin_lock_irqsave(&ioc->FreeQlock, flags);
5736 list_add_tail(&pCfg->linkage, &ioc->configQ);
5737 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5738
5739 add_timer(&pCfg->timer);
5740 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5741 wait_event(mpt_waitq, pCfg->wait_done);
5742
5743 /* mf has been freed - do not access */
5744
5745 rc = pCfg->status;
5746
5747 return rc;
5748}
5749
5750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005751/**
5752 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 * Used only internal config functionality.
5754 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5755 */
5756static void
5757mpt_timer_expired(unsigned long data)
5758{
5759 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5760
Prakash, Sathya436ace72007-07-24 15:42:08 +05305761 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
5763 /* Perform a FW reload */
5764 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5765 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5766
5767 /* No more processing.
5768 * Hard reset clean-up will wake up
5769 * process and free all resources.
5770 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305771 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
5773 return;
5774}
5775
5776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005777/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 * mpt_ioc_reset - Base cleanup for hard reset
5779 * @ioc: Pointer to the adapter structure
5780 * @reset_phase: Indicates pre- or post-reset functionality
5781 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005782 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 */
5784static int
5785mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5786{
5787 CONFIGPARMS *pCfg;
5788 unsigned long flags;
5789
Eric Moore29dd3602007-09-14 18:46:51 -06005790 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5791 ": IOC %s_reset routed to MPT base driver!\n",
5792 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5793 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
5795 if (reset_phase == MPT_IOC_SETUP_RESET) {
5796 ;
5797 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5798 /* If the internal config Q is not empty -
5799 * delete timer. MF resources will be freed when
5800 * the FIFO's are primed.
5801 */
5802 spin_lock_irqsave(&ioc->FreeQlock, flags);
5803 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5804 del_timer(&pCfg->timer);
5805 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5806
5807 } else {
5808 CONFIGPARMS *pNext;
5809
5810 /* Search the configQ for internal commands.
5811 * Flush the Q, and wake up all suspended threads.
5812 */
5813 spin_lock_irqsave(&ioc->FreeQlock, flags);
5814 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5815 list_del(&pCfg->linkage);
5816
5817 pCfg->status = MPT_CONFIG_ERROR;
5818 pCfg->wait_done = 1;
5819 wake_up(&mpt_waitq);
5820 }
5821 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5822 }
5823
5824 return 1; /* currently means nothing really */
5825}
5826
5827
5828#ifdef CONFIG_PROC_FS /* { */
5829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5830/*
5831 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5832 */
5833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005834/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5836 *
5837 * Returns 0 for success, non-zero for failure.
5838 */
5839static int
5840procmpt_create(void)
5841{
5842 struct proc_dir_entry *ent;
5843
5844 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5845 if (mpt_proc_root_dir == NULL)
5846 return -ENOTDIR;
5847
5848 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5849 if (ent)
5850 ent->read_proc = procmpt_summary_read;
5851
5852 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5853 if (ent)
5854 ent->read_proc = procmpt_version_read;
5855
5856 return 0;
5857}
5858
5859/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005860/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5862 *
5863 * Returns 0 for success, non-zero for failure.
5864 */
5865static void
5866procmpt_destroy(void)
5867{
5868 remove_proc_entry("version", mpt_proc_root_dir);
5869 remove_proc_entry("summary", mpt_proc_root_dir);
5870 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5871}
5872
5873/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005874/**
5875 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 * @buf: Pointer to area to write information
5877 * @start: Pointer to start pointer
5878 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005879 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 * @eof: Pointer to EOF integer
5881 * @data: Pointer
5882 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005883 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 * Returns number of characters written to process performing the read.
5885 */
5886static int
5887procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5888{
5889 MPT_ADAPTER *ioc;
5890 char *out = buf;
5891 int len;
5892
5893 if (data) {
5894 int more = 0;
5895
5896 ioc = data;
5897 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5898
5899 out += more;
5900 } else {
5901 list_for_each_entry(ioc, &ioc_list, list) {
5902 int more = 0;
5903
5904 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5905
5906 out += more;
5907 if ((out-buf) >= request)
5908 break;
5909 }
5910 }
5911
5912 len = out - buf;
5913
5914 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5915}
5916
5917/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005918/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 * procmpt_version_read - Handle read request from /proc/mpt/version.
5920 * @buf: Pointer to area to write information
5921 * @start: Pointer to start pointer
5922 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005923 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 * @eof: Pointer to EOF integer
5925 * @data: Pointer
5926 *
5927 * Returns number of characters written to process performing the read.
5928 */
5929static int
5930procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5931{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305932 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005933 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 char *drvname;
5935 int len;
5936
5937 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5938 len += sprintf(buf+len, " Fusion MPT base driver\n");
5939
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005940 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06005941 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305943 if (MptCallbacks[cb_idx]) {
5944 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005945 case MPTSPI_DRIVER:
5946 if (!scsi++) drvname = "SPI host";
5947 break;
5948 case MPTFC_DRIVER:
5949 if (!fc++) drvname = "FC host";
5950 break;
5951 case MPTSAS_DRIVER:
5952 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 break;
5954 case MPTLAN_DRIVER:
5955 if (!lan++) drvname = "LAN";
5956 break;
5957 case MPTSTM_DRIVER:
5958 if (!targ++) drvname = "SCSI target";
5959 break;
5960 case MPTCTL_DRIVER:
5961 if (!ctl++) drvname = "ioctl";
5962 break;
5963 }
5964
5965 if (drvname)
5966 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5967 }
5968 }
5969
5970 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5971}
5972
5973/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005974/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5976 * @buf: Pointer to area to write information
5977 * @start: Pointer to start pointer
5978 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005979 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 * @eof: Pointer to EOF integer
5981 * @data: Pointer
5982 *
5983 * Returns number of characters written to process performing the read.
5984 */
5985static int
5986procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5987{
5988 MPT_ADAPTER *ioc = data;
5989 int len;
5990 char expVer[32];
5991 int sz;
5992 int p;
5993
5994 mpt_get_fw_exp_ver(expVer, ioc);
5995
5996 len = sprintf(buf, "%s:", ioc->name);
5997 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5998 len += sprintf(buf+len, " (f/w download boot flag set)");
5999// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6000// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6001
6002 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6003 ioc->facts.ProductID,
6004 ioc->prod_name);
6005 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6006 if (ioc->facts.FWImageSize)
6007 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6008 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6009 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6010 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6011
6012 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6013 ioc->facts.CurrentHostMfaHighAddr);
6014 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6015 ioc->facts.CurrentSenseBufferHighAddr);
6016
6017 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6018 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6019
6020 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6021 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6022 /*
6023 * Rounding UP to nearest 4-kB boundary here...
6024 */
6025 sz = (ioc->req_sz * ioc->req_depth) + 128;
6026 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6027 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6028 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6029 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6030 4*ioc->facts.RequestFrameSize,
6031 ioc->facts.GlobalCredits);
6032
6033 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6034 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6035 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6036 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6037 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6038 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6039 ioc->facts.CurReplyFrameSize,
6040 ioc->facts.ReplyQueueDepth);
6041
6042 len += sprintf(buf+len, " MaxDevices = %d\n",
6043 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6044 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6045
6046 /* per-port info */
6047 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6048 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6049 p+1,
6050 ioc->facts.NumberOfPorts);
6051 if (ioc->bus_type == FC) {
6052 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6053 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6054 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6055 a[5], a[4], a[3], a[2], a[1], a[0]);
6056 }
6057 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6058 ioc->fc_port_page0[p].WWNN.High,
6059 ioc->fc_port_page0[p].WWNN.Low,
6060 ioc->fc_port_page0[p].WWPN.High,
6061 ioc->fc_port_page0[p].WWPN.Low);
6062 }
6063 }
6064
6065 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6066}
6067
6068#endif /* CONFIG_PROC_FS } */
6069
6070/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6071static void
6072mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6073{
6074 buf[0] ='\0';
6075 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6076 sprintf(buf, " (Exp %02d%02d)",
6077 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6078 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6079
6080 /* insider hack! */
6081 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6082 strcat(buf, " [MDBG]");
6083 }
6084}
6085
6086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6087/**
6088 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6089 * @ioc: Pointer to MPT_ADAPTER structure
6090 * @buffer: Pointer to buffer where IOC summary info should be written
6091 * @size: Pointer to number of bytes we wrote (set by this routine)
6092 * @len: Offset at which to start writing in buffer
6093 * @showlan: Display LAN stuff?
6094 *
6095 * This routine writes (english readable) ASCII text, which represents
6096 * a summary of IOC information, to a buffer.
6097 */
6098void
6099mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6100{
6101 char expVer[32];
6102 int y;
6103
6104 mpt_get_fw_exp_ver(expVer, ioc);
6105
6106 /*
6107 * Shorter summary of attached ioc's...
6108 */
6109 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6110 ioc->name,
6111 ioc->prod_name,
6112 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6113 ioc->facts.FWVersion.Word,
6114 expVer,
6115 ioc->facts.NumberOfPorts,
6116 ioc->req_depth);
6117
6118 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6119 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6120 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6121 a[5], a[4], a[3], a[2], a[1], a[0]);
6122 }
6123
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125
6126 if (!ioc->active)
6127 y += sprintf(buffer+len+y, " (disabled)");
6128
6129 y += sprintf(buffer+len+y, "\n");
6130
6131 *size = y;
6132}
6133
6134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6135/*
6136 * Reset Handling
6137 */
6138/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6139/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006140 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 * @ioc: Pointer to MPT_ADAPTER structure
6142 * @sleepFlag: Indicates if sleep or schedule must be called.
6143 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006144 * Issues SCSI Task Management call based on input arg values.
6145 * If TaskMgmt fails, returns associated SCSI request.
6146 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6148 * or a non-interrupt thread. In the former, must not call schedule().
6149 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006150 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 * FW reload/initialization failed.
6152 *
6153 * Returns 0 for SUCCESS or -1 if FAILED.
6154 */
6155int
6156mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6157{
6158 int rc;
6159 unsigned long flags;
6160
Prakash, Sathya436ace72007-07-24 15:42:08 +05306161 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162#ifdef MFCNT
6163 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6164 printk("MF count 0x%x !\n", ioc->mfcnt);
6165#endif
6166
6167 /* Reset the adapter. Prevent more than 1 call to
6168 * mpt_do_ioc_recovery at any instant in time.
6169 */
6170 spin_lock_irqsave(&ioc->diagLock, flags);
6171 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6172 spin_unlock_irqrestore(&ioc->diagLock, flags);
6173 return 0;
6174 } else {
6175 ioc->diagPending = 1;
6176 }
6177 spin_unlock_irqrestore(&ioc->diagLock, flags);
6178
6179 /* FIXME: If do_ioc_recovery fails, repeat....
6180 */
6181
6182 /* The SCSI driver needs to adjust timeouts on all current
6183 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006184 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 * For all other protocol drivers, this is a no-op.
6186 */
6187 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306188 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 int r = 0;
6190
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306191 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6192 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306193 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306194 ioc->name, cb_idx));
6195 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306197 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306198 ioc->name, ioc->alt_ioc->name, cb_idx));
6199 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 }
6201 }
6202 }
6203 }
6204
6205 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006206 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 }
6208 ioc->reload_fw = 0;
6209 if (ioc->alt_ioc)
6210 ioc->alt_ioc->reload_fw = 0;
6211
6212 spin_lock_irqsave(&ioc->diagLock, flags);
6213 ioc->diagPending = 0;
6214 if (ioc->alt_ioc)
6215 ioc->alt_ioc->diagPending = 0;
6216 spin_unlock_irqrestore(&ioc->diagLock, flags);
6217
Prakash, Sathya436ace72007-07-24 15:42:08 +05306218 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219
6220 return rc;
6221}
6222
6223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006224static void
6225EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226{
Eric Moore509e5e52006-04-26 13:22:37 -06006227 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
6229 switch(event) {
6230 case MPI_EVENT_NONE:
6231 ds = "None";
6232 break;
6233 case MPI_EVENT_LOG_DATA:
6234 ds = "Log Data";
6235 break;
6236 case MPI_EVENT_STATE_CHANGE:
6237 ds = "State Change";
6238 break;
6239 case MPI_EVENT_UNIT_ATTENTION:
6240 ds = "Unit Attention";
6241 break;
6242 case MPI_EVENT_IOC_BUS_RESET:
6243 ds = "IOC Bus Reset";
6244 break;
6245 case MPI_EVENT_EXT_BUS_RESET:
6246 ds = "External Bus Reset";
6247 break;
6248 case MPI_EVENT_RESCAN:
6249 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 break;
6251 case MPI_EVENT_LINK_STATUS_CHANGE:
6252 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6253 ds = "Link Status(FAILURE) Change";
6254 else
6255 ds = "Link Status(ACTIVE) Change";
6256 break;
6257 case MPI_EVENT_LOOP_STATE_CHANGE:
6258 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6259 ds = "Loop State(LIP) Change";
6260 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006261 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 else
Eric Moore509e5e52006-04-26 13:22:37 -06006263 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 break;
6265 case MPI_EVENT_LOGOUT:
6266 ds = "Logout";
6267 break;
6268 case MPI_EVENT_EVENT_CHANGE:
6269 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006270 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006272 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 break;
6274 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006275 {
6276 u8 ReasonCode = (u8)(evData0 >> 16);
6277 switch (ReasonCode) {
6278 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6279 ds = "Integrated Raid: Volume Created";
6280 break;
6281 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6282 ds = "Integrated Raid: Volume Deleted";
6283 break;
6284 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6285 ds = "Integrated Raid: Volume Settings Changed";
6286 break;
6287 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6288 ds = "Integrated Raid: Volume Status Changed";
6289 break;
6290 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6291 ds = "Integrated Raid: Volume Physdisk Changed";
6292 break;
6293 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6294 ds = "Integrated Raid: Physdisk Created";
6295 break;
6296 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6297 ds = "Integrated Raid: Physdisk Deleted";
6298 break;
6299 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6300 ds = "Integrated Raid: Physdisk Settings Changed";
6301 break;
6302 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6303 ds = "Integrated Raid: Physdisk Status Changed";
6304 break;
6305 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6306 ds = "Integrated Raid: Domain Validation Needed";
6307 break;
6308 case MPI_EVENT_RAID_RC_SMART_DATA :
6309 ds = "Integrated Raid; Smart Data";
6310 break;
6311 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6312 ds = "Integrated Raid: Replace Action Started";
6313 break;
6314 default:
6315 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006317 }
6318 break;
6319 }
6320 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6321 ds = "SCSI Device Status Change";
6322 break;
6323 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6324 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006325 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006326 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006327 u8 ReasonCode = (u8)(evData0 >> 16);
6328 switch (ReasonCode) {
6329 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006330 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006331 "SAS Device Status Change: Added: "
6332 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006333 break;
6334 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006335 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006336 "SAS Device Status Change: Deleted: "
6337 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006338 break;
6339 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006340 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006341 "SAS Device Status Change: SMART Data: "
6342 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006343 break;
6344 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006345 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006346 "SAS Device Status Change: No Persistancy: "
6347 "id=%d channel=%d", id, channel);
6348 break;
6349 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6350 snprintf(evStr, EVENT_DESCR_STR_SZ,
6351 "SAS Device Status Change: Unsupported Device "
6352 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006353 break;
6354 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6355 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006356 "SAS Device Status Change: Internal Device "
6357 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006358 break;
6359 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6360 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006361 "SAS Device Status Change: Internal Task "
6362 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006363 break;
6364 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6365 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006366 "SAS Device Status Change: Internal Abort "
6367 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006368 break;
6369 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6370 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006371 "SAS Device Status Change: Internal Clear "
6372 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006373 break;
6374 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6375 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006376 "SAS Device Status Change: Internal Query "
6377 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006378 break;
6379 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006380 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006381 "SAS Device Status Change: Unknown: "
6382 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006383 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006384 }
6385 break;
6386 }
6387 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6388 ds = "Bus Timer Expired";
6389 break;
6390 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006391 {
6392 u16 curr_depth = (u16)(evData0 >> 16);
6393 u8 channel = (u8)(evData0 >> 8);
6394 u8 id = (u8)(evData0);
6395
6396 snprintf(evStr, EVENT_DESCR_STR_SZ,
6397 "Queue Full: channel=%d id=%d depth=%d",
6398 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006399 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006400 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006401 case MPI_EVENT_SAS_SES:
6402 ds = "SAS SES Event";
6403 break;
6404 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6405 ds = "Persistent Table Full";
6406 break;
6407 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006408 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006409 u8 LinkRates = (u8)(evData0 >> 8);
6410 u8 PhyNumber = (u8)(evData0);
6411 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6412 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6413 switch (LinkRates) {
6414 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006415 snprintf(evStr, EVENT_DESCR_STR_SZ,
6416 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006417 " Rate Unknown",PhyNumber);
6418 break;
6419 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006420 snprintf(evStr, EVENT_DESCR_STR_SZ,
6421 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006422 " Phy Disabled",PhyNumber);
6423 break;
6424 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006425 snprintf(evStr, EVENT_DESCR_STR_SZ,
6426 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006427 " Failed Speed Nego",PhyNumber);
6428 break;
6429 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006430 snprintf(evStr, EVENT_DESCR_STR_SZ,
6431 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006432 " Sata OOB Completed",PhyNumber);
6433 break;
6434 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006435 snprintf(evStr, EVENT_DESCR_STR_SZ,
6436 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006437 " Rate 1.5 Gbps",PhyNumber);
6438 break;
6439 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006440 snprintf(evStr, EVENT_DESCR_STR_SZ,
6441 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006442 " Rate 3.0 Gpbs",PhyNumber);
6443 break;
6444 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006445 snprintf(evStr, EVENT_DESCR_STR_SZ,
6446 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006447 break;
6448 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006449 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006450 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006451 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6452 ds = "SAS Discovery Error";
6453 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006454 case MPI_EVENT_IR_RESYNC_UPDATE:
6455 {
6456 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006457 snprintf(evStr, EVENT_DESCR_STR_SZ,
6458 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006459 break;
6460 }
6461 case MPI_EVENT_IR2:
6462 {
6463 u8 ReasonCode = (u8)(evData0 >> 16);
6464 switch (ReasonCode) {
6465 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6466 ds = "IR2: LD State Changed";
6467 break;
6468 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6469 ds = "IR2: PD State Changed";
6470 break;
6471 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6472 ds = "IR2: Bad Block Table Full";
6473 break;
6474 case MPI_EVENT_IR2_RC_PD_INSERTED:
6475 ds = "IR2: PD Inserted";
6476 break;
6477 case MPI_EVENT_IR2_RC_PD_REMOVED:
6478 ds = "IR2: PD Removed";
6479 break;
6480 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6481 ds = "IR2: Foreign CFG Detected";
6482 break;
6483 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6484 ds = "IR2: Rebuild Medium Error";
6485 break;
6486 default:
6487 ds = "IR2";
6488 break;
6489 }
6490 break;
6491 }
6492 case MPI_EVENT_SAS_DISCOVERY:
6493 {
6494 if (evData0)
6495 ds = "SAS Discovery: Start";
6496 else
6497 ds = "SAS Discovery: Stop";
6498 break;
6499 }
6500 case MPI_EVENT_LOG_ENTRY_ADDED:
6501 ds = "SAS Log Entry Added";
6502 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006503
Eric Moorec6c727a2007-01-29 09:44:54 -07006504 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6505 {
6506 u8 phy_num = (u8)(evData0);
6507 u8 port_num = (u8)(evData0 >> 8);
6508 u8 port_width = (u8)(evData0 >> 16);
6509 u8 primative = (u8)(evData0 >> 24);
6510 snprintf(evStr, EVENT_DESCR_STR_SZ,
6511 "SAS Broadcase Primative: phy=%d port=%d "
6512 "width=%d primative=0x%02x",
6513 phy_num, port_num, port_width, primative);
6514 break;
6515 }
6516
6517 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6518 {
6519 u8 reason = (u8)(evData0);
6520 u8 port_num = (u8)(evData0 >> 8);
6521 u16 handle = le16_to_cpu(evData0 >> 16);
6522
6523 snprintf(evStr, EVENT_DESCR_STR_SZ,
6524 "SAS Initiator Device Status Change: reason=0x%02x "
6525 "port=%d handle=0x%04x",
6526 reason, port_num, handle);
6527 break;
6528 }
6529
6530 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6531 {
6532 u8 max_init = (u8)(evData0);
6533 u8 current_init = (u8)(evData0 >> 8);
6534
6535 snprintf(evStr, EVENT_DESCR_STR_SZ,
6536 "SAS Initiator Device Table Overflow: max initiators=%02d "
6537 "current initators=%02d",
6538 max_init, current_init);
6539 break;
6540 }
6541 case MPI_EVENT_SAS_SMP_ERROR:
6542 {
6543 u8 status = (u8)(evData0);
6544 u8 port_num = (u8)(evData0 >> 8);
6545 u8 result = (u8)(evData0 >> 16);
6546
6547 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6548 snprintf(evStr, EVENT_DESCR_STR_SZ,
6549 "SAS SMP Error: port=%d result=0x%02x",
6550 port_num, result);
6551 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6552 snprintf(evStr, EVENT_DESCR_STR_SZ,
6553 "SAS SMP Error: port=%d : CRC Error",
6554 port_num);
6555 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6556 snprintf(evStr, EVENT_DESCR_STR_SZ,
6557 "SAS SMP Error: port=%d : Timeout",
6558 port_num);
6559 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6560 snprintf(evStr, EVENT_DESCR_STR_SZ,
6561 "SAS SMP Error: port=%d : No Destination",
6562 port_num);
6563 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6564 snprintf(evStr, EVENT_DESCR_STR_SZ,
6565 "SAS SMP Error: port=%d : Bad Destination",
6566 port_num);
6567 else
6568 snprintf(evStr, EVENT_DESCR_STR_SZ,
6569 "SAS SMP Error: port=%d : status=0x%02x",
6570 port_num, status);
6571 break;
6572 }
6573
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 /*
6575 * MPT base "custom" events may be added here...
6576 */
6577 default:
6578 ds = "Unknown";
6579 break;
6580 }
Eric Moore509e5e52006-04-26 13:22:37 -06006581 if (ds)
6582 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583}
6584
6585/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006586/**
6587 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588 * @ioc: Pointer to MPT_ADAPTER structure
6589 * @pEventReply: Pointer to EventNotification reply frame
6590 * @evHandlers: Pointer to integer, number of event handlers
6591 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006592 * Routes a received EventNotificationReply to all currently registered
6593 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006594 * Returns sum of event handlers return values.
6595 */
6596static int
6597ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6598{
6599 u16 evDataLen;
6600 u32 evData0 = 0;
6601// u32 evCtx;
6602 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306603 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604 int r = 0;
6605 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006606 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 u8 event;
6608
6609 /*
6610 * Do platform normalization of values
6611 */
6612 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6613// evCtx = le32_to_cpu(pEventReply->EventContext);
6614 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6615 if (evDataLen) {
6616 evData0 = le32_to_cpu(pEventReply->Data[0]);
6617 }
6618
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006619 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306620 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006621 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006622 event,
6623 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624
Prakash, Sathya436ace72007-07-24 15:42:08 +05306625#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006626 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6627 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306629 devtverboseprintk(ioc, printk(" %08x",
6630 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006631 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632#endif
6633
6634 /*
6635 * Do general / base driver event processing
6636 */
6637 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6639 if (evDataLen) {
6640 u8 evState = evData0 & 0xFF;
6641
6642 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6643
6644 /* Update EventState field in cached IocFacts */
6645 if (ioc->facts.Function) {
6646 ioc->facts.EventState = evState;
6647 }
6648 }
6649 break;
Moore, Ericece50912006-01-16 18:53:19 -07006650 case MPI_EVENT_INTEGRATED_RAID:
6651 mptbase_raid_process_event_data(ioc,
6652 (MpiEventDataRaid_t *)pEventReply->Data);
6653 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006654 default:
6655 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656 }
6657
6658 /*
6659 * Should this event be logged? Events are written sequentially.
6660 * When buffer is full, start again at the top.
6661 */
6662 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6663 int idx;
6664
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006665 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666
6667 ioc->events[idx].event = event;
6668 ioc->events[idx].eventContext = ioc->eventContext;
6669
6670 for (ii = 0; ii < 2; ii++) {
6671 if (ii < evDataLen)
6672 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6673 else
6674 ioc->events[idx].data[ii] = 0;
6675 }
6676
6677 ioc->eventContext++;
6678 }
6679
6680
6681 /*
6682 * Call each currently registered protocol event handler.
6683 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006684 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306685 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306686 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306687 ioc->name, cb_idx));
6688 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689 handlers++;
6690 }
6691 }
6692 /* FIXME? Examine results here? */
6693
6694 /*
6695 * If needed, send (a single) EventAck.
6696 */
6697 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306698 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006699 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306701 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 ioc->name, ii));
6703 }
6704 }
6705
6706 *evHandlers = handlers;
6707 return r;
6708}
6709
6710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006711/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6713 * @ioc: Pointer to MPT_ADAPTER structure
6714 * @log_info: U32 LogInfo reply word from the IOC
6715 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006716 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717 */
6718static void
6719mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6720{
Eric Moore7c431e52007-06-13 16:34:36 -06006721 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722
Eric Moore7c431e52007-06-13 16:34:36 -06006723 switch (log_info & 0xFF000000) {
6724 case MPI_IOCLOGINFO_FC_INIT_BASE:
6725 desc = "FCP Initiator";
6726 break;
6727 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6728 desc = "FCP Target";
6729 break;
6730 case MPI_IOCLOGINFO_FC_LAN_BASE:
6731 desc = "LAN";
6732 break;
6733 case MPI_IOCLOGINFO_FC_MSG_BASE:
6734 desc = "MPI Message Layer";
6735 break;
6736 case MPI_IOCLOGINFO_FC_LINK_BASE:
6737 desc = "FC Link";
6738 break;
6739 case MPI_IOCLOGINFO_FC_CTX_BASE:
6740 desc = "Context Manager";
6741 break;
6742 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6743 desc = "Invalid Field Offset";
6744 break;
6745 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6746 desc = "State Change Info";
6747 break;
6748 }
6749
6750 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6751 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752}
6753
6754/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006755/**
Moore, Eric335a9412006-01-17 17:06:23 -07006756 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757 * @ioc: Pointer to MPT_ADAPTER structure
6758 * @mr: Pointer to MPT reply frame
6759 * @log_info: U32 LogInfo word from the IOC
6760 *
6761 * Refer to lsi/sp_log.h.
6762 */
6763static void
Moore, Eric335a9412006-01-17 17:06:23 -07006764mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765{
6766 u32 info = log_info & 0x00FF0000;
6767 char *desc = "unknown";
6768
6769 switch (info) {
6770 case 0x00010000:
6771 desc = "bug! MID not found";
6772 if (ioc->reload_fw == 0)
6773 ioc->reload_fw++;
6774 break;
6775
6776 case 0x00020000:
6777 desc = "Parity Error";
6778 break;
6779
6780 case 0x00030000:
6781 desc = "ASYNC Outbound Overrun";
6782 break;
6783
6784 case 0x00040000:
6785 desc = "SYNC Offset Error";
6786 break;
6787
6788 case 0x00050000:
6789 desc = "BM Change";
6790 break;
6791
6792 case 0x00060000:
6793 desc = "Msg In Overflow";
6794 break;
6795
6796 case 0x00070000:
6797 desc = "DMA Error";
6798 break;
6799
6800 case 0x00080000:
6801 desc = "Outbound DMA Overrun";
6802 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006803
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804 case 0x00090000:
6805 desc = "Task Management";
6806 break;
6807
6808 case 0x000A0000:
6809 desc = "Device Problem";
6810 break;
6811
6812 case 0x000B0000:
6813 desc = "Invalid Phase Change";
6814 break;
6815
6816 case 0x000C0000:
6817 desc = "Untagged Table Size";
6818 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006819
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820 }
6821
6822 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6823}
6824
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006825/* strings for sas loginfo */
6826 static char *originator_str[] = {
6827 "IOP", /* 00h */
6828 "PL", /* 01h */
6829 "IR" /* 02h */
6830 };
6831 static char *iop_code_str[] = {
6832 NULL, /* 00h */
6833 "Invalid SAS Address", /* 01h */
6834 NULL, /* 02h */
6835 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006836 "Diag Message Error", /* 04h */
6837 "Task Terminated", /* 05h */
6838 "Enclosure Management", /* 06h */
6839 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006840 };
6841 static char *pl_code_str[] = {
6842 NULL, /* 00h */
6843 "Open Failure", /* 01h */
6844 "Invalid Scatter Gather List", /* 02h */
6845 "Wrong Relative Offset or Frame Length", /* 03h */
6846 "Frame Transfer Error", /* 04h */
6847 "Transmit Frame Connected Low", /* 05h */
6848 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6849 "SATA Read Log Receive Data Error", /* 07h */
6850 "SATA NCQ Fail All Commands After Error", /* 08h */
6851 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6852 "Receive Frame Invalid Message", /* 0Ah */
6853 "Receive Context Message Valid Error", /* 0Bh */
6854 "Receive Frame Current Frame Error", /* 0Ch */
6855 "SATA Link Down", /* 0Dh */
6856 "Discovery SATA Init W IOS", /* 0Eh */
6857 "Config Invalid Page", /* 0Fh */
6858 "Discovery SATA Init Timeout", /* 10h */
6859 "Reset", /* 11h */
6860 "Abort", /* 12h */
6861 "IO Not Yet Executed", /* 13h */
6862 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006863 "Persistent Reservation Out Not Affiliation "
6864 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006865 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006866 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006867 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006868 NULL, /* 19h */
6869 NULL, /* 1Ah */
6870 NULL, /* 1Bh */
6871 NULL, /* 1Ch */
6872 NULL, /* 1Dh */
6873 NULL, /* 1Eh */
6874 NULL, /* 1Fh */
6875 "Enclosure Management" /* 20h */
6876 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006877 static char *ir_code_str[] = {
6878 "Raid Action Error", /* 00h */
6879 NULL, /* 00h */
6880 NULL, /* 01h */
6881 NULL, /* 02h */
6882 NULL, /* 03h */
6883 NULL, /* 04h */
6884 NULL, /* 05h */
6885 NULL, /* 06h */
6886 NULL /* 07h */
6887 };
6888 static char *raid_sub_code_str[] = {
6889 NULL, /* 00h */
6890 "Volume Creation Failed: Data Passed too "
6891 "Large", /* 01h */
6892 "Volume Creation Failed: Duplicate Volumes "
6893 "Attempted", /* 02h */
6894 "Volume Creation Failed: Max Number "
6895 "Supported Volumes Exceeded", /* 03h */
6896 "Volume Creation Failed: DMA Error", /* 04h */
6897 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6898 "Volume Creation Failed: Error Reading "
6899 "MFG Page 4", /* 06h */
6900 "Volume Creation Failed: Creating Internal "
6901 "Structures", /* 07h */
6902 NULL, /* 08h */
6903 NULL, /* 09h */
6904 NULL, /* 0Ah */
6905 NULL, /* 0Bh */
6906 NULL, /* 0Ch */
6907 NULL, /* 0Dh */
6908 NULL, /* 0Eh */
6909 NULL, /* 0Fh */
6910 "Activation failed: Already Active Volume", /* 10h */
6911 "Activation failed: Unsupported Volume Type", /* 11h */
6912 "Activation failed: Too Many Active Volumes", /* 12h */
6913 "Activation failed: Volume ID in Use", /* 13h */
6914 "Activation failed: Reported Failure", /* 14h */
6915 "Activation failed: Importing a Volume", /* 15h */
6916 NULL, /* 16h */
6917 NULL, /* 17h */
6918 NULL, /* 18h */
6919 NULL, /* 19h */
6920 NULL, /* 1Ah */
6921 NULL, /* 1Bh */
6922 NULL, /* 1Ch */
6923 NULL, /* 1Dh */
6924 NULL, /* 1Eh */
6925 NULL, /* 1Fh */
6926 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6927 "Phys Disk failed: Data Passed too Large", /* 21h */
6928 "Phys Disk failed: DMA Error", /* 22h */
6929 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6930 "Phys Disk failed: Creating Phys Disk Config "
6931 "Page", /* 24h */
6932 NULL, /* 25h */
6933 NULL, /* 26h */
6934 NULL, /* 27h */
6935 NULL, /* 28h */
6936 NULL, /* 29h */
6937 NULL, /* 2Ah */
6938 NULL, /* 2Bh */
6939 NULL, /* 2Ch */
6940 NULL, /* 2Dh */
6941 NULL, /* 2Eh */
6942 NULL, /* 2Fh */
6943 "Compatibility Error: IR Disabled", /* 30h */
6944 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6945 "Compatibility Error: Device not Direct Access "
6946 "Device ", /* 32h */
6947 "Compatibility Error: Removable Device Found", /* 33h */
6948 "Compatibility Error: Device SCSI Version not "
6949 "2 or Higher", /* 34h */
6950 "Compatibility Error: SATA Device, 48 BIT LBA "
6951 "not Supported", /* 35h */
6952 "Compatibility Error: Device doesn't have "
6953 "512 Byte Block Sizes", /* 36h */
6954 "Compatibility Error: Volume Type Check Failed", /* 37h */
6955 "Compatibility Error: Volume Type is "
6956 "Unsupported by FW", /* 38h */
6957 "Compatibility Error: Disk Drive too Small for "
6958 "use in Volume", /* 39h */
6959 "Compatibility Error: Phys Disk for Create "
6960 "Volume not Found", /* 3Ah */
6961 "Compatibility Error: Too Many or too Few "
6962 "Disks for Volume Type", /* 3Bh */
6963 "Compatibility Error: Disk stripe Sizes "
6964 "Must be 64KB", /* 3Ch */
6965 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6966 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006967
6968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006969/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006970 * mpt_sas_log_info - Log information returned from SAS IOC.
6971 * @ioc: Pointer to MPT_ADAPTER structure
6972 * @log_info: U32 LogInfo reply word from the IOC
6973 *
6974 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006975 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006976static void
6977mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6978{
6979union loginfo_type {
6980 u32 loginfo;
6981 struct {
6982 u32 subcode:16;
6983 u32 code:8;
6984 u32 originator:4;
6985 u32 bus_type:4;
6986 }dw;
6987};
6988 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006989 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006990 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006991 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006992
6993 sas_loginfo.loginfo = log_info;
6994 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6995 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6996 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006997
6998 originator_desc = originator_str[sas_loginfo.dw.originator];
6999
7000 switch (sas_loginfo.dw.originator) {
7001
7002 case 0: /* IOP */
7003 if (sas_loginfo.dw.code <
7004 sizeof(iop_code_str)/sizeof(char*))
7005 code_desc = iop_code_str[sas_loginfo.dw.code];
7006 break;
7007 case 1: /* PL */
7008 if (sas_loginfo.dw.code <
7009 sizeof(pl_code_str)/sizeof(char*))
7010 code_desc = pl_code_str[sas_loginfo.dw.code];
7011 break;
7012 case 2: /* IR */
7013 if (sas_loginfo.dw.code >=
7014 sizeof(ir_code_str)/sizeof(char*))
7015 break;
7016 code_desc = ir_code_str[sas_loginfo.dw.code];
7017 if (sas_loginfo.dw.subcode >=
7018 sizeof(raid_sub_code_str)/sizeof(char*))
7019 break;
7020 if (sas_loginfo.dw.code == 0)
7021 sub_code_desc =
7022 raid_sub_code_str[sas_loginfo.dw.subcode];
7023 break;
7024 default:
7025 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007026 }
7027
Eric Moorec6c727a2007-01-29 09:44:54 -07007028 if (sub_code_desc != NULL)
7029 printk(MYIOC_s_INFO_FMT
7030 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7031 " SubCode={%s}\n",
7032 ioc->name, log_info, originator_desc, code_desc,
7033 sub_code_desc);
7034 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007035 printk(MYIOC_s_INFO_FMT
7036 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7037 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007038 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007039 sas_loginfo.dw.subcode);
7040 else
7041 printk(MYIOC_s_INFO_FMT
7042 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7043 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007044 ioc->name, log_info, originator_desc,
7045 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007046}
7047
Linus Torvalds1da177e2005-04-16 15:20:36 -07007048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007049/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007050 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7051 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007052 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007053 * @mf: Pointer to MPT request frame
7054 *
7055 * Refer to lsi/mpi.h.
7056 **/
7057static void
7058mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7059{
7060 Config_t *pReq = (Config_t *)mf;
7061 char extend_desc[EVENT_DESCR_STR_SZ];
7062 char *desc = NULL;
7063 u32 form;
7064 u8 page_type;
7065
7066 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7067 page_type = pReq->ExtPageType;
7068 else
7069 page_type = pReq->Header.PageType;
7070
7071 /*
7072 * ignore invalid page messages for GET_NEXT_HANDLE
7073 */
7074 form = le32_to_cpu(pReq->PageAddress);
7075 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7076 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7077 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7078 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7079 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7080 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7081 return;
7082 }
7083 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7084 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7085 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7086 return;
7087 }
7088
7089 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7090 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7091 page_type, pReq->Header.PageNumber, pReq->Action, form);
7092
7093 switch (ioc_status) {
7094
7095 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7096 desc = "Config Page Invalid Action";
7097 break;
7098
7099 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7100 desc = "Config Page Invalid Type";
7101 break;
7102
7103 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7104 desc = "Config Page Invalid Page";
7105 break;
7106
7107 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7108 desc = "Config Page Invalid Data";
7109 break;
7110
7111 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7112 desc = "Config Page No Defaults";
7113 break;
7114
7115 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7116 desc = "Config Page Can't Commit";
7117 break;
7118 }
7119
7120 if (!desc)
7121 return;
7122
Eric Moore29dd3602007-09-14 18:46:51 -06007123 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7124 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007125}
7126
7127/**
7128 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007129 * @ioc: Pointer to MPT_ADAPTER structure
7130 * @ioc_status: U32 IOCStatus word from IOC
7131 * @mf: Pointer to MPT request frame
7132 *
7133 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007134 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007136mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137{
7138 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007139 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007140
7141 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007142
7143/****************************************************************************/
7144/* Common IOCStatus values for all replies */
7145/****************************************************************************/
7146
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7148 desc = "Invalid Function";
7149 break;
7150
7151 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7152 desc = "Busy";
7153 break;
7154
7155 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7156 desc = "Invalid SGL";
7157 break;
7158
7159 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7160 desc = "Internal Error";
7161 break;
7162
7163 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7164 desc = "Reserved";
7165 break;
7166
7167 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7168 desc = "Insufficient Resources";
7169 break;
7170
7171 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7172 desc = "Invalid Field";
7173 break;
7174
7175 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7176 desc = "Invalid State";
7177 break;
7178
Eric Moorec6c727a2007-01-29 09:44:54 -07007179/****************************************************************************/
7180/* Config IOCStatus values */
7181/****************************************************************************/
7182
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7184 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7185 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7186 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7187 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7188 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007189 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190 break;
7191
Eric Moorec6c727a2007-01-29 09:44:54 -07007192/****************************************************************************/
7193/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7194/* */
7195/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7196/* */
7197/****************************************************************************/
7198
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007201 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7202 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7203 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7204 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007206 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007211 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212 break;
7213
Eric Moorec6c727a2007-01-29 09:44:54 -07007214/****************************************************************************/
7215/* SCSI Target values */
7216/****************************************************************************/
7217
7218 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7219 desc = "Target: Priority IO";
7220 break;
7221
7222 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7223 desc = "Target: Invalid Port";
7224 break;
7225
7226 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7227 desc = "Target Invalid IO Index:";
7228 break;
7229
7230 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7231 desc = "Target: Aborted";
7232 break;
7233
7234 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7235 desc = "Target: No Conn Retryable";
7236 break;
7237
7238 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7239 desc = "Target: No Connection";
7240 break;
7241
7242 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7243 desc = "Target: Transfer Count Mismatch";
7244 break;
7245
7246 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7247 desc = "Target: STS Data not Sent";
7248 break;
7249
7250 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7251 desc = "Target: Data Offset Error";
7252 break;
7253
7254 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7255 desc = "Target: Too Much Write Data";
7256 break;
7257
7258 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7259 desc = "Target: IU Too Short";
7260 break;
7261
7262 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7263 desc = "Target: ACK NAK Timeout";
7264 break;
7265
7266 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7267 desc = "Target: Nak Received";
7268 break;
7269
7270/****************************************************************************/
7271/* Fibre Channel Direct Access values */
7272/****************************************************************************/
7273
7274 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7275 desc = "FC: Aborted";
7276 break;
7277
7278 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7279 desc = "FC: RX ID Invalid";
7280 break;
7281
7282 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7283 desc = "FC: DID Invalid";
7284 break;
7285
7286 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7287 desc = "FC: Node Logged Out";
7288 break;
7289
7290 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7291 desc = "FC: Exchange Canceled";
7292 break;
7293
7294/****************************************************************************/
7295/* LAN values */
7296/****************************************************************************/
7297
7298 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7299 desc = "LAN: Device not Found";
7300 break;
7301
7302 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7303 desc = "LAN: Device Failure";
7304 break;
7305
7306 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7307 desc = "LAN: Transmit Error";
7308 break;
7309
7310 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7311 desc = "LAN: Transmit Aborted";
7312 break;
7313
7314 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7315 desc = "LAN: Receive Error";
7316 break;
7317
7318 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7319 desc = "LAN: Receive Aborted";
7320 break;
7321
7322 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7323 desc = "LAN: Partial Packet";
7324 break;
7325
7326 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7327 desc = "LAN: Canceled";
7328 break;
7329
7330/****************************************************************************/
7331/* Serial Attached SCSI values */
7332/****************************************************************************/
7333
7334 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7335 desc = "SAS: SMP Request Failed";
7336 break;
7337
7338 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7339 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340 break;
7341
7342 default:
7343 desc = "Others";
7344 break;
7345 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007346
7347 if (!desc)
7348 return;
7349
Eric Moore29dd3602007-09-14 18:46:51 -06007350 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7351 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352}
7353
7354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007355EXPORT_SYMBOL(mpt_attach);
7356EXPORT_SYMBOL(mpt_detach);
7357#ifdef CONFIG_PM
7358EXPORT_SYMBOL(mpt_resume);
7359EXPORT_SYMBOL(mpt_suspend);
7360#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007362EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363EXPORT_SYMBOL(mpt_register);
7364EXPORT_SYMBOL(mpt_deregister);
7365EXPORT_SYMBOL(mpt_event_register);
7366EXPORT_SYMBOL(mpt_event_deregister);
7367EXPORT_SYMBOL(mpt_reset_register);
7368EXPORT_SYMBOL(mpt_reset_deregister);
7369EXPORT_SYMBOL(mpt_device_driver_register);
7370EXPORT_SYMBOL(mpt_device_driver_deregister);
7371EXPORT_SYMBOL(mpt_get_msg_frame);
7372EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307373EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374EXPORT_SYMBOL(mpt_free_msg_frame);
7375EXPORT_SYMBOL(mpt_add_sge);
7376EXPORT_SYMBOL(mpt_send_handshake_request);
7377EXPORT_SYMBOL(mpt_verify_adapter);
7378EXPORT_SYMBOL(mpt_GetIocState);
7379EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380EXPORT_SYMBOL(mpt_HardResetHandler);
7381EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383EXPORT_SYMBOL(mpt_alloc_fw_memory);
7384EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007385EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007386EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007387
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007389/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390 * fusion_init - Fusion MPT base driver initialization routine.
7391 *
7392 * Returns 0 for success, non-zero for failure.
7393 */
7394static int __init
7395fusion_init(void)
7396{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307397 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398
7399 show_mptmod_ver(my_NAME, my_VERSION);
7400 printk(KERN_INFO COPYRIGHT "\n");
7401
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307402 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7403 MptCallbacks[cb_idx] = NULL;
7404 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7405 MptEvHandlers[cb_idx] = NULL;
7406 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007407 }
7408
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007409 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410 * EventNotification handling.
7411 */
7412 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7413
7414 /* Register for hard reset handling callbacks.
7415 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307416 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007417
7418#ifdef CONFIG_PROC_FS
7419 (void) procmpt_create();
7420#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007421 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007422}
7423
7424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007425/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007426 * fusion_exit - Perform driver unload cleanup.
7427 *
7428 * This routine frees all resources associated with each MPT adapter
7429 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7430 */
7431static void __exit
7432fusion_exit(void)
7433{
7434
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435 mpt_reset_deregister(mpt_base_index);
7436
7437#ifdef CONFIG_PROC_FS
7438 procmpt_destroy();
7439#endif
7440}
7441
Linus Torvalds1da177e2005-04-16 15:20:36 -07007442module_init(fusion_init);
7443module_exit(fusion_exit);