blob: 5987f8b6a59bfa8659f14b480f091cb79b39b2ea [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;
1455 unsigned long mem_phys;
1456 unsigned long port;
1457 u32 msize;
1458 u32 psize;
1459 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301460 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 u8 revision;
1463 u8 pcixcmd;
1464 static int mpt_ids = 0;
1465#ifdef CONFIG_PROC_FS
1466 struct proc_dir_entry *dent, *ent;
1467#endif
1468
Prakash, Sathya436ace72007-07-24 15:42:08 +05301469 if (mpt_debug_level)
1470 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (pci_enable_device(pdev))
1473 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001474
Jesper Juhl56876192007-08-10 14:50:51 -07001475 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1476 if (ioc == NULL) {
1477 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1478 return -ENOMEM;
1479 }
1480 ioc->debug_level = mpt_debug_level;
Eric Moore29dd3602007-09-14 18:46:51 -06001481 ioc->id = mpt_ids++;
1482 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001483
Eric Moore29dd3602007-09-14 18:46:51 -06001484 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001485
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001486 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001487 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1488 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001489 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001490 printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
1491 ioc->name);
Jesper Juhl56876192007-08-10 14:50:51 -07001492 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return r;
1494 }
1495
Prakash, Sathya436ace72007-07-24 15:42:08 +05301496 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001497 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1498 ": Using 64 bit consistent mask\n", ioc->name));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301499 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001500 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1501 ": Not using 64 bit consistent mask\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 ioc->alloc_total = sizeof(MPT_ADAPTER);
1505 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1506 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001507
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 ioc->pcidev = pdev;
1509 ioc->diagPending = 0;
1510 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001511 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
1513 /* Initialize the event logging.
1514 */
1515 ioc->eventTypes = 0; /* None */
1516 ioc->eventContext = 0;
1517 ioc->eventLogSize = 0;
1518 ioc->events = NULL;
1519
1520#ifdef MFCNT
1521 ioc->mfcnt = 0;
1522#endif
1523
1524 ioc->cached_fw = NULL;
1525
1526 /* Initilize SCSI Config Data structure
1527 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001528 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 /* Initialize the running configQ head.
1531 */
1532 INIT_LIST_HEAD(&ioc->configQ);
1533
Michael Reed05e8ec12006-01-13 14:31:54 -06001534 /* Initialize the fc rport list head.
1535 */
1536 INIT_LIST_HEAD(&ioc->fc_rports);
1537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 /* Find lookup slot. */
1539 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 mem_phys = msize = 0;
1542 port = psize = 0;
1543 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1544 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001545 if (psize)
1546 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 /* Get I/O space! */
1548 port = pci_resource_start(pdev, ii);
1549 psize = pci_resource_len(pdev,ii);
1550 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001551 if (msize)
1552 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* Get memmap */
1554 mem_phys = pci_resource_start(pdev, ii);
1555 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557 }
1558 ioc->mem_size = msize;
1559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 mem = NULL;
1561 /* Get logical ptr for PciMem0 space */
1562 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001563 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 if (mem == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001565 printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 kfree(ioc);
1567 return -EINVAL;
1568 }
1569 ioc->memmap = mem;
Eric Moore29dd3602007-09-14 18:46:51 -06001570 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 -07001571
Eric Moore29dd3602007-09-14 18:46:51 -06001572 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1573 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 ioc->mem_phys = mem_phys;
1576 ioc->chip = (SYSIF_REGS __iomem *)mem;
1577
1578 /* Save Port IO values in case we need to do downloadboot */
1579 {
1580 u8 *pmem = (u8*)port;
1581 ioc->pio_mem_phys = port;
1582 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
1583 }
1584
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301585 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1586 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1587
1588 switch (pdev->device)
1589 {
1590 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1591 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1592 ioc->errata_flag_1064 = 1;
1593 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1594 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1595 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1596 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301598 break;
1599
1600 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 /* 929X Chip Fix. Set Split transactions level
1603 * for PCIX. Set MOST bits to zero.
1604 */
1605 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1606 pcixcmd &= 0x8F;
1607 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1608 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 /* 929XL Chip Fix. Set MMRBC to 0x08.
1610 */
1611 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1612 pcixcmd |= 0x08;
1613 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301616 break;
1617
1618 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 /* 919X Chip Fix. Set Split transactions level
1620 * for PCIX. Set MOST bits to zero.
1621 */
1622 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1623 pcixcmd &= 0x8F;
1624 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001625 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301626 break;
1627
1628 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* 1030 Chip Fix. Disable Split transactions
1630 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1631 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 if (revision < C0_1030) {
1633 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1634 pcixcmd &= 0x8F;
1635 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1636 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301637
1638 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001639 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301640 break;
1641
1642 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1643 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001644 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301645
1646 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1647 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1648 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001649 ioc->bus_type = SAS;
1650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001652 if (ioc->errata_flag_1064)
1653 pci_disable_io_access(pdev);
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 spin_lock_init(&ioc->FreeQlock);
1656
1657 /* Disable all! */
1658 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1659 ioc->active = 0;
1660 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1661
1662 /* Set lookup ptr. */
1663 list_add_tail(&ioc->list, &ioc_list);
1664
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001665 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 */
1667 mpt_detect_bound_ports(ioc, pdev);
1668
James Bottomleyc92f2222006-03-01 09:02:49 -06001669 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1670 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001671 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1672 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001675 if (ioc->alt_ioc)
1676 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 iounmap(mem);
1678 kfree(ioc);
1679 pci_set_drvdata(pdev, NULL);
1680 return r;
1681 }
1682
1683 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001684 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301685 if(MptDeviceDriverHandlers[cb_idx] &&
1686 MptDeviceDriverHandlers[cb_idx]->probe) {
1687 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 }
1689 }
1690
1691#ifdef CONFIG_PROC_FS
1692 /*
1693 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1694 */
1695 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1696 if (dent) {
1697 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1698 if (ent) {
1699 ent->read_proc = procmpt_iocinfo_read;
1700 ent->data = ioc;
1701 }
1702 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1703 if (ent) {
1704 ent->read_proc = procmpt_summary_read;
1705 ent->data = ioc;
1706 }
1707 }
1708#endif
1709
1710 return 0;
1711}
1712
1713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001714/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001715 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 */
1718
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001719void
1720mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721{
1722 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1723 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301724 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1727 remove_proc_entry(pname, NULL);
1728 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1729 remove_proc_entry(pname, NULL);
1730 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1731 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001734 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301735 if(MptDeviceDriverHandlers[cb_idx] &&
1736 MptDeviceDriverHandlers[cb_idx]->remove) {
1737 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 }
1739 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001740
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 /* Disable interrupts! */
1742 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1743
1744 ioc->active = 0;
1745 synchronize_irq(pdev->irq);
1746
1747 /* Clear any lingering interrupt */
1748 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1749
1750 CHIPREG_READ32(&ioc->chip->IntStatus);
1751
1752 mpt_adapter_dispose(ioc);
1753
1754 pci_set_drvdata(pdev, NULL);
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757/**************************************************************************
1758 * Power Management
1759 */
1760#ifdef CONFIG_PM
1761/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001762/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001763 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001764 * @pdev: Pointer to pci_dev structure
1765 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001767int
1768mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769{
1770 u32 device_state;
1771 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Pavel Machek2a569572005-07-07 17:56:40 -07001773 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
1775 printk(MYIOC_s_INFO_FMT
1776 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1777 ioc->name, pdev, pci_name(pdev), device_state);
1778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 pci_save_state(pdev);
1780
1781 /* put ioc into READY_STATE */
1782 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1783 printk(MYIOC_s_ERR_FMT
1784 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1785 }
1786
1787 /* disable interrupts */
1788 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1789 ioc->active = 0;
1790
1791 /* Clear any lingering interrupt */
1792 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1793
1794 pci_disable_device(pdev);
1795 pci_set_power_state(pdev, device_state);
1796
1797 return 0;
1798}
1799
1800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001801/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001802 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001803 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001805int
1806mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
1808 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1809 u32 device_state = pdev->current_state;
1810 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001811 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001812
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 printk(MYIOC_s_INFO_FMT
1814 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1815 ioc->name, pdev, pci_name(pdev), device_state);
1816
1817 pci_set_power_state(pdev, 0);
1818 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001819 err = pci_enable_device(pdev);
1820 if (err)
1821 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
1823 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001824 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 ioc->active = 1;
1826
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 printk(MYIOC_s_INFO_FMT
1828 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1829 ioc->name,
1830 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1831 CHIPREG_READ32(&ioc->chip->Doorbell));
1832
1833 /* bring ioc to operational state */
1834 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1835 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1836 printk(MYIOC_s_INFO_FMT
1837 "pci-resume: Cannot recover, error:[%x]\n",
1838 ioc->name, recovery_state);
1839 } else {
1840 printk(MYIOC_s_INFO_FMT
1841 "pci-resume: success\n", ioc->name);
1842 }
1843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 return 0;
1845}
1846#endif
1847
James Bottomley4ff42a62006-05-17 18:06:52 -05001848static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301849mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001850{
1851 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1852 ioc->bus_type != SPI) ||
1853 (MptDriverClass[index] == MPTFC_DRIVER &&
1854 ioc->bus_type != FC) ||
1855 (MptDriverClass[index] == MPTSAS_DRIVER &&
1856 ioc->bus_type != SAS))
1857 /* make sure we only call the relevant reset handler
1858 * for the bus */
1859 return 0;
1860 return (MptResetHandlers[index])(ioc, reset_phase);
1861}
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001864/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1866 * @ioc: Pointer to MPT adapter structure
1867 * @reason: Event word / reason
1868 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1869 *
1870 * This routine performs all the steps necessary to bring the IOC
1871 * to a OPERATIONAL state.
1872 *
1873 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1874 * MPT adapter.
1875 *
1876 * Returns:
1877 * 0 for success
1878 * -1 if failed to get board READY
1879 * -2 if READY but IOCFacts Failed
1880 * -3 if READY but PrimeIOCFifos Failed
1881 * -4 if READY but IOCInit Failed
1882 */
1883static int
1884mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1885{
1886 int hard_reset_done = 0;
1887 int alt_ioc_ready = 0;
1888 int hard;
1889 int rc=0;
1890 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301891 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 int handlers;
1893 int ret = 0;
1894 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001895 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301896 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Eric Moore29dd3602007-09-14 18:46:51 -06001898 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1899 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 /* Disable reply interrupts (also blocks FreeQ) */
1902 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1903 ioc->active = 0;
1904
1905 if (ioc->alt_ioc) {
1906 if (ioc->alt_ioc->active)
1907 reset_alt_ioc_active = 1;
1908
1909 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1910 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1911 ioc->alt_ioc->active = 0;
1912 }
1913
1914 hard = 1;
1915 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1916 hard = 0;
1917
1918 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1919 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001920 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1921 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 if (reset_alt_ioc_active && ioc->alt_ioc) {
1924 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001925 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1926 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001927 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 ioc->alt_ioc->active = 1;
1929 }
1930
1931 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001932 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
1934 return -1;
1935 }
1936
1937 /* hard_reset_done = 0 if a soft reset was performed
1938 * and 1 if a hard reset was performed.
1939 */
1940 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1941 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1942 alt_ioc_ready = 1;
1943 else
Eric Moore29dd3602007-09-14 18:46:51 -06001944 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 }
1946
1947 for (ii=0; ii<5; ii++) {
1948 /* Get IOC facts! Allow 5 retries */
1949 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1950 break;
1951 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
1954 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06001955 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1956 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 ret = -2;
1958 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1959 MptDisplayIocCapabilities(ioc);
1960 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (alt_ioc_ready) {
1963 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301964 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001965 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 /* Retry - alt IOC was initialized once
1967 */
1968 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1969 }
1970 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301971 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001972 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 alt_ioc_ready = 0;
1974 reset_alt_ioc_active = 0;
1975 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1976 MptDisplayIocCapabilities(ioc->alt_ioc);
1977 }
1978 }
1979
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001980 /*
1981 * Device is reset now. It must have de-asserted the interrupt line
1982 * (if it was asserted) and it should be safe to register for the
1983 * interrupt now.
1984 */
1985 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1986 ioc->pci_irq = -1;
1987 if (ioc->pcidev->irq) {
1988 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1989 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001990 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001991 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06001992 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001993 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001994 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06001995 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001996 if (mpt_msi_enable)
1997 pci_disable_msi(ioc->pcidev);
1998 return -EBUSY;
1999 }
2000 irq_allocated = 1;
2001 ioc->pci_irq = ioc->pcidev->irq;
2002 pci_set_master(ioc->pcidev); /* ?? */
2003 pci_set_drvdata(ioc->pcidev, ioc);
Eric Moore29dd3602007-09-14 18:46:51 -06002004 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2005 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002006 }
2007 }
2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 /* Prime reply & request queues!
2010 * (mucho alloc's) Must be done prior to
2011 * init as upper addresses are needed for init.
2012 * If fails, continue with alt-ioc processing
2013 */
2014 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2015 ret = -3;
2016
2017 /* May need to check/upload firmware & data here!
2018 * If fails, continue with alt-ioc processing
2019 */
2020 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2021 ret = -4;
2022// NEW!
2023 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002024 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2025 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 alt_ioc_ready = 0;
2027 reset_alt_ioc_active = 0;
2028 }
2029
2030 if (alt_ioc_ready) {
2031 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2032 alt_ioc_ready = 0;
2033 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002034 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2035 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037 }
2038
2039 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2040 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302041 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002042 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
2044 /* Controller is not operational, cannot do upload
2045 */
2046 if (ret == 0) {
2047 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002048 if (rc == 0) {
2049 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2050 /*
2051 * Maintain only one pointer to FW memory
2052 * so there will not be two attempt to
2053 * downloadboot onboard dual function
2054 * chips (mpt_adapter_disable,
2055 * mpt_diag_reset)
2056 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302057 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002058 "mpt_upload: alt_%s has cached_fw=%p \n",
2059 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Eric Moore0ccdb002006-07-11 17:33:13 -06002060 ioc->alt_ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002061 }
2062 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002063 printk(MYIOC_s_WARN_FMT
2064 "firmware upload failure!\n", ioc->name);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002065 ret = -5;
2066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 }
2068 }
2069 }
2070
2071 if (ret == 0) {
2072 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002073 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 ioc->active = 1;
2075 }
2076
2077 if (reset_alt_ioc_active && ioc->alt_ioc) {
2078 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002079 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2080 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002081 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 ioc->alt_ioc->active = 1;
2083 }
2084
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002085 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 * and EventAck handling.
2087 */
2088 if ((ret == 0) && (!ioc->facts.EventState))
2089 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2090
2091 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2092 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2093
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002094 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2096 * recursive scenario; GetLanConfigPages times out, timer expired
2097 * routine calls HardResetHandler, which calls into here again,
2098 * and we try GetLanConfigPages again...
2099 */
2100 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002101
2102 /*
2103 * Initalize link list for inactive raid volumes.
2104 */
2105 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2106 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2107
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002108 if (ioc->bus_type == SAS) {
2109
2110 /* clear persistency table */
2111 if(ioc->facts.IOCExceptions &
2112 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2113 ret = mptbase_sas_persist_operation(ioc,
2114 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2115 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002116 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002117 }
2118
2119 /* Find IM volumes
2120 */
2121 mpt_findImVolumes(ioc);
2122
2123 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2125 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2126 /*
2127 * Pre-fetch the ports LAN MAC address!
2128 * (LANPage1_t stuff)
2129 */
2130 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302131 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2132 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002133 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2134 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 }
2137 } else {
2138 /* Get NVRAM and adapter maximums from SPP 0 and 2
2139 */
2140 mpt_GetScsiPortSettings(ioc, 0);
2141
2142 /* Get version and length of SDP 1
2143 */
2144 mpt_readScsiDevicePageHeaders(ioc, 0);
2145
2146 /* Find IM volumes
2147 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002148 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 mpt_findImVolumes(ioc);
2150
2151 /* Check, and possibly reset, the coalescing value
2152 */
2153 mpt_read_ioc_pg_1(ioc);
2154
2155 mpt_read_ioc_pg_4(ioc);
2156 }
2157
2158 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302159 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 }
2161
2162 /*
2163 * Call each currently registered protocol IOC reset handler
2164 * with post-reset indication.
2165 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2166 * MptResetHandlers[] registered yet.
2167 */
2168 if (hard_reset_done) {
2169 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302170 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2171 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302172 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002173 "Calling IOC post_reset handler #%d\n",
2174 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302175 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 handlers++;
2177 }
2178
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302179 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302180 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002181 "Calling IOC post_reset handler #%d\n",
2182 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302183 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 handlers++;
2185 }
2186 }
2187 /* FIXME? Examine results here? */
2188 }
2189
Eric Moore0ccdb002006-07-11 17:33:13 -06002190 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002191 if ((ret != 0) && irq_allocated) {
2192 free_irq(ioc->pci_irq, ioc);
2193 if (mpt_msi_enable)
2194 pci_disable_msi(ioc->pcidev);
2195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 return ret;
2197}
2198
2199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002200/**
2201 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 * @ioc: Pointer to MPT adapter structure
2203 * @pdev: Pointer to (struct pci_dev) structure
2204 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002205 * Search for PCI bus/dev_function which matches
2206 * PCI bus/dev_function (+/-1) for newly discovered 929,
2207 * 929X, 1030 or 1035.
2208 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2210 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2211 */
2212static void
2213mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2214{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002215 struct pci_dev *peer=NULL;
2216 unsigned int slot = PCI_SLOT(pdev->devfn);
2217 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 MPT_ADAPTER *ioc_srch;
2219
Prakash, Sathya436ace72007-07-24 15:42:08 +05302220 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002221 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002222 ioc->name, pci_name(pdev), pdev->bus->number,
2223 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002224
2225 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2226 if (!peer) {
2227 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2228 if (!peer)
2229 return;
2230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 list_for_each_entry(ioc_srch, &ioc_list, list) {
2233 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002234 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 /* Paranoia checks */
2236 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002237 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002238 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 break;
2240 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002241 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002242 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 break;
2244 }
Eric Moore29dd3602007-09-14 18:46:51 -06002245 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002246 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 ioc_srch->alt_ioc = ioc;
2248 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 }
2250 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002251 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253
2254/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002255/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002257 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 */
2259static void
2260mpt_adapter_disable(MPT_ADAPTER *ioc)
2261{
2262 int sz;
2263 int ret;
2264
2265 if (ioc->cached_fw != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002266 ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
2267 "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002268 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002269 printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
2270 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
2272 }
2273
2274 /* Disable adapter interrupts! */
2275 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2276 ioc->active = 0;
2277 /* Clear any lingering interrupt */
2278 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2279
2280 if (ioc->alloc != NULL) {
2281 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002282 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2283 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 pci_free_consistent(ioc->pcidev, sz,
2285 ioc->alloc, ioc->alloc_dma);
2286 ioc->reply_frames = NULL;
2287 ioc->req_frames = NULL;
2288 ioc->alloc = NULL;
2289 ioc->alloc_total -= sz;
2290 }
2291
2292 if (ioc->sense_buf_pool != NULL) {
2293 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2294 pci_free_consistent(ioc->pcidev, sz,
2295 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2296 ioc->sense_buf_pool = NULL;
2297 ioc->alloc_total -= sz;
2298 }
2299
2300 if (ioc->events != NULL){
2301 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2302 kfree(ioc->events);
2303 ioc->events = NULL;
2304 ioc->alloc_total -= sz;
2305 }
2306
2307 if (ioc->cached_fw != NULL) {
2308 sz = ioc->facts.FWImageSize;
2309 pci_free_consistent(ioc->pcidev, sz,
2310 ioc->cached_fw, ioc->cached_fw_dma);
2311 ioc->cached_fw = NULL;
2312 ioc->alloc_total -= sz;
2313 }
2314
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002315 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002316 mpt_inactive_raid_list_free(ioc);
2317 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002318 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002319 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002320 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
2322 if (ioc->spi_data.pIocPg4 != NULL) {
2323 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302324 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 ioc->spi_data.pIocPg4,
2326 ioc->spi_data.IocPg4_dma);
2327 ioc->spi_data.pIocPg4 = NULL;
2328 ioc->alloc_total -= sz;
2329 }
2330
2331 if (ioc->ReqToChain != NULL) {
2332 kfree(ioc->ReqToChain);
2333 kfree(ioc->RequestNB);
2334 ioc->ReqToChain = NULL;
2335 }
2336
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002337 kfree(ioc->ChainToChain);
2338 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002339
2340 if (ioc->HostPageBuffer != NULL) {
2341 if((ret = mpt_host_page_access_control(ioc,
2342 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002343 printk(MYIOC_s_ERR_FMT
2344 "host page buffers free failed (%d)!\n",
2345 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002346 }
Eric Moore29dd3602007-09-14 18:46:51 -06002347 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002348 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2349 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002350 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002351 ioc->HostPageBuffer = NULL;
2352 ioc->HostPageBuffer_sz = 0;
2353 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355}
2356
2357/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002358/**
2359 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 * @ioc: Pointer to MPT adapter structure
2361 *
2362 * This routine unregisters h/w resources and frees all alloc'd memory
2363 * associated with a MPT adapter structure.
2364 */
2365static void
2366mpt_adapter_dispose(MPT_ADAPTER *ioc)
2367{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002368 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002370 if (ioc == NULL)
2371 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002373 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002375 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002377 if (ioc->pci_irq != -1) {
2378 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002379 if (mpt_msi_enable)
2380 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002381 ioc->pci_irq = -1;
2382 }
2383
2384 if (ioc->memmap != NULL) {
2385 iounmap(ioc->memmap);
2386 ioc->memmap = NULL;
2387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
2389#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002390 if (ioc->mtrr_reg > 0) {
2391 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002392 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394#endif
2395
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002396 /* Zap the adapter lookup ptr! */
2397 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002399 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002400 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2401 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002402
2403 if (ioc->alt_ioc)
2404 ioc->alt_ioc->alt_ioc = NULL;
2405
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002406 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407}
2408
2409/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002410/**
2411 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 * @ioc: Pointer to MPT adapter structure
2413 */
2414static void
2415MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2416{
2417 int i = 0;
2418
2419 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302420 if (ioc->prod_name)
2421 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 printk("Capabilities={");
2423
2424 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2425 printk("Initiator");
2426 i++;
2427 }
2428
2429 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2430 printk("%sTarget", i ? "," : "");
2431 i++;
2432 }
2433
2434 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2435 printk("%sLAN", i ? "," : "");
2436 i++;
2437 }
2438
2439#if 0
2440 /*
2441 * This would probably evoke more questions than it's worth
2442 */
2443 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2444 printk("%sLogBusAddr", i ? "," : "");
2445 i++;
2446 }
2447#endif
2448
2449 printk("}\n");
2450}
2451
2452/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002453/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2455 * @ioc: Pointer to MPT_ADAPTER structure
2456 * @force: Force hard KickStart of IOC
2457 * @sleepFlag: Specifies whether the process can sleep
2458 *
2459 * Returns:
2460 * 1 - DIAG reset and READY
2461 * 0 - READY initially OR soft reset and READY
2462 * -1 - Any failure on KickStart
2463 * -2 - Msg Unit Reset Failed
2464 * -3 - IO Unit Reset Failed
2465 * -4 - IOC owned by a PEER
2466 */
2467static int
2468MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2469{
2470 u32 ioc_state;
2471 int statefault = 0;
2472 int cntdn;
2473 int hard_reset_done = 0;
2474 int r;
2475 int ii;
2476 int whoinit;
2477
2478 /* Get current [raw] IOC state */
2479 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002480 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 /*
2483 * Check to see if IOC got left/stuck in doorbell handshake
2484 * grip of death. If so, hard reset the IOC.
2485 */
2486 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2487 statefault = 1;
2488 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2489 ioc->name);
2490 }
2491
2492 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002493 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 return 0;
2495
2496 /*
2497 * Check to see if IOC is in FAULT state.
2498 */
2499 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2500 statefault = 2;
2501 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002502 ioc->name);
2503 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2504 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
2506
2507 /*
2508 * Hmmm... Did it get left operational?
2509 */
2510 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302511 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 ioc->name));
2513
2514 /* Check WhoInit.
2515 * If PCI Peer, exit.
2516 * Else, if no fault conditions are present, issue a MessageUnitReset
2517 * Else, fall through to KickStart case
2518 */
2519 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002520 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2521 "whoinit 0x%x statefault %d force %d\n",
2522 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 if (whoinit == MPI_WHOINIT_PCI_PEER)
2524 return -4;
2525 else {
2526 if ((statefault == 0 ) && (force == 0)) {
2527 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2528 return 0;
2529 }
2530 statefault = 3;
2531 }
2532 }
2533
2534 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2535 if (hard_reset_done < 0)
2536 return -1;
2537
2538 /*
2539 * Loop here waiting for IOC to come READY.
2540 */
2541 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002542 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
2544 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2545 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2546 /*
2547 * BIOS or previous driver load left IOC in OP state.
2548 * Reset messaging FIFOs.
2549 */
2550 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2551 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2552 return -2;
2553 }
2554 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2555 /*
2556 * Something is wrong. Try to get IOC back
2557 * to a known state.
2558 */
2559 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2560 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2561 return -3;
2562 }
2563 }
2564
2565 ii++; cntdn--;
2566 if (!cntdn) {
2567 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2568 ioc->name, (int)((ii+5)/HZ));
2569 return -ETIME;
2570 }
2571
2572 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002573 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 } else {
2575 mdelay (1); /* 1 msec delay */
2576 }
2577
2578 }
2579
2580 if (statefault < 3) {
2581 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2582 ioc->name,
2583 statefault==1 ? "stuck handshake" : "IOC FAULT");
2584 }
2585
2586 return hard_reset_done;
2587}
2588
2589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002590/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 * mpt_GetIocState - Get the current state of a MPT adapter.
2592 * @ioc: Pointer to MPT_ADAPTER structure
2593 * @cooked: Request raw or cooked IOC state
2594 *
2595 * Returns all IOC Doorbell register bits if cooked==0, else just the
2596 * Doorbell bits in MPI_IOC_STATE_MASK.
2597 */
2598u32
2599mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2600{
2601 u32 s, sc;
2602
2603 /* Get! */
2604 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 sc = s & MPI_IOC_STATE_MASK;
2606
2607 /* Save! */
2608 ioc->last_state = sc;
2609
2610 return cooked ? sc : s;
2611}
2612
2613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002614/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 * GetIocFacts - Send IOCFacts request to MPT adapter.
2616 * @ioc: Pointer to MPT_ADAPTER structure
2617 * @sleepFlag: Specifies whether the process can sleep
2618 * @reason: If recovery, only update facts.
2619 *
2620 * Returns 0 for success, non-zero for failure.
2621 */
2622static int
2623GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2624{
2625 IOCFacts_t get_facts;
2626 IOCFactsReply_t *facts;
2627 int r;
2628 int req_sz;
2629 int reply_sz;
2630 int sz;
2631 u32 status, vv;
2632 u8 shiftFactor=1;
2633
2634 /* IOC *must* NOT be in RESET state! */
2635 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002636 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2637 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 return -44;
2639 }
2640
2641 facts = &ioc->facts;
2642
2643 /* Destination (reply area)... */
2644 reply_sz = sizeof(*facts);
2645 memset(facts, 0, reply_sz);
2646
2647 /* Request area (get_facts on the stack right now!) */
2648 req_sz = sizeof(get_facts);
2649 memset(&get_facts, 0, req_sz);
2650
2651 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2652 /* Assert: All other get_facts fields are zero! */
2653
Prakash, Sathya436ace72007-07-24 15:42:08 +05302654 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002655 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ioc->name, req_sz, reply_sz));
2657
2658 /* No non-zero fields in the get_facts request are greater than
2659 * 1 byte in size, so we can just fire it off as is.
2660 */
2661 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2662 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2663 if (r != 0)
2664 return r;
2665
2666 /*
2667 * Now byte swap (GRRR) the necessary fields before any further
2668 * inspection of reply contents.
2669 *
2670 * But need to do some sanity checks on MsgLength (byte) field
2671 * to make sure we don't zero IOC's req_sz!
2672 */
2673 /* Did we get a valid reply? */
2674 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2675 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2676 /*
2677 * If not been here, done that, save off first WhoInit value
2678 */
2679 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2680 ioc->FirstWhoInit = facts->WhoInit;
2681 }
2682
2683 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2684 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2685 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2686 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2687 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002688 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* CHECKME! IOCStatus, IOCLogInfo */
2690
2691 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2692 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2693
2694 /*
2695 * FC f/w version changed between 1.1 and 1.2
2696 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2697 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2698 */
2699 if (facts->MsgVersion < 0x0102) {
2700 /*
2701 * Handle old FC f/w style, convert to new...
2702 */
2703 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2704 facts->FWVersion.Word =
2705 ((oldv<<12) & 0xFF000000) |
2706 ((oldv<<8) & 0x000FFF00);
2707 } else
2708 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2709
2710 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002711 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2712 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2713 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 facts->CurrentHostMfaHighAddr =
2715 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2716 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2717 facts->CurrentSenseBufferHighAddr =
2718 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2719 facts->CurReplyFrameSize =
2720 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 /*
2724 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2725 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2726 * to 14 in MPI-1.01.0x.
2727 */
2728 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2729 facts->MsgVersion > 0x0100) {
2730 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2731 }
2732
2733 sz = facts->FWImageSize;
2734 if ( sz & 0x01 )
2735 sz += 1;
2736 if ( sz & 0x02 )
2737 sz += 2;
2738 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002739
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 if (!facts->RequestFrameSize) {
2741 /* Something is wrong! */
2742 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2743 ioc->name);
2744 return -55;
2745 }
2746
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002747 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 vv = ((63 / (sz * 4)) + 1) & 0x03;
2749 ioc->NB_for_64_byte_frame = vv;
2750 while ( sz )
2751 {
2752 shiftFactor++;
2753 sz = sz >> 1;
2754 }
2755 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302756 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002757 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2758 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2761 /*
2762 * Set values for this IOC's request & reply frame sizes,
2763 * and request & reply queue depths...
2764 */
2765 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2766 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2767 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2768 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2769
Prakash, Sathya436ace72007-07-24 15:42:08 +05302770 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302772 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 ioc->name, ioc->req_sz, ioc->req_depth));
2774
2775 /* Get port facts! */
2776 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2777 return r;
2778 }
2779 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2782 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2783 RequestFrameSize)/sizeof(u32)));
2784 return -66;
2785 }
2786
2787 return 0;
2788}
2789
2790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002791/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 * GetPortFacts - Send PortFacts request to MPT adapter.
2793 * @ioc: Pointer to MPT_ADAPTER structure
2794 * @portnum: Port number
2795 * @sleepFlag: Specifies whether the process can sleep
2796 *
2797 * Returns 0 for success, non-zero for failure.
2798 */
2799static int
2800GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2801{
2802 PortFacts_t get_pfacts;
2803 PortFactsReply_t *pfacts;
2804 int ii;
2805 int req_sz;
2806 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002807 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 /* IOC *must* NOT be in RESET state! */
2810 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002811 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2812 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 return -4;
2814 }
2815
2816 pfacts = &ioc->pfacts[portnum];
2817
2818 /* Destination (reply area)... */
2819 reply_sz = sizeof(*pfacts);
2820 memset(pfacts, 0, reply_sz);
2821
2822 /* Request area (get_pfacts on the stack right now!) */
2823 req_sz = sizeof(get_pfacts);
2824 memset(&get_pfacts, 0, req_sz);
2825
2826 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2827 get_pfacts.PortNumber = portnum;
2828 /* Assert: All other get_pfacts fields are zero! */
2829
Prakash, Sathya436ace72007-07-24 15:42:08 +05302830 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 ioc->name, portnum));
2832
2833 /* No non-zero fields in the get_pfacts request are greater than
2834 * 1 byte in size, so we can just fire it off as is.
2835 */
2836 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2837 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2838 if (ii != 0)
2839 return ii;
2840
2841 /* Did we get a valid reply? */
2842
2843 /* Now byte swap the necessary fields in the response. */
2844 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2845 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2846 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2847 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2848 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2849 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2850 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2851 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2852 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2853
Eric Moore793955f2007-01-29 09:42:20 -07002854 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2855 pfacts->MaxDevices;
2856 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2857 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2858
2859 /*
2860 * Place all the devices on channels
2861 *
2862 * (for debuging)
2863 */
2864 if (mpt_channel_mapping) {
2865 ioc->devices_per_bus = 1;
2866 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2867 }
2868
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return 0;
2870}
2871
2872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002873/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 * SendIocInit - Send IOCInit request to MPT adapter.
2875 * @ioc: Pointer to MPT_ADAPTER structure
2876 * @sleepFlag: Specifies whether the process can sleep
2877 *
2878 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2879 *
2880 * Returns 0 for success, non-zero for failure.
2881 */
2882static int
2883SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2884{
2885 IOCInit_t ioc_init;
2886 MPIDefaultReply_t init_reply;
2887 u32 state;
2888 int r;
2889 int count;
2890 int cntdn;
2891
2892 memset(&ioc_init, 0, sizeof(ioc_init));
2893 memset(&init_reply, 0, sizeof(init_reply));
2894
2895 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2896 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2897
2898 /* If we are in a recovery mode and we uploaded the FW image,
2899 * then this pointer is not NULL. Skip the upload a second time.
2900 * Set this flag if cached_fw set for either IOC.
2901 */
2902 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2903 ioc->upload_fw = 1;
2904 else
2905 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302906 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2908
Eric Moore793955f2007-01-29 09:42:20 -07002909 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2910 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302911 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002912 ioc->name, ioc->facts.MsgVersion));
2913 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2914 // set MsgVersion and HeaderVersion host driver was built with
2915 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2916 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002918 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2919 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2920 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2921 return -99;
2922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2924
2925 if (sizeof(dma_addr_t) == sizeof(u64)) {
2926 /* Save the upper 32-bits of the request
2927 * (reply) and sense buffers.
2928 */
2929 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2930 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2931 } else {
2932 /* Force 32-bit addressing */
2933 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2934 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2935 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002936
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2938 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002939 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2940 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941
Prakash, Sathya436ace72007-07-24 15:42:08 +05302942 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 ioc->name, &ioc_init));
2944
2945 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2946 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002947 if (r != 0) {
2948 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
2952 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002953 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 */
2955
Prakash, Sathya436ace72007-07-24 15:42:08 +05302956 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002958
2959 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2960 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
2964 /* YIKES! SUPER IMPORTANT!!!
2965 * Poll IocState until _OPERATIONAL while IOC is doing
2966 * LoopInit and TargetDiscovery!
2967 */
2968 count = 0;
2969 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2970 state = mpt_GetIocState(ioc, 1);
2971 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2972 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002973 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 } else {
2975 mdelay(1);
2976 }
2977
2978 if (!cntdn) {
2979 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2980 ioc->name, (int)((count+5)/HZ));
2981 return -9;
2982 }
2983
2984 state = mpt_GetIocState(ioc, 1);
2985 count++;
2986 }
Eric Moore29dd3602007-09-14 18:46:51 -06002987 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 ioc->name, count));
2989
Eric Mooreba856d32006-07-11 17:34:01 -06002990 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 return r;
2992}
2993
2994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002995/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 * SendPortEnable - Send PortEnable request to MPT adapter port.
2997 * @ioc: Pointer to MPT_ADAPTER structure
2998 * @portnum: Port number to enable
2999 * @sleepFlag: Specifies whether the process can sleep
3000 *
3001 * Send PortEnable to bring IOC to OPERATIONAL state.
3002 *
3003 * Returns 0 for success, non-zero for failure.
3004 */
3005static int
3006SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3007{
3008 PortEnable_t port_enable;
3009 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003010 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 int req_sz;
3012 int reply_sz;
3013
3014 /* Destination... */
3015 reply_sz = sizeof(MPIDefaultReply_t);
3016 memset(&reply_buf, 0, reply_sz);
3017
3018 req_sz = sizeof(PortEnable_t);
3019 memset(&port_enable, 0, req_sz);
3020
3021 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3022 port_enable.PortNumber = portnum;
3023/* port_enable.ChainOffset = 0; */
3024/* port_enable.MsgFlags = 0; */
3025/* port_enable.MsgContext = 0; */
3026
Prakash, Sathya436ace72007-07-24 15:42:08 +05303027 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 ioc->name, portnum, &port_enable));
3029
3030 /* RAID FW may take a long time to enable
3031 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003032 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003033 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3034 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3035 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003036 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003037 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3038 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3039 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003041 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042}
3043
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003044/**
3045 * mpt_alloc_fw_memory - allocate firmware memory
3046 * @ioc: Pointer to MPT_ADAPTER structure
3047 * @size: total FW bytes
3048 *
3049 * If memory has already been allocated, the same (cached) value
3050 * is returned.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 */
3052void
3053mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3054{
3055 if (ioc->cached_fw)
3056 return; /* use already allocated memory */
3057 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
3058 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3059 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Eric Moore0ccdb002006-07-11 17:33:13 -06003060 ioc->alloc_total += size;
3061 ioc->alt_ioc->alloc_total -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 } else {
3063 if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
3064 ioc->alloc_total += size;
3065 }
3066}
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003067/**
3068 * mpt_free_fw_memory - free firmware memory
3069 * @ioc: Pointer to MPT_ADAPTER structure
3070 *
3071 * If alt_img is NULL, delete from ioc structure.
3072 * Else, delete a secondary image in same format.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 */
3074void
3075mpt_free_fw_memory(MPT_ADAPTER *ioc)
3076{
3077 int sz;
3078
3079 sz = ioc->facts.FWImageSize;
Eric Moore29dd3602007-09-14 18:46:51 -06003080 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3081 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
3082 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 ioc->cached_fw = NULL;
3084
3085 return;
3086}
3087
3088
3089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003090/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3092 * @ioc: Pointer to MPT_ADAPTER structure
3093 * @sleepFlag: Specifies whether the process can sleep
3094 *
3095 * Returns 0 for success, >0 for handshake failure
3096 * <0 for fw upload failure.
3097 *
3098 * Remark: If bound IOC and a successful FWUpload was performed
3099 * on the bound IOC, the second image is discarded
3100 * and memory is free'd. Both channels must upload to prevent
3101 * IOC from running in degraded mode.
3102 */
3103static int
3104mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3105{
3106 u8 request[ioc->req_sz];
3107 u8 reply[sizeof(FWUploadReply_t)];
3108 FWUpload_t *prequest;
3109 FWUploadReply_t *preply;
3110 FWUploadTCSGE_t *ptcsge;
3111 int sgeoffset;
3112 u32 flagsLength;
3113 int ii, sz, reply_sz;
3114 int cmdStatus;
3115
3116 /* If the image size is 0, we are done.
3117 */
3118 if ((sz = ioc->facts.FWImageSize) == 0)
3119 return 0;
3120
3121 mpt_alloc_fw_memory(ioc, sz);
3122
Eric Moore29dd3602007-09-14 18:46:51 -06003123 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3124 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003125
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 if (ioc->cached_fw == NULL) {
3127 /* Major Failure.
3128 */
3129 return -ENOMEM;
3130 }
3131
3132 prequest = (FWUpload_t *)&request;
3133 preply = (FWUploadReply_t *)&reply;
3134
3135 /* Destination... */
3136 memset(prequest, 0, ioc->req_sz);
3137
3138 reply_sz = sizeof(reply);
3139 memset(preply, 0, reply_sz);
3140
3141 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3142 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3143
3144 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3145 ptcsge->DetailsLength = 12;
3146 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3147 ptcsge->ImageSize = cpu_to_le32(sz);
3148
3149 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3150
3151 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
3152 mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
3153
3154 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003155 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3156 ioc->name, prequest, sgeoffset));
3157 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
3159 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3160 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3161
Eric Moore29dd3602007-09-14 18:46:51 -06003162 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 cmdStatus = -EFAULT;
3165 if (ii == 0) {
3166 /* Handshake transfer was complete and successful.
3167 * Check the Reply Frame.
3168 */
3169 int status, transfer_sz;
3170 status = le16_to_cpu(preply->IOCStatus);
3171 if (status == MPI_IOCSTATUS_SUCCESS) {
3172 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3173 if (transfer_sz == sz)
3174 cmdStatus = 0;
3175 }
3176 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 ioc->name, cmdStatus));
3179
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 if (cmdStatus) {
3182
Prakash, Sathya436ace72007-07-24 15:42:08 +05303183 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 ioc->name));
3185 mpt_free_fw_memory(ioc);
3186 }
3187
3188 return cmdStatus;
3189}
3190
3191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003192/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 * mpt_downloadboot - DownloadBoot code
3194 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003195 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 * @sleepFlag: Specifies whether the process can sleep
3197 *
3198 * FwDownloadBoot requires Programmed IO access.
3199 *
3200 * Returns 0 for success
3201 * -1 FW Image size is 0
3202 * -2 No valid cached_fw Pointer
3203 * <0 for fw upload failure.
3204 */
3205static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003206mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 MpiExtImageHeader_t *pExtImage;
3209 u32 fwSize;
3210 u32 diag0val;
3211 int count;
3212 u32 *ptrFw;
3213 u32 diagRwData;
3214 u32 nextImage;
3215 u32 load_addr;
3216 u32 ioc_state=0;
3217
Prakash, Sathya436ace72007-07-24 15:42:08 +05303218 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003219 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003220
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3222 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3223 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3224 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3225 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3226 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3227
3228 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3229
3230 /* wait 1 msec */
3231 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003232 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 } else {
3234 mdelay (1);
3235 }
3236
3237 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3238 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3239
3240 for (count = 0; count < 30; count ++) {
3241 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3242 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303243 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 ioc->name, count));
3245 break;
3246 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003247 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003249 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003251 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 }
3253 }
3254
3255 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303256 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003257 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 ioc->name, diag0val));
3259 return -3;
3260 }
3261
3262 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3263 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3264 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3265 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3266 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3267 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3268
3269 /* Set the DiagRwEn and Disable ARM bits */
3270 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3271
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 fwSize = (pFwHeader->ImageSize + 3)/4;
3273 ptrFw = (u32 *) pFwHeader;
3274
3275 /* Write the LoadStartAddress to the DiagRw Address Register
3276 * using Programmed IO
3277 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003278 if (ioc->errata_flag_1064)
3279 pci_enable_io_access(ioc->pcidev);
3280
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303282 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 ioc->name, pFwHeader->LoadStartAddress));
3284
Prakash, Sathya436ace72007-07-24 15:42:08 +05303285 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 ioc->name, fwSize*4, ptrFw));
3287 while (fwSize--) {
3288 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3289 }
3290
3291 nextImage = pFwHeader->NextImageHeaderOffset;
3292 while (nextImage) {
3293 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3294
3295 load_addr = pExtImage->LoadStartAddress;
3296
3297 fwSize = (pExtImage->ImageSize + 3) >> 2;
3298 ptrFw = (u32 *)pExtImage;
3299
Prakash, Sathya436ace72007-07-24 15:42:08 +05303300 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 +02003301 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3303
3304 while (fwSize--) {
3305 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3306 }
3307 nextImage = pExtImage->NextImageHeaderOffset;
3308 }
3309
3310 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303311 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3313
3314 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303315 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3317
3318 /* Clear the internal flash bad bit - autoincrementing register,
3319 * so must do two writes.
3320 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003321 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003322 /*
3323 * 1030 and 1035 H/W errata, workaround to access
3324 * the ClearFlashBadSignatureBit
3325 */
3326 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3327 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3328 diagRwData |= 0x40000000;
3329 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3330 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3331
3332 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3333 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3334 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3335 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3336
3337 /* wait 1 msec */
3338 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003339 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003340 } else {
3341 mdelay (1);
3342 }
3343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003345 if (ioc->errata_flag_1064)
3346 pci_disable_io_access(ioc->pcidev);
3347
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303349 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003350 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003352 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303353 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 ioc->name, diag0val));
3355 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3356
3357 /* Write 0xFF to reset the sequencer */
3358 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3359
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003360 if (ioc->bus_type == SAS) {
3361 ioc_state = mpt_GetIocState(ioc, 0);
3362 if ( (GetIocFacts(ioc, sleepFlag,
3363 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303364 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003365 ioc->name, ioc_state));
3366 return -EFAULT;
3367 }
3368 }
3369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 for (count=0; count<HZ*20; count++) {
3371 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303372 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3373 "downloadboot successful! (count=%d) IocState=%x\n",
3374 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003375 if (ioc->bus_type == SAS) {
3376 return 0;
3377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303379 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3380 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 ioc->name));
3382 return -EFAULT;
3383 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303384 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3385 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 ioc->name));
3387 return 0;
3388 }
3389 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003390 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 } else {
3392 mdelay (10);
3393 }
3394 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303395 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3396 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 return -EFAULT;
3398}
3399
3400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003401/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 * KickStart - Perform hard reset of MPT adapter.
3403 * @ioc: Pointer to MPT_ADAPTER structure
3404 * @force: Force hard reset
3405 * @sleepFlag: Specifies whether the process can sleep
3406 *
3407 * This routine places MPT adapter in diagnostic mode via the
3408 * WriteSequence register, and then performs a hard reset of adapter
3409 * via the Diagnostic register.
3410 *
3411 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3412 * or NO_SLEEP (interrupt thread, use mdelay)
3413 * force - 1 if doorbell active, board fault state
3414 * board operational, IOC_RECOVERY or
3415 * IOC_BRINGUP and there is an alt_ioc.
3416 * 0 else
3417 *
3418 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003419 * 1 - hard reset, READY
3420 * 0 - no reset due to History bit, READY
3421 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 * OR reset but failed to come READY
3423 * -2 - no reset, could not enter DIAG mode
3424 * -3 - reset but bad FW bit
3425 */
3426static int
3427KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3428{
3429 int hard_reset_done = 0;
3430 u32 ioc_state=0;
3431 int cnt,cntdn;
3432
Eric Moore29dd3602007-09-14 18:46:51 -06003433 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003434 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 /* Always issue a Msg Unit Reset first. This will clear some
3436 * SCSI bus hang conditions.
3437 */
3438 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3439
3440 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003441 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 } else {
3443 mdelay (1000);
3444 }
3445 }
3446
3447 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3448 if (hard_reset_done < 0)
3449 return hard_reset_done;
3450
Prakash, Sathya436ace72007-07-24 15:42:08 +05303451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003452 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
3454 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3455 for (cnt=0; cnt<cntdn; cnt++) {
3456 ioc_state = mpt_GetIocState(ioc, 1);
3457 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 ioc->name, cnt));
3460 return hard_reset_done;
3461 }
3462 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003463 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 } else {
3465 mdelay (10);
3466 }
3467 }
3468
Eric Moore29dd3602007-09-14 18:46:51 -06003469 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3470 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 return -1;
3472}
3473
3474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003475/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 * mpt_diag_reset - Perform hard reset of the adapter.
3477 * @ioc: Pointer to MPT_ADAPTER structure
3478 * @ignore: Set if to honor and clear to ignore
3479 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003480 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 * else set to NO_SLEEP (use mdelay instead)
3482 *
3483 * This routine places the adapter in diagnostic mode via the
3484 * WriteSequence register and then performs a hard reset of adapter
3485 * via the Diagnostic register. Adapter should be in ready state
3486 * upon successful completion.
3487 *
3488 * Returns: 1 hard reset successful
3489 * 0 no reset performed because reset history bit set
3490 * -2 enabling diagnostic mode failed
3491 * -3 diagnostic reset failed
3492 */
3493static int
3494mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3495{
Eric Moore0ccdb002006-07-11 17:33:13 -06003496 MPT_ADAPTER *iocp=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 u32 diag0val;
3498 u32 doorbell;
3499 int hard_reset_done = 0;
3500 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 u32 diag1val = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
Eric Moorecd2c6192007-01-29 09:47:47 -07003503 /* Clear any existing interrupts */
3504 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3505
Eric Moore87cf8982006-06-27 16:09:26 -06003506 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303507 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003508 "address=%p\n", ioc->name, __FUNCTION__,
3509 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3510 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3511 if (sleepFlag == CAN_SLEEP)
3512 msleep(1);
3513 else
3514 mdelay(1);
3515
3516 for (count = 0; count < 60; count ++) {
3517 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3518 doorbell &= MPI_IOC_STATE_MASK;
3519
Prakash, Sathya436ace72007-07-24 15:42:08 +05303520 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003521 "looking for READY STATE: doorbell=%x"
3522 " count=%d\n",
3523 ioc->name, doorbell, count));
3524 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003525 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003526 }
3527
3528 /* wait 1 sec */
3529 if (sleepFlag == CAN_SLEEP)
3530 msleep(1000);
3531 else
3532 mdelay(1000);
3533 }
3534 return -1;
3535 }
3536
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 /* Use "Diagnostic reset" method! (only thing available!) */
3538 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3539
Prakash, Sathya436ace72007-07-24 15:42:08 +05303540 if (ioc->debug_level & MPT_DEBUG) {
3541 if (ioc->alt_ioc)
3542 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3543 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
3547 /* Do the reset if we are told to ignore the reset history
3548 * or if the reset history is 0
3549 */
3550 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3551 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3552 /* Write magic sequence to WriteSequence register
3553 * Loop until in diagnostic mode
3554 */
3555 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3556 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3557 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3558 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3559 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3560 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3561
3562 /* wait 100 msec */
3563 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003564 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 } else {
3566 mdelay (100);
3567 }
3568
3569 count++;
3570 if (count > 20) {
3571 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3572 ioc->name, diag0val);
3573 return -2;
3574
3575 }
3576
3577 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3578
Prakash, Sathya436ace72007-07-24 15:42:08 +05303579 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 ioc->name, diag0val));
3581 }
3582
Prakash, Sathya436ace72007-07-24 15:42:08 +05303583 if (ioc->debug_level & MPT_DEBUG) {
3584 if (ioc->alt_ioc)
3585 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3586 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 /*
3590 * Disable the ARM (Bug fix)
3591 *
3592 */
3593 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003594 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595
3596 /*
3597 * Now hit the reset bit in the Diagnostic register
3598 * (THE BIG HAMMER!) (Clears DRWE bit).
3599 */
3600 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3601 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303602 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 ioc->name));
3604
3605 /*
3606 * Call each currently registered protocol IOC reset handler
3607 * with pre-reset indication.
3608 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3609 * MptResetHandlers[] registered yet.
3610 */
3611 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303612 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 int r = 0;
3614
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303615 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3616 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303617 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3618 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303619 ioc->name, cb_idx));
3620 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303622 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3623 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303624 ioc->name, ioc->alt_ioc->name, cb_idx));
3625 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 }
3627 }
3628 }
3629 /* FIXME? Examine results here? */
3630 }
3631
Eric Moore0ccdb002006-07-11 17:33:13 -06003632 if (ioc->cached_fw)
3633 iocp = ioc;
3634 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
3635 iocp = ioc->alt_ioc;
3636 if (iocp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 /* If the DownloadBoot operation fails, the
3638 * IOC will be left unusable. This is a fatal error
3639 * case. _diag_reset will return < 0
3640 */
3641 for (count = 0; count < 30; count ++) {
Eric Moore0ccdb002006-07-11 17:33:13 -06003642 diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3644 break;
3645 }
3646
Prakash, Sathya436ace72007-07-24 15:42:08 +05303647 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Eric Moore0ccdb002006-07-11 17:33:13 -06003648 iocp->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 /* wait 1 sec */
3650 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003651 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 } else {
3653 mdelay (1000);
3654 }
3655 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003656 if ((count = mpt_downloadboot(ioc,
Eric Moore0ccdb002006-07-11 17:33:13 -06003657 (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003658 printk(MYIOC_s_WARN_FMT
3659 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 }
3661
3662 } else {
3663 /* Wait for FW to reload and for board
3664 * to go to the READY state.
3665 * Maximum wait is 60 seconds.
3666 * If fail, no error will check again
3667 * with calling program.
3668 */
3669 for (count = 0; count < 60; count ++) {
3670 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3671 doorbell &= MPI_IOC_STATE_MASK;
3672
3673 if (doorbell == MPI_IOC_STATE_READY) {
3674 break;
3675 }
3676
3677 /* wait 1 sec */
3678 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003679 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 } else {
3681 mdelay (1000);
3682 }
3683 }
3684 }
3685 }
3686
3687 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303688 if (ioc->debug_level & MPT_DEBUG) {
3689 if (ioc->alt_ioc)
3690 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3691 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3692 ioc->name, diag0val, diag1val));
3693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694
3695 /* Clear RESET_HISTORY bit! Place board in the
3696 * diagnostic mode to update the diag register.
3697 */
3698 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3699 count = 0;
3700 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3701 /* Write magic sequence to WriteSequence register
3702 * Loop until in diagnostic mode
3703 */
3704 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3708 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3710
3711 /* wait 100 msec */
3712 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003713 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 } else {
3715 mdelay (100);
3716 }
3717
3718 count++;
3719 if (count > 20) {
3720 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3721 ioc->name, diag0val);
3722 break;
3723 }
3724 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3725 }
3726 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3727 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3728 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3729 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3730 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3731 ioc->name);
3732 }
3733
3734 /* Disable Diagnostic Mode
3735 */
3736 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3737
3738 /* Check FW reload status flags.
3739 */
3740 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3741 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3742 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3743 ioc->name, diag0val);
3744 return -3;
3745 }
3746
Prakash, Sathya436ace72007-07-24 15:42:08 +05303747 if (ioc->debug_level & MPT_DEBUG) {
3748 if (ioc->alt_ioc)
3749 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3750 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
3754 /*
3755 * Reset flag that says we've enabled event notification
3756 */
3757 ioc->facts.EventState = 0;
3758
3759 if (ioc->alt_ioc)
3760 ioc->alt_ioc->facts.EventState = 0;
3761
3762 return hard_reset_done;
3763}
3764
3765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003766/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 * SendIocReset - Send IOCReset request to MPT adapter.
3768 * @ioc: Pointer to MPT_ADAPTER structure
3769 * @reset_type: reset type, expected values are
3770 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003771 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 *
3773 * Send IOCReset request to the MPT adapter.
3774 *
3775 * Returns 0 for success, non-zero for failure.
3776 */
3777static int
3778SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3779{
3780 int r;
3781 u32 state;
3782 int cntdn, count;
3783
Prakash, Sathya436ace72007-07-24 15:42:08 +05303784 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 ioc->name, reset_type));
3786 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3787 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3788 return r;
3789
3790 /* FW ACK'd request, wait for READY state
3791 */
3792 count = 0;
3793 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3794
3795 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3796 cntdn--;
3797 count++;
3798 if (!cntdn) {
3799 if (sleepFlag != CAN_SLEEP)
3800 count *= 10;
3801
Eric Moore29dd3602007-09-14 18:46:51 -06003802 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3803 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 return -ETIME;
3805 }
3806
3807 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003808 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 } else {
3810 mdelay (1); /* 1 msec delay */
3811 }
3812 }
3813
3814 /* TODO!
3815 * Cleanup all event stuff for this IOC; re-issue EventNotification
3816 * request if needed.
3817 */
3818 if (ioc->facts.Function)
3819 ioc->facts.EventState = 0;
3820
3821 return 0;
3822}
3823
3824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003825/**
3826 * initChainBuffers - Allocate memory for and initialize chain buffers
3827 * @ioc: Pointer to MPT_ADAPTER structure
3828 *
3829 * Allocates memory for and initializes chain buffers,
3830 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 */
3832static int
3833initChainBuffers(MPT_ADAPTER *ioc)
3834{
3835 u8 *mem;
3836 int sz, ii, num_chain;
3837 int scale, num_sge, numSGE;
3838
3839 /* ReqToChain size must equal the req_depth
3840 * index = req_idx
3841 */
3842 if (ioc->ReqToChain == NULL) {
3843 sz = ioc->req_depth * sizeof(int);
3844 mem = kmalloc(sz, GFP_ATOMIC);
3845 if (mem == NULL)
3846 return -1;
3847
3848 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303849 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 ioc->name, mem, sz));
3851 mem = kmalloc(sz, GFP_ATOMIC);
3852 if (mem == NULL)
3853 return -1;
3854
3855 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303856 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 ioc->name, mem, sz));
3858 }
3859 for (ii = 0; ii < ioc->req_depth; ii++) {
3860 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3861 }
3862
3863 /* ChainToChain size must equal the total number
3864 * of chain buffers to be allocated.
3865 * index = chain_idx
3866 *
3867 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003868 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 *
3870 * num_sge = num sge in request frame + last chain buffer
3871 * scale = num sge per chain buffer if no chain element
3872 */
3873 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3874 if (sizeof(dma_addr_t) == sizeof(u64))
3875 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3876 else
3877 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3878
3879 if (sizeof(dma_addr_t) == sizeof(u64)) {
3880 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3881 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3882 } else {
3883 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3884 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3885 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303886 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 ioc->name, num_sge, numSGE));
3888
3889 if ( numSGE > MPT_SCSI_SG_DEPTH )
3890 numSGE = MPT_SCSI_SG_DEPTH;
3891
3892 num_chain = 1;
3893 while (numSGE - num_sge > 0) {
3894 num_chain++;
3895 num_sge += (scale - 1);
3896 }
3897 num_chain++;
3898
Prakash, Sathya436ace72007-07-24 15:42:08 +05303899 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 ioc->name, numSGE, num_sge, num_chain));
3901
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003902 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 num_chain *= MPT_SCSI_CAN_QUEUE;
3904 else
3905 num_chain *= MPT_FC_CAN_QUEUE;
3906
3907 ioc->num_chain = num_chain;
3908
3909 sz = num_chain * sizeof(int);
3910 if (ioc->ChainToChain == NULL) {
3911 mem = kmalloc(sz, GFP_ATOMIC);
3912 if (mem == NULL)
3913 return -1;
3914
3915 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303916 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 ioc->name, mem, sz));
3918 } else {
3919 mem = (u8 *) ioc->ChainToChain;
3920 }
3921 memset(mem, 0xFF, sz);
3922 return num_chain;
3923}
3924
3925/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003926/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3928 * @ioc: Pointer to MPT_ADAPTER structure
3929 *
3930 * This routine allocates memory for the MPT reply and request frame
3931 * pools (if necessary), and primes the IOC reply FIFO with
3932 * reply frames.
3933 *
3934 * Returns 0 for success, non-zero for failure.
3935 */
3936static int
3937PrimeIocFifos(MPT_ADAPTER *ioc)
3938{
3939 MPT_FRAME_HDR *mf;
3940 unsigned long flags;
3941 dma_addr_t alloc_dma;
3942 u8 *mem;
3943 int i, reply_sz, sz, total_size, num_chain;
3944
3945 /* Prime reply FIFO... */
3946
3947 if (ioc->reply_frames == NULL) {
3948 if ( (num_chain = initChainBuffers(ioc)) < 0)
3949 return -1;
3950
3951 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303952 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303954 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 ioc->name, reply_sz, reply_sz));
3956
3957 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303958 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303960 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 ioc->name, sz, sz));
3962 total_size += sz;
3963
3964 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 ioc->name, sz, sz, num_chain));
3969
3970 total_size += sz;
3971 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3972 if (mem == NULL) {
3973 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3974 ioc->name);
3975 goto out_fail;
3976 }
3977
Prakash, Sathya436ace72007-07-24 15:42:08 +05303978 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3980
3981 memset(mem, 0, total_size);
3982 ioc->alloc_total += total_size;
3983 ioc->alloc = mem;
3984 ioc->alloc_dma = alloc_dma;
3985 ioc->alloc_sz = total_size;
3986 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
3987 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
3988
Prakash, Sathya436ace72007-07-24 15:42:08 +05303989 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003990 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
3991
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 alloc_dma += reply_sz;
3993 mem += reply_sz;
3994
3995 /* Request FIFO - WE manage this! */
3996
3997 ioc->req_frames = (MPT_FRAME_HDR *) mem;
3998 ioc->req_frames_dma = alloc_dma;
3999
Prakash, Sathya436ace72007-07-24 15:42:08 +05304000 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 ioc->name, mem, (void *)(ulong)alloc_dma));
4002
4003 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4004
4005#if defined(CONFIG_MTRR) && 0
4006 /*
4007 * Enable Write Combining MTRR for IOC's memory region.
4008 * (at least as much as we can; "size and base must be
4009 * multiples of 4 kiB"
4010 */
4011 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4012 sz,
4013 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304014 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 ioc->name, ioc->req_frames_dma, sz));
4016#endif
4017
4018 for (i = 0; i < ioc->req_depth; i++) {
4019 alloc_dma += ioc->req_sz;
4020 mem += ioc->req_sz;
4021 }
4022
4023 ioc->ChainBuffer = mem;
4024 ioc->ChainBufferDMA = alloc_dma;
4025
Prakash, Sathya436ace72007-07-24 15:42:08 +05304026 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4028
4029 /* Initialize the free chain Q.
4030 */
4031
4032 INIT_LIST_HEAD(&ioc->FreeChainQ);
4033
4034 /* Post the chain buffers to the FreeChainQ.
4035 */
4036 mem = (u8 *)ioc->ChainBuffer;
4037 for (i=0; i < num_chain; i++) {
4038 mf = (MPT_FRAME_HDR *) mem;
4039 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4040 mem += ioc->req_sz;
4041 }
4042
4043 /* Initialize Request frames linked list
4044 */
4045 alloc_dma = ioc->req_frames_dma;
4046 mem = (u8 *) ioc->req_frames;
4047
4048 spin_lock_irqsave(&ioc->FreeQlock, flags);
4049 INIT_LIST_HEAD(&ioc->FreeQ);
4050 for (i = 0; i < ioc->req_depth; i++) {
4051 mf = (MPT_FRAME_HDR *) mem;
4052
4053 /* Queue REQUESTs *internally*! */
4054 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4055
4056 mem += ioc->req_sz;
4057 }
4058 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4059
4060 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4061 ioc->sense_buf_pool =
4062 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4063 if (ioc->sense_buf_pool == NULL) {
4064 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4065 ioc->name);
4066 goto out_fail;
4067 }
4068
4069 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4070 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304071 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4073
4074 }
4075
4076 /* Post Reply frames to FIFO
4077 */
4078 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304079 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4081
4082 for (i = 0; i < ioc->reply_depth; i++) {
4083 /* Write each address to the IOC! */
4084 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4085 alloc_dma += ioc->reply_sz;
4086 }
4087
4088 return 0;
4089
4090out_fail:
4091 if (ioc->alloc != NULL) {
4092 sz = ioc->alloc_sz;
4093 pci_free_consistent(ioc->pcidev,
4094 sz,
4095 ioc->alloc, ioc->alloc_dma);
4096 ioc->reply_frames = NULL;
4097 ioc->req_frames = NULL;
4098 ioc->alloc_total -= sz;
4099 }
4100 if (ioc->sense_buf_pool != NULL) {
4101 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4102 pci_free_consistent(ioc->pcidev,
4103 sz,
4104 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4105 ioc->sense_buf_pool = NULL;
4106 }
4107 return -1;
4108}
4109
4110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4111/**
4112 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4113 * from IOC via doorbell handshake method.
4114 * @ioc: Pointer to MPT_ADAPTER structure
4115 * @reqBytes: Size of the request in bytes
4116 * @req: Pointer to MPT request frame
4117 * @replyBytes: Expected size of the reply in bytes
4118 * @u16reply: Pointer to area where reply should be written
4119 * @maxwait: Max wait time for a reply (in seconds)
4120 * @sleepFlag: Specifies whether the process can sleep
4121 *
4122 * NOTES: It is the callers responsibility to byte-swap fields in the
4123 * request which are greater than 1 byte in size. It is also the
4124 * callers responsibility to byte-swap response fields which are
4125 * greater than 1 byte in size.
4126 *
4127 * Returns 0 for success, non-zero for failure.
4128 */
4129static int
4130mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004131 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132{
4133 MPIDefaultReply_t *mptReply;
4134 int failcnt = 0;
4135 int t;
4136
4137 /*
4138 * Get ready to cache a handshake reply
4139 */
4140 ioc->hs_reply_idx = 0;
4141 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4142 mptReply->MsgLength = 0;
4143
4144 /*
4145 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4146 * then tell IOC that we want to handshake a request of N words.
4147 * (WRITE u32val to Doorbell reg).
4148 */
4149 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4150 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4151 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4152 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4153
4154 /*
4155 * Wait for IOC's doorbell handshake int
4156 */
4157 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4158 failcnt++;
4159
Prakash, Sathya436ace72007-07-24 15:42:08 +05304160 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4162
4163 /* Read doorbell and check for active bit */
4164 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4165 return -1;
4166
4167 /*
4168 * Clear doorbell int (WRITE 0 to IntStatus reg),
4169 * then wait for IOC to ACKnowledge that it's ready for
4170 * our handshake request.
4171 */
4172 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4173 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4174 failcnt++;
4175
4176 if (!failcnt) {
4177 int ii;
4178 u8 *req_as_bytes = (u8 *) req;
4179
4180 /*
4181 * Stuff request words via doorbell handshake,
4182 * with ACK from IOC for each.
4183 */
4184 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4185 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4186 (req_as_bytes[(ii*4) + 1] << 8) |
4187 (req_as_bytes[(ii*4) + 2] << 16) |
4188 (req_as_bytes[(ii*4) + 3] << 24));
4189
4190 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4191 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4192 failcnt++;
4193 }
4194
Prakash, Sathya436ace72007-07-24 15:42:08 +05304195 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004196 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Prakash, Sathya436ace72007-07-24 15:42:08 +05304198 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4200
4201 /*
4202 * Wait for completion of doorbell handshake reply from the IOC
4203 */
4204 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4205 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004206
Prakash, Sathya436ace72007-07-24 15:42:08 +05304207 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4209
4210 /*
4211 * Copy out the cached reply...
4212 */
4213 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4214 u16reply[ii] = ioc->hs_reply[ii];
4215 } else {
4216 return -99;
4217 }
4218
4219 return -failcnt;
4220}
4221
4222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004223/**
4224 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 * @ioc: Pointer to MPT_ADAPTER structure
4226 * @howlong: How long to wait (in seconds)
4227 * @sleepFlag: Specifies whether the process can sleep
4228 *
4229 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004230 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4231 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 *
4233 * Returns a negative value on failure, else wait loop count.
4234 */
4235static int
4236WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4237{
4238 int cntdn;
4239 int count = 0;
4240 u32 intstat=0;
4241
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004242 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
4244 if (sleepFlag == CAN_SLEEP) {
4245 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004246 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4248 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4249 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 count++;
4251 }
4252 } else {
4253 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004254 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4256 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4257 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 count++;
4259 }
4260 }
4261
4262 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304263 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 ioc->name, count));
4265 return count;
4266 }
4267
4268 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4269 ioc->name, count, intstat);
4270 return -1;
4271}
4272
4273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004274/**
4275 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 * @ioc: Pointer to MPT_ADAPTER structure
4277 * @howlong: How long to wait (in seconds)
4278 * @sleepFlag: Specifies whether the process can sleep
4279 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004280 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4281 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 *
4283 * Returns a negative value on failure, else wait loop count.
4284 */
4285static int
4286WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4287{
4288 int cntdn;
4289 int count = 0;
4290 u32 intstat=0;
4291
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004292 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 if (sleepFlag == CAN_SLEEP) {
4294 while (--cntdn) {
4295 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4296 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4297 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004298 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 count++;
4300 }
4301 } else {
4302 while (--cntdn) {
4303 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4304 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4305 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004306 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 count++;
4308 }
4309 }
4310
4311 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304312 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 ioc->name, count, howlong));
4314 return count;
4315 }
4316
4317 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4318 ioc->name, count, intstat);
4319 return -1;
4320}
4321
4322/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004323/**
4324 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 * @ioc: Pointer to MPT_ADAPTER structure
4326 * @howlong: How long to wait (in seconds)
4327 * @sleepFlag: Specifies whether the process can sleep
4328 *
4329 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4330 * Reply is cached to IOC private area large enough to hold a maximum
4331 * of 128 bytes of reply data.
4332 *
4333 * Returns a negative value on failure, else size of reply in WORDS.
4334 */
4335static int
4336WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4337{
4338 int u16cnt = 0;
4339 int failcnt = 0;
4340 int t;
4341 u16 *hs_reply = ioc->hs_reply;
4342 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4343 u16 hword;
4344
4345 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4346
4347 /*
4348 * Get first two u16's so we can look at IOC's intended reply MsgLength
4349 */
4350 u16cnt=0;
4351 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4352 failcnt++;
4353 } else {
4354 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4355 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4356 if ((t = WaitForDoorbellInt(ioc, 5, 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 }
4362 }
4363
Prakash, Sathya436ace72007-07-24 15:42:08 +05304364 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004365 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4367
4368 /*
4369 * If no error (and IOC said MsgLength is > 0), piece together
4370 * reply 16 bits at a time.
4371 */
4372 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4373 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4374 failcnt++;
4375 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4376 /* don't overflow our IOC hs_reply[] buffer! */
4377 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4378 hs_reply[u16cnt] = hword;
4379 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4380 }
4381
4382 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4383 failcnt++;
4384 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4385
4386 if (failcnt) {
4387 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4388 ioc->name);
4389 return -failcnt;
4390 }
4391#if 0
4392 else if (u16cnt != (2 * mptReply->MsgLength)) {
4393 return -101;
4394 }
4395 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4396 return -102;
4397 }
4398#endif
4399
Prakash, Sathya436ace72007-07-24 15:42:08 +05304400 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004401 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402
Prakash, Sathya436ace72007-07-24 15:42:08 +05304403 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 ioc->name, t, u16cnt/2));
4405 return u16cnt/2;
4406}
4407
4408/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004409/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 * GetLanConfigPages - Fetch LANConfig pages.
4411 * @ioc: Pointer to MPT_ADAPTER structure
4412 *
4413 * Return: 0 for success
4414 * -ENOMEM if no memory available
4415 * -EPERM if not allowed due to ISR context
4416 * -EAGAIN if no msg frames currently available
4417 * -EFAULT for non-successful reply or no reply (timeout)
4418 */
4419static int
4420GetLanConfigPages(MPT_ADAPTER *ioc)
4421{
4422 ConfigPageHeader_t hdr;
4423 CONFIGPARMS cfg;
4424 LANPage0_t *ppage0_alloc;
4425 dma_addr_t page0_dma;
4426 LANPage1_t *ppage1_alloc;
4427 dma_addr_t page1_dma;
4428 int rc = 0;
4429 int data_sz;
4430 int copy_sz;
4431
4432 /* Get LAN Page 0 header */
4433 hdr.PageVersion = 0;
4434 hdr.PageLength = 0;
4435 hdr.PageNumber = 0;
4436 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004437 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 cfg.physAddr = -1;
4439 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4440 cfg.dir = 0;
4441 cfg.pageAddr = 0;
4442 cfg.timeout = 0;
4443
4444 if ((rc = mpt_config(ioc, &cfg)) != 0)
4445 return rc;
4446
4447 if (hdr.PageLength > 0) {
4448 data_sz = hdr.PageLength * 4;
4449 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4450 rc = -ENOMEM;
4451 if (ppage0_alloc) {
4452 memset((u8 *)ppage0_alloc, 0, data_sz);
4453 cfg.physAddr = page0_dma;
4454 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4455
4456 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4457 /* save the data */
4458 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4459 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4460
4461 }
4462
4463 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4464
4465 /* FIXME!
4466 * Normalize endianness of structure data,
4467 * by byte-swapping all > 1 byte fields!
4468 */
4469
4470 }
4471
4472 if (rc)
4473 return rc;
4474 }
4475
4476 /* Get LAN Page 1 header */
4477 hdr.PageVersion = 0;
4478 hdr.PageLength = 0;
4479 hdr.PageNumber = 1;
4480 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004481 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 cfg.physAddr = -1;
4483 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4484 cfg.dir = 0;
4485 cfg.pageAddr = 0;
4486
4487 if ((rc = mpt_config(ioc, &cfg)) != 0)
4488 return rc;
4489
4490 if (hdr.PageLength == 0)
4491 return 0;
4492
4493 data_sz = hdr.PageLength * 4;
4494 rc = -ENOMEM;
4495 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4496 if (ppage1_alloc) {
4497 memset((u8 *)ppage1_alloc, 0, data_sz);
4498 cfg.physAddr = page1_dma;
4499 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4500
4501 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4502 /* save the data */
4503 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4504 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4505 }
4506
4507 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4508
4509 /* FIXME!
4510 * Normalize endianness of structure data,
4511 * by byte-swapping all > 1 byte fields!
4512 */
4513
4514 }
4515
4516 return rc;
4517}
4518
4519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004520/**
4521 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004522 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004523 * @persist_opcode: see below
4524 *
4525 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4526 * devices not currently present.
4527 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4528 *
4529 * NOTE: Don't use not this function during interrupt time.
4530 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004531 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004532 */
4533
4534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4535int
4536mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4537{
4538 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4539 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4540 MPT_FRAME_HDR *mf = NULL;
4541 MPIHeader_t *mpi_hdr;
4542
4543
4544 /* insure garbage is not sent to fw */
4545 switch(persist_opcode) {
4546
4547 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4548 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4549 break;
4550
4551 default:
4552 return -1;
4553 break;
4554 }
4555
4556 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4557
4558 /* Get a MF for this command.
4559 */
4560 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4561 printk("%s: no msg frames!\n",__FUNCTION__);
4562 return -1;
4563 }
4564
4565 mpi_hdr = (MPIHeader_t *) mf;
4566 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4567 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4568 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4569 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4570 sasIoUnitCntrReq->Operation = persist_opcode;
4571
4572 init_timer(&ioc->persist_timer);
4573 ioc->persist_timer.data = (unsigned long) ioc;
4574 ioc->persist_timer.function = mpt_timer_expired;
4575 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4576 ioc->persist_wait_done=0;
4577 add_timer(&ioc->persist_timer);
4578 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4579 wait_event(mpt_waitq, ioc->persist_wait_done);
4580
4581 sasIoUnitCntrReply =
4582 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4583 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4584 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4585 __FUNCTION__,
4586 sasIoUnitCntrReply->IOCStatus,
4587 sasIoUnitCntrReply->IOCLogInfo);
4588 return -1;
4589 }
4590
4591 printk("%s: success\n",__FUNCTION__);
4592 return 0;
4593}
4594
4595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004596
4597static void
4598mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4599 MpiEventDataRaid_t * pRaidEventData)
4600{
4601 int volume;
4602 int reason;
4603 int disk;
4604 int status;
4605 int flags;
4606 int state;
4607
4608 volume = pRaidEventData->VolumeID;
4609 reason = pRaidEventData->ReasonCode;
4610 disk = pRaidEventData->PhysDiskNum;
4611 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4612 flags = (status >> 0) & 0xff;
4613 state = (status >> 8) & 0xff;
4614
4615 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4616 return;
4617 }
4618
4619 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4620 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4621 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004622 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4623 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004624 } else {
4625 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4626 ioc->name, volume);
4627 }
4628
4629 switch(reason) {
4630 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4631 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4632 ioc->name);
4633 break;
4634
4635 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4636
4637 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4638 ioc->name);
4639 break;
4640
4641 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4642 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4643 ioc->name);
4644 break;
4645
4646 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4647 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4648 ioc->name,
4649 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4650 ? "optimal"
4651 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4652 ? "degraded"
4653 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4654 ? "failed"
4655 : "state unknown",
4656 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4657 ? ", enabled" : "",
4658 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4659 ? ", quiesced" : "",
4660 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4661 ? ", resync in progress" : "" );
4662 break;
4663
4664 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4665 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4666 ioc->name, disk);
4667 break;
4668
4669 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4670 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4671 ioc->name);
4672 break;
4673
4674 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4675 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4676 ioc->name);
4677 break;
4678
4679 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4680 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4681 ioc->name);
4682 break;
4683
4684 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4685 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4686 ioc->name,
4687 state == MPI_PHYSDISK0_STATUS_ONLINE
4688 ? "online"
4689 : state == MPI_PHYSDISK0_STATUS_MISSING
4690 ? "missing"
4691 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4692 ? "not compatible"
4693 : state == MPI_PHYSDISK0_STATUS_FAILED
4694 ? "failed"
4695 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4696 ? "initializing"
4697 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4698 ? "offline requested"
4699 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4700 ? "failed requested"
4701 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4702 ? "offline"
4703 : "state unknown",
4704 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4705 ? ", out of sync" : "",
4706 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4707 ? ", quiesced" : "" );
4708 break;
4709
4710 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4711 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4712 ioc->name, disk);
4713 break;
4714
4715 case MPI_EVENT_RAID_RC_SMART_DATA:
4716 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4717 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4718 break;
4719
4720 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4721 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4722 ioc->name, disk);
4723 break;
4724 }
4725}
4726
4727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004728/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4730 * @ioc: Pointer to MPT_ADAPTER structure
4731 *
4732 * Returns: 0 for success
4733 * -ENOMEM if no memory available
4734 * -EPERM if not allowed due to ISR context
4735 * -EAGAIN if no msg frames currently available
4736 * -EFAULT for non-successful reply or no reply (timeout)
4737 */
4738static int
4739GetIoUnitPage2(MPT_ADAPTER *ioc)
4740{
4741 ConfigPageHeader_t hdr;
4742 CONFIGPARMS cfg;
4743 IOUnitPage2_t *ppage_alloc;
4744 dma_addr_t page_dma;
4745 int data_sz;
4746 int rc;
4747
4748 /* Get the page header */
4749 hdr.PageVersion = 0;
4750 hdr.PageLength = 0;
4751 hdr.PageNumber = 2;
4752 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004753 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 cfg.physAddr = -1;
4755 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4756 cfg.dir = 0;
4757 cfg.pageAddr = 0;
4758 cfg.timeout = 0;
4759
4760 if ((rc = mpt_config(ioc, &cfg)) != 0)
4761 return rc;
4762
4763 if (hdr.PageLength == 0)
4764 return 0;
4765
4766 /* Read the config page */
4767 data_sz = hdr.PageLength * 4;
4768 rc = -ENOMEM;
4769 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4770 if (ppage_alloc) {
4771 memset((u8 *)ppage_alloc, 0, data_sz);
4772 cfg.physAddr = page_dma;
4773 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4774
4775 /* If Good, save data */
4776 if ((rc = mpt_config(ioc, &cfg)) == 0)
4777 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4778
4779 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4780 }
4781
4782 return rc;
4783}
4784
4785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004786/**
4787 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 * @ioc: Pointer to a Adapter Strucutre
4789 * @portnum: IOC port number
4790 *
4791 * Return: -EFAULT if read of config page header fails
4792 * or if no nvram
4793 * If read of SCSI Port Page 0 fails,
4794 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4795 * Adapter settings: async, narrow
4796 * Return 1
4797 * If read of SCSI Port Page 2 fails,
4798 * Adapter settings valid
4799 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4800 * Return 1
4801 * Else
4802 * Both valid
4803 * Return 0
4804 * CHECK - what type of locking mechanisms should be used????
4805 */
4806static int
4807mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4808{
4809 u8 *pbuf;
4810 dma_addr_t buf_dma;
4811 CONFIGPARMS cfg;
4812 ConfigPageHeader_t header;
4813 int ii;
4814 int data, rc = 0;
4815
4816 /* Allocate memory
4817 */
4818 if (!ioc->spi_data.nvram) {
4819 int sz;
4820 u8 *mem;
4821 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4822 mem = kmalloc(sz, GFP_ATOMIC);
4823 if (mem == NULL)
4824 return -EFAULT;
4825
4826 ioc->spi_data.nvram = (int *) mem;
4827
Prakash, Sathya436ace72007-07-24 15:42:08 +05304828 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 ioc->name, ioc->spi_data.nvram, sz));
4830 }
4831
4832 /* Invalidate NVRAM information
4833 */
4834 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4835 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4836 }
4837
4838 /* Read SPP0 header, allocate memory, then read page.
4839 */
4840 header.PageVersion = 0;
4841 header.PageLength = 0;
4842 header.PageNumber = 0;
4843 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004844 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 cfg.physAddr = -1;
4846 cfg.pageAddr = portnum;
4847 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4848 cfg.dir = 0;
4849 cfg.timeout = 0; /* use default */
4850 if (mpt_config(ioc, &cfg) != 0)
4851 return -EFAULT;
4852
4853 if (header.PageLength > 0) {
4854 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4855 if (pbuf) {
4856 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4857 cfg.physAddr = buf_dma;
4858 if (mpt_config(ioc, &cfg) != 0) {
4859 ioc->spi_data.maxBusWidth = MPT_NARROW;
4860 ioc->spi_data.maxSyncOffset = 0;
4861 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4862 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4863 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304864 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4865 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004866 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 } else {
4868 /* Save the Port Page 0 data
4869 */
4870 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4871 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4872 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4873
4874 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4875 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004876 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4877 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 ioc->name, pPP0->Capabilities));
4879 }
4880 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4881 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4882 if (data) {
4883 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4884 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4885 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304886 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4887 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004888 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 } else {
4890 ioc->spi_data.maxSyncOffset = 0;
4891 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4892 }
4893
4894 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4895
4896 /* Update the minSyncFactor based on bus type.
4897 */
4898 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4899 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4900
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004901 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304903 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4904 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004905 ioc->name, ioc->spi_data.minSyncFactor));
4906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 }
4908 }
4909 if (pbuf) {
4910 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4911 }
4912 }
4913 }
4914
4915 /* SCSI Port Page 2 - Read the header then the page.
4916 */
4917 header.PageVersion = 0;
4918 header.PageLength = 0;
4919 header.PageNumber = 2;
4920 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004921 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 cfg.physAddr = -1;
4923 cfg.pageAddr = portnum;
4924 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4925 cfg.dir = 0;
4926 if (mpt_config(ioc, &cfg) != 0)
4927 return -EFAULT;
4928
4929 if (header.PageLength > 0) {
4930 /* Allocate memory and read SCSI Port Page 2
4931 */
4932 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4933 if (pbuf) {
4934 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4935 cfg.physAddr = buf_dma;
4936 if (mpt_config(ioc, &cfg) != 0) {
4937 /* Nvram data is left with INVALID mark
4938 */
4939 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004940 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4941
4942 /* This is an ATTO adapter, read Page2 accordingly
4943 */
4944 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4945 ATTODeviceInfo_t *pdevice = NULL;
4946 u16 ATTOFlags;
4947
4948 /* Save the Port Page 2 data
4949 * (reformat into a 32bit quantity)
4950 */
4951 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4952 pdevice = &pPP2->DeviceSettings[ii];
4953 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4954 data = 0;
4955
4956 /* Translate ATTO device flags to LSI format
4957 */
4958 if (ATTOFlags & ATTOFLAG_DISC)
4959 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4960 if (ATTOFlags & ATTOFLAG_ID_ENB)
4961 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4962 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4963 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4964 if (ATTOFlags & ATTOFLAG_TAGGED)
4965 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4966 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4967 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4968
4969 data = (data << 16) | (pdevice->Period << 8) | 10;
4970 ioc->spi_data.nvram[ii] = data;
4971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 } else {
4973 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4974 MpiDeviceInfo_t *pdevice = NULL;
4975
Moore, Ericd8e925d2006-01-16 18:53:06 -07004976 /*
4977 * Save "Set to Avoid SCSI Bus Resets" flag
4978 */
4979 ioc->spi_data.bus_reset =
4980 (le32_to_cpu(pPP2->PortFlags) &
4981 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4982 0 : 1 ;
4983
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 /* Save the Port Page 2 data
4985 * (reformat into a 32bit quantity)
4986 */
4987 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
4988 ioc->spi_data.PortFlags = data;
4989 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4990 pdevice = &pPP2->DeviceSettings[ii];
4991 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
4992 (pdevice->SyncFactor << 8) | pdevice->Timeout;
4993 ioc->spi_data.nvram[ii] = data;
4994 }
4995 }
4996
4997 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4998 }
4999 }
5000
5001 /* Update Adapter limits with those from NVRAM
5002 * Comment: Don't need to do this. Target performance
5003 * parameters will never exceed the adapters limits.
5004 */
5005
5006 return rc;
5007}
5008
5009/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005010/**
5011 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 * @ioc: Pointer to a Adapter Strucutre
5013 * @portnum: IOC port number
5014 *
5015 * Return: -EFAULT if read of config page header fails
5016 * or 0 if success.
5017 */
5018static int
5019mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5020{
5021 CONFIGPARMS cfg;
5022 ConfigPageHeader_t header;
5023
5024 /* Read the SCSI Device Page 1 header
5025 */
5026 header.PageVersion = 0;
5027 header.PageLength = 0;
5028 header.PageNumber = 1;
5029 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005030 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 cfg.physAddr = -1;
5032 cfg.pageAddr = portnum;
5033 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5034 cfg.dir = 0;
5035 cfg.timeout = 0;
5036 if (mpt_config(ioc, &cfg) != 0)
5037 return -EFAULT;
5038
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005039 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5040 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041
5042 header.PageVersion = 0;
5043 header.PageLength = 0;
5044 header.PageNumber = 0;
5045 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5046 if (mpt_config(ioc, &cfg) != 0)
5047 return -EFAULT;
5048
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005049 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5050 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
Prakash, Sathya436ace72007-07-24 15:42:08 +05305052 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5054
Prakash, Sathya436ace72007-07-24 15:42:08 +05305055 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5057 return 0;
5058}
5059
Eric Mooreb506ade2007-01-29 09:45:37 -07005060/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005061 * mpt_inactive_raid_list_free - This clears this link list.
5062 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005063 **/
5064static void
5065mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5066{
5067 struct inactive_raid_component_info *component_info, *pNext;
5068
5069 if (list_empty(&ioc->raid_data.inactive_list))
5070 return;
5071
5072 down(&ioc->raid_data.inactive_list_mutex);
5073 list_for_each_entry_safe(component_info, pNext,
5074 &ioc->raid_data.inactive_list, list) {
5075 list_del(&component_info->list);
5076 kfree(component_info);
5077 }
5078 up(&ioc->raid_data.inactive_list_mutex);
5079}
5080
5081/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005082 * 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 -07005083 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005084 * @ioc : pointer to per adapter structure
5085 * @channel : volume channel
5086 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005087 **/
5088static void
5089mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5090{
5091 CONFIGPARMS cfg;
5092 ConfigPageHeader_t hdr;
5093 dma_addr_t dma_handle;
5094 pRaidVolumePage0_t buffer = NULL;
5095 int i;
5096 RaidPhysDiskPage0_t phys_disk;
5097 struct inactive_raid_component_info *component_info;
5098 int handle_inactive_volumes;
5099
5100 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5101 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5102 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5103 cfg.pageAddr = (channel << 8) + id;
5104 cfg.cfghdr.hdr = &hdr;
5105 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5106
5107 if (mpt_config(ioc, &cfg) != 0)
5108 goto out;
5109
5110 if (!hdr.PageLength)
5111 goto out;
5112
5113 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5114 &dma_handle);
5115
5116 if (!buffer)
5117 goto out;
5118
5119 cfg.physAddr = dma_handle;
5120 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5121
5122 if (mpt_config(ioc, &cfg) != 0)
5123 goto out;
5124
5125 if (!buffer->NumPhysDisks)
5126 goto out;
5127
5128 handle_inactive_volumes =
5129 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5130 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5131 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5132 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5133
5134 if (!handle_inactive_volumes)
5135 goto out;
5136
5137 down(&ioc->raid_data.inactive_list_mutex);
5138 for (i = 0; i < buffer->NumPhysDisks; i++) {
5139 if(mpt_raid_phys_disk_pg0(ioc,
5140 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5141 continue;
5142
5143 if ((component_info = kmalloc(sizeof (*component_info),
5144 GFP_KERNEL)) == NULL)
5145 continue;
5146
5147 component_info->volumeID = id;
5148 component_info->volumeBus = channel;
5149 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5150 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5151 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5152 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5153
5154 list_add_tail(&component_info->list,
5155 &ioc->raid_data.inactive_list);
5156 }
5157 up(&ioc->raid_data.inactive_list_mutex);
5158
5159 out:
5160 if (buffer)
5161 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5162 dma_handle);
5163}
5164
5165/**
5166 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5167 * @ioc: Pointer to a Adapter Structure
5168 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5169 * @phys_disk: requested payload data returned
5170 *
5171 * Return:
5172 * 0 on success
5173 * -EFAULT if read of config page header fails or data pointer not NULL
5174 * -ENOMEM if pci_alloc failed
5175 **/
5176int
5177mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5178{
5179 CONFIGPARMS cfg;
5180 ConfigPageHeader_t hdr;
5181 dma_addr_t dma_handle;
5182 pRaidPhysDiskPage0_t buffer = NULL;
5183 int rc;
5184
5185 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5186 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5187
5188 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5189 cfg.cfghdr.hdr = &hdr;
5190 cfg.physAddr = -1;
5191 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5192
5193 if (mpt_config(ioc, &cfg) != 0) {
5194 rc = -EFAULT;
5195 goto out;
5196 }
5197
5198 if (!hdr.PageLength) {
5199 rc = -EFAULT;
5200 goto out;
5201 }
5202
5203 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5204 &dma_handle);
5205
5206 if (!buffer) {
5207 rc = -ENOMEM;
5208 goto out;
5209 }
5210
5211 cfg.physAddr = dma_handle;
5212 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5213 cfg.pageAddr = phys_disk_num;
5214
5215 if (mpt_config(ioc, &cfg) != 0) {
5216 rc = -EFAULT;
5217 goto out;
5218 }
5219
5220 rc = 0;
5221 memcpy(phys_disk, buffer, sizeof(*buffer));
5222 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5223
5224 out:
5225
5226 if (buffer)
5227 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5228 dma_handle);
5229
5230 return rc;
5231}
5232
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233/**
5234 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5235 * @ioc: Pointer to a Adapter Strucutre
5236 * @portnum: IOC port number
5237 *
5238 * Return:
5239 * 0 on success
5240 * -EFAULT if read of config page header fails or data pointer not NULL
5241 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005242 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243int
5244mpt_findImVolumes(MPT_ADAPTER *ioc)
5245{
5246 IOCPage2_t *pIoc2;
5247 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 dma_addr_t ioc2_dma;
5249 CONFIGPARMS cfg;
5250 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 int rc = 0;
5252 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005253 int i;
5254
5255 if (!ioc->ir_firmware)
5256 return 0;
5257
5258 /* Free the old page
5259 */
5260 kfree(ioc->raid_data.pIocPg2);
5261 ioc->raid_data.pIocPg2 = NULL;
5262 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
5264 /* Read IOCP2 header then the page.
5265 */
5266 header.PageVersion = 0;
5267 header.PageLength = 0;
5268 header.PageNumber = 2;
5269 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005270 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 cfg.physAddr = -1;
5272 cfg.pageAddr = 0;
5273 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5274 cfg.dir = 0;
5275 cfg.timeout = 0;
5276 if (mpt_config(ioc, &cfg) != 0)
5277 return -EFAULT;
5278
5279 if (header.PageLength == 0)
5280 return -EFAULT;
5281
5282 iocpage2sz = header.PageLength * 4;
5283 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5284 if (!pIoc2)
5285 return -ENOMEM;
5286
5287 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5288 cfg.physAddr = ioc2_dma;
5289 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005290 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291
Eric Mooreb506ade2007-01-29 09:45:37 -07005292 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5293 if (!mem)
5294 goto out;
5295
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005297 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298
Eric Mooreb506ade2007-01-29 09:45:37 -07005299 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300
Eric Mooreb506ade2007-01-29 09:45:37 -07005301 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5302 mpt_inactive_raid_volumes(ioc,
5303 pIoc2->RaidVolume[i].VolumeBus,
5304 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
Eric Mooreb506ade2007-01-29 09:45:37 -07005306 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5308
5309 return rc;
5310}
5311
Moore, Ericc972c702006-03-14 09:14:06 -07005312static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5314{
5315 IOCPage3_t *pIoc3;
5316 u8 *mem;
5317 CONFIGPARMS cfg;
5318 ConfigPageHeader_t header;
5319 dma_addr_t ioc3_dma;
5320 int iocpage3sz = 0;
5321
5322 /* Free the old page
5323 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005324 kfree(ioc->raid_data.pIocPg3);
5325 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326
5327 /* There is at least one physical disk.
5328 * Read and save IOC Page 3
5329 */
5330 header.PageVersion = 0;
5331 header.PageLength = 0;
5332 header.PageNumber = 3;
5333 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005334 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 cfg.physAddr = -1;
5336 cfg.pageAddr = 0;
5337 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5338 cfg.dir = 0;
5339 cfg.timeout = 0;
5340 if (mpt_config(ioc, &cfg) != 0)
5341 return 0;
5342
5343 if (header.PageLength == 0)
5344 return 0;
5345
5346 /* Read Header good, alloc memory
5347 */
5348 iocpage3sz = header.PageLength * 4;
5349 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5350 if (!pIoc3)
5351 return 0;
5352
5353 /* Read the Page and save the data
5354 * into malloc'd memory.
5355 */
5356 cfg.physAddr = ioc3_dma;
5357 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5358 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005359 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 if (mem) {
5361 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005362 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 }
5364 }
5365
5366 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5367
5368 return 0;
5369}
5370
5371static void
5372mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5373{
5374 IOCPage4_t *pIoc4;
5375 CONFIGPARMS cfg;
5376 ConfigPageHeader_t header;
5377 dma_addr_t ioc4_dma;
5378 int iocpage4sz;
5379
5380 /* Read and save IOC Page 4
5381 */
5382 header.PageVersion = 0;
5383 header.PageLength = 0;
5384 header.PageNumber = 4;
5385 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005386 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 cfg.physAddr = -1;
5388 cfg.pageAddr = 0;
5389 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5390 cfg.dir = 0;
5391 cfg.timeout = 0;
5392 if (mpt_config(ioc, &cfg) != 0)
5393 return;
5394
5395 if (header.PageLength == 0)
5396 return;
5397
5398 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5399 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5400 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5401 if (!pIoc4)
5402 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005403 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 } else {
5405 ioc4_dma = ioc->spi_data.IocPg4_dma;
5406 iocpage4sz = ioc->spi_data.IocPg4Sz;
5407 }
5408
5409 /* Read the Page into dma memory.
5410 */
5411 cfg.physAddr = ioc4_dma;
5412 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5413 if (mpt_config(ioc, &cfg) == 0) {
5414 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5415 ioc->spi_data.IocPg4_dma = ioc4_dma;
5416 ioc->spi_data.IocPg4Sz = iocpage4sz;
5417 } else {
5418 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5419 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005420 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 }
5422}
5423
5424static void
5425mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5426{
5427 IOCPage1_t *pIoc1;
5428 CONFIGPARMS cfg;
5429 ConfigPageHeader_t header;
5430 dma_addr_t ioc1_dma;
5431 int iocpage1sz = 0;
5432 u32 tmp;
5433
5434 /* Check the Coalescing Timeout in IOC Page 1
5435 */
5436 header.PageVersion = 0;
5437 header.PageLength = 0;
5438 header.PageNumber = 1;
5439 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005440 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 cfg.physAddr = -1;
5442 cfg.pageAddr = 0;
5443 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5444 cfg.dir = 0;
5445 cfg.timeout = 0;
5446 if (mpt_config(ioc, &cfg) != 0)
5447 return;
5448
5449 if (header.PageLength == 0)
5450 return;
5451
5452 /* Read Header good, alloc memory
5453 */
5454 iocpage1sz = header.PageLength * 4;
5455 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5456 if (!pIoc1)
5457 return;
5458
5459 /* Read the Page and check coalescing timeout
5460 */
5461 cfg.physAddr = ioc1_dma;
5462 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5463 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305464
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5466 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5467 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5468
Prakash, Sathya436ace72007-07-24 15:42:08 +05305469 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 ioc->name, tmp));
5471
5472 if (tmp > MPT_COALESCING_TIMEOUT) {
5473 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5474
5475 /* Write NVRAM and current
5476 */
5477 cfg.dir = 1;
5478 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5479 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305480 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 ioc->name, MPT_COALESCING_TIMEOUT));
5482
5483 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5484 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305485 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5486 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 ioc->name, MPT_COALESCING_TIMEOUT));
5488 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305489 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5490 "Reset NVRAM Coalescing Timeout Failed\n",
5491 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 }
5493
5494 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305495 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5496 "Reset of Current Coalescing Timeout Failed!\n",
5497 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 }
5499 }
5500
5501 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305502 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 }
5504 }
5505
5506 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5507
5508 return;
5509}
5510
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305511static void
5512mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5513{
5514 CONFIGPARMS cfg;
5515 ConfigPageHeader_t hdr;
5516 dma_addr_t buf_dma;
5517 ManufacturingPage0_t *pbuf = NULL;
5518
5519 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5520 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5521
5522 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5523 cfg.cfghdr.hdr = &hdr;
5524 cfg.physAddr = -1;
5525 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5526 cfg.timeout = 10;
5527
5528 if (mpt_config(ioc, &cfg) != 0)
5529 goto out;
5530
5531 if (!cfg.cfghdr.hdr->PageLength)
5532 goto out;
5533
5534 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5535 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5536 if (!pbuf)
5537 goto out;
5538
5539 cfg.physAddr = buf_dma;
5540
5541 if (mpt_config(ioc, &cfg) != 0)
5542 goto out;
5543
5544 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5545 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5546 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5547
5548 out:
5549
5550 if (pbuf)
5551 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5552}
5553
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005555/**
5556 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 * @ioc: Pointer to MPT_ADAPTER structure
5558 * @EvSwitch: Event switch flags
5559 */
5560static int
5561SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5562{
5563 EventNotification_t *evnp;
5564
5565 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5566 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305567 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 ioc->name));
5569 return 0;
5570 }
5571 memset(evnp, 0, sizeof(*evnp));
5572
Prakash, Sathya436ace72007-07-24 15:42:08 +05305573 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574
5575 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5576 evnp->ChainOffset = 0;
5577 evnp->MsgFlags = 0;
5578 evnp->Switch = EvSwitch;
5579
5580 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5581
5582 return 0;
5583}
5584
5585/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5586/**
5587 * SendEventAck - Send EventAck request to MPT adapter.
5588 * @ioc: Pointer to MPT_ADAPTER structure
5589 * @evnp: Pointer to original EventNotification request
5590 */
5591static int
5592SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5593{
5594 EventAck_t *pAck;
5595
5596 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305597 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005598 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 return -1;
5600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Prakash, Sathya436ace72007-07-24 15:42:08 +05305602 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603
5604 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5605 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005606 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005608 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 pAck->Event = evnp->Event;
5610 pAck->EventContext = evnp->EventContext;
5611
5612 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5613
5614 return 0;
5615}
5616
5617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5618/**
5619 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005620 * @ioc: Pointer to an adapter structure
5621 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 * action, page address, direction, physical address
5623 * and pointer to a configuration page header
5624 * Page header is updated.
5625 *
5626 * Returns 0 for success
5627 * -EPERM if not allowed due to ISR context
5628 * -EAGAIN if no msg frames currently available
5629 * -EFAULT for non-successful reply or no reply (timeout)
5630 */
5631int
5632mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5633{
5634 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005635 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 MPT_FRAME_HDR *mf;
5637 unsigned long flags;
5638 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005639 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 int in_isr;
5641
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005642 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 * to be in ISR context, because that is fatal!
5644 */
5645 in_isr = in_interrupt();
5646 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305647 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 ioc->name));
5649 return -EPERM;
5650 }
5651
5652 /* Get and Populate a free Frame
5653 */
5654 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305655 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 ioc->name));
5657 return -EAGAIN;
5658 }
5659 pReq = (Config_t *)mf;
5660 pReq->Action = pCfg->action;
5661 pReq->Reserved = 0;
5662 pReq->ChainOffset = 0;
5663 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005664
5665 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 pReq->ExtPageLength = 0;
5667 pReq->ExtPageType = 0;
5668 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005669
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 for (ii=0; ii < 8; ii++)
5671 pReq->Reserved2[ii] = 0;
5672
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005673 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5674 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5675 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5676 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5677
5678 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5679 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5680 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5681 pReq->ExtPageType = pExtHdr->ExtPageType;
5682 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5683
5684 /* Page Length must be treated as a reserved field for the extended header. */
5685 pReq->Header.PageLength = 0;
5686 }
5687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5689
5690 /* Add a SGE to the config request.
5691 */
5692 if (pCfg->dir)
5693 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5694 else
5695 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5696
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005697 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5698 flagsLength |= pExtHdr->ExtPageLength * 4;
5699
Prakash, Sathya436ace72007-07-24 15:42:08 +05305700 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 +02005701 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5702 }
5703 else {
5704 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5705
Prakash, Sathya436ace72007-07-24 15:42:08 +05305706 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 +02005707 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709
5710 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5711
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712 /* Append pCfg pointer to end of mf
5713 */
5714 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5715
5716 /* Initalize the timer
5717 */
5718 init_timer(&pCfg->timer);
5719 pCfg->timer.data = (unsigned long) ioc;
5720 pCfg->timer.function = mpt_timer_expired;
5721 pCfg->wait_done = 0;
5722
5723 /* Set the timer; ensure 10 second minimum */
5724 if (pCfg->timeout < 10)
5725 pCfg->timer.expires = jiffies + HZ*10;
5726 else
5727 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5728
5729 /* Add to end of Q, set timer and then issue this command */
5730 spin_lock_irqsave(&ioc->FreeQlock, flags);
5731 list_add_tail(&pCfg->linkage, &ioc->configQ);
5732 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5733
5734 add_timer(&pCfg->timer);
5735 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5736 wait_event(mpt_waitq, pCfg->wait_done);
5737
5738 /* mf has been freed - do not access */
5739
5740 rc = pCfg->status;
5741
5742 return rc;
5743}
5744
5745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005746/**
5747 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 * Used only internal config functionality.
5749 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5750 */
5751static void
5752mpt_timer_expired(unsigned long data)
5753{
5754 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5755
Prakash, Sathya436ace72007-07-24 15:42:08 +05305756 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757
5758 /* Perform a FW reload */
5759 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5760 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5761
5762 /* No more processing.
5763 * Hard reset clean-up will wake up
5764 * process and free all resources.
5765 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305766 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767
5768 return;
5769}
5770
5771/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005772/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773 * mpt_ioc_reset - Base cleanup for hard reset
5774 * @ioc: Pointer to the adapter structure
5775 * @reset_phase: Indicates pre- or post-reset functionality
5776 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005777 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 */
5779static int
5780mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5781{
5782 CONFIGPARMS *pCfg;
5783 unsigned long flags;
5784
Eric Moore29dd3602007-09-14 18:46:51 -06005785 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5786 ": IOC %s_reset routed to MPT base driver!\n",
5787 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5788 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
5790 if (reset_phase == MPT_IOC_SETUP_RESET) {
5791 ;
5792 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5793 /* If the internal config Q is not empty -
5794 * delete timer. MF resources will be freed when
5795 * the FIFO's are primed.
5796 */
5797 spin_lock_irqsave(&ioc->FreeQlock, flags);
5798 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5799 del_timer(&pCfg->timer);
5800 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5801
5802 } else {
5803 CONFIGPARMS *pNext;
5804
5805 /* Search the configQ for internal commands.
5806 * Flush the Q, and wake up all suspended threads.
5807 */
5808 spin_lock_irqsave(&ioc->FreeQlock, flags);
5809 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5810 list_del(&pCfg->linkage);
5811
5812 pCfg->status = MPT_CONFIG_ERROR;
5813 pCfg->wait_done = 1;
5814 wake_up(&mpt_waitq);
5815 }
5816 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5817 }
5818
5819 return 1; /* currently means nothing really */
5820}
5821
5822
5823#ifdef CONFIG_PROC_FS /* { */
5824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5825/*
5826 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5827 */
5828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005829/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5831 *
5832 * Returns 0 for success, non-zero for failure.
5833 */
5834static int
5835procmpt_create(void)
5836{
5837 struct proc_dir_entry *ent;
5838
5839 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5840 if (mpt_proc_root_dir == NULL)
5841 return -ENOTDIR;
5842
5843 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5844 if (ent)
5845 ent->read_proc = procmpt_summary_read;
5846
5847 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5848 if (ent)
5849 ent->read_proc = procmpt_version_read;
5850
5851 return 0;
5852}
5853
5854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005855/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5857 *
5858 * Returns 0 for success, non-zero for failure.
5859 */
5860static void
5861procmpt_destroy(void)
5862{
5863 remove_proc_entry("version", mpt_proc_root_dir);
5864 remove_proc_entry("summary", mpt_proc_root_dir);
5865 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5866}
5867
5868/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005869/**
5870 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 * @buf: Pointer to area to write information
5872 * @start: Pointer to start pointer
5873 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005874 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 * @eof: Pointer to EOF integer
5876 * @data: Pointer
5877 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005878 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 * Returns number of characters written to process performing the read.
5880 */
5881static int
5882procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5883{
5884 MPT_ADAPTER *ioc;
5885 char *out = buf;
5886 int len;
5887
5888 if (data) {
5889 int more = 0;
5890
5891 ioc = data;
5892 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5893
5894 out += more;
5895 } else {
5896 list_for_each_entry(ioc, &ioc_list, list) {
5897 int more = 0;
5898
5899 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5900
5901 out += more;
5902 if ((out-buf) >= request)
5903 break;
5904 }
5905 }
5906
5907 len = out - buf;
5908
5909 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5910}
5911
5912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005913/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 * procmpt_version_read - Handle read request from /proc/mpt/version.
5915 * @buf: Pointer to area to write information
5916 * @start: Pointer to start pointer
5917 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005918 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 * @eof: Pointer to EOF integer
5920 * @data: Pointer
5921 *
5922 * Returns number of characters written to process performing the read.
5923 */
5924static int
5925procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5926{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305927 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005928 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 char *drvname;
5930 int len;
5931
5932 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5933 len += sprintf(buf+len, " Fusion MPT base driver\n");
5934
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005935 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06005936 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305938 if (MptCallbacks[cb_idx]) {
5939 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005940 case MPTSPI_DRIVER:
5941 if (!scsi++) drvname = "SPI host";
5942 break;
5943 case MPTFC_DRIVER:
5944 if (!fc++) drvname = "FC host";
5945 break;
5946 case MPTSAS_DRIVER:
5947 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948 break;
5949 case MPTLAN_DRIVER:
5950 if (!lan++) drvname = "LAN";
5951 break;
5952 case MPTSTM_DRIVER:
5953 if (!targ++) drvname = "SCSI target";
5954 break;
5955 case MPTCTL_DRIVER:
5956 if (!ctl++) drvname = "ioctl";
5957 break;
5958 }
5959
5960 if (drvname)
5961 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5962 }
5963 }
5964
5965 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5966}
5967
5968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005969/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5971 * @buf: Pointer to area to write information
5972 * @start: Pointer to start pointer
5973 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005974 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 * @eof: Pointer to EOF integer
5976 * @data: Pointer
5977 *
5978 * Returns number of characters written to process performing the read.
5979 */
5980static int
5981procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5982{
5983 MPT_ADAPTER *ioc = data;
5984 int len;
5985 char expVer[32];
5986 int sz;
5987 int p;
5988
5989 mpt_get_fw_exp_ver(expVer, ioc);
5990
5991 len = sprintf(buf, "%s:", ioc->name);
5992 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
5993 len += sprintf(buf+len, " (f/w download boot flag set)");
5994// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
5995// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
5996
5997 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
5998 ioc->facts.ProductID,
5999 ioc->prod_name);
6000 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6001 if (ioc->facts.FWImageSize)
6002 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6003 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6004 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6005 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6006
6007 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6008 ioc->facts.CurrentHostMfaHighAddr);
6009 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6010 ioc->facts.CurrentSenseBufferHighAddr);
6011
6012 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6013 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6014
6015 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6016 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6017 /*
6018 * Rounding UP to nearest 4-kB boundary here...
6019 */
6020 sz = (ioc->req_sz * ioc->req_depth) + 128;
6021 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6022 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6023 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6024 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6025 4*ioc->facts.RequestFrameSize,
6026 ioc->facts.GlobalCredits);
6027
6028 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6029 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6030 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6031 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6032 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6033 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6034 ioc->facts.CurReplyFrameSize,
6035 ioc->facts.ReplyQueueDepth);
6036
6037 len += sprintf(buf+len, " MaxDevices = %d\n",
6038 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6039 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6040
6041 /* per-port info */
6042 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6043 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6044 p+1,
6045 ioc->facts.NumberOfPorts);
6046 if (ioc->bus_type == FC) {
6047 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6048 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6049 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6050 a[5], a[4], a[3], a[2], a[1], a[0]);
6051 }
6052 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6053 ioc->fc_port_page0[p].WWNN.High,
6054 ioc->fc_port_page0[p].WWNN.Low,
6055 ioc->fc_port_page0[p].WWPN.High,
6056 ioc->fc_port_page0[p].WWPN.Low);
6057 }
6058 }
6059
6060 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6061}
6062
6063#endif /* CONFIG_PROC_FS } */
6064
6065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6066static void
6067mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6068{
6069 buf[0] ='\0';
6070 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6071 sprintf(buf, " (Exp %02d%02d)",
6072 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6073 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6074
6075 /* insider hack! */
6076 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6077 strcat(buf, " [MDBG]");
6078 }
6079}
6080
6081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6082/**
6083 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6084 * @ioc: Pointer to MPT_ADAPTER structure
6085 * @buffer: Pointer to buffer where IOC summary info should be written
6086 * @size: Pointer to number of bytes we wrote (set by this routine)
6087 * @len: Offset at which to start writing in buffer
6088 * @showlan: Display LAN stuff?
6089 *
6090 * This routine writes (english readable) ASCII text, which represents
6091 * a summary of IOC information, to a buffer.
6092 */
6093void
6094mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6095{
6096 char expVer[32];
6097 int y;
6098
6099 mpt_get_fw_exp_ver(expVer, ioc);
6100
6101 /*
6102 * Shorter summary of attached ioc's...
6103 */
6104 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6105 ioc->name,
6106 ioc->prod_name,
6107 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6108 ioc->facts.FWVersion.Word,
6109 expVer,
6110 ioc->facts.NumberOfPorts,
6111 ioc->req_depth);
6112
6113 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6114 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6115 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6116 a[5], a[4], a[3], a[2], a[1], a[0]);
6117 }
6118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120
6121 if (!ioc->active)
6122 y += sprintf(buffer+len+y, " (disabled)");
6123
6124 y += sprintf(buffer+len+y, "\n");
6125
6126 *size = y;
6127}
6128
6129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6130/*
6131 * Reset Handling
6132 */
6133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6134/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006135 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 * @ioc: Pointer to MPT_ADAPTER structure
6137 * @sleepFlag: Indicates if sleep or schedule must be called.
6138 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006139 * Issues SCSI Task Management call based on input arg values.
6140 * If TaskMgmt fails, returns associated SCSI request.
6141 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6143 * or a non-interrupt thread. In the former, must not call schedule().
6144 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006145 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 * FW reload/initialization failed.
6147 *
6148 * Returns 0 for SUCCESS or -1 if FAILED.
6149 */
6150int
6151mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6152{
6153 int rc;
6154 unsigned long flags;
6155
Prakash, Sathya436ace72007-07-24 15:42:08 +05306156 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157#ifdef MFCNT
6158 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6159 printk("MF count 0x%x !\n", ioc->mfcnt);
6160#endif
6161
6162 /* Reset the adapter. Prevent more than 1 call to
6163 * mpt_do_ioc_recovery at any instant in time.
6164 */
6165 spin_lock_irqsave(&ioc->diagLock, flags);
6166 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6167 spin_unlock_irqrestore(&ioc->diagLock, flags);
6168 return 0;
6169 } else {
6170 ioc->diagPending = 1;
6171 }
6172 spin_unlock_irqrestore(&ioc->diagLock, flags);
6173
6174 /* FIXME: If do_ioc_recovery fails, repeat....
6175 */
6176
6177 /* The SCSI driver needs to adjust timeouts on all current
6178 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006179 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 * For all other protocol drivers, this is a no-op.
6181 */
6182 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306183 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 int r = 0;
6185
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306186 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6187 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306188 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306189 ioc->name, cb_idx));
6190 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306192 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306193 ioc->name, ioc->alt_ioc->name, cb_idx));
6194 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 }
6196 }
6197 }
6198 }
6199
6200 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006201 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202 }
6203 ioc->reload_fw = 0;
6204 if (ioc->alt_ioc)
6205 ioc->alt_ioc->reload_fw = 0;
6206
6207 spin_lock_irqsave(&ioc->diagLock, flags);
6208 ioc->diagPending = 0;
6209 if (ioc->alt_ioc)
6210 ioc->alt_ioc->diagPending = 0;
6211 spin_unlock_irqrestore(&ioc->diagLock, flags);
6212
Prakash, Sathya436ace72007-07-24 15:42:08 +05306213 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214
6215 return rc;
6216}
6217
6218/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006219static void
6220EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221{
Eric Moore509e5e52006-04-26 13:22:37 -06006222 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
6224 switch(event) {
6225 case MPI_EVENT_NONE:
6226 ds = "None";
6227 break;
6228 case MPI_EVENT_LOG_DATA:
6229 ds = "Log Data";
6230 break;
6231 case MPI_EVENT_STATE_CHANGE:
6232 ds = "State Change";
6233 break;
6234 case MPI_EVENT_UNIT_ATTENTION:
6235 ds = "Unit Attention";
6236 break;
6237 case MPI_EVENT_IOC_BUS_RESET:
6238 ds = "IOC Bus Reset";
6239 break;
6240 case MPI_EVENT_EXT_BUS_RESET:
6241 ds = "External Bus Reset";
6242 break;
6243 case MPI_EVENT_RESCAN:
6244 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 break;
6246 case MPI_EVENT_LINK_STATUS_CHANGE:
6247 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6248 ds = "Link Status(FAILURE) Change";
6249 else
6250 ds = "Link Status(ACTIVE) Change";
6251 break;
6252 case MPI_EVENT_LOOP_STATE_CHANGE:
6253 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6254 ds = "Loop State(LIP) Change";
6255 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006256 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 else
Eric Moore509e5e52006-04-26 13:22:37 -06006258 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 break;
6260 case MPI_EVENT_LOGOUT:
6261 ds = "Logout";
6262 break;
6263 case MPI_EVENT_EVENT_CHANGE:
6264 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006265 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006267 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268 break;
6269 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006270 {
6271 u8 ReasonCode = (u8)(evData0 >> 16);
6272 switch (ReasonCode) {
6273 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6274 ds = "Integrated Raid: Volume Created";
6275 break;
6276 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6277 ds = "Integrated Raid: Volume Deleted";
6278 break;
6279 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6280 ds = "Integrated Raid: Volume Settings Changed";
6281 break;
6282 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6283 ds = "Integrated Raid: Volume Status Changed";
6284 break;
6285 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6286 ds = "Integrated Raid: Volume Physdisk Changed";
6287 break;
6288 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6289 ds = "Integrated Raid: Physdisk Created";
6290 break;
6291 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6292 ds = "Integrated Raid: Physdisk Deleted";
6293 break;
6294 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6295 ds = "Integrated Raid: Physdisk Settings Changed";
6296 break;
6297 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6298 ds = "Integrated Raid: Physdisk Status Changed";
6299 break;
6300 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6301 ds = "Integrated Raid: Domain Validation Needed";
6302 break;
6303 case MPI_EVENT_RAID_RC_SMART_DATA :
6304 ds = "Integrated Raid; Smart Data";
6305 break;
6306 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6307 ds = "Integrated Raid: Replace Action Started";
6308 break;
6309 default:
6310 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006312 }
6313 break;
6314 }
6315 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6316 ds = "SCSI Device Status Change";
6317 break;
6318 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6319 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006320 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006321 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006322 u8 ReasonCode = (u8)(evData0 >> 16);
6323 switch (ReasonCode) {
6324 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006325 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006326 "SAS Device Status Change: Added: "
6327 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006328 break;
6329 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
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: Deleted: "
6332 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006333 break;
6334 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
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: SMART Data: "
6337 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006338 break;
6339 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
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: No Persistancy: "
6342 "id=%d channel=%d", id, channel);
6343 break;
6344 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6345 snprintf(evStr, EVENT_DESCR_STR_SZ,
6346 "SAS Device Status Change: Unsupported Device "
6347 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006348 break;
6349 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6350 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006351 "SAS Device Status Change: Internal Device "
6352 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006353 break;
6354 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6355 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006356 "SAS Device Status Change: Internal Task "
6357 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006358 break;
6359 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6360 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006361 "SAS Device Status Change: Internal Abort "
6362 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006363 break;
6364 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6365 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006366 "SAS Device Status Change: Internal Clear "
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_QUERY_TASK_INTERNAL:
6370 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006371 "SAS Device Status Change: Internal Query "
6372 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006373 break;
6374 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006375 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006376 "SAS Device Status Change: Unknown: "
6377 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006378 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006379 }
6380 break;
6381 }
6382 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6383 ds = "Bus Timer Expired";
6384 break;
6385 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006386 {
6387 u16 curr_depth = (u16)(evData0 >> 16);
6388 u8 channel = (u8)(evData0 >> 8);
6389 u8 id = (u8)(evData0);
6390
6391 snprintf(evStr, EVENT_DESCR_STR_SZ,
6392 "Queue Full: channel=%d id=%d depth=%d",
6393 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006394 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006395 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006396 case MPI_EVENT_SAS_SES:
6397 ds = "SAS SES Event";
6398 break;
6399 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6400 ds = "Persistent Table Full";
6401 break;
6402 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006403 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006404 u8 LinkRates = (u8)(evData0 >> 8);
6405 u8 PhyNumber = (u8)(evData0);
6406 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6407 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6408 switch (LinkRates) {
6409 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006410 snprintf(evStr, EVENT_DESCR_STR_SZ,
6411 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006412 " Rate Unknown",PhyNumber);
6413 break;
6414 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
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 " Phy Disabled",PhyNumber);
6418 break;
6419 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
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 " Failed Speed Nego",PhyNumber);
6423 break;
6424 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
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 " Sata OOB Completed",PhyNumber);
6428 break;
6429 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
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 " Rate 1.5 Gbps",PhyNumber);
6433 break;
6434 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
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 3.0 Gpbs",PhyNumber);
6438 break;
6439 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006440 snprintf(evStr, EVENT_DESCR_STR_SZ,
6441 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006442 break;
6443 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006444 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006445 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006446 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6447 ds = "SAS Discovery Error";
6448 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006449 case MPI_EVENT_IR_RESYNC_UPDATE:
6450 {
6451 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006452 snprintf(evStr, EVENT_DESCR_STR_SZ,
6453 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006454 break;
6455 }
6456 case MPI_EVENT_IR2:
6457 {
6458 u8 ReasonCode = (u8)(evData0 >> 16);
6459 switch (ReasonCode) {
6460 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6461 ds = "IR2: LD State Changed";
6462 break;
6463 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6464 ds = "IR2: PD State Changed";
6465 break;
6466 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6467 ds = "IR2: Bad Block Table Full";
6468 break;
6469 case MPI_EVENT_IR2_RC_PD_INSERTED:
6470 ds = "IR2: PD Inserted";
6471 break;
6472 case MPI_EVENT_IR2_RC_PD_REMOVED:
6473 ds = "IR2: PD Removed";
6474 break;
6475 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6476 ds = "IR2: Foreign CFG Detected";
6477 break;
6478 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6479 ds = "IR2: Rebuild Medium Error";
6480 break;
6481 default:
6482 ds = "IR2";
6483 break;
6484 }
6485 break;
6486 }
6487 case MPI_EVENT_SAS_DISCOVERY:
6488 {
6489 if (evData0)
6490 ds = "SAS Discovery: Start";
6491 else
6492 ds = "SAS Discovery: Stop";
6493 break;
6494 }
6495 case MPI_EVENT_LOG_ENTRY_ADDED:
6496 ds = "SAS Log Entry Added";
6497 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006498
Eric Moorec6c727a2007-01-29 09:44:54 -07006499 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6500 {
6501 u8 phy_num = (u8)(evData0);
6502 u8 port_num = (u8)(evData0 >> 8);
6503 u8 port_width = (u8)(evData0 >> 16);
6504 u8 primative = (u8)(evData0 >> 24);
6505 snprintf(evStr, EVENT_DESCR_STR_SZ,
6506 "SAS Broadcase Primative: phy=%d port=%d "
6507 "width=%d primative=0x%02x",
6508 phy_num, port_num, port_width, primative);
6509 break;
6510 }
6511
6512 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6513 {
6514 u8 reason = (u8)(evData0);
6515 u8 port_num = (u8)(evData0 >> 8);
6516 u16 handle = le16_to_cpu(evData0 >> 16);
6517
6518 snprintf(evStr, EVENT_DESCR_STR_SZ,
6519 "SAS Initiator Device Status Change: reason=0x%02x "
6520 "port=%d handle=0x%04x",
6521 reason, port_num, handle);
6522 break;
6523 }
6524
6525 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6526 {
6527 u8 max_init = (u8)(evData0);
6528 u8 current_init = (u8)(evData0 >> 8);
6529
6530 snprintf(evStr, EVENT_DESCR_STR_SZ,
6531 "SAS Initiator Device Table Overflow: max initiators=%02d "
6532 "current initators=%02d",
6533 max_init, current_init);
6534 break;
6535 }
6536 case MPI_EVENT_SAS_SMP_ERROR:
6537 {
6538 u8 status = (u8)(evData0);
6539 u8 port_num = (u8)(evData0 >> 8);
6540 u8 result = (u8)(evData0 >> 16);
6541
6542 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6543 snprintf(evStr, EVENT_DESCR_STR_SZ,
6544 "SAS SMP Error: port=%d result=0x%02x",
6545 port_num, result);
6546 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6547 snprintf(evStr, EVENT_DESCR_STR_SZ,
6548 "SAS SMP Error: port=%d : CRC Error",
6549 port_num);
6550 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6551 snprintf(evStr, EVENT_DESCR_STR_SZ,
6552 "SAS SMP Error: port=%d : Timeout",
6553 port_num);
6554 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6555 snprintf(evStr, EVENT_DESCR_STR_SZ,
6556 "SAS SMP Error: port=%d : No Destination",
6557 port_num);
6558 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6559 snprintf(evStr, EVENT_DESCR_STR_SZ,
6560 "SAS SMP Error: port=%d : Bad Destination",
6561 port_num);
6562 else
6563 snprintf(evStr, EVENT_DESCR_STR_SZ,
6564 "SAS SMP Error: port=%d : status=0x%02x",
6565 port_num, status);
6566 break;
6567 }
6568
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569 /*
6570 * MPT base "custom" events may be added here...
6571 */
6572 default:
6573 ds = "Unknown";
6574 break;
6575 }
Eric Moore509e5e52006-04-26 13:22:37 -06006576 if (ds)
6577 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578}
6579
6580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006581/**
6582 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 * @ioc: Pointer to MPT_ADAPTER structure
6584 * @pEventReply: Pointer to EventNotification reply frame
6585 * @evHandlers: Pointer to integer, number of event handlers
6586 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006587 * Routes a received EventNotificationReply to all currently registered
6588 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006589 * Returns sum of event handlers return values.
6590 */
6591static int
6592ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6593{
6594 u16 evDataLen;
6595 u32 evData0 = 0;
6596// u32 evCtx;
6597 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306598 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599 int r = 0;
6600 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006601 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 u8 event;
6603
6604 /*
6605 * Do platform normalization of values
6606 */
6607 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6608// evCtx = le32_to_cpu(pEventReply->EventContext);
6609 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6610 if (evDataLen) {
6611 evData0 = le32_to_cpu(pEventReply->Data[0]);
6612 }
6613
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006614 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306615 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006617 event,
6618 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619
Prakash, Sathya436ace72007-07-24 15:42:08 +05306620#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006621 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6622 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306624 devtverboseprintk(ioc, printk(" %08x",
6625 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006626 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627#endif
6628
6629 /*
6630 * Do general / base driver event processing
6631 */
6632 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6634 if (evDataLen) {
6635 u8 evState = evData0 & 0xFF;
6636
6637 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6638
6639 /* Update EventState field in cached IocFacts */
6640 if (ioc->facts.Function) {
6641 ioc->facts.EventState = evState;
6642 }
6643 }
6644 break;
Moore, Ericece50912006-01-16 18:53:19 -07006645 case MPI_EVENT_INTEGRATED_RAID:
6646 mptbase_raid_process_event_data(ioc,
6647 (MpiEventDataRaid_t *)pEventReply->Data);
6648 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006649 default:
6650 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651 }
6652
6653 /*
6654 * Should this event be logged? Events are written sequentially.
6655 * When buffer is full, start again at the top.
6656 */
6657 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6658 int idx;
6659
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006660 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661
6662 ioc->events[idx].event = event;
6663 ioc->events[idx].eventContext = ioc->eventContext;
6664
6665 for (ii = 0; ii < 2; ii++) {
6666 if (ii < evDataLen)
6667 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6668 else
6669 ioc->events[idx].data[ii] = 0;
6670 }
6671
6672 ioc->eventContext++;
6673 }
6674
6675
6676 /*
6677 * Call each currently registered protocol event handler.
6678 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006679 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306680 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306681 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306682 ioc->name, cb_idx));
6683 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684 handlers++;
6685 }
6686 }
6687 /* FIXME? Examine results here? */
6688
6689 /*
6690 * If needed, send (a single) EventAck.
6691 */
6692 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306693 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006694 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306696 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697 ioc->name, ii));
6698 }
6699 }
6700
6701 *evHandlers = handlers;
6702 return r;
6703}
6704
6705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006706/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6708 * @ioc: Pointer to MPT_ADAPTER structure
6709 * @log_info: U32 LogInfo reply word from the IOC
6710 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006711 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 */
6713static void
6714mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6715{
Eric Moore7c431e52007-06-13 16:34:36 -06006716 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717
Eric Moore7c431e52007-06-13 16:34:36 -06006718 switch (log_info & 0xFF000000) {
6719 case MPI_IOCLOGINFO_FC_INIT_BASE:
6720 desc = "FCP Initiator";
6721 break;
6722 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6723 desc = "FCP Target";
6724 break;
6725 case MPI_IOCLOGINFO_FC_LAN_BASE:
6726 desc = "LAN";
6727 break;
6728 case MPI_IOCLOGINFO_FC_MSG_BASE:
6729 desc = "MPI Message Layer";
6730 break;
6731 case MPI_IOCLOGINFO_FC_LINK_BASE:
6732 desc = "FC Link";
6733 break;
6734 case MPI_IOCLOGINFO_FC_CTX_BASE:
6735 desc = "Context Manager";
6736 break;
6737 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6738 desc = "Invalid Field Offset";
6739 break;
6740 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6741 desc = "State Change Info";
6742 break;
6743 }
6744
6745 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6746 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747}
6748
6749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006750/**
Moore, Eric335a9412006-01-17 17:06:23 -07006751 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752 * @ioc: Pointer to MPT_ADAPTER structure
6753 * @mr: Pointer to MPT reply frame
6754 * @log_info: U32 LogInfo word from the IOC
6755 *
6756 * Refer to lsi/sp_log.h.
6757 */
6758static void
Moore, Eric335a9412006-01-17 17:06:23 -07006759mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760{
6761 u32 info = log_info & 0x00FF0000;
6762 char *desc = "unknown";
6763
6764 switch (info) {
6765 case 0x00010000:
6766 desc = "bug! MID not found";
6767 if (ioc->reload_fw == 0)
6768 ioc->reload_fw++;
6769 break;
6770
6771 case 0x00020000:
6772 desc = "Parity Error";
6773 break;
6774
6775 case 0x00030000:
6776 desc = "ASYNC Outbound Overrun";
6777 break;
6778
6779 case 0x00040000:
6780 desc = "SYNC Offset Error";
6781 break;
6782
6783 case 0x00050000:
6784 desc = "BM Change";
6785 break;
6786
6787 case 0x00060000:
6788 desc = "Msg In Overflow";
6789 break;
6790
6791 case 0x00070000:
6792 desc = "DMA Error";
6793 break;
6794
6795 case 0x00080000:
6796 desc = "Outbound DMA Overrun";
6797 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006798
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799 case 0x00090000:
6800 desc = "Task Management";
6801 break;
6802
6803 case 0x000A0000:
6804 desc = "Device Problem";
6805 break;
6806
6807 case 0x000B0000:
6808 desc = "Invalid Phase Change";
6809 break;
6810
6811 case 0x000C0000:
6812 desc = "Untagged Table Size";
6813 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006814
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815 }
6816
6817 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6818}
6819
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006820/* strings for sas loginfo */
6821 static char *originator_str[] = {
6822 "IOP", /* 00h */
6823 "PL", /* 01h */
6824 "IR" /* 02h */
6825 };
6826 static char *iop_code_str[] = {
6827 NULL, /* 00h */
6828 "Invalid SAS Address", /* 01h */
6829 NULL, /* 02h */
6830 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006831 "Diag Message Error", /* 04h */
6832 "Task Terminated", /* 05h */
6833 "Enclosure Management", /* 06h */
6834 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006835 };
6836 static char *pl_code_str[] = {
6837 NULL, /* 00h */
6838 "Open Failure", /* 01h */
6839 "Invalid Scatter Gather List", /* 02h */
6840 "Wrong Relative Offset or Frame Length", /* 03h */
6841 "Frame Transfer Error", /* 04h */
6842 "Transmit Frame Connected Low", /* 05h */
6843 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6844 "SATA Read Log Receive Data Error", /* 07h */
6845 "SATA NCQ Fail All Commands After Error", /* 08h */
6846 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6847 "Receive Frame Invalid Message", /* 0Ah */
6848 "Receive Context Message Valid Error", /* 0Bh */
6849 "Receive Frame Current Frame Error", /* 0Ch */
6850 "SATA Link Down", /* 0Dh */
6851 "Discovery SATA Init W IOS", /* 0Eh */
6852 "Config Invalid Page", /* 0Fh */
6853 "Discovery SATA Init Timeout", /* 10h */
6854 "Reset", /* 11h */
6855 "Abort", /* 12h */
6856 "IO Not Yet Executed", /* 13h */
6857 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006858 "Persistent Reservation Out Not Affiliation "
6859 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006860 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006861 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006862 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006863 NULL, /* 19h */
6864 NULL, /* 1Ah */
6865 NULL, /* 1Bh */
6866 NULL, /* 1Ch */
6867 NULL, /* 1Dh */
6868 NULL, /* 1Eh */
6869 NULL, /* 1Fh */
6870 "Enclosure Management" /* 20h */
6871 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006872 static char *ir_code_str[] = {
6873 "Raid Action Error", /* 00h */
6874 NULL, /* 00h */
6875 NULL, /* 01h */
6876 NULL, /* 02h */
6877 NULL, /* 03h */
6878 NULL, /* 04h */
6879 NULL, /* 05h */
6880 NULL, /* 06h */
6881 NULL /* 07h */
6882 };
6883 static char *raid_sub_code_str[] = {
6884 NULL, /* 00h */
6885 "Volume Creation Failed: Data Passed too "
6886 "Large", /* 01h */
6887 "Volume Creation Failed: Duplicate Volumes "
6888 "Attempted", /* 02h */
6889 "Volume Creation Failed: Max Number "
6890 "Supported Volumes Exceeded", /* 03h */
6891 "Volume Creation Failed: DMA Error", /* 04h */
6892 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6893 "Volume Creation Failed: Error Reading "
6894 "MFG Page 4", /* 06h */
6895 "Volume Creation Failed: Creating Internal "
6896 "Structures", /* 07h */
6897 NULL, /* 08h */
6898 NULL, /* 09h */
6899 NULL, /* 0Ah */
6900 NULL, /* 0Bh */
6901 NULL, /* 0Ch */
6902 NULL, /* 0Dh */
6903 NULL, /* 0Eh */
6904 NULL, /* 0Fh */
6905 "Activation failed: Already Active Volume", /* 10h */
6906 "Activation failed: Unsupported Volume Type", /* 11h */
6907 "Activation failed: Too Many Active Volumes", /* 12h */
6908 "Activation failed: Volume ID in Use", /* 13h */
6909 "Activation failed: Reported Failure", /* 14h */
6910 "Activation failed: Importing a Volume", /* 15h */
6911 NULL, /* 16h */
6912 NULL, /* 17h */
6913 NULL, /* 18h */
6914 NULL, /* 19h */
6915 NULL, /* 1Ah */
6916 NULL, /* 1Bh */
6917 NULL, /* 1Ch */
6918 NULL, /* 1Dh */
6919 NULL, /* 1Eh */
6920 NULL, /* 1Fh */
6921 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6922 "Phys Disk failed: Data Passed too Large", /* 21h */
6923 "Phys Disk failed: DMA Error", /* 22h */
6924 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6925 "Phys Disk failed: Creating Phys Disk Config "
6926 "Page", /* 24h */
6927 NULL, /* 25h */
6928 NULL, /* 26h */
6929 NULL, /* 27h */
6930 NULL, /* 28h */
6931 NULL, /* 29h */
6932 NULL, /* 2Ah */
6933 NULL, /* 2Bh */
6934 NULL, /* 2Ch */
6935 NULL, /* 2Dh */
6936 NULL, /* 2Eh */
6937 NULL, /* 2Fh */
6938 "Compatibility Error: IR Disabled", /* 30h */
6939 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6940 "Compatibility Error: Device not Direct Access "
6941 "Device ", /* 32h */
6942 "Compatibility Error: Removable Device Found", /* 33h */
6943 "Compatibility Error: Device SCSI Version not "
6944 "2 or Higher", /* 34h */
6945 "Compatibility Error: SATA Device, 48 BIT LBA "
6946 "not Supported", /* 35h */
6947 "Compatibility Error: Device doesn't have "
6948 "512 Byte Block Sizes", /* 36h */
6949 "Compatibility Error: Volume Type Check Failed", /* 37h */
6950 "Compatibility Error: Volume Type is "
6951 "Unsupported by FW", /* 38h */
6952 "Compatibility Error: Disk Drive too Small for "
6953 "use in Volume", /* 39h */
6954 "Compatibility Error: Phys Disk for Create "
6955 "Volume not Found", /* 3Ah */
6956 "Compatibility Error: Too Many or too Few "
6957 "Disks for Volume Type", /* 3Bh */
6958 "Compatibility Error: Disk stripe Sizes "
6959 "Must be 64KB", /* 3Ch */
6960 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6961 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006962
6963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006964/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006965 * mpt_sas_log_info - Log information returned from SAS IOC.
6966 * @ioc: Pointer to MPT_ADAPTER structure
6967 * @log_info: U32 LogInfo reply word from the IOC
6968 *
6969 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006970 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006971static void
6972mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6973{
6974union loginfo_type {
6975 u32 loginfo;
6976 struct {
6977 u32 subcode:16;
6978 u32 code:8;
6979 u32 originator:4;
6980 u32 bus_type:4;
6981 }dw;
6982};
6983 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006984 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006985 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07006986 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006987
6988 sas_loginfo.loginfo = log_info;
6989 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
6990 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
6991 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07006992
6993 originator_desc = originator_str[sas_loginfo.dw.originator];
6994
6995 switch (sas_loginfo.dw.originator) {
6996
6997 case 0: /* IOP */
6998 if (sas_loginfo.dw.code <
6999 sizeof(iop_code_str)/sizeof(char*))
7000 code_desc = iop_code_str[sas_loginfo.dw.code];
7001 break;
7002 case 1: /* PL */
7003 if (sas_loginfo.dw.code <
7004 sizeof(pl_code_str)/sizeof(char*))
7005 code_desc = pl_code_str[sas_loginfo.dw.code];
7006 break;
7007 case 2: /* IR */
7008 if (sas_loginfo.dw.code >=
7009 sizeof(ir_code_str)/sizeof(char*))
7010 break;
7011 code_desc = ir_code_str[sas_loginfo.dw.code];
7012 if (sas_loginfo.dw.subcode >=
7013 sizeof(raid_sub_code_str)/sizeof(char*))
7014 break;
7015 if (sas_loginfo.dw.code == 0)
7016 sub_code_desc =
7017 raid_sub_code_str[sas_loginfo.dw.subcode];
7018 break;
7019 default:
7020 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007021 }
7022
Eric Moorec6c727a2007-01-29 09:44:54 -07007023 if (sub_code_desc != NULL)
7024 printk(MYIOC_s_INFO_FMT
7025 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7026 " SubCode={%s}\n",
7027 ioc->name, log_info, originator_desc, code_desc,
7028 sub_code_desc);
7029 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007030 printk(MYIOC_s_INFO_FMT
7031 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7032 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007033 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007034 sas_loginfo.dw.subcode);
7035 else
7036 printk(MYIOC_s_INFO_FMT
7037 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7038 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007039 ioc->name, log_info, originator_desc,
7040 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007041}
7042
Linus Torvalds1da177e2005-04-16 15:20:36 -07007043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007044/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007045 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7046 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007047 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007048 * @mf: Pointer to MPT request frame
7049 *
7050 * Refer to lsi/mpi.h.
7051 **/
7052static void
7053mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7054{
7055 Config_t *pReq = (Config_t *)mf;
7056 char extend_desc[EVENT_DESCR_STR_SZ];
7057 char *desc = NULL;
7058 u32 form;
7059 u8 page_type;
7060
7061 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7062 page_type = pReq->ExtPageType;
7063 else
7064 page_type = pReq->Header.PageType;
7065
7066 /*
7067 * ignore invalid page messages for GET_NEXT_HANDLE
7068 */
7069 form = le32_to_cpu(pReq->PageAddress);
7070 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7071 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7072 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7073 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7074 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7075 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7076 return;
7077 }
7078 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7079 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7080 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7081 return;
7082 }
7083
7084 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7085 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7086 page_type, pReq->Header.PageNumber, pReq->Action, form);
7087
7088 switch (ioc_status) {
7089
7090 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7091 desc = "Config Page Invalid Action";
7092 break;
7093
7094 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7095 desc = "Config Page Invalid Type";
7096 break;
7097
7098 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7099 desc = "Config Page Invalid Page";
7100 break;
7101
7102 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7103 desc = "Config Page Invalid Data";
7104 break;
7105
7106 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7107 desc = "Config Page No Defaults";
7108 break;
7109
7110 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7111 desc = "Config Page Can't Commit";
7112 break;
7113 }
7114
7115 if (!desc)
7116 return;
7117
Eric Moore29dd3602007-09-14 18:46:51 -06007118 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7119 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007120}
7121
7122/**
7123 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124 * @ioc: Pointer to MPT_ADAPTER structure
7125 * @ioc_status: U32 IOCStatus word from IOC
7126 * @mf: Pointer to MPT request frame
7127 *
7128 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007129 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007131mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132{
7133 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007134 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135
7136 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007137
7138/****************************************************************************/
7139/* Common IOCStatus values for all replies */
7140/****************************************************************************/
7141
Linus Torvalds1da177e2005-04-16 15:20:36 -07007142 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7143 desc = "Invalid Function";
7144 break;
7145
7146 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7147 desc = "Busy";
7148 break;
7149
7150 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7151 desc = "Invalid SGL";
7152 break;
7153
7154 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7155 desc = "Internal Error";
7156 break;
7157
7158 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7159 desc = "Reserved";
7160 break;
7161
7162 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7163 desc = "Insufficient Resources";
7164 break;
7165
7166 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7167 desc = "Invalid Field";
7168 break;
7169
7170 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7171 desc = "Invalid State";
7172 break;
7173
Eric Moorec6c727a2007-01-29 09:44:54 -07007174/****************************************************************************/
7175/* Config IOCStatus values */
7176/****************************************************************************/
7177
Linus Torvalds1da177e2005-04-16 15:20:36 -07007178 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7179 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7180 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7181 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7182 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7183 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007184 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185 break;
7186
Eric Moorec6c727a2007-01-29 09:44:54 -07007187/****************************************************************************/
7188/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7189/* */
7190/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7191/* */
7192/****************************************************************************/
7193
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007196 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7197 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7198 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7199 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007201 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007206 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 break;
7208
Eric Moorec6c727a2007-01-29 09:44:54 -07007209/****************************************************************************/
7210/* SCSI Target values */
7211/****************************************************************************/
7212
7213 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7214 desc = "Target: Priority IO";
7215 break;
7216
7217 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7218 desc = "Target: Invalid Port";
7219 break;
7220
7221 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7222 desc = "Target Invalid IO Index:";
7223 break;
7224
7225 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7226 desc = "Target: Aborted";
7227 break;
7228
7229 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7230 desc = "Target: No Conn Retryable";
7231 break;
7232
7233 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7234 desc = "Target: No Connection";
7235 break;
7236
7237 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7238 desc = "Target: Transfer Count Mismatch";
7239 break;
7240
7241 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7242 desc = "Target: STS Data not Sent";
7243 break;
7244
7245 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7246 desc = "Target: Data Offset Error";
7247 break;
7248
7249 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7250 desc = "Target: Too Much Write Data";
7251 break;
7252
7253 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7254 desc = "Target: IU Too Short";
7255 break;
7256
7257 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7258 desc = "Target: ACK NAK Timeout";
7259 break;
7260
7261 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7262 desc = "Target: Nak Received";
7263 break;
7264
7265/****************************************************************************/
7266/* Fibre Channel Direct Access values */
7267/****************************************************************************/
7268
7269 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7270 desc = "FC: Aborted";
7271 break;
7272
7273 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7274 desc = "FC: RX ID Invalid";
7275 break;
7276
7277 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7278 desc = "FC: DID Invalid";
7279 break;
7280
7281 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7282 desc = "FC: Node Logged Out";
7283 break;
7284
7285 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7286 desc = "FC: Exchange Canceled";
7287 break;
7288
7289/****************************************************************************/
7290/* LAN values */
7291/****************************************************************************/
7292
7293 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7294 desc = "LAN: Device not Found";
7295 break;
7296
7297 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7298 desc = "LAN: Device Failure";
7299 break;
7300
7301 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7302 desc = "LAN: Transmit Error";
7303 break;
7304
7305 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7306 desc = "LAN: Transmit Aborted";
7307 break;
7308
7309 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7310 desc = "LAN: Receive Error";
7311 break;
7312
7313 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7314 desc = "LAN: Receive Aborted";
7315 break;
7316
7317 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7318 desc = "LAN: Partial Packet";
7319 break;
7320
7321 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7322 desc = "LAN: Canceled";
7323 break;
7324
7325/****************************************************************************/
7326/* Serial Attached SCSI values */
7327/****************************************************************************/
7328
7329 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7330 desc = "SAS: SMP Request Failed";
7331 break;
7332
7333 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7334 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007335 break;
7336
7337 default:
7338 desc = "Others";
7339 break;
7340 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007341
7342 if (!desc)
7343 return;
7344
Eric Moore29dd3602007-09-14 18:46:51 -06007345 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7346 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007347}
7348
7349/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007350EXPORT_SYMBOL(mpt_attach);
7351EXPORT_SYMBOL(mpt_detach);
7352#ifdef CONFIG_PM
7353EXPORT_SYMBOL(mpt_resume);
7354EXPORT_SYMBOL(mpt_suspend);
7355#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007356EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007357EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007358EXPORT_SYMBOL(mpt_register);
7359EXPORT_SYMBOL(mpt_deregister);
7360EXPORT_SYMBOL(mpt_event_register);
7361EXPORT_SYMBOL(mpt_event_deregister);
7362EXPORT_SYMBOL(mpt_reset_register);
7363EXPORT_SYMBOL(mpt_reset_deregister);
7364EXPORT_SYMBOL(mpt_device_driver_register);
7365EXPORT_SYMBOL(mpt_device_driver_deregister);
7366EXPORT_SYMBOL(mpt_get_msg_frame);
7367EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307368EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369EXPORT_SYMBOL(mpt_free_msg_frame);
7370EXPORT_SYMBOL(mpt_add_sge);
7371EXPORT_SYMBOL(mpt_send_handshake_request);
7372EXPORT_SYMBOL(mpt_verify_adapter);
7373EXPORT_SYMBOL(mpt_GetIocState);
7374EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375EXPORT_SYMBOL(mpt_HardResetHandler);
7376EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378EXPORT_SYMBOL(mpt_alloc_fw_memory);
7379EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007380EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007381EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007384/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385 * fusion_init - Fusion MPT base driver initialization routine.
7386 *
7387 * Returns 0 for success, non-zero for failure.
7388 */
7389static int __init
7390fusion_init(void)
7391{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307392 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393
7394 show_mptmod_ver(my_NAME, my_VERSION);
7395 printk(KERN_INFO COPYRIGHT "\n");
7396
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307397 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7398 MptCallbacks[cb_idx] = NULL;
7399 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7400 MptEvHandlers[cb_idx] = NULL;
7401 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402 }
7403
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007404 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405 * EventNotification handling.
7406 */
7407 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7408
7409 /* Register for hard reset handling callbacks.
7410 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307411 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007412
7413#ifdef CONFIG_PROC_FS
7414 (void) procmpt_create();
7415#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007416 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007417}
7418
7419/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007420/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421 * fusion_exit - Perform driver unload cleanup.
7422 *
7423 * This routine frees all resources associated with each MPT adapter
7424 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7425 */
7426static void __exit
7427fusion_exit(void)
7428{
7429
Linus Torvalds1da177e2005-04-16 15:20:36 -07007430 mpt_reset_deregister(mpt_base_index);
7431
7432#ifdef CONFIG_PROC_FS
7433 procmpt_destroy();
7434#endif
7435}
7436
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437module_init(fusion_init);
7438module_exit(fusion_exit);