blob: 425f60c21fddb19c44d0821fdafe0b663a3d2bda [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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-09-09 16:25:54 +02001129 ioc->alloc_total += host_page_buffer_sz;
1130 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1131 break;
1132 }
1133
1134 host_page_buffer_sz -= (4*1024);
1135 }
1136 }
1137
1138 if(!ioc->HostPageBuffer) {
1139 printk(MYIOC_s_ERR_FMT
1140 "Failed to alloc memory for host_page_buffer!\n",
1141 ioc->name);
1142 return -999;
1143 }
1144
1145 psge = (char *)&ioc_init->HostPageBufferSGE;
1146 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1147 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1148 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1149 MPI_SGE_FLAGS_HOST_TO_IOC |
1150 MPI_SGE_FLAGS_END_OF_BUFFER;
1151 if (sizeof(dma_addr_t) == sizeof(u64)) {
1152 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1153 }
1154 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1155 flags_length |= ioc->HostPageBuffer_sz;
1156 mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
1157 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1158
1159return 0;
1160}
1161
1162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1163/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001164 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 * @iocid: IOC unique identifier (integer)
1166 * @iocpp: Pointer to pointer to IOC adapter
1167 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001168 * Given a unique IOC identifier, set pointer to the associated MPT
1169 * adapter structure.
1170 *
1171 * Returns iocid and sets iocpp if iocid is found.
1172 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 */
1174int
1175mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1176{
1177 MPT_ADAPTER *ioc;
1178
1179 list_for_each_entry(ioc,&ioc_list,list) {
1180 if (ioc->id == iocid) {
1181 *iocpp =ioc;
1182 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 *iocpp = NULL;
1187 return -1;
1188}
1189
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301190/**
1191 * mpt_get_product_name - returns product string
1192 * @vendor: pci vendor id
1193 * @device: pci device id
1194 * @revision: pci revision id
1195 * @prod_name: string returned
1196 *
1197 * Returns product string displayed when driver loads,
1198 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1199 *
1200 **/
1201static void
1202mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1203{
1204 char *product_str = NULL;
1205
1206 if (vendor == PCI_VENDOR_ID_BROCADE) {
1207 switch (device)
1208 {
1209 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1210 switch (revision)
1211 {
1212 case 0x00:
1213 product_str = "BRE040 A0";
1214 break;
1215 case 0x01:
1216 product_str = "BRE040 A1";
1217 break;
1218 default:
1219 product_str = "BRE040";
1220 break;
1221 }
1222 break;
1223 }
1224 goto out;
1225 }
1226
1227 switch (device)
1228 {
1229 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1230 product_str = "LSIFC909 B1";
1231 break;
1232 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1233 product_str = "LSIFC919 B0";
1234 break;
1235 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1236 product_str = "LSIFC929 B0";
1237 break;
1238 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1239 if (revision < 0x80)
1240 product_str = "LSIFC919X A0";
1241 else
1242 product_str = "LSIFC919XL A1";
1243 break;
1244 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1245 if (revision < 0x80)
1246 product_str = "LSIFC929X A0";
1247 else
1248 product_str = "LSIFC929XL A1";
1249 break;
1250 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1251 product_str = "LSIFC939X A1";
1252 break;
1253 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1254 product_str = "LSIFC949X A1";
1255 break;
1256 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1257 switch (revision)
1258 {
1259 case 0x00:
1260 product_str = "LSIFC949E A0";
1261 break;
1262 case 0x01:
1263 product_str = "LSIFC949E A1";
1264 break;
1265 default:
1266 product_str = "LSIFC949E";
1267 break;
1268 }
1269 break;
1270 case MPI_MANUFACTPAGE_DEVID_53C1030:
1271 switch (revision)
1272 {
1273 case 0x00:
1274 product_str = "LSI53C1030 A0";
1275 break;
1276 case 0x01:
1277 product_str = "LSI53C1030 B0";
1278 break;
1279 case 0x03:
1280 product_str = "LSI53C1030 B1";
1281 break;
1282 case 0x07:
1283 product_str = "LSI53C1030 B2";
1284 break;
1285 case 0x08:
1286 product_str = "LSI53C1030 C0";
1287 break;
1288 case 0x80:
1289 product_str = "LSI53C1030T A0";
1290 break;
1291 case 0x83:
1292 product_str = "LSI53C1030T A2";
1293 break;
1294 case 0x87:
1295 product_str = "LSI53C1030T A3";
1296 break;
1297 case 0xc1:
1298 product_str = "LSI53C1020A A1";
1299 break;
1300 default:
1301 product_str = "LSI53C1030";
1302 break;
1303 }
1304 break;
1305 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1306 switch (revision)
1307 {
1308 case 0x03:
1309 product_str = "LSI53C1035 A2";
1310 break;
1311 case 0x04:
1312 product_str = "LSI53C1035 B0";
1313 break;
1314 default:
1315 product_str = "LSI53C1035";
1316 break;
1317 }
1318 break;
1319 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1320 switch (revision)
1321 {
1322 case 0x00:
1323 product_str = "LSISAS1064 A1";
1324 break;
1325 case 0x01:
1326 product_str = "LSISAS1064 A2";
1327 break;
1328 case 0x02:
1329 product_str = "LSISAS1064 A3";
1330 break;
1331 case 0x03:
1332 product_str = "LSISAS1064 A4";
1333 break;
1334 default:
1335 product_str = "LSISAS1064";
1336 break;
1337 }
1338 break;
1339 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1340 switch (revision)
1341 {
1342 case 0x00:
1343 product_str = "LSISAS1064E A0";
1344 break;
1345 case 0x01:
1346 product_str = "LSISAS1064E B0";
1347 break;
1348 case 0x02:
1349 product_str = "LSISAS1064E B1";
1350 break;
1351 case 0x04:
1352 product_str = "LSISAS1064E B2";
1353 break;
1354 case 0x08:
1355 product_str = "LSISAS1064E B3";
1356 break;
1357 default:
1358 product_str = "LSISAS1064E";
1359 break;
1360 }
1361 break;
1362 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "LSISAS1068 A0";
1367 break;
1368 case 0x01:
1369 product_str = "LSISAS1068 B0";
1370 break;
1371 case 0x02:
1372 product_str = "LSISAS1068 B1";
1373 break;
1374 default:
1375 product_str = "LSISAS1068";
1376 break;
1377 }
1378 break;
1379 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1380 switch (revision)
1381 {
1382 case 0x00:
1383 product_str = "LSISAS1068E A0";
1384 break;
1385 case 0x01:
1386 product_str = "LSISAS1068E B0";
1387 break;
1388 case 0x02:
1389 product_str = "LSISAS1068E B1";
1390 break;
1391 case 0x04:
1392 product_str = "LSISAS1068E B2";
1393 break;
1394 case 0x08:
1395 product_str = "LSISAS1068E B3";
1396 break;
1397 default:
1398 product_str = "LSISAS1068E";
1399 break;
1400 }
1401 break;
1402 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1403 switch (revision)
1404 {
1405 case 0x00:
1406 product_str = "LSISAS1078 A0";
1407 break;
1408 case 0x01:
1409 product_str = "LSISAS1078 B0";
1410 break;
1411 case 0x02:
1412 product_str = "LSISAS1078 C0";
1413 break;
1414 case 0x03:
1415 product_str = "LSISAS1078 C1";
1416 break;
1417 case 0x04:
1418 product_str = "LSISAS1078 C2";
1419 break;
1420 default:
1421 product_str = "LSISAS1078";
1422 break;
1423 }
1424 break;
1425 }
1426
1427 out:
1428 if (product_str)
1429 sprintf(prod_name, "%s", product_str);
1430}
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001433/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001434 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 *
1438 * This routine performs all the steps necessary to bring the IOC of
1439 * a MPT adapter to a OPERATIONAL state. This includes registering
1440 * memory regions, registering the interrupt, and allocating request
1441 * and reply memory pools.
1442 *
1443 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1444 * MPT adapter.
1445 *
1446 * Returns 0 for success, non-zero for failure.
1447 *
1448 * TODO: Add support for polled controllers
1449 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001450int
1451mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 MPT_ADAPTER *ioc;
1454 u8 __iomem *mem;
Eric Moorebc6e0892007-09-29 10:16:28 -06001455 u8 __iomem *pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long mem_phys;
1457 unsigned long port;
1458 u32 msize;
1459 u32 psize;
1460 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301461 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 u8 revision;
1464 u8 pcixcmd;
1465 static int mpt_ids = 0;
1466#ifdef CONFIG_PROC_FS
1467 struct proc_dir_entry *dent, *ent;
1468#endif
1469
Prakash, Sathya436ace72007-07-24 15:42:08 +05301470 if (mpt_debug_level)
1471 printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
1472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (pci_enable_device(pdev))
1474 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001475
Jesper Juhl56876192007-08-10 14:50:51 -07001476 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1477 if (ioc == NULL) {
1478 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1479 return -ENOMEM;
1480 }
1481 ioc->debug_level = mpt_debug_level;
Eric Moore29dd3602007-09-14 18:46:51 -06001482 ioc->id = mpt_ids++;
1483 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001484
Eric Moore29dd3602007-09-14 18:46:51 -06001485 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001486
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001487 if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001488 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1489 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001490 } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001491 printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
1492 ioc->name);
Jesper Juhl56876192007-08-10 14:50:51 -07001493 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 return r;
1495 }
1496
Prakash, Sathya436ace72007-07-24 15:42:08 +05301497 if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
Eric Moore29dd3602007-09-14 18:46:51 -06001498 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1499 ": Using 64 bit consistent mask\n", ioc->name));
Prakash, Sathya436ace72007-07-24 15:42:08 +05301500 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001501 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1502 ": Not using 64 bit consistent mask\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05301504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 ioc->alloc_total = sizeof(MPT_ADAPTER);
1506 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1507 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 ioc->pcidev = pdev;
1510 ioc->diagPending = 0;
1511 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001512 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 /* Initialize the event logging.
1515 */
1516 ioc->eventTypes = 0; /* None */
1517 ioc->eventContext = 0;
1518 ioc->eventLogSize = 0;
1519 ioc->events = NULL;
1520
1521#ifdef MFCNT
1522 ioc->mfcnt = 0;
1523#endif
1524
1525 ioc->cached_fw = NULL;
1526
1527 /* Initilize SCSI Config Data structure
1528 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001529 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 /* Initialize the running configQ head.
1532 */
1533 INIT_LIST_HEAD(&ioc->configQ);
1534
Michael Reed05e8ec12006-01-13 14:31:54 -06001535 /* Initialize the fc rport list head.
1536 */
1537 INIT_LIST_HEAD(&ioc->fc_rports);
1538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 /* Find lookup slot. */
1540 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 mem_phys = msize = 0;
1543 port = psize = 0;
1544 for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1545 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
Eric Moore87cf8982006-06-27 16:09:26 -06001546 if (psize)
1547 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 /* Get I/O space! */
1549 port = pci_resource_start(pdev, ii);
1550 psize = pci_resource_len(pdev,ii);
1551 } else {
Eric Moore87cf8982006-06-27 16:09:26 -06001552 if (msize)
1553 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* Get memmap */
1555 mem_phys = pci_resource_start(pdev, ii);
1556 msize = pci_resource_len(pdev,ii);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 }
1559 ioc->mem_size = msize;
1560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 mem = NULL;
1562 /* Get logical ptr for PciMem0 space */
1563 /*mem = ioremap(mem_phys, msize);*/
Eric Moore87cf8982006-06-27 16:09:26 -06001564 mem = ioremap(mem_phys, msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (mem == NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06001566 printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 kfree(ioc);
1568 return -EINVAL;
1569 }
1570 ioc->memmap = mem;
Eric Moore29dd3602007-09-14 18:46:51 -06001571 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Eric Moore29dd3602007-09-14 18:46:51 -06001573 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1574 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
1576 ioc->mem_phys = mem_phys;
1577 ioc->chip = (SYSIF_REGS __iomem *)mem;
1578
1579 /* Save Port IO values in case we need to do downloadboot */
Eric Moorebc6e0892007-09-29 10:16:28 -06001580 ioc->pio_mem_phys = port;
1581 pmem = (u8 __iomem *)port;
1582 ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301584 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1585 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1586
1587 switch (pdev->device)
1588 {
1589 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1590 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1591 ioc->errata_flag_1064 = 1;
1592 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1593 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1594 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1595 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301597 break;
1598
1599 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* 929X Chip Fix. Set Split transactions level
1602 * for PCIX. Set MOST bits to zero.
1603 */
1604 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1605 pcixcmd &= 0x8F;
1606 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1607 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* 929XL Chip Fix. Set MMRBC to 0x08.
1609 */
1610 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1611 pcixcmd |= 0x08;
1612 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301615 break;
1616
1617 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* 919X Chip Fix. Set Split transactions level
1619 * for PCIX. Set MOST bits to zero.
1620 */
1621 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1622 pcixcmd &= 0x8F;
1623 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001624 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301625 break;
1626
1627 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* 1030 Chip Fix. Disable Split transactions
1629 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1630 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (revision < C0_1030) {
1632 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1633 pcixcmd &= 0x8F;
1634 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1635 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301636
1637 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001638 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301639 break;
1640
1641 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1642 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001643 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301644
1645 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1646 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1647 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001648 ioc->bus_type = SAS;
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001651 if (ioc->errata_flag_1064)
1652 pci_disable_io_access(pdev);
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 spin_lock_init(&ioc->FreeQlock);
1655
1656 /* Disable all! */
1657 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1658 ioc->active = 0;
1659 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1660
1661 /* Set lookup ptr. */
1662 list_add_tail(&ioc->list, &ioc_list);
1663
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001664 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 */
1666 mpt_detect_bound_ports(ioc, pdev);
1667
James Bottomleyc92f2222006-03-01 09:02:49 -06001668 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1669 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001670 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1671 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001674 if (ioc->alt_ioc)
1675 ioc->alt_ioc->alt_ioc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 iounmap(mem);
1677 kfree(ioc);
1678 pci_set_drvdata(pdev, NULL);
1679 return r;
1680 }
1681
1682 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001683 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301684 if(MptDeviceDriverHandlers[cb_idx] &&
1685 MptDeviceDriverHandlers[cb_idx]->probe) {
1686 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 }
1688 }
1689
1690#ifdef CONFIG_PROC_FS
1691 /*
1692 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1693 */
1694 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1695 if (dent) {
1696 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1697 if (ent) {
1698 ent->read_proc = procmpt_iocinfo_read;
1699 ent->data = ioc;
1700 }
1701 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1702 if (ent) {
1703 ent->read_proc = procmpt_summary_read;
1704 ent->data = ioc;
1705 }
1706 }
1707#endif
1708
1709 return 0;
1710}
1711
1712/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001713/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001714 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 */
1717
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001718void
1719mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1722 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301723 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1726 remove_proc_entry(pname, NULL);
1727 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
1728 remove_proc_entry(pname, NULL);
1729 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
1730 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001733 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301734 if(MptDeviceDriverHandlers[cb_idx] &&
1735 MptDeviceDriverHandlers[cb_idx]->remove) {
1736 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 }
1738 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001739
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 /* Disable interrupts! */
1741 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1742
1743 ioc->active = 0;
1744 synchronize_irq(pdev->irq);
1745
1746 /* Clear any lingering interrupt */
1747 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1748
1749 CHIPREG_READ32(&ioc->chip->IntStatus);
1750
1751 mpt_adapter_dispose(ioc);
1752
1753 pci_set_drvdata(pdev, NULL);
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756/**************************************************************************
1757 * Power Management
1758 */
1759#ifdef CONFIG_PM
1760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001761/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001762 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001763 * @pdev: Pointer to pci_dev structure
1764 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001766int
1767mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 u32 device_state;
1770 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Pavel Machek2a569572005-07-07 17:56:40 -07001772 device_state=pci_choose_state(pdev, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 printk(MYIOC_s_INFO_FMT
1775 "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
1776 ioc->name, pdev, pci_name(pdev), device_state);
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pci_save_state(pdev);
1779
1780 /* put ioc into READY_STATE */
1781 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
1782 printk(MYIOC_s_ERR_FMT
1783 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
1784 }
1785
1786 /* disable interrupts */
1787 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1788 ioc->active = 0;
1789
1790 /* Clear any lingering interrupt */
1791 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1792
1793 pci_disable_device(pdev);
1794 pci_set_power_state(pdev, device_state);
1795
1796 return 0;
1797}
1798
1799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001800/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001801 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001802 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001804int
1805mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
1807 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1808 u32 device_state = pdev->current_state;
1809 int recovery_state;
Hormsb364fd52007-03-19 15:06:44 +09001810 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 printk(MYIOC_s_INFO_FMT
1813 "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
1814 ioc->name, pdev, pci_name(pdev), device_state);
1815
1816 pci_set_power_state(pdev, 0);
1817 pci_restore_state(pdev);
Hormsb364fd52007-03-19 15:06:44 +09001818 err = pci_enable_device(pdev);
1819 if (err)
1820 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822 /* enable interrupts */
Moore, Eric569b11d2006-01-13 16:25:29 -07001823 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 ioc->active = 1;
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 printk(MYIOC_s_INFO_FMT
1827 "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
1828 ioc->name,
1829 (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
1830 CHIPREG_READ32(&ioc->chip->Doorbell));
1831
1832 /* bring ioc to operational state */
1833 if ((recovery_state = mpt_do_ioc_recovery(ioc,
1834 MPT_HOSTEVENT_IOC_RECOVER, CAN_SLEEP)) != 0) {
1835 printk(MYIOC_s_INFO_FMT
1836 "pci-resume: Cannot recover, error:[%x]\n",
1837 ioc->name, recovery_state);
1838 } else {
1839 printk(MYIOC_s_INFO_FMT
1840 "pci-resume: success\n", ioc->name);
1841 }
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 return 0;
1844}
1845#endif
1846
James Bottomley4ff42a62006-05-17 18:06:52 -05001847static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301848mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05001849{
1850 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
1851 ioc->bus_type != SPI) ||
1852 (MptDriverClass[index] == MPTFC_DRIVER &&
1853 ioc->bus_type != FC) ||
1854 (MptDriverClass[index] == MPTSAS_DRIVER &&
1855 ioc->bus_type != SAS))
1856 /* make sure we only call the relevant reset handler
1857 * for the bus */
1858 return 0;
1859 return (MptResetHandlers[index])(ioc, reset_phase);
1860}
1861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001863/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
1865 * @ioc: Pointer to MPT adapter structure
1866 * @reason: Event word / reason
1867 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1868 *
1869 * This routine performs all the steps necessary to bring the IOC
1870 * to a OPERATIONAL state.
1871 *
1872 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1873 * MPT adapter.
1874 *
1875 * Returns:
1876 * 0 for success
1877 * -1 if failed to get board READY
1878 * -2 if READY but IOCFacts Failed
1879 * -3 if READY but PrimeIOCFifos Failed
1880 * -4 if READY but IOCInit Failed
1881 */
1882static int
1883mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
1884{
1885 int hard_reset_done = 0;
1886 int alt_ioc_ready = 0;
1887 int hard;
1888 int rc=0;
1889 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301890 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 int handlers;
1892 int ret = 0;
1893 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001894 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05301895 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Eric Moore29dd3602007-09-14 18:46:51 -06001897 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
1898 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 /* Disable reply interrupts (also blocks FreeQ) */
1901 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1902 ioc->active = 0;
1903
1904 if (ioc->alt_ioc) {
1905 if (ioc->alt_ioc->active)
1906 reset_alt_ioc_active = 1;
1907
1908 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
1909 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
1910 ioc->alt_ioc->active = 0;
1911 }
1912
1913 hard = 1;
1914 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
1915 hard = 0;
1916
1917 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
1918 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06001919 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
1920 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 if (reset_alt_ioc_active && ioc->alt_ioc) {
1923 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06001924 dprintk(ioc, printk(MYIOC_s_INFO_FMT
1925 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07001926 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 ioc->alt_ioc->active = 1;
1928 }
1929
1930 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001931 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
1933 return -1;
1934 }
1935
1936 /* hard_reset_done = 0 if a soft reset was performed
1937 * and 1 if a hard reset was performed.
1938 */
1939 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
1940 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
1941 alt_ioc_ready = 1;
1942 else
Eric Moore29dd3602007-09-14 18:46:51 -06001943 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 }
1945
1946 for (ii=0; ii<5; ii++) {
1947 /* Get IOC facts! Allow 5 retries */
1948 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
1949 break;
1950 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
1953 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06001954 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1955 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 ret = -2;
1957 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1958 MptDisplayIocCapabilities(ioc);
1959 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (alt_ioc_ready) {
1962 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301963 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001964 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 /* Retry - alt IOC was initialized once
1966 */
1967 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
1968 }
1969 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05301970 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06001971 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 alt_ioc_ready = 0;
1973 reset_alt_ioc_active = 0;
1974 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
1975 MptDisplayIocCapabilities(ioc->alt_ioc);
1976 }
1977 }
1978
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001979 /*
1980 * Device is reset now. It must have de-asserted the interrupt line
1981 * (if it was asserted) and it should be safe to register for the
1982 * interrupt now.
1983 */
1984 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
1985 ioc->pci_irq = -1;
1986 if (ioc->pcidev->irq) {
1987 if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
1988 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001989 ioc->name);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001990 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06001991 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001992 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001993 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06001994 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07001995 if (mpt_msi_enable)
1996 pci_disable_msi(ioc->pcidev);
1997 return -EBUSY;
1998 }
1999 irq_allocated = 1;
2000 ioc->pci_irq = ioc->pcidev->irq;
2001 pci_set_master(ioc->pcidev); /* ?? */
2002 pci_set_drvdata(ioc->pcidev, ioc);
Eric Moore29dd3602007-09-14 18:46:51 -06002003 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2004 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002005 }
2006 }
2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 /* Prime reply & request queues!
2009 * (mucho alloc's) Must be done prior to
2010 * init as upper addresses are needed for init.
2011 * If fails, continue with alt-ioc processing
2012 */
2013 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2014 ret = -3;
2015
2016 /* May need to check/upload firmware & data here!
2017 * If fails, continue with alt-ioc processing
2018 */
2019 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2020 ret = -4;
2021// NEW!
2022 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002023 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2024 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 alt_ioc_ready = 0;
2026 reset_alt_ioc_active = 0;
2027 }
2028
2029 if (alt_ioc_ready) {
2030 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2031 alt_ioc_ready = 0;
2032 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002033 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2034 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 }
2036 }
2037
2038 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2039 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302040 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002041 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
2043 /* Controller is not operational, cannot do upload
2044 */
2045 if (ret == 0) {
2046 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002047 if (rc == 0) {
2048 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2049 /*
2050 * Maintain only one pointer to FW memory
2051 * so there will not be two attempt to
2052 * downloadboot onboard dual function
2053 * chips (mpt_adapter_disable,
2054 * mpt_diag_reset)
2055 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302056 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002057 "mpt_upload: alt_%s has cached_fw=%p \n",
2058 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302059 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002060 }
2061 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002062 printk(MYIOC_s_WARN_FMT
2063 "firmware upload failure!\n", ioc->name);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002064 ret = -5;
2065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 }
2067 }
2068 }
2069
2070 if (ret == 0) {
2071 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002072 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 ioc->active = 1;
2074 }
2075
2076 if (reset_alt_ioc_active && ioc->alt_ioc) {
2077 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002078 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2079 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002080 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 ioc->alt_ioc->active = 1;
2082 }
2083
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002084 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 * and EventAck handling.
2086 */
2087 if ((ret == 0) && (!ioc->facts.EventState))
2088 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2089
2090 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2091 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2092
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002093 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2095 * recursive scenario; GetLanConfigPages times out, timer expired
2096 * routine calls HardResetHandler, which calls into here again,
2097 * and we try GetLanConfigPages again...
2098 */
2099 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002100
2101 /*
2102 * Initalize link list for inactive raid volumes.
2103 */
2104 init_MUTEX(&ioc->raid_data.inactive_list_mutex);
2105 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2106
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002107 if (ioc->bus_type == SAS) {
2108
2109 /* clear persistency table */
2110 if(ioc->facts.IOCExceptions &
2111 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2112 ret = mptbase_sas_persist_operation(ioc,
2113 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2114 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002115 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002116 }
2117
2118 /* Find IM volumes
2119 */
2120 mpt_findImVolumes(ioc);
2121
2122 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2124 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2125 /*
2126 * Pre-fetch the ports LAN MAC address!
2127 * (LANPage1_t stuff)
2128 */
2129 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302130 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2131 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002132 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2133 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 }
2136 } else {
2137 /* Get NVRAM and adapter maximums from SPP 0 and 2
2138 */
2139 mpt_GetScsiPortSettings(ioc, 0);
2140
2141 /* Get version and length of SDP 1
2142 */
2143 mpt_readScsiDevicePageHeaders(ioc, 0);
2144
2145 /* Find IM volumes
2146 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002147 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 mpt_findImVolumes(ioc);
2149
2150 /* Check, and possibly reset, the coalescing value
2151 */
2152 mpt_read_ioc_pg_1(ioc);
2153
2154 mpt_read_ioc_pg_4(ioc);
2155 }
2156
2157 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302158 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160
2161 /*
2162 * Call each currently registered protocol IOC reset handler
2163 * with post-reset indication.
2164 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2165 * MptResetHandlers[] registered yet.
2166 */
2167 if (hard_reset_done) {
2168 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302169 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2170 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002172 "Calling IOC post_reset handler #%d\n",
2173 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302174 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 handlers++;
2176 }
2177
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302178 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302179 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002180 "Calling IOC post_reset handler #%d\n",
2181 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302182 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 handlers++;
2184 }
2185 }
2186 /* FIXME? Examine results here? */
2187 }
2188
Eric Moore0ccdb002006-07-11 17:33:13 -06002189 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002190 if ((ret != 0) && irq_allocated) {
2191 free_irq(ioc->pci_irq, ioc);
2192 if (mpt_msi_enable)
2193 pci_disable_msi(ioc->pcidev);
2194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 return ret;
2196}
2197
2198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002199/**
2200 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 * @ioc: Pointer to MPT adapter structure
2202 * @pdev: Pointer to (struct pci_dev) structure
2203 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002204 * Search for PCI bus/dev_function which matches
2205 * PCI bus/dev_function (+/-1) for newly discovered 929,
2206 * 929X, 1030 or 1035.
2207 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2209 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2210 */
2211static void
2212mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2213{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002214 struct pci_dev *peer=NULL;
2215 unsigned int slot = PCI_SLOT(pdev->devfn);
2216 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 MPT_ADAPTER *ioc_srch;
2218
Prakash, Sathya436ace72007-07-24 15:42:08 +05302219 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002220 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002221 ioc->name, pci_name(pdev), pdev->bus->number,
2222 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002223
2224 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2225 if (!peer) {
2226 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2227 if (!peer)
2228 return;
2229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 list_for_each_entry(ioc_srch, &ioc_list, list) {
2232 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002233 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 /* Paranoia checks */
2235 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002236 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002237 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 break;
2239 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002240 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002241 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 break;
2243 }
Eric Moore29dd3602007-09-14 18:46:51 -06002244 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002245 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 ioc_srch->alt_ioc = ioc;
2247 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002250 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251}
2252
2253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002254/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002256 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 */
2258static void
2259mpt_adapter_disable(MPT_ADAPTER *ioc)
2260{
2261 int sz;
2262 int ret;
2263
2264 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302265 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
2266 "adapter\n", __FUNCTION__, ioc->name));
2267 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2268 ioc->cached_fw, CAN_SLEEP)) < 0) {
2269 printk(MYIOC_s_WARN_FMT
2270 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002271 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
2273 }
2274
2275 /* Disable adapter interrupts! */
2276 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2277 ioc->active = 0;
2278 /* Clear any lingering interrupt */
2279 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2280
2281 if (ioc->alloc != NULL) {
2282 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002283 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2284 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 pci_free_consistent(ioc->pcidev, sz,
2286 ioc->alloc, ioc->alloc_dma);
2287 ioc->reply_frames = NULL;
2288 ioc->req_frames = NULL;
2289 ioc->alloc = NULL;
2290 ioc->alloc_total -= sz;
2291 }
2292
2293 if (ioc->sense_buf_pool != NULL) {
2294 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2295 pci_free_consistent(ioc->pcidev, sz,
2296 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2297 ioc->sense_buf_pool = NULL;
2298 ioc->alloc_total -= sz;
2299 }
2300
2301 if (ioc->events != NULL){
2302 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2303 kfree(ioc->events);
2304 ioc->events = NULL;
2305 ioc->alloc_total -= sz;
2306 }
2307
Prakash, Sathya984621b2008-01-11 14:42:17 +05302308 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002310 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002311 mpt_inactive_raid_list_free(ioc);
2312 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002313 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002314 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002315 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 if (ioc->spi_data.pIocPg4 != NULL) {
2318 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302319 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 ioc->spi_data.pIocPg4,
2321 ioc->spi_data.IocPg4_dma);
2322 ioc->spi_data.pIocPg4 = NULL;
2323 ioc->alloc_total -= sz;
2324 }
2325
2326 if (ioc->ReqToChain != NULL) {
2327 kfree(ioc->ReqToChain);
2328 kfree(ioc->RequestNB);
2329 ioc->ReqToChain = NULL;
2330 }
2331
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002332 kfree(ioc->ChainToChain);
2333 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002334
2335 if (ioc->HostPageBuffer != NULL) {
2336 if((ret = mpt_host_page_access_control(ioc,
2337 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002338 printk(MYIOC_s_ERR_FMT
2339 "host page buffers free failed (%d)!\n",
2340 ioc->name, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002341 }
Eric Moore29dd3602007-09-14 18:46:51 -06002342 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002343 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2344 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002345 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002346 ioc->HostPageBuffer = NULL;
2347 ioc->HostPageBuffer_sz = 0;
2348 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350}
2351
2352/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002353/**
2354 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 * @ioc: Pointer to MPT adapter structure
2356 *
2357 * This routine unregisters h/w resources and frees all alloc'd memory
2358 * associated with a MPT adapter structure.
2359 */
2360static void
2361mpt_adapter_dispose(MPT_ADAPTER *ioc)
2362{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002363 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002365 if (ioc == NULL)
2366 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002368 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002370 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002372 if (ioc->pci_irq != -1) {
2373 free_irq(ioc->pci_irq, ioc);
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002374 if (mpt_msi_enable)
2375 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002376 ioc->pci_irq = -1;
2377 }
2378
2379 if (ioc->memmap != NULL) {
2380 iounmap(ioc->memmap);
2381 ioc->memmap = NULL;
2382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
2384#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002385 if (ioc->mtrr_reg > 0) {
2386 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002387 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389#endif
2390
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002391 /* Zap the adapter lookup ptr! */
2392 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002394 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002395 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2396 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002397
2398 if (ioc->alt_ioc)
2399 ioc->alt_ioc->alt_ioc = NULL;
2400
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002401 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402}
2403
2404/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002405/**
2406 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 * @ioc: Pointer to MPT adapter structure
2408 */
2409static void
2410MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2411{
2412 int i = 0;
2413
2414 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302415 if (ioc->prod_name)
2416 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 printk("Capabilities={");
2418
2419 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2420 printk("Initiator");
2421 i++;
2422 }
2423
2424 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2425 printk("%sTarget", i ? "," : "");
2426 i++;
2427 }
2428
2429 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2430 printk("%sLAN", i ? "," : "");
2431 i++;
2432 }
2433
2434#if 0
2435 /*
2436 * This would probably evoke more questions than it's worth
2437 */
2438 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2439 printk("%sLogBusAddr", i ? "," : "");
2440 i++;
2441 }
2442#endif
2443
2444 printk("}\n");
2445}
2446
2447/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002448/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2450 * @ioc: Pointer to MPT_ADAPTER structure
2451 * @force: Force hard KickStart of IOC
2452 * @sleepFlag: Specifies whether the process can sleep
2453 *
2454 * Returns:
2455 * 1 - DIAG reset and READY
2456 * 0 - READY initially OR soft reset and READY
2457 * -1 - Any failure on KickStart
2458 * -2 - Msg Unit Reset Failed
2459 * -3 - IO Unit Reset Failed
2460 * -4 - IOC owned by a PEER
2461 */
2462static int
2463MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2464{
2465 u32 ioc_state;
2466 int statefault = 0;
2467 int cntdn;
2468 int hard_reset_done = 0;
2469 int r;
2470 int ii;
2471 int whoinit;
2472
2473 /* Get current [raw] IOC state */
2474 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002475 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
2477 /*
2478 * Check to see if IOC got left/stuck in doorbell handshake
2479 * grip of death. If so, hard reset the IOC.
2480 */
2481 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2482 statefault = 1;
2483 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2484 ioc->name);
2485 }
2486
2487 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002488 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 return 0;
2490
2491 /*
2492 * Check to see if IOC is in FAULT state.
2493 */
2494 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2495 statefault = 2;
2496 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002497 ioc->name);
2498 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2499 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501
2502 /*
2503 * Hmmm... Did it get left operational?
2504 */
2505 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302506 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 ioc->name));
2508
2509 /* Check WhoInit.
2510 * If PCI Peer, exit.
2511 * Else, if no fault conditions are present, issue a MessageUnitReset
2512 * Else, fall through to KickStart case
2513 */
2514 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002515 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2516 "whoinit 0x%x statefault %d force %d\n",
2517 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 if (whoinit == MPI_WHOINIT_PCI_PEER)
2519 return -4;
2520 else {
2521 if ((statefault == 0 ) && (force == 0)) {
2522 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2523 return 0;
2524 }
2525 statefault = 3;
2526 }
2527 }
2528
2529 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2530 if (hard_reset_done < 0)
2531 return -1;
2532
2533 /*
2534 * Loop here waiting for IOC to come READY.
2535 */
2536 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002537 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
2539 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2540 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2541 /*
2542 * BIOS or previous driver load left IOC in OP state.
2543 * Reset messaging FIFOs.
2544 */
2545 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2546 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2547 return -2;
2548 }
2549 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2550 /*
2551 * Something is wrong. Try to get IOC back
2552 * to a known state.
2553 */
2554 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2555 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2556 return -3;
2557 }
2558 }
2559
2560 ii++; cntdn--;
2561 if (!cntdn) {
2562 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2563 ioc->name, (int)((ii+5)/HZ));
2564 return -ETIME;
2565 }
2566
2567 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002568 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 } else {
2570 mdelay (1); /* 1 msec delay */
2571 }
2572
2573 }
2574
2575 if (statefault < 3) {
2576 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2577 ioc->name,
2578 statefault==1 ? "stuck handshake" : "IOC FAULT");
2579 }
2580
2581 return hard_reset_done;
2582}
2583
2584/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002585/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 * mpt_GetIocState - Get the current state of a MPT adapter.
2587 * @ioc: Pointer to MPT_ADAPTER structure
2588 * @cooked: Request raw or cooked IOC state
2589 *
2590 * Returns all IOC Doorbell register bits if cooked==0, else just the
2591 * Doorbell bits in MPI_IOC_STATE_MASK.
2592 */
2593u32
2594mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2595{
2596 u32 s, sc;
2597
2598 /* Get! */
2599 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 sc = s & MPI_IOC_STATE_MASK;
2601
2602 /* Save! */
2603 ioc->last_state = sc;
2604
2605 return cooked ? sc : s;
2606}
2607
2608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002609/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 * GetIocFacts - Send IOCFacts request to MPT adapter.
2611 * @ioc: Pointer to MPT_ADAPTER structure
2612 * @sleepFlag: Specifies whether the process can sleep
2613 * @reason: If recovery, only update facts.
2614 *
2615 * Returns 0 for success, non-zero for failure.
2616 */
2617static int
2618GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2619{
2620 IOCFacts_t get_facts;
2621 IOCFactsReply_t *facts;
2622 int r;
2623 int req_sz;
2624 int reply_sz;
2625 int sz;
2626 u32 status, vv;
2627 u8 shiftFactor=1;
2628
2629 /* IOC *must* NOT be in RESET state! */
2630 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002631 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2632 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return -44;
2634 }
2635
2636 facts = &ioc->facts;
2637
2638 /* Destination (reply area)... */
2639 reply_sz = sizeof(*facts);
2640 memset(facts, 0, reply_sz);
2641
2642 /* Request area (get_facts on the stack right now!) */
2643 req_sz = sizeof(get_facts);
2644 memset(&get_facts, 0, req_sz);
2645
2646 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2647 /* Assert: All other get_facts fields are zero! */
2648
Prakash, Sathya436ace72007-07-24 15:42:08 +05302649 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002650 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 ioc->name, req_sz, reply_sz));
2652
2653 /* No non-zero fields in the get_facts request are greater than
2654 * 1 byte in size, so we can just fire it off as is.
2655 */
2656 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
2657 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
2658 if (r != 0)
2659 return r;
2660
2661 /*
2662 * Now byte swap (GRRR) the necessary fields before any further
2663 * inspection of reply contents.
2664 *
2665 * But need to do some sanity checks on MsgLength (byte) field
2666 * to make sure we don't zero IOC's req_sz!
2667 */
2668 /* Did we get a valid reply? */
2669 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
2670 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2671 /*
2672 * If not been here, done that, save off first WhoInit value
2673 */
2674 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
2675 ioc->FirstWhoInit = facts->WhoInit;
2676 }
2677
2678 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
2679 facts->MsgContext = le32_to_cpu(facts->MsgContext);
2680 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
2681 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
2682 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02002683 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 /* CHECKME! IOCStatus, IOCLogInfo */
2685
2686 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
2687 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
2688
2689 /*
2690 * FC f/w version changed between 1.1 and 1.2
2691 * Old: u16{Major(4),Minor(4),SubMinor(8)}
2692 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
2693 */
2694 if (facts->MsgVersion < 0x0102) {
2695 /*
2696 * Handle old FC f/w style, convert to new...
2697 */
2698 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
2699 facts->FWVersion.Word =
2700 ((oldv<<12) & 0xFF000000) |
2701 ((oldv<<8) & 0x000FFF00);
2702 } else
2703 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
2704
2705 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07002706 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
2707 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
2708 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 facts->CurrentHostMfaHighAddr =
2710 le32_to_cpu(facts->CurrentHostMfaHighAddr);
2711 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
2712 facts->CurrentSenseBufferHighAddr =
2713 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
2714 facts->CurReplyFrameSize =
2715 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002716 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
2718 /*
2719 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
2720 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
2721 * to 14 in MPI-1.01.0x.
2722 */
2723 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
2724 facts->MsgVersion > 0x0100) {
2725 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
2726 }
2727
2728 sz = facts->FWImageSize;
2729 if ( sz & 0x01 )
2730 sz += 1;
2731 if ( sz & 0x02 )
2732 sz += 2;
2733 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002734
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 if (!facts->RequestFrameSize) {
2736 /* Something is wrong! */
2737 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
2738 ioc->name);
2739 return -55;
2740 }
2741
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002742 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 vv = ((63 / (sz * 4)) + 1) & 0x03;
2744 ioc->NB_for_64_byte_frame = vv;
2745 while ( sz )
2746 {
2747 shiftFactor++;
2748 sz = sz >> 1;
2749 }
2750 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302751 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002752 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
2753 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2756 /*
2757 * Set values for this IOC's request & reply frame sizes,
2758 * and request & reply queue depths...
2759 */
2760 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
2761 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
2762 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
2763 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
2764
Prakash, Sathya436ace72007-07-24 15:42:08 +05302765 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302767 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 ioc->name, ioc->req_sz, ioc->req_depth));
2769
2770 /* Get port facts! */
2771 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
2772 return r;
2773 }
2774 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002775 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
2777 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
2778 RequestFrameSize)/sizeof(u32)));
2779 return -66;
2780 }
2781
2782 return 0;
2783}
2784
2785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002786/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 * GetPortFacts - Send PortFacts request to MPT adapter.
2788 * @ioc: Pointer to MPT_ADAPTER structure
2789 * @portnum: Port number
2790 * @sleepFlag: Specifies whether the process can sleep
2791 *
2792 * Returns 0 for success, non-zero for failure.
2793 */
2794static int
2795GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
2796{
2797 PortFacts_t get_pfacts;
2798 PortFactsReply_t *pfacts;
2799 int ii;
2800 int req_sz;
2801 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07002802 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
2804 /* IOC *must* NOT be in RESET state! */
2805 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002806 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
2807 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 return -4;
2809 }
2810
2811 pfacts = &ioc->pfacts[portnum];
2812
2813 /* Destination (reply area)... */
2814 reply_sz = sizeof(*pfacts);
2815 memset(pfacts, 0, reply_sz);
2816
2817 /* Request area (get_pfacts on the stack right now!) */
2818 req_sz = sizeof(get_pfacts);
2819 memset(&get_pfacts, 0, req_sz);
2820
2821 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
2822 get_pfacts.PortNumber = portnum;
2823 /* Assert: All other get_pfacts fields are zero! */
2824
Prakash, Sathya436ace72007-07-24 15:42:08 +05302825 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 ioc->name, portnum));
2827
2828 /* No non-zero fields in the get_pfacts request are greater than
2829 * 1 byte in size, so we can just fire it off as is.
2830 */
2831 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
2832 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
2833 if (ii != 0)
2834 return ii;
2835
2836 /* Did we get a valid reply? */
2837
2838 /* Now byte swap the necessary fields in the response. */
2839 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
2840 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
2841 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
2842 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
2843 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
2844 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
2845 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
2846 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
2847 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
2848
Eric Moore793955f2007-01-29 09:42:20 -07002849 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
2850 pfacts->MaxDevices;
2851 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
2852 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
2853
2854 /*
2855 * Place all the devices on channels
2856 *
2857 * (for debuging)
2858 */
2859 if (mpt_channel_mapping) {
2860 ioc->devices_per_bus = 1;
2861 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
2862 }
2863
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 return 0;
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002868/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 * SendIocInit - Send IOCInit request to MPT adapter.
2870 * @ioc: Pointer to MPT_ADAPTER structure
2871 * @sleepFlag: Specifies whether the process can sleep
2872 *
2873 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
2874 *
2875 * Returns 0 for success, non-zero for failure.
2876 */
2877static int
2878SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
2879{
2880 IOCInit_t ioc_init;
2881 MPIDefaultReply_t init_reply;
2882 u32 state;
2883 int r;
2884 int count;
2885 int cntdn;
2886
2887 memset(&ioc_init, 0, sizeof(ioc_init));
2888 memset(&init_reply, 0, sizeof(init_reply));
2889
2890 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
2891 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
2892
2893 /* If we are in a recovery mode and we uploaded the FW image,
2894 * then this pointer is not NULL. Skip the upload a second time.
2895 * Set this flag if cached_fw set for either IOC.
2896 */
2897 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
2898 ioc->upload_fw = 1;
2899 else
2900 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302901 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 ioc->name, ioc->upload_fw, ioc->facts.Flags));
2903
Eric Moore793955f2007-01-29 09:42:20 -07002904 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
2905 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302906 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002907 ioc->name, ioc->facts.MsgVersion));
2908 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
2909 // set MsgVersion and HeaderVersion host driver was built with
2910 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
2911 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002913 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
2914 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
2915 } else if(mpt_host_page_alloc(ioc, &ioc_init))
2916 return -99;
2917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
2919
2920 if (sizeof(dma_addr_t) == sizeof(u64)) {
2921 /* Save the upper 32-bits of the request
2922 * (reply) and sense buffers.
2923 */
2924 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
2925 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
2926 } else {
2927 /* Force 32-bit addressing */
2928 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
2929 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
2930 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
2933 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002934 ioc->facts.MaxDevices = ioc_init.MaxDevices;
2935 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
Prakash, Sathya436ace72007-07-24 15:42:08 +05302937 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 ioc->name, &ioc_init));
2939
2940 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
2941 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002942 if (r != 0) {
2943 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002948 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 */
2950
Prakash, Sathya436ace72007-07-24 15:42:08 +05302951 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002953
2954 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
2955 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
2959 /* YIKES! SUPER IMPORTANT!!!
2960 * Poll IocState until _OPERATIONAL while IOC is doing
2961 * LoopInit and TargetDiscovery!
2962 */
2963 count = 0;
2964 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
2965 state = mpt_GetIocState(ioc, 1);
2966 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
2967 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002968 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 } else {
2970 mdelay(1);
2971 }
2972
2973 if (!cntdn) {
2974 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
2975 ioc->name, (int)((count+5)/HZ));
2976 return -9;
2977 }
2978
2979 state = mpt_GetIocState(ioc, 1);
2980 count++;
2981 }
Eric Moore29dd3602007-09-14 18:46:51 -06002982 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 ioc->name, count));
2984
Eric Mooreba856d32006-07-11 17:34:01 -06002985 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 return r;
2987}
2988
2989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002990/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 * SendPortEnable - Send PortEnable request to MPT adapter port.
2992 * @ioc: Pointer to MPT_ADAPTER structure
2993 * @portnum: Port number to enable
2994 * @sleepFlag: Specifies whether the process can sleep
2995 *
2996 * Send PortEnable to bring IOC to OPERATIONAL state.
2997 *
2998 * Returns 0 for success, non-zero for failure.
2999 */
3000static int
3001SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3002{
3003 PortEnable_t port_enable;
3004 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003005 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 int req_sz;
3007 int reply_sz;
3008
3009 /* Destination... */
3010 reply_sz = sizeof(MPIDefaultReply_t);
3011 memset(&reply_buf, 0, reply_sz);
3012
3013 req_sz = sizeof(PortEnable_t);
3014 memset(&port_enable, 0, req_sz);
3015
3016 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3017 port_enable.PortNumber = portnum;
3018/* port_enable.ChainOffset = 0; */
3019/* port_enable.MsgFlags = 0; */
3020/* port_enable.MsgContext = 0; */
3021
Prakash, Sathya436ace72007-07-24 15:42:08 +05303022 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 ioc->name, portnum, &port_enable));
3024
3025 /* RAID FW may take a long time to enable
3026 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003027 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003028 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3029 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3030 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003031 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003032 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3033 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3034 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003036 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037}
3038
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003039/**
3040 * mpt_alloc_fw_memory - allocate firmware memory
3041 * @ioc: Pointer to MPT_ADAPTER structure
3042 * @size: total FW bytes
3043 *
3044 * If memory has already been allocated, the same (cached) value
3045 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303046 *
3047 * Return 0 if successfull, or non-zero for failure
3048 **/
3049int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3051{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303052 int rc;
3053
3054 if (ioc->cached_fw) {
3055 rc = 0; /* use already allocated memory */
3056 goto out;
3057 }
3058 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3060 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303061 rc = 0;
3062 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303064 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3065 if (!ioc->cached_fw) {
3066 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3067 ioc->name);
3068 rc = -1;
3069 } else {
3070 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3071 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3072 ioc->alloc_total += size;
3073 rc = 0;
3074 }
3075 out:
3076 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303078
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003079/**
3080 * mpt_free_fw_memory - free firmware memory
3081 * @ioc: Pointer to MPT_ADAPTER structure
3082 *
3083 * If alt_img is NULL, delete from ioc structure.
3084 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303085 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086void
3087mpt_free_fw_memory(MPT_ADAPTER *ioc)
3088{
3089 int sz;
3090
Prakash, Sathya984621b2008-01-11 14:42:17 +05303091 if (!ioc->cached_fw)
3092 return;
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303095 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3096 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003097 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303098 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100}
3101
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003103/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3105 * @ioc: Pointer to MPT_ADAPTER structure
3106 * @sleepFlag: Specifies whether the process can sleep
3107 *
3108 * Returns 0 for success, >0 for handshake failure
3109 * <0 for fw upload failure.
3110 *
3111 * Remark: If bound IOC and a successful FWUpload was performed
3112 * on the bound IOC, the second image is discarded
3113 * and memory is free'd. Both channels must upload to prevent
3114 * IOC from running in degraded mode.
3115 */
3116static int
3117mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3118{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 u8 reply[sizeof(FWUploadReply_t)];
3120 FWUpload_t *prequest;
3121 FWUploadReply_t *preply;
3122 FWUploadTCSGE_t *ptcsge;
3123 int sgeoffset;
3124 u32 flagsLength;
3125 int ii, sz, reply_sz;
3126 int cmdStatus;
3127
3128 /* If the image size is 0, we are done.
3129 */
3130 if ((sz = ioc->facts.FWImageSize) == 0)
3131 return 0;
3132
Prakash, Sathya984621b2008-01-11 14:42:17 +05303133 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3134 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
Eric Moore29dd3602007-09-14 18:46:51 -06003136 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3137 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003138
Eric Moorebc6e0892007-09-29 10:16:28 -06003139 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3140 kzalloc(ioc->req_sz, GFP_KERNEL);
3141 if (!prequest) {
3142 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3143 "while allocating memory \n", ioc->name));
3144 mpt_free_fw_memory(ioc);
3145 return -ENOMEM;
3146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147
Eric Moorebc6e0892007-09-29 10:16:28 -06003148 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
3150 reply_sz = sizeof(reply);
3151 memset(preply, 0, reply_sz);
3152
3153 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3154 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3155
3156 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3157 ptcsge->DetailsLength = 12;
3158 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3159 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003160 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
3162 sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
3163
3164 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Eric Moorebc6e0892007-09-29 10:16:28 -06003165 mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
3167 sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
Eric Moore29dd3602007-09-14 18:46:51 -06003168 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
3169 ioc->name, prequest, sgeoffset));
3170 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
3173 reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
3174
Eric Moore29dd3602007-09-14 18:46:51 -06003175 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177 cmdStatus = -EFAULT;
3178 if (ii == 0) {
3179 /* Handshake transfer was complete and successful.
3180 * Check the Reply Frame.
3181 */
3182 int status, transfer_sz;
3183 status = le16_to_cpu(preply->IOCStatus);
3184 if (status == MPI_IOCSTATUS_SUCCESS) {
3185 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3186 if (transfer_sz == sz)
3187 cmdStatus = 0;
3188 }
3189 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303190 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 ioc->name, cmdStatus));
3192
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003193
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 if (cmdStatus) {
3195
Prakash, Sathya436ace72007-07-24 15:42:08 +05303196 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 ioc->name));
3198 mpt_free_fw_memory(ioc);
3199 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003200 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
3202 return cmdStatus;
3203}
3204
3205/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003206/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 * mpt_downloadboot - DownloadBoot code
3208 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003209 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 * @sleepFlag: Specifies whether the process can sleep
3211 *
3212 * FwDownloadBoot requires Programmed IO access.
3213 *
3214 * Returns 0 for success
3215 * -1 FW Image size is 0
3216 * -2 No valid cached_fw Pointer
3217 * <0 for fw upload failure.
3218 */
3219static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003220mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 MpiExtImageHeader_t *pExtImage;
3223 u32 fwSize;
3224 u32 diag0val;
3225 int count;
3226 u32 *ptrFw;
3227 u32 diagRwData;
3228 u32 nextImage;
3229 u32 load_addr;
3230 u32 ioc_state=0;
3231
Prakash, Sathya436ace72007-07-24 15:42:08 +05303232 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003233 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003234
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3236 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3237 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3238 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3239 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3240 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3241
3242 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3243
3244 /* wait 1 msec */
3245 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003246 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 } else {
3248 mdelay (1);
3249 }
3250
3251 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3252 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3253
3254 for (count = 0; count < 30; count ++) {
3255 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3256 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303257 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 ioc->name, count));
3259 break;
3260 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003261 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003263 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003265 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 }
3267 }
3268
3269 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303270 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003271 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 ioc->name, diag0val));
3273 return -3;
3274 }
3275
3276 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3277 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3278 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3279 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3280 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3281 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3282
3283 /* Set the DiagRwEn and Disable ARM bits */
3284 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3285
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 fwSize = (pFwHeader->ImageSize + 3)/4;
3287 ptrFw = (u32 *) pFwHeader;
3288
3289 /* Write the LoadStartAddress to the DiagRw Address Register
3290 * using Programmed IO
3291 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003292 if (ioc->errata_flag_1064)
3293 pci_enable_io_access(ioc->pcidev);
3294
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303296 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 ioc->name, pFwHeader->LoadStartAddress));
3298
Prakash, Sathya436ace72007-07-24 15:42:08 +05303299 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 ioc->name, fwSize*4, ptrFw));
3301 while (fwSize--) {
3302 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3303 }
3304
3305 nextImage = pFwHeader->NextImageHeaderOffset;
3306 while (nextImage) {
3307 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3308
3309 load_addr = pExtImage->LoadStartAddress;
3310
3311 fwSize = (pExtImage->ImageSize + 3) >> 2;
3312 ptrFw = (u32 *)pExtImage;
3313
Prakash, Sathya436ace72007-07-24 15:42:08 +05303314 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 +02003315 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3317
3318 while (fwSize--) {
3319 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3320 }
3321 nextImage = pExtImage->NextImageHeaderOffset;
3322 }
3323
3324 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303325 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3327
3328 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303329 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3331
3332 /* Clear the internal flash bad bit - autoincrementing register,
3333 * so must do two writes.
3334 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003335 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003336 /*
3337 * 1030 and 1035 H/W errata, workaround to access
3338 * the ClearFlashBadSignatureBit
3339 */
3340 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3341 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3342 diagRwData |= 0x40000000;
3343 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3344 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3345
3346 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3347 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3348 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3349 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3350
3351 /* wait 1 msec */
3352 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003353 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003354 } else {
3355 mdelay (1);
3356 }
3357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003359 if (ioc->errata_flag_1064)
3360 pci_disable_io_access(ioc->pcidev);
3361
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303363 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003364 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003366 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303367 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 ioc->name, diag0val));
3369 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3370
3371 /* Write 0xFF to reset the sequencer */
3372 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3373
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003374 if (ioc->bus_type == SAS) {
3375 ioc_state = mpt_GetIocState(ioc, 0);
3376 if ( (GetIocFacts(ioc, sleepFlag,
3377 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303378 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003379 ioc->name, ioc_state));
3380 return -EFAULT;
3381 }
3382 }
3383
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 for (count=0; count<HZ*20; count++) {
3385 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303386 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3387 "downloadboot successful! (count=%d) IocState=%x\n",
3388 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003389 if (ioc->bus_type == SAS) {
3390 return 0;
3391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303393 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3394 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 ioc->name));
3396 return -EFAULT;
3397 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303398 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3399 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 ioc->name));
3401 return 0;
3402 }
3403 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003404 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 } else {
3406 mdelay (10);
3407 }
3408 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303409 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3410 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 return -EFAULT;
3412}
3413
3414/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003415/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 * KickStart - Perform hard reset of MPT adapter.
3417 * @ioc: Pointer to MPT_ADAPTER structure
3418 * @force: Force hard reset
3419 * @sleepFlag: Specifies whether the process can sleep
3420 *
3421 * This routine places MPT adapter in diagnostic mode via the
3422 * WriteSequence register, and then performs a hard reset of adapter
3423 * via the Diagnostic register.
3424 *
3425 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3426 * or NO_SLEEP (interrupt thread, use mdelay)
3427 * force - 1 if doorbell active, board fault state
3428 * board operational, IOC_RECOVERY or
3429 * IOC_BRINGUP and there is an alt_ioc.
3430 * 0 else
3431 *
3432 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003433 * 1 - hard reset, READY
3434 * 0 - no reset due to History bit, READY
3435 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 * OR reset but failed to come READY
3437 * -2 - no reset, could not enter DIAG mode
3438 * -3 - reset but bad FW bit
3439 */
3440static int
3441KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3442{
3443 int hard_reset_done = 0;
3444 u32 ioc_state=0;
3445 int cnt,cntdn;
3446
Eric Moore29dd3602007-09-14 18:46:51 -06003447 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003448 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 /* Always issue a Msg Unit Reset first. This will clear some
3450 * SCSI bus hang conditions.
3451 */
3452 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3453
3454 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003455 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 } else {
3457 mdelay (1000);
3458 }
3459 }
3460
3461 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3462 if (hard_reset_done < 0)
3463 return hard_reset_done;
3464
Prakash, Sathya436ace72007-07-24 15:42:08 +05303465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003466 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
3468 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3469 for (cnt=0; cnt<cntdn; cnt++) {
3470 ioc_state = mpt_GetIocState(ioc, 1);
3471 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303472 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 ioc->name, cnt));
3474 return hard_reset_done;
3475 }
3476 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003477 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 } else {
3479 mdelay (10);
3480 }
3481 }
3482
Eric Moore29dd3602007-09-14 18:46:51 -06003483 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3484 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 return -1;
3486}
3487
3488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003489/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 * mpt_diag_reset - Perform hard reset of the adapter.
3491 * @ioc: Pointer to MPT_ADAPTER structure
3492 * @ignore: Set if to honor and clear to ignore
3493 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003494 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 * else set to NO_SLEEP (use mdelay instead)
3496 *
3497 * This routine places the adapter in diagnostic mode via the
3498 * WriteSequence register and then performs a hard reset of adapter
3499 * via the Diagnostic register. Adapter should be in ready state
3500 * upon successful completion.
3501 *
3502 * Returns: 1 hard reset successful
3503 * 0 no reset performed because reset history bit set
3504 * -2 enabling diagnostic mode failed
3505 * -3 diagnostic reset failed
3506 */
3507static int
3508mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3509{
3510 u32 diag0val;
3511 u32 doorbell;
3512 int hard_reset_done = 0;
3513 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303515 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
Eric Moorecd2c6192007-01-29 09:47:47 -07003517 /* Clear any existing interrupts */
3518 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3519
Eric Moore87cf8982006-06-27 16:09:26 -06003520 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303521 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Eric Moore87cf8982006-06-27 16:09:26 -06003522 "address=%p\n", ioc->name, __FUNCTION__,
3523 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3524 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3525 if (sleepFlag == CAN_SLEEP)
3526 msleep(1);
3527 else
3528 mdelay(1);
3529
3530 for (count = 0; count < 60; count ++) {
3531 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3532 doorbell &= MPI_IOC_STATE_MASK;
3533
Prakash, Sathya436ace72007-07-24 15:42:08 +05303534 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003535 "looking for READY STATE: doorbell=%x"
3536 " count=%d\n",
3537 ioc->name, doorbell, count));
3538 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003539 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003540 }
3541
3542 /* wait 1 sec */
3543 if (sleepFlag == CAN_SLEEP)
3544 msleep(1000);
3545 else
3546 mdelay(1000);
3547 }
3548 return -1;
3549 }
3550
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 /* Use "Diagnostic reset" method! (only thing available!) */
3552 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3553
Prakash, Sathya436ace72007-07-24 15:42:08 +05303554 if (ioc->debug_level & MPT_DEBUG) {
3555 if (ioc->alt_ioc)
3556 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3557 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
3561 /* Do the reset if we are told to ignore the reset history
3562 * or if the reset history is 0
3563 */
3564 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3565 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3566 /* Write magic sequence to WriteSequence register
3567 * Loop until in diagnostic mode
3568 */
3569 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3570 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3571 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3572 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3573 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3574 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3575
3576 /* wait 100 msec */
3577 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003578 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 } else {
3580 mdelay (100);
3581 }
3582
3583 count++;
3584 if (count > 20) {
3585 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3586 ioc->name, diag0val);
3587 return -2;
3588
3589 }
3590
3591 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3592
Prakash, Sathya436ace72007-07-24 15:42:08 +05303593 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 ioc->name, diag0val));
3595 }
3596
Prakash, Sathya436ace72007-07-24 15:42:08 +05303597 if (ioc->debug_level & MPT_DEBUG) {
3598 if (ioc->alt_ioc)
3599 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3600 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 /*
3604 * Disable the ARM (Bug fix)
3605 *
3606 */
3607 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003608 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
3610 /*
3611 * Now hit the reset bit in the Diagnostic register
3612 * (THE BIG HAMMER!) (Clears DRWE bit).
3613 */
3614 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3615 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303616 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 ioc->name));
3618
3619 /*
3620 * Call each currently registered protocol IOC reset handler
3621 * with pre-reset indication.
3622 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3623 * MptResetHandlers[] registered yet.
3624 */
3625 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303626 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 int r = 0;
3628
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303629 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3630 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303631 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3632 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303633 ioc->name, cb_idx));
3634 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303636 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3637 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303638 ioc->name, ioc->alt_ioc->name, cb_idx));
3639 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 }
3641 }
3642 }
3643 /* FIXME? Examine results here? */
3644 }
3645
Eric Moore0ccdb002006-07-11 17:33:13 -06003646 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303647 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003648 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303649 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3650 else
3651 cached_fw = NULL;
3652 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 /* If the DownloadBoot operation fails, the
3654 * IOC will be left unusable. This is a fatal error
3655 * case. _diag_reset will return < 0
3656 */
3657 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05303658 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
3660 break;
3661 }
3662
Prakash, Sathya436ace72007-07-24 15:42:08 +05303663 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05303664 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 /* wait 1 sec */
3666 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003667 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 } else {
3669 mdelay (1000);
3670 }
3671 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303672 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06003673 printk(MYIOC_s_WARN_FMT
3674 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 }
3676
3677 } else {
3678 /* Wait for FW to reload and for board
3679 * to go to the READY state.
3680 * Maximum wait is 60 seconds.
3681 * If fail, no error will check again
3682 * with calling program.
3683 */
3684 for (count = 0; count < 60; count ++) {
3685 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3686 doorbell &= MPI_IOC_STATE_MASK;
3687
3688 if (doorbell == MPI_IOC_STATE_READY) {
3689 break;
3690 }
3691
3692 /* wait 1 sec */
3693 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003694 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 } else {
3696 mdelay (1000);
3697 }
3698 }
3699 }
3700 }
3701
3702 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303703 if (ioc->debug_level & MPT_DEBUG) {
3704 if (ioc->alt_ioc)
3705 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3706 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
3707 ioc->name, diag0val, diag1val));
3708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710 /* Clear RESET_HISTORY bit! Place board in the
3711 * diagnostic mode to update the diag register.
3712 */
3713 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3714 count = 0;
3715 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3716 /* Write magic sequence to WriteSequence register
3717 * Loop until in diagnostic mode
3718 */
3719 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3720 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3721 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3722 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3723 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3724 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3725
3726 /* wait 100 msec */
3727 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003728 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 } else {
3730 mdelay (100);
3731 }
3732
3733 count++;
3734 if (count > 20) {
3735 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3736 ioc->name, diag0val);
3737 break;
3738 }
3739 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3740 }
3741 diag0val &= ~MPI_DIAG_RESET_HISTORY;
3742 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3743 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3744 if (diag0val & MPI_DIAG_RESET_HISTORY) {
3745 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
3746 ioc->name);
3747 }
3748
3749 /* Disable Diagnostic Mode
3750 */
3751 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
3752
3753 /* Check FW reload status flags.
3754 */
3755 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3756 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
3757 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
3758 ioc->name, diag0val);
3759 return -3;
3760 }
3761
Prakash, Sathya436ace72007-07-24 15:42:08 +05303762 if (ioc->debug_level & MPT_DEBUG) {
3763 if (ioc->alt_ioc)
3764 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3765 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768
3769 /*
3770 * Reset flag that says we've enabled event notification
3771 */
3772 ioc->facts.EventState = 0;
3773
3774 if (ioc->alt_ioc)
3775 ioc->alt_ioc->facts.EventState = 0;
3776
3777 return hard_reset_done;
3778}
3779
3780/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003781/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 * SendIocReset - Send IOCReset request to MPT adapter.
3783 * @ioc: Pointer to MPT_ADAPTER structure
3784 * @reset_type: reset type, expected values are
3785 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003786 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 *
3788 * Send IOCReset request to the MPT adapter.
3789 *
3790 * Returns 0 for success, non-zero for failure.
3791 */
3792static int
3793SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
3794{
3795 int r;
3796 u32 state;
3797 int cntdn, count;
3798
Prakash, Sathya436ace72007-07-24 15:42:08 +05303799 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 ioc->name, reset_type));
3801 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
3802 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
3803 return r;
3804
3805 /* FW ACK'd request, wait for READY state
3806 */
3807 count = 0;
3808 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
3809
3810 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
3811 cntdn--;
3812 count++;
3813 if (!cntdn) {
3814 if (sleepFlag != CAN_SLEEP)
3815 count *= 10;
3816
Eric Moore29dd3602007-09-14 18:46:51 -06003817 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
3818 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 return -ETIME;
3820 }
3821
3822 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003823 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 } else {
3825 mdelay (1); /* 1 msec delay */
3826 }
3827 }
3828
3829 /* TODO!
3830 * Cleanup all event stuff for this IOC; re-issue EventNotification
3831 * request if needed.
3832 */
3833 if (ioc->facts.Function)
3834 ioc->facts.EventState = 0;
3835
3836 return 0;
3837}
3838
3839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003840/**
3841 * initChainBuffers - Allocate memory for and initialize chain buffers
3842 * @ioc: Pointer to MPT_ADAPTER structure
3843 *
3844 * Allocates memory for and initializes chain buffers,
3845 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 */
3847static int
3848initChainBuffers(MPT_ADAPTER *ioc)
3849{
3850 u8 *mem;
3851 int sz, ii, num_chain;
3852 int scale, num_sge, numSGE;
3853
3854 /* ReqToChain size must equal the req_depth
3855 * index = req_idx
3856 */
3857 if (ioc->ReqToChain == NULL) {
3858 sz = ioc->req_depth * sizeof(int);
3859 mem = kmalloc(sz, GFP_ATOMIC);
3860 if (mem == NULL)
3861 return -1;
3862
3863 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303864 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 ioc->name, mem, sz));
3866 mem = kmalloc(sz, GFP_ATOMIC);
3867 if (mem == NULL)
3868 return -1;
3869
3870 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303871 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 ioc->name, mem, sz));
3873 }
3874 for (ii = 0; ii < ioc->req_depth; ii++) {
3875 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
3876 }
3877
3878 /* ChainToChain size must equal the total number
3879 * of chain buffers to be allocated.
3880 * index = chain_idx
3881 *
3882 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02003883 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 *
3885 * num_sge = num sge in request frame + last chain buffer
3886 * scale = num sge per chain buffer if no chain element
3887 */
3888 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3889 if (sizeof(dma_addr_t) == sizeof(u64))
3890 num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3891 else
3892 num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3893
3894 if (sizeof(dma_addr_t) == sizeof(u64)) {
3895 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3896 (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
3897 } else {
3898 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
3899 (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
3900 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303901 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 ioc->name, num_sge, numSGE));
3903
3904 if ( numSGE > MPT_SCSI_SG_DEPTH )
3905 numSGE = MPT_SCSI_SG_DEPTH;
3906
3907 num_chain = 1;
3908 while (numSGE - num_sge > 0) {
3909 num_chain++;
3910 num_sge += (scale - 1);
3911 }
3912 num_chain++;
3913
Prakash, Sathya436ace72007-07-24 15:42:08 +05303914 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 ioc->name, numSGE, num_sge, num_chain));
3916
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003917 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 num_chain *= MPT_SCSI_CAN_QUEUE;
3919 else
3920 num_chain *= MPT_FC_CAN_QUEUE;
3921
3922 ioc->num_chain = num_chain;
3923
3924 sz = num_chain * sizeof(int);
3925 if (ioc->ChainToChain == NULL) {
3926 mem = kmalloc(sz, GFP_ATOMIC);
3927 if (mem == NULL)
3928 return -1;
3929
3930 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303931 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 ioc->name, mem, sz));
3933 } else {
3934 mem = (u8 *) ioc->ChainToChain;
3935 }
3936 memset(mem, 0xFF, sz);
3937 return num_chain;
3938}
3939
3940/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003941/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
3943 * @ioc: Pointer to MPT_ADAPTER structure
3944 *
3945 * This routine allocates memory for the MPT reply and request frame
3946 * pools (if necessary), and primes the IOC reply FIFO with
3947 * reply frames.
3948 *
3949 * Returns 0 for success, non-zero for failure.
3950 */
3951static int
3952PrimeIocFifos(MPT_ADAPTER *ioc)
3953{
3954 MPT_FRAME_HDR *mf;
3955 unsigned long flags;
3956 dma_addr_t alloc_dma;
3957 u8 *mem;
3958 int i, reply_sz, sz, total_size, num_chain;
3959
3960 /* Prime reply FIFO... */
3961
3962 if (ioc->reply_frames == NULL) {
3963 if ( (num_chain = initChainBuffers(ioc)) < 0)
3964 return -1;
3965
3966 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 ioc->name, reply_sz, reply_sz));
3971
3972 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303973 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303975 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 ioc->name, sz, sz));
3977 total_size += sz;
3978
3979 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303980 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303982 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 ioc->name, sz, sz, num_chain));
3984
3985 total_size += sz;
3986 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
3987 if (mem == NULL) {
3988 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
3989 ioc->name);
3990 goto out_fail;
3991 }
3992
Prakash, Sathya436ace72007-07-24 15:42:08 +05303993 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
3995
3996 memset(mem, 0, total_size);
3997 ioc->alloc_total += total_size;
3998 ioc->alloc = mem;
3999 ioc->alloc_dma = alloc_dma;
4000 ioc->alloc_sz = total_size;
4001 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4002 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4003
Prakash, Sathya436ace72007-07-24 15:42:08 +05304004 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004005 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4006
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 alloc_dma += reply_sz;
4008 mem += reply_sz;
4009
4010 /* Request FIFO - WE manage this! */
4011
4012 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4013 ioc->req_frames_dma = alloc_dma;
4014
Prakash, Sathya436ace72007-07-24 15:42:08 +05304015 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 ioc->name, mem, (void *)(ulong)alloc_dma));
4017
4018 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4019
4020#if defined(CONFIG_MTRR) && 0
4021 /*
4022 * Enable Write Combining MTRR for IOC's memory region.
4023 * (at least as much as we can; "size and base must be
4024 * multiples of 4 kiB"
4025 */
4026 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4027 sz,
4028 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304029 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 ioc->name, ioc->req_frames_dma, sz));
4031#endif
4032
4033 for (i = 0; i < ioc->req_depth; i++) {
4034 alloc_dma += ioc->req_sz;
4035 mem += ioc->req_sz;
4036 }
4037
4038 ioc->ChainBuffer = mem;
4039 ioc->ChainBufferDMA = alloc_dma;
4040
Prakash, Sathya436ace72007-07-24 15:42:08 +05304041 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4043
4044 /* Initialize the free chain Q.
4045 */
4046
4047 INIT_LIST_HEAD(&ioc->FreeChainQ);
4048
4049 /* Post the chain buffers to the FreeChainQ.
4050 */
4051 mem = (u8 *)ioc->ChainBuffer;
4052 for (i=0; i < num_chain; i++) {
4053 mf = (MPT_FRAME_HDR *) mem;
4054 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4055 mem += ioc->req_sz;
4056 }
4057
4058 /* Initialize Request frames linked list
4059 */
4060 alloc_dma = ioc->req_frames_dma;
4061 mem = (u8 *) ioc->req_frames;
4062
4063 spin_lock_irqsave(&ioc->FreeQlock, flags);
4064 INIT_LIST_HEAD(&ioc->FreeQ);
4065 for (i = 0; i < ioc->req_depth; i++) {
4066 mf = (MPT_FRAME_HDR *) mem;
4067
4068 /* Queue REQUESTs *internally*! */
4069 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4070
4071 mem += ioc->req_sz;
4072 }
4073 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4074
4075 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4076 ioc->sense_buf_pool =
4077 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4078 if (ioc->sense_buf_pool == NULL) {
4079 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4080 ioc->name);
4081 goto out_fail;
4082 }
4083
4084 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4085 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304086 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4088
4089 }
4090
4091 /* Post Reply frames to FIFO
4092 */
4093 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304094 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4096
4097 for (i = 0; i < ioc->reply_depth; i++) {
4098 /* Write each address to the IOC! */
4099 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4100 alloc_dma += ioc->reply_sz;
4101 }
4102
4103 return 0;
4104
4105out_fail:
4106 if (ioc->alloc != NULL) {
4107 sz = ioc->alloc_sz;
4108 pci_free_consistent(ioc->pcidev,
4109 sz,
4110 ioc->alloc, ioc->alloc_dma);
4111 ioc->reply_frames = NULL;
4112 ioc->req_frames = NULL;
4113 ioc->alloc_total -= sz;
4114 }
4115 if (ioc->sense_buf_pool != NULL) {
4116 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4117 pci_free_consistent(ioc->pcidev,
4118 sz,
4119 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4120 ioc->sense_buf_pool = NULL;
4121 }
4122 return -1;
4123}
4124
4125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4126/**
4127 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4128 * from IOC via doorbell handshake method.
4129 * @ioc: Pointer to MPT_ADAPTER structure
4130 * @reqBytes: Size of the request in bytes
4131 * @req: Pointer to MPT request frame
4132 * @replyBytes: Expected size of the reply in bytes
4133 * @u16reply: Pointer to area where reply should be written
4134 * @maxwait: Max wait time for a reply (in seconds)
4135 * @sleepFlag: Specifies whether the process can sleep
4136 *
4137 * NOTES: It is the callers responsibility to byte-swap fields in the
4138 * request which are greater than 1 byte in size. It is also the
4139 * callers responsibility to byte-swap response fields which are
4140 * greater than 1 byte in size.
4141 *
4142 * Returns 0 for success, non-zero for failure.
4143 */
4144static int
4145mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004146 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147{
4148 MPIDefaultReply_t *mptReply;
4149 int failcnt = 0;
4150 int t;
4151
4152 /*
4153 * Get ready to cache a handshake reply
4154 */
4155 ioc->hs_reply_idx = 0;
4156 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4157 mptReply->MsgLength = 0;
4158
4159 /*
4160 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4161 * then tell IOC that we want to handshake a request of N words.
4162 * (WRITE u32val to Doorbell reg).
4163 */
4164 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4165 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4166 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4167 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4168
4169 /*
4170 * Wait for IOC's doorbell handshake int
4171 */
4172 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4173 failcnt++;
4174
Prakash, Sathya436ace72007-07-24 15:42:08 +05304175 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4177
4178 /* Read doorbell and check for active bit */
4179 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4180 return -1;
4181
4182 /*
4183 * Clear doorbell int (WRITE 0 to IntStatus reg),
4184 * then wait for IOC to ACKnowledge that it's ready for
4185 * our handshake request.
4186 */
4187 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4188 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4189 failcnt++;
4190
4191 if (!failcnt) {
4192 int ii;
4193 u8 *req_as_bytes = (u8 *) req;
4194
4195 /*
4196 * Stuff request words via doorbell handshake,
4197 * with ACK from IOC for each.
4198 */
4199 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4200 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4201 (req_as_bytes[(ii*4) + 1] << 8) |
4202 (req_as_bytes[(ii*4) + 2] << 16) |
4203 (req_as_bytes[(ii*4) + 3] << 24));
4204
4205 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4206 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4207 failcnt++;
4208 }
4209
Prakash, Sathya436ace72007-07-24 15:42:08 +05304210 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004211 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212
Prakash, Sathya436ace72007-07-24 15:42:08 +05304213 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4215
4216 /*
4217 * Wait for completion of doorbell handshake reply from the IOC
4218 */
4219 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4220 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004221
Prakash, Sathya436ace72007-07-24 15:42:08 +05304222 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4224
4225 /*
4226 * Copy out the cached reply...
4227 */
4228 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4229 u16reply[ii] = ioc->hs_reply[ii];
4230 } else {
4231 return -99;
4232 }
4233
4234 return -failcnt;
4235}
4236
4237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004238/**
4239 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 * @ioc: Pointer to MPT_ADAPTER structure
4241 * @howlong: How long to wait (in seconds)
4242 * @sleepFlag: Specifies whether the process can sleep
4243 *
4244 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004245 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4246 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 *
4248 * Returns a negative value on failure, else wait loop count.
4249 */
4250static int
4251WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4252{
4253 int cntdn;
4254 int count = 0;
4255 u32 intstat=0;
4256
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004257 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
4259 if (sleepFlag == CAN_SLEEP) {
4260 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004261 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4263 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4264 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 count++;
4266 }
4267 } else {
4268 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004269 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4271 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4272 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 count++;
4274 }
4275 }
4276
4277 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304278 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 ioc->name, count));
4280 return count;
4281 }
4282
4283 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4284 ioc->name, count, intstat);
4285 return -1;
4286}
4287
4288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004289/**
4290 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 * @ioc: Pointer to MPT_ADAPTER structure
4292 * @howlong: How long to wait (in seconds)
4293 * @sleepFlag: Specifies whether the process can sleep
4294 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004295 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4296 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 *
4298 * Returns a negative value on failure, else wait loop count.
4299 */
4300static int
4301WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4302{
4303 int cntdn;
4304 int count = 0;
4305 u32 intstat=0;
4306
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004307 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 if (sleepFlag == CAN_SLEEP) {
4309 while (--cntdn) {
4310 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4311 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4312 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004313 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 count++;
4315 }
4316 } else {
4317 while (--cntdn) {
4318 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4319 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4320 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004321 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 count++;
4323 }
4324 }
4325
4326 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304327 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 ioc->name, count, howlong));
4329 return count;
4330 }
4331
4332 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4333 ioc->name, count, intstat);
4334 return -1;
4335}
4336
4337/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004338/**
4339 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 * @ioc: Pointer to MPT_ADAPTER structure
4341 * @howlong: How long to wait (in seconds)
4342 * @sleepFlag: Specifies whether the process can sleep
4343 *
4344 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4345 * Reply is cached to IOC private area large enough to hold a maximum
4346 * of 128 bytes of reply data.
4347 *
4348 * Returns a negative value on failure, else size of reply in WORDS.
4349 */
4350static int
4351WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4352{
4353 int u16cnt = 0;
4354 int failcnt = 0;
4355 int t;
4356 u16 *hs_reply = ioc->hs_reply;
4357 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4358 u16 hword;
4359
4360 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4361
4362 /*
4363 * Get first two u16's so we can look at IOC's intended reply MsgLength
4364 */
4365 u16cnt=0;
4366 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4367 failcnt++;
4368 } else {
4369 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4370 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4371 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4372 failcnt++;
4373 else {
4374 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4375 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4376 }
4377 }
4378
Prakash, Sathya436ace72007-07-24 15:42:08 +05304379 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004380 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4382
4383 /*
4384 * If no error (and IOC said MsgLength is > 0), piece together
4385 * reply 16 bits at a time.
4386 */
4387 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4388 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4389 failcnt++;
4390 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4391 /* don't overflow our IOC hs_reply[] buffer! */
4392 if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0]))
4393 hs_reply[u16cnt] = hword;
4394 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4395 }
4396
4397 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4398 failcnt++;
4399 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4400
4401 if (failcnt) {
4402 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4403 ioc->name);
4404 return -failcnt;
4405 }
4406#if 0
4407 else if (u16cnt != (2 * mptReply->MsgLength)) {
4408 return -101;
4409 }
4410 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4411 return -102;
4412 }
4413#endif
4414
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004416 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Prakash, Sathya436ace72007-07-24 15:42:08 +05304418 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 ioc->name, t, u16cnt/2));
4420 return u16cnt/2;
4421}
4422
4423/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004424/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 * GetLanConfigPages - Fetch LANConfig pages.
4426 * @ioc: Pointer to MPT_ADAPTER structure
4427 *
4428 * Return: 0 for success
4429 * -ENOMEM if no memory available
4430 * -EPERM if not allowed due to ISR context
4431 * -EAGAIN if no msg frames currently available
4432 * -EFAULT for non-successful reply or no reply (timeout)
4433 */
4434static int
4435GetLanConfigPages(MPT_ADAPTER *ioc)
4436{
4437 ConfigPageHeader_t hdr;
4438 CONFIGPARMS cfg;
4439 LANPage0_t *ppage0_alloc;
4440 dma_addr_t page0_dma;
4441 LANPage1_t *ppage1_alloc;
4442 dma_addr_t page1_dma;
4443 int rc = 0;
4444 int data_sz;
4445 int copy_sz;
4446
4447 /* Get LAN Page 0 header */
4448 hdr.PageVersion = 0;
4449 hdr.PageLength = 0;
4450 hdr.PageNumber = 0;
4451 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004452 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 cfg.physAddr = -1;
4454 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4455 cfg.dir = 0;
4456 cfg.pageAddr = 0;
4457 cfg.timeout = 0;
4458
4459 if ((rc = mpt_config(ioc, &cfg)) != 0)
4460 return rc;
4461
4462 if (hdr.PageLength > 0) {
4463 data_sz = hdr.PageLength * 4;
4464 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4465 rc = -ENOMEM;
4466 if (ppage0_alloc) {
4467 memset((u8 *)ppage0_alloc, 0, data_sz);
4468 cfg.physAddr = page0_dma;
4469 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4470
4471 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4472 /* save the data */
4473 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4474 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4475
4476 }
4477
4478 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4479
4480 /* FIXME!
4481 * Normalize endianness of structure data,
4482 * by byte-swapping all > 1 byte fields!
4483 */
4484
4485 }
4486
4487 if (rc)
4488 return rc;
4489 }
4490
4491 /* Get LAN Page 1 header */
4492 hdr.PageVersion = 0;
4493 hdr.PageLength = 0;
4494 hdr.PageNumber = 1;
4495 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004496 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 cfg.physAddr = -1;
4498 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4499 cfg.dir = 0;
4500 cfg.pageAddr = 0;
4501
4502 if ((rc = mpt_config(ioc, &cfg)) != 0)
4503 return rc;
4504
4505 if (hdr.PageLength == 0)
4506 return 0;
4507
4508 data_sz = hdr.PageLength * 4;
4509 rc = -ENOMEM;
4510 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4511 if (ppage1_alloc) {
4512 memset((u8 *)ppage1_alloc, 0, data_sz);
4513 cfg.physAddr = page1_dma;
4514 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4515
4516 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4517 /* save the data */
4518 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4519 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4520 }
4521
4522 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4523
4524 /* FIXME!
4525 * Normalize endianness of structure data,
4526 * by byte-swapping all > 1 byte fields!
4527 */
4528
4529 }
4530
4531 return rc;
4532}
4533
4534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004535/**
4536 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004537 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004538 * @persist_opcode: see below
4539 *
4540 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4541 * devices not currently present.
4542 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4543 *
4544 * NOTE: Don't use not this function during interrupt time.
4545 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004546 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004547 */
4548
4549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4550int
4551mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4552{
4553 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4554 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4555 MPT_FRAME_HDR *mf = NULL;
4556 MPIHeader_t *mpi_hdr;
4557
4558
4559 /* insure garbage is not sent to fw */
4560 switch(persist_opcode) {
4561
4562 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4563 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4564 break;
4565
4566 default:
4567 return -1;
4568 break;
4569 }
4570
4571 printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
4572
4573 /* Get a MF for this command.
4574 */
4575 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
4576 printk("%s: no msg frames!\n",__FUNCTION__);
4577 return -1;
4578 }
4579
4580 mpi_hdr = (MPIHeader_t *) mf;
4581 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4582 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4583 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4584 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4585 sasIoUnitCntrReq->Operation = persist_opcode;
4586
4587 init_timer(&ioc->persist_timer);
4588 ioc->persist_timer.data = (unsigned long) ioc;
4589 ioc->persist_timer.function = mpt_timer_expired;
4590 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4591 ioc->persist_wait_done=0;
4592 add_timer(&ioc->persist_timer);
4593 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4594 wait_event(mpt_waitq, ioc->persist_wait_done);
4595
4596 sasIoUnitCntrReply =
4597 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4598 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4599 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
4600 __FUNCTION__,
4601 sasIoUnitCntrReply->IOCStatus,
4602 sasIoUnitCntrReply->IOCLogInfo);
4603 return -1;
4604 }
4605
4606 printk("%s: success\n",__FUNCTION__);
4607 return 0;
4608}
4609
4610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07004611
4612static void
4613mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
4614 MpiEventDataRaid_t * pRaidEventData)
4615{
4616 int volume;
4617 int reason;
4618 int disk;
4619 int status;
4620 int flags;
4621 int state;
4622
4623 volume = pRaidEventData->VolumeID;
4624 reason = pRaidEventData->ReasonCode;
4625 disk = pRaidEventData->PhysDiskNum;
4626 status = le32_to_cpu(pRaidEventData->SettingsStatus);
4627 flags = (status >> 0) & 0xff;
4628 state = (status >> 8) & 0xff;
4629
4630 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
4631 return;
4632 }
4633
4634 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
4635 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
4636 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004637 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
4638 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07004639 } else {
4640 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
4641 ioc->name, volume);
4642 }
4643
4644 switch(reason) {
4645 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4646 printk(MYIOC_s_INFO_FMT " volume has been created\n",
4647 ioc->name);
4648 break;
4649
4650 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4651
4652 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
4653 ioc->name);
4654 break;
4655
4656 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
4657 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
4658 ioc->name);
4659 break;
4660
4661 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4662 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
4663 ioc->name,
4664 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
4665 ? "optimal"
4666 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
4667 ? "degraded"
4668 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
4669 ? "failed"
4670 : "state unknown",
4671 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
4672 ? ", enabled" : "",
4673 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
4674 ? ", quiesced" : "",
4675 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
4676 ? ", resync in progress" : "" );
4677 break;
4678
4679 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
4680 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
4681 ioc->name, disk);
4682 break;
4683
4684 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4685 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
4686 ioc->name);
4687 break;
4688
4689 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4690 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
4691 ioc->name);
4692 break;
4693
4694 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
4695 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
4696 ioc->name);
4697 break;
4698
4699 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4700 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
4701 ioc->name,
4702 state == MPI_PHYSDISK0_STATUS_ONLINE
4703 ? "online"
4704 : state == MPI_PHYSDISK0_STATUS_MISSING
4705 ? "missing"
4706 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
4707 ? "not compatible"
4708 : state == MPI_PHYSDISK0_STATUS_FAILED
4709 ? "failed"
4710 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
4711 ? "initializing"
4712 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
4713 ? "offline requested"
4714 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
4715 ? "failed requested"
4716 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
4717 ? "offline"
4718 : "state unknown",
4719 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
4720 ? ", out of sync" : "",
4721 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
4722 ? ", quiesced" : "" );
4723 break;
4724
4725 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
4726 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
4727 ioc->name, disk);
4728 break;
4729
4730 case MPI_EVENT_RAID_RC_SMART_DATA:
4731 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
4732 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
4733 break;
4734
4735 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
4736 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
4737 ioc->name, disk);
4738 break;
4739 }
4740}
4741
4742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004743/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
4745 * @ioc: Pointer to MPT_ADAPTER structure
4746 *
4747 * Returns: 0 for success
4748 * -ENOMEM if no memory available
4749 * -EPERM if not allowed due to ISR context
4750 * -EAGAIN if no msg frames currently available
4751 * -EFAULT for non-successful reply or no reply (timeout)
4752 */
4753static int
4754GetIoUnitPage2(MPT_ADAPTER *ioc)
4755{
4756 ConfigPageHeader_t hdr;
4757 CONFIGPARMS cfg;
4758 IOUnitPage2_t *ppage_alloc;
4759 dma_addr_t page_dma;
4760 int data_sz;
4761 int rc;
4762
4763 /* Get the page header */
4764 hdr.PageVersion = 0;
4765 hdr.PageLength = 0;
4766 hdr.PageNumber = 2;
4767 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004768 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 cfg.physAddr = -1;
4770 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4771 cfg.dir = 0;
4772 cfg.pageAddr = 0;
4773 cfg.timeout = 0;
4774
4775 if ((rc = mpt_config(ioc, &cfg)) != 0)
4776 return rc;
4777
4778 if (hdr.PageLength == 0)
4779 return 0;
4780
4781 /* Read the config page */
4782 data_sz = hdr.PageLength * 4;
4783 rc = -ENOMEM;
4784 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
4785 if (ppage_alloc) {
4786 memset((u8 *)ppage_alloc, 0, data_sz);
4787 cfg.physAddr = page_dma;
4788 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4789
4790 /* If Good, save data */
4791 if ((rc = mpt_config(ioc, &cfg)) == 0)
4792 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
4793
4794 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
4795 }
4796
4797 return rc;
4798}
4799
4800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004801/**
4802 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 * @ioc: Pointer to a Adapter Strucutre
4804 * @portnum: IOC port number
4805 *
4806 * Return: -EFAULT if read of config page header fails
4807 * or if no nvram
4808 * If read of SCSI Port Page 0 fails,
4809 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4810 * Adapter settings: async, narrow
4811 * Return 1
4812 * If read of SCSI Port Page 2 fails,
4813 * Adapter settings valid
4814 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
4815 * Return 1
4816 * Else
4817 * Both valid
4818 * Return 0
4819 * CHECK - what type of locking mechanisms should be used????
4820 */
4821static int
4822mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
4823{
4824 u8 *pbuf;
4825 dma_addr_t buf_dma;
4826 CONFIGPARMS cfg;
4827 ConfigPageHeader_t header;
4828 int ii;
4829 int data, rc = 0;
4830
4831 /* Allocate memory
4832 */
4833 if (!ioc->spi_data.nvram) {
4834 int sz;
4835 u8 *mem;
4836 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
4837 mem = kmalloc(sz, GFP_ATOMIC);
4838 if (mem == NULL)
4839 return -EFAULT;
4840
4841 ioc->spi_data.nvram = (int *) mem;
4842
Prakash, Sathya436ace72007-07-24 15:42:08 +05304843 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 ioc->name, ioc->spi_data.nvram, sz));
4845 }
4846
4847 /* Invalidate NVRAM information
4848 */
4849 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4850 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
4851 }
4852
4853 /* Read SPP0 header, allocate memory, then read page.
4854 */
4855 header.PageVersion = 0;
4856 header.PageLength = 0;
4857 header.PageNumber = 0;
4858 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004859 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 cfg.physAddr = -1;
4861 cfg.pageAddr = portnum;
4862 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4863 cfg.dir = 0;
4864 cfg.timeout = 0; /* use default */
4865 if (mpt_config(ioc, &cfg) != 0)
4866 return -EFAULT;
4867
4868 if (header.PageLength > 0) {
4869 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4870 if (pbuf) {
4871 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4872 cfg.physAddr = buf_dma;
4873 if (mpt_config(ioc, &cfg) != 0) {
4874 ioc->spi_data.maxBusWidth = MPT_NARROW;
4875 ioc->spi_data.maxSyncOffset = 0;
4876 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4877 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
4878 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304879 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4880 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004881 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 } else {
4883 /* Save the Port Page 0 data
4884 */
4885 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
4886 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
4887 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
4888
4889 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
4890 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06004891 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4892 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 ioc->name, pPP0->Capabilities));
4894 }
4895 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
4896 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
4897 if (data) {
4898 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
4899 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
4900 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304901 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4902 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004903 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 } else {
4905 ioc->spi_data.maxSyncOffset = 0;
4906 ioc->spi_data.minSyncFactor = MPT_ASYNC;
4907 }
4908
4909 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
4910
4911 /* Update the minSyncFactor based on bus type.
4912 */
4913 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
4914 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
4915
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004916 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304918 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4919 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004920 ioc->name, ioc->spi_data.minSyncFactor));
4921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 }
4923 }
4924 if (pbuf) {
4925 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
4926 }
4927 }
4928 }
4929
4930 /* SCSI Port Page 2 - Read the header then the page.
4931 */
4932 header.PageVersion = 0;
4933 header.PageLength = 0;
4934 header.PageNumber = 2;
4935 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004936 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 cfg.physAddr = -1;
4938 cfg.pageAddr = portnum;
4939 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4940 cfg.dir = 0;
4941 if (mpt_config(ioc, &cfg) != 0)
4942 return -EFAULT;
4943
4944 if (header.PageLength > 0) {
4945 /* Allocate memory and read SCSI Port Page 2
4946 */
4947 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
4948 if (pbuf) {
4949 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
4950 cfg.physAddr = buf_dma;
4951 if (mpt_config(ioc, &cfg) != 0) {
4952 /* Nvram data is left with INVALID mark
4953 */
4954 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06004955 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
4956
4957 /* This is an ATTO adapter, read Page2 accordingly
4958 */
4959 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
4960 ATTODeviceInfo_t *pdevice = NULL;
4961 u16 ATTOFlags;
4962
4963 /* Save the Port Page 2 data
4964 * (reformat into a 32bit quantity)
4965 */
4966 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
4967 pdevice = &pPP2->DeviceSettings[ii];
4968 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
4969 data = 0;
4970
4971 /* Translate ATTO device flags to LSI format
4972 */
4973 if (ATTOFlags & ATTOFLAG_DISC)
4974 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
4975 if (ATTOFlags & ATTOFLAG_ID_ENB)
4976 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
4977 if (ATTOFlags & ATTOFLAG_LUN_ENB)
4978 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
4979 if (ATTOFlags & ATTOFLAG_TAGGED)
4980 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
4981 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
4982 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
4983
4984 data = (data << 16) | (pdevice->Period << 8) | 10;
4985 ioc->spi_data.nvram[ii] = data;
4986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 } else {
4988 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
4989 MpiDeviceInfo_t *pdevice = NULL;
4990
Moore, Ericd8e925d2006-01-16 18:53:06 -07004991 /*
4992 * Save "Set to Avoid SCSI Bus Resets" flag
4993 */
4994 ioc->spi_data.bus_reset =
4995 (le32_to_cpu(pPP2->PortFlags) &
4996 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
4997 0 : 1 ;
4998
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 /* Save the Port Page 2 data
5000 * (reformat into a 32bit quantity)
5001 */
5002 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5003 ioc->spi_data.PortFlags = data;
5004 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5005 pdevice = &pPP2->DeviceSettings[ii];
5006 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5007 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5008 ioc->spi_data.nvram[ii] = data;
5009 }
5010 }
5011
5012 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5013 }
5014 }
5015
5016 /* Update Adapter limits with those from NVRAM
5017 * Comment: Don't need to do this. Target performance
5018 * parameters will never exceed the adapters limits.
5019 */
5020
5021 return rc;
5022}
5023
5024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005025/**
5026 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027 * @ioc: Pointer to a Adapter Strucutre
5028 * @portnum: IOC port number
5029 *
5030 * Return: -EFAULT if read of config page header fails
5031 * or 0 if success.
5032 */
5033static int
5034mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5035{
5036 CONFIGPARMS cfg;
5037 ConfigPageHeader_t header;
5038
5039 /* Read the SCSI Device Page 1 header
5040 */
5041 header.PageVersion = 0;
5042 header.PageLength = 0;
5043 header.PageNumber = 1;
5044 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005045 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 cfg.physAddr = -1;
5047 cfg.pageAddr = portnum;
5048 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5049 cfg.dir = 0;
5050 cfg.timeout = 0;
5051 if (mpt_config(ioc, &cfg) != 0)
5052 return -EFAULT;
5053
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005054 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5055 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
5057 header.PageVersion = 0;
5058 header.PageLength = 0;
5059 header.PageNumber = 0;
5060 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5061 if (mpt_config(ioc, &cfg) != 0)
5062 return -EFAULT;
5063
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005064 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5065 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066
Prakash, Sathya436ace72007-07-24 15:42:08 +05305067 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5069
Prakash, Sathya436ace72007-07-24 15:42:08 +05305070 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5072 return 0;
5073}
5074
Eric Mooreb506ade2007-01-29 09:45:37 -07005075/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005076 * mpt_inactive_raid_list_free - This clears this link list.
5077 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005078 **/
5079static void
5080mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5081{
5082 struct inactive_raid_component_info *component_info, *pNext;
5083
5084 if (list_empty(&ioc->raid_data.inactive_list))
5085 return;
5086
5087 down(&ioc->raid_data.inactive_list_mutex);
5088 list_for_each_entry_safe(component_info, pNext,
5089 &ioc->raid_data.inactive_list, list) {
5090 list_del(&component_info->list);
5091 kfree(component_info);
5092 }
5093 up(&ioc->raid_data.inactive_list_mutex);
5094}
5095
5096/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005097 * 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 -07005098 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005099 * @ioc : pointer to per adapter structure
5100 * @channel : volume channel
5101 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005102 **/
5103static void
5104mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5105{
5106 CONFIGPARMS cfg;
5107 ConfigPageHeader_t hdr;
5108 dma_addr_t dma_handle;
5109 pRaidVolumePage0_t buffer = NULL;
5110 int i;
5111 RaidPhysDiskPage0_t phys_disk;
5112 struct inactive_raid_component_info *component_info;
5113 int handle_inactive_volumes;
5114
5115 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5116 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5117 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5118 cfg.pageAddr = (channel << 8) + id;
5119 cfg.cfghdr.hdr = &hdr;
5120 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5121
5122 if (mpt_config(ioc, &cfg) != 0)
5123 goto out;
5124
5125 if (!hdr.PageLength)
5126 goto out;
5127
5128 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5129 &dma_handle);
5130
5131 if (!buffer)
5132 goto out;
5133
5134 cfg.physAddr = dma_handle;
5135 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5136
5137 if (mpt_config(ioc, &cfg) != 0)
5138 goto out;
5139
5140 if (!buffer->NumPhysDisks)
5141 goto out;
5142
5143 handle_inactive_volumes =
5144 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5145 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5146 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5147 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5148
5149 if (!handle_inactive_volumes)
5150 goto out;
5151
5152 down(&ioc->raid_data.inactive_list_mutex);
5153 for (i = 0; i < buffer->NumPhysDisks; i++) {
5154 if(mpt_raid_phys_disk_pg0(ioc,
5155 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5156 continue;
5157
5158 if ((component_info = kmalloc(sizeof (*component_info),
5159 GFP_KERNEL)) == NULL)
5160 continue;
5161
5162 component_info->volumeID = id;
5163 component_info->volumeBus = channel;
5164 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5165 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5166 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5167 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5168
5169 list_add_tail(&component_info->list,
5170 &ioc->raid_data.inactive_list);
5171 }
5172 up(&ioc->raid_data.inactive_list_mutex);
5173
5174 out:
5175 if (buffer)
5176 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5177 dma_handle);
5178}
5179
5180/**
5181 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5182 * @ioc: Pointer to a Adapter Structure
5183 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5184 * @phys_disk: requested payload data returned
5185 *
5186 * Return:
5187 * 0 on success
5188 * -EFAULT if read of config page header fails or data pointer not NULL
5189 * -ENOMEM if pci_alloc failed
5190 **/
5191int
5192mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5193{
5194 CONFIGPARMS cfg;
5195 ConfigPageHeader_t hdr;
5196 dma_addr_t dma_handle;
5197 pRaidPhysDiskPage0_t buffer = NULL;
5198 int rc;
5199
5200 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5201 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5202
5203 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5204 cfg.cfghdr.hdr = &hdr;
5205 cfg.physAddr = -1;
5206 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5207
5208 if (mpt_config(ioc, &cfg) != 0) {
5209 rc = -EFAULT;
5210 goto out;
5211 }
5212
5213 if (!hdr.PageLength) {
5214 rc = -EFAULT;
5215 goto out;
5216 }
5217
5218 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5219 &dma_handle);
5220
5221 if (!buffer) {
5222 rc = -ENOMEM;
5223 goto out;
5224 }
5225
5226 cfg.physAddr = dma_handle;
5227 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5228 cfg.pageAddr = phys_disk_num;
5229
5230 if (mpt_config(ioc, &cfg) != 0) {
5231 rc = -EFAULT;
5232 goto out;
5233 }
5234
5235 rc = 0;
5236 memcpy(phys_disk, buffer, sizeof(*buffer));
5237 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5238
5239 out:
5240
5241 if (buffer)
5242 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5243 dma_handle);
5244
5245 return rc;
5246}
5247
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248/**
5249 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5250 * @ioc: Pointer to a Adapter Strucutre
5251 * @portnum: IOC port number
5252 *
5253 * Return:
5254 * 0 on success
5255 * -EFAULT if read of config page header fails or data pointer not NULL
5256 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005257 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258int
5259mpt_findImVolumes(MPT_ADAPTER *ioc)
5260{
5261 IOCPage2_t *pIoc2;
5262 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 dma_addr_t ioc2_dma;
5264 CONFIGPARMS cfg;
5265 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 int rc = 0;
5267 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005268 int i;
5269
5270 if (!ioc->ir_firmware)
5271 return 0;
5272
5273 /* Free the old page
5274 */
5275 kfree(ioc->raid_data.pIocPg2);
5276 ioc->raid_data.pIocPg2 = NULL;
5277 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
5279 /* Read IOCP2 header then the page.
5280 */
5281 header.PageVersion = 0;
5282 header.PageLength = 0;
5283 header.PageNumber = 2;
5284 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005285 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 cfg.physAddr = -1;
5287 cfg.pageAddr = 0;
5288 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5289 cfg.dir = 0;
5290 cfg.timeout = 0;
5291 if (mpt_config(ioc, &cfg) != 0)
5292 return -EFAULT;
5293
5294 if (header.PageLength == 0)
5295 return -EFAULT;
5296
5297 iocpage2sz = header.PageLength * 4;
5298 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5299 if (!pIoc2)
5300 return -ENOMEM;
5301
5302 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5303 cfg.physAddr = ioc2_dma;
5304 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005305 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306
Eric Mooreb506ade2007-01-29 09:45:37 -07005307 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5308 if (!mem)
5309 goto out;
5310
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005312 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313
Eric Mooreb506ade2007-01-29 09:45:37 -07005314 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
Eric Mooreb506ade2007-01-29 09:45:37 -07005316 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5317 mpt_inactive_raid_volumes(ioc,
5318 pIoc2->RaidVolume[i].VolumeBus,
5319 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320
Eric Mooreb506ade2007-01-29 09:45:37 -07005321 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5323
5324 return rc;
5325}
5326
Moore, Ericc972c702006-03-14 09:14:06 -07005327static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5329{
5330 IOCPage3_t *pIoc3;
5331 u8 *mem;
5332 CONFIGPARMS cfg;
5333 ConfigPageHeader_t header;
5334 dma_addr_t ioc3_dma;
5335 int iocpage3sz = 0;
5336
5337 /* Free the old page
5338 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005339 kfree(ioc->raid_data.pIocPg3);
5340 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341
5342 /* There is at least one physical disk.
5343 * Read and save IOC Page 3
5344 */
5345 header.PageVersion = 0;
5346 header.PageLength = 0;
5347 header.PageNumber = 3;
5348 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005349 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005350 cfg.physAddr = -1;
5351 cfg.pageAddr = 0;
5352 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5353 cfg.dir = 0;
5354 cfg.timeout = 0;
5355 if (mpt_config(ioc, &cfg) != 0)
5356 return 0;
5357
5358 if (header.PageLength == 0)
5359 return 0;
5360
5361 /* Read Header good, alloc memory
5362 */
5363 iocpage3sz = header.PageLength * 4;
5364 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5365 if (!pIoc3)
5366 return 0;
5367
5368 /* Read the Page and save the data
5369 * into malloc'd memory.
5370 */
5371 cfg.physAddr = ioc3_dma;
5372 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5373 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005374 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 if (mem) {
5376 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005377 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 }
5379 }
5380
5381 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5382
5383 return 0;
5384}
5385
5386static void
5387mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5388{
5389 IOCPage4_t *pIoc4;
5390 CONFIGPARMS cfg;
5391 ConfigPageHeader_t header;
5392 dma_addr_t ioc4_dma;
5393 int iocpage4sz;
5394
5395 /* Read and save IOC Page 4
5396 */
5397 header.PageVersion = 0;
5398 header.PageLength = 0;
5399 header.PageNumber = 4;
5400 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005401 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 cfg.physAddr = -1;
5403 cfg.pageAddr = 0;
5404 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5405 cfg.dir = 0;
5406 cfg.timeout = 0;
5407 if (mpt_config(ioc, &cfg) != 0)
5408 return;
5409
5410 if (header.PageLength == 0)
5411 return;
5412
5413 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5414 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5415 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5416 if (!pIoc4)
5417 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005418 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 } else {
5420 ioc4_dma = ioc->spi_data.IocPg4_dma;
5421 iocpage4sz = ioc->spi_data.IocPg4Sz;
5422 }
5423
5424 /* Read the Page into dma memory.
5425 */
5426 cfg.physAddr = ioc4_dma;
5427 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5428 if (mpt_config(ioc, &cfg) == 0) {
5429 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5430 ioc->spi_data.IocPg4_dma = ioc4_dma;
5431 ioc->spi_data.IocPg4Sz = iocpage4sz;
5432 } else {
5433 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5434 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005435 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 }
5437}
5438
5439static void
5440mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5441{
5442 IOCPage1_t *pIoc1;
5443 CONFIGPARMS cfg;
5444 ConfigPageHeader_t header;
5445 dma_addr_t ioc1_dma;
5446 int iocpage1sz = 0;
5447 u32 tmp;
5448
5449 /* Check the Coalescing Timeout in IOC Page 1
5450 */
5451 header.PageVersion = 0;
5452 header.PageLength = 0;
5453 header.PageNumber = 1;
5454 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005455 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 cfg.physAddr = -1;
5457 cfg.pageAddr = 0;
5458 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5459 cfg.dir = 0;
5460 cfg.timeout = 0;
5461 if (mpt_config(ioc, &cfg) != 0)
5462 return;
5463
5464 if (header.PageLength == 0)
5465 return;
5466
5467 /* Read Header good, alloc memory
5468 */
5469 iocpage1sz = header.PageLength * 4;
5470 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5471 if (!pIoc1)
5472 return;
5473
5474 /* Read the Page and check coalescing timeout
5475 */
5476 cfg.physAddr = ioc1_dma;
5477 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5478 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305479
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5481 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5482 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5483
Prakash, Sathya436ace72007-07-24 15:42:08 +05305484 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 ioc->name, tmp));
5486
5487 if (tmp > MPT_COALESCING_TIMEOUT) {
5488 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5489
5490 /* Write NVRAM and current
5491 */
5492 cfg.dir = 1;
5493 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5494 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305495 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 ioc->name, MPT_COALESCING_TIMEOUT));
5497
5498 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5499 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305500 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5501 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 ioc->name, MPT_COALESCING_TIMEOUT));
5503 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305504 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5505 "Reset NVRAM Coalescing Timeout Failed\n",
5506 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 }
5508
5509 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305510 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5511 "Reset of Current Coalescing Timeout Failed!\n",
5512 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 }
5514 }
5515
5516 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305517 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 }
5519 }
5520
5521 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5522
5523 return;
5524}
5525
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305526static void
5527mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5528{
5529 CONFIGPARMS cfg;
5530 ConfigPageHeader_t hdr;
5531 dma_addr_t buf_dma;
5532 ManufacturingPage0_t *pbuf = NULL;
5533
5534 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5535 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5536
5537 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5538 cfg.cfghdr.hdr = &hdr;
5539 cfg.physAddr = -1;
5540 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5541 cfg.timeout = 10;
5542
5543 if (mpt_config(ioc, &cfg) != 0)
5544 goto out;
5545
5546 if (!cfg.cfghdr.hdr->PageLength)
5547 goto out;
5548
5549 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5550 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5551 if (!pbuf)
5552 goto out;
5553
5554 cfg.physAddr = buf_dma;
5555
5556 if (mpt_config(ioc, &cfg) != 0)
5557 goto out;
5558
5559 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5560 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5561 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5562
5563 out:
5564
5565 if (pbuf)
5566 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5567}
5568
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005570/**
5571 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 * @ioc: Pointer to MPT_ADAPTER structure
5573 * @EvSwitch: Event switch flags
5574 */
5575static int
5576SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5577{
5578 EventNotification_t *evnp;
5579
5580 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5581 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305582 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 ioc->name));
5584 return 0;
5585 }
5586 memset(evnp, 0, sizeof(*evnp));
5587
Prakash, Sathya436ace72007-07-24 15:42:08 +05305588 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589
5590 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5591 evnp->ChainOffset = 0;
5592 evnp->MsgFlags = 0;
5593 evnp->Switch = EvSwitch;
5594
5595 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5596
5597 return 0;
5598}
5599
5600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5601/**
5602 * SendEventAck - Send EventAck request to MPT adapter.
5603 * @ioc: Pointer to MPT_ADAPTER structure
5604 * @evnp: Pointer to original EventNotification request
5605 */
5606static int
5607SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
5608{
5609 EventAck_t *pAck;
5610
5611 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305612 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Eric Moore4f766dc2006-07-11 17:24:07 -06005613 ioc->name,__FUNCTION__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 return -1;
5615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
Prakash, Sathya436ace72007-07-24 15:42:08 +05305617 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
5619 pAck->Function = MPI_FUNCTION_EVENT_ACK;
5620 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005621 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06005623 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pAck->Event = evnp->Event;
5625 pAck->EventContext = evnp->EventContext;
5626
5627 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
5628
5629 return 0;
5630}
5631
5632/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5633/**
5634 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005635 * @ioc: Pointer to an adapter structure
5636 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 * action, page address, direction, physical address
5638 * and pointer to a configuration page header
5639 * Page header is updated.
5640 *
5641 * Returns 0 for success
5642 * -EPERM if not allowed due to ISR context
5643 * -EAGAIN if no msg frames currently available
5644 * -EFAULT for non-successful reply or no reply (timeout)
5645 */
5646int
5647mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
5648{
5649 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005650 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 MPT_FRAME_HDR *mf;
5652 unsigned long flags;
5653 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005654 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 int in_isr;
5656
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005657 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 * to be in ISR context, because that is fatal!
5659 */
5660 in_isr = in_interrupt();
5661 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305662 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 ioc->name));
5664 return -EPERM;
5665 }
5666
5667 /* Get and Populate a free Frame
5668 */
5669 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305670 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 ioc->name));
5672 return -EAGAIN;
5673 }
5674 pReq = (Config_t *)mf;
5675 pReq->Action = pCfg->action;
5676 pReq->Reserved = 0;
5677 pReq->ChainOffset = 0;
5678 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005679
5680 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 pReq->ExtPageLength = 0;
5682 pReq->ExtPageType = 0;
5683 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005684
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 for (ii=0; ii < 8; ii++)
5686 pReq->Reserved2[ii] = 0;
5687
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005688 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
5689 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
5690 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
5691 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
5692
5693 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5694 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
5695 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
5696 pReq->ExtPageType = pExtHdr->ExtPageType;
5697 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
5698
5699 /* Page Length must be treated as a reserved field for the extended header. */
5700 pReq->Header.PageLength = 0;
5701 }
5702
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
5704
5705 /* Add a SGE to the config request.
5706 */
5707 if (pCfg->dir)
5708 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
5709 else
5710 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
5711
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005712 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
5713 flagsLength |= pExtHdr->ExtPageLength * 4;
5714
Prakash, Sathya436ace72007-07-24 15:42:08 +05305715 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 +02005716 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
5717 }
5718 else {
5719 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
5720
Prakash, Sathya436ace72007-07-24 15:42:08 +05305721 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 +02005722 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
5723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
5725 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
5726
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 /* Append pCfg pointer to end of mf
5728 */
5729 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
5730
5731 /* Initalize the timer
5732 */
5733 init_timer(&pCfg->timer);
5734 pCfg->timer.data = (unsigned long) ioc;
5735 pCfg->timer.function = mpt_timer_expired;
5736 pCfg->wait_done = 0;
5737
5738 /* Set the timer; ensure 10 second minimum */
5739 if (pCfg->timeout < 10)
5740 pCfg->timer.expires = jiffies + HZ*10;
5741 else
5742 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
5743
5744 /* Add to end of Q, set timer and then issue this command */
5745 spin_lock_irqsave(&ioc->FreeQlock, flags);
5746 list_add_tail(&pCfg->linkage, &ioc->configQ);
5747 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5748
5749 add_timer(&pCfg->timer);
5750 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5751 wait_event(mpt_waitq, pCfg->wait_done);
5752
5753 /* mf has been freed - do not access */
5754
5755 rc = pCfg->status;
5756
5757 return rc;
5758}
5759
5760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005761/**
5762 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 * Used only internal config functionality.
5764 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
5765 */
5766static void
5767mpt_timer_expired(unsigned long data)
5768{
5769 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
5770
Prakash, Sathya436ace72007-07-24 15:42:08 +05305771 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
5773 /* Perform a FW reload */
5774 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
5775 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
5776
5777 /* No more processing.
5778 * Hard reset clean-up will wake up
5779 * process and free all resources.
5780 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05305781 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
5783 return;
5784}
5785
5786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005787/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 * mpt_ioc_reset - Base cleanup for hard reset
5789 * @ioc: Pointer to the adapter structure
5790 * @reset_phase: Indicates pre- or post-reset functionality
5791 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005792 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 */
5794static int
5795mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
5796{
5797 CONFIGPARMS *pCfg;
5798 unsigned long flags;
5799
Eric Moore29dd3602007-09-14 18:46:51 -06005800 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5801 ": IOC %s_reset routed to MPT base driver!\n",
5802 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
5803 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
5805 if (reset_phase == MPT_IOC_SETUP_RESET) {
5806 ;
5807 } else if (reset_phase == MPT_IOC_PRE_RESET) {
5808 /* If the internal config Q is not empty -
5809 * delete timer. MF resources will be freed when
5810 * the FIFO's are primed.
5811 */
5812 spin_lock_irqsave(&ioc->FreeQlock, flags);
5813 list_for_each_entry(pCfg, &ioc->configQ, linkage)
5814 del_timer(&pCfg->timer);
5815 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5816
5817 } else {
5818 CONFIGPARMS *pNext;
5819
5820 /* Search the configQ for internal commands.
5821 * Flush the Q, and wake up all suspended threads.
5822 */
5823 spin_lock_irqsave(&ioc->FreeQlock, flags);
5824 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
5825 list_del(&pCfg->linkage);
5826
5827 pCfg->status = MPT_CONFIG_ERROR;
5828 pCfg->wait_done = 1;
5829 wake_up(&mpt_waitq);
5830 }
5831 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5832 }
5833
5834 return 1; /* currently means nothing really */
5835}
5836
5837
5838#ifdef CONFIG_PROC_FS /* { */
5839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5840/*
5841 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
5842 */
5843/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005844/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
5846 *
5847 * Returns 0 for success, non-zero for failure.
5848 */
5849static int
5850procmpt_create(void)
5851{
5852 struct proc_dir_entry *ent;
5853
5854 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
5855 if (mpt_proc_root_dir == NULL)
5856 return -ENOTDIR;
5857
5858 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5859 if (ent)
5860 ent->read_proc = procmpt_summary_read;
5861
5862 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
5863 if (ent)
5864 ent->read_proc = procmpt_version_read;
5865
5866 return 0;
5867}
5868
5869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005870/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
5872 *
5873 * Returns 0 for success, non-zero for failure.
5874 */
5875static void
5876procmpt_destroy(void)
5877{
5878 remove_proc_entry("version", mpt_proc_root_dir);
5879 remove_proc_entry("summary", mpt_proc_root_dir);
5880 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
5881}
5882
5883/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005884/**
5885 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 * @buf: Pointer to area to write information
5887 * @start: Pointer to start pointer
5888 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005889 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 * @eof: Pointer to EOF integer
5891 * @data: Pointer
5892 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005893 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 * Returns number of characters written to process performing the read.
5895 */
5896static int
5897procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5898{
5899 MPT_ADAPTER *ioc;
5900 char *out = buf;
5901 int len;
5902
5903 if (data) {
5904 int more = 0;
5905
5906 ioc = data;
5907 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5908
5909 out += more;
5910 } else {
5911 list_for_each_entry(ioc, &ioc_list, list) {
5912 int more = 0;
5913
5914 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
5915
5916 out += more;
5917 if ((out-buf) >= request)
5918 break;
5919 }
5920 }
5921
5922 len = out - buf;
5923
5924 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5925}
5926
5927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005928/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 * procmpt_version_read - Handle read request from /proc/mpt/version.
5930 * @buf: Pointer to area to write information
5931 * @start: Pointer to start pointer
5932 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005933 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 * @eof: Pointer to EOF integer
5935 * @data: Pointer
5936 *
5937 * Returns number of characters written to process performing the read.
5938 */
5939static int
5940procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5941{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305942 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005943 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 char *drvname;
5945 int len;
5946
5947 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
5948 len += sprintf(buf+len, " Fusion MPT base driver\n");
5949
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005950 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06005951 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05305953 if (MptCallbacks[cb_idx]) {
5954 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04005955 case MPTSPI_DRIVER:
5956 if (!scsi++) drvname = "SPI host";
5957 break;
5958 case MPTFC_DRIVER:
5959 if (!fc++) drvname = "FC host";
5960 break;
5961 case MPTSAS_DRIVER:
5962 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 break;
5964 case MPTLAN_DRIVER:
5965 if (!lan++) drvname = "LAN";
5966 break;
5967 case MPTSTM_DRIVER:
5968 if (!targ++) drvname = "SCSI target";
5969 break;
5970 case MPTCTL_DRIVER:
5971 if (!ctl++) drvname = "ioctl";
5972 break;
5973 }
5974
5975 if (drvname)
5976 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
5977 }
5978 }
5979
5980 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
5981}
5982
5983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005984/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
5986 * @buf: Pointer to area to write information
5987 * @start: Pointer to start pointer
5988 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005989 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 * @eof: Pointer to EOF integer
5991 * @data: Pointer
5992 *
5993 * Returns number of characters written to process performing the read.
5994 */
5995static int
5996procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
5997{
5998 MPT_ADAPTER *ioc = data;
5999 int len;
6000 char expVer[32];
6001 int sz;
6002 int p;
6003
6004 mpt_get_fw_exp_ver(expVer, ioc);
6005
6006 len = sprintf(buf, "%s:", ioc->name);
6007 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6008 len += sprintf(buf+len, " (f/w download boot flag set)");
6009// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6010// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6011
6012 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6013 ioc->facts.ProductID,
6014 ioc->prod_name);
6015 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6016 if (ioc->facts.FWImageSize)
6017 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6018 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6019 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6020 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6021
6022 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6023 ioc->facts.CurrentHostMfaHighAddr);
6024 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6025 ioc->facts.CurrentSenseBufferHighAddr);
6026
6027 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6028 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6029
6030 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6031 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6032 /*
6033 * Rounding UP to nearest 4-kB boundary here...
6034 */
6035 sz = (ioc->req_sz * ioc->req_depth) + 128;
6036 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6037 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6038 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6039 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6040 4*ioc->facts.RequestFrameSize,
6041 ioc->facts.GlobalCredits);
6042
6043 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6044 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6045 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6046 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6047 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6048 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6049 ioc->facts.CurReplyFrameSize,
6050 ioc->facts.ReplyQueueDepth);
6051
6052 len += sprintf(buf+len, " MaxDevices = %d\n",
6053 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6054 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6055
6056 /* per-port info */
6057 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6058 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6059 p+1,
6060 ioc->facts.NumberOfPorts);
6061 if (ioc->bus_type == FC) {
6062 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6063 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6064 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6065 a[5], a[4], a[3], a[2], a[1], a[0]);
6066 }
6067 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6068 ioc->fc_port_page0[p].WWNN.High,
6069 ioc->fc_port_page0[p].WWNN.Low,
6070 ioc->fc_port_page0[p].WWPN.High,
6071 ioc->fc_port_page0[p].WWPN.Low);
6072 }
6073 }
6074
6075 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6076}
6077
6078#endif /* CONFIG_PROC_FS } */
6079
6080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6081static void
6082mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6083{
6084 buf[0] ='\0';
6085 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6086 sprintf(buf, " (Exp %02d%02d)",
6087 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6088 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6089
6090 /* insider hack! */
6091 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6092 strcat(buf, " [MDBG]");
6093 }
6094}
6095
6096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6097/**
6098 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6099 * @ioc: Pointer to MPT_ADAPTER structure
6100 * @buffer: Pointer to buffer where IOC summary info should be written
6101 * @size: Pointer to number of bytes we wrote (set by this routine)
6102 * @len: Offset at which to start writing in buffer
6103 * @showlan: Display LAN stuff?
6104 *
6105 * This routine writes (english readable) ASCII text, which represents
6106 * a summary of IOC information, to a buffer.
6107 */
6108void
6109mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6110{
6111 char expVer[32];
6112 int y;
6113
6114 mpt_get_fw_exp_ver(expVer, ioc);
6115
6116 /*
6117 * Shorter summary of attached ioc's...
6118 */
6119 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6120 ioc->name,
6121 ioc->prod_name,
6122 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6123 ioc->facts.FWVersion.Word,
6124 expVer,
6125 ioc->facts.NumberOfPorts,
6126 ioc->req_depth);
6127
6128 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6129 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6130 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6131 a[5], a[4], a[3], a[2], a[1], a[0]);
6132 }
6133
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135
6136 if (!ioc->active)
6137 y += sprintf(buffer+len+y, " (disabled)");
6138
6139 y += sprintf(buffer+len+y, "\n");
6140
6141 *size = y;
6142}
6143
6144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6145/*
6146 * Reset Handling
6147 */
6148/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6149/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006150 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 * @ioc: Pointer to MPT_ADAPTER structure
6152 * @sleepFlag: Indicates if sleep or schedule must be called.
6153 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006154 * Issues SCSI Task Management call based on input arg values.
6155 * If TaskMgmt fails, returns associated SCSI request.
6156 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6158 * or a non-interrupt thread. In the former, must not call schedule().
6159 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006160 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 * FW reload/initialization failed.
6162 *
6163 * Returns 0 for SUCCESS or -1 if FAILED.
6164 */
6165int
6166mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6167{
6168 int rc;
6169 unsigned long flags;
6170
Prakash, Sathya436ace72007-07-24 15:42:08 +05306171 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172#ifdef MFCNT
6173 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6174 printk("MF count 0x%x !\n", ioc->mfcnt);
6175#endif
6176
6177 /* Reset the adapter. Prevent more than 1 call to
6178 * mpt_do_ioc_recovery at any instant in time.
6179 */
6180 spin_lock_irqsave(&ioc->diagLock, flags);
6181 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6182 spin_unlock_irqrestore(&ioc->diagLock, flags);
6183 return 0;
6184 } else {
6185 ioc->diagPending = 1;
6186 }
6187 spin_unlock_irqrestore(&ioc->diagLock, flags);
6188
6189 /* FIXME: If do_ioc_recovery fails, repeat....
6190 */
6191
6192 /* The SCSI driver needs to adjust timeouts on all current
6193 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006194 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 * For all other protocol drivers, this is a no-op.
6196 */
6197 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306198 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 int r = 0;
6200
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306201 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6202 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306203 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306204 ioc->name, cb_idx));
6205 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306207 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306208 ioc->name, ioc->alt_ioc->name, cb_idx));
6209 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210 }
6211 }
6212 }
6213 }
6214
6215 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006216 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218 ioc->reload_fw = 0;
6219 if (ioc->alt_ioc)
6220 ioc->alt_ioc->reload_fw = 0;
6221
6222 spin_lock_irqsave(&ioc->diagLock, flags);
6223 ioc->diagPending = 0;
6224 if (ioc->alt_ioc)
6225 ioc->alt_ioc->diagPending = 0;
6226 spin_unlock_irqrestore(&ioc->diagLock, flags);
6227
Prakash, Sathya436ace72007-07-24 15:42:08 +05306228 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
6230 return rc;
6231}
6232
6233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006234static void
6235EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236{
Eric Moore509e5e52006-04-26 13:22:37 -06006237 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238
6239 switch(event) {
6240 case MPI_EVENT_NONE:
6241 ds = "None";
6242 break;
6243 case MPI_EVENT_LOG_DATA:
6244 ds = "Log Data";
6245 break;
6246 case MPI_EVENT_STATE_CHANGE:
6247 ds = "State Change";
6248 break;
6249 case MPI_EVENT_UNIT_ATTENTION:
6250 ds = "Unit Attention";
6251 break;
6252 case MPI_EVENT_IOC_BUS_RESET:
6253 ds = "IOC Bus Reset";
6254 break;
6255 case MPI_EVENT_EXT_BUS_RESET:
6256 ds = "External Bus Reset";
6257 break;
6258 case MPI_EVENT_RESCAN:
6259 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 break;
6261 case MPI_EVENT_LINK_STATUS_CHANGE:
6262 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6263 ds = "Link Status(FAILURE) Change";
6264 else
6265 ds = "Link Status(ACTIVE) Change";
6266 break;
6267 case MPI_EVENT_LOOP_STATE_CHANGE:
6268 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6269 ds = "Loop State(LIP) Change";
6270 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006271 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 else
Eric Moore509e5e52006-04-26 13:22:37 -06006273 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 break;
6275 case MPI_EVENT_LOGOUT:
6276 ds = "Logout";
6277 break;
6278 case MPI_EVENT_EVENT_CHANGE:
6279 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006280 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006282 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 break;
6284 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006285 {
6286 u8 ReasonCode = (u8)(evData0 >> 16);
6287 switch (ReasonCode) {
6288 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6289 ds = "Integrated Raid: Volume Created";
6290 break;
6291 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6292 ds = "Integrated Raid: Volume Deleted";
6293 break;
6294 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6295 ds = "Integrated Raid: Volume Settings Changed";
6296 break;
6297 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6298 ds = "Integrated Raid: Volume Status Changed";
6299 break;
6300 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6301 ds = "Integrated Raid: Volume Physdisk Changed";
6302 break;
6303 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6304 ds = "Integrated Raid: Physdisk Created";
6305 break;
6306 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6307 ds = "Integrated Raid: Physdisk Deleted";
6308 break;
6309 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6310 ds = "Integrated Raid: Physdisk Settings Changed";
6311 break;
6312 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6313 ds = "Integrated Raid: Physdisk Status Changed";
6314 break;
6315 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6316 ds = "Integrated Raid: Domain Validation Needed";
6317 break;
6318 case MPI_EVENT_RAID_RC_SMART_DATA :
6319 ds = "Integrated Raid; Smart Data";
6320 break;
6321 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6322 ds = "Integrated Raid: Replace Action Started";
6323 break;
6324 default:
6325 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006327 }
6328 break;
6329 }
6330 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6331 ds = "SCSI Device Status Change";
6332 break;
6333 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6334 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006335 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006336 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006337 u8 ReasonCode = (u8)(evData0 >> 16);
6338 switch (ReasonCode) {
6339 case MPI_EVENT_SAS_DEV_STAT_RC_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: Added: "
6342 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006343 break;
6344 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006345 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006346 "SAS Device Status Change: Deleted: "
6347 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006348 break;
6349 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006350 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006351 "SAS Device Status Change: SMART Data: "
6352 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006353 break;
6354 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006355 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006356 "SAS Device Status Change: No Persistancy: "
6357 "id=%d channel=%d", id, channel);
6358 break;
6359 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6360 snprintf(evStr, EVENT_DESCR_STR_SZ,
6361 "SAS Device Status Change: Unsupported Device "
6362 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006363 break;
6364 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6365 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006366 "SAS Device Status Change: Internal Device "
6367 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006368 break;
6369 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6370 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006371 "SAS Device Status Change: Internal Task "
6372 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006373 break;
6374 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6375 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006376 "SAS Device Status Change: Internal Abort "
6377 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006378 break;
6379 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6380 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006381 "SAS Device Status Change: Internal Clear "
6382 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006383 break;
6384 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6385 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006386 "SAS Device Status Change: Internal Query "
6387 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006388 break;
6389 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006390 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006391 "SAS Device Status Change: Unknown: "
6392 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006393 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006394 }
6395 break;
6396 }
6397 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6398 ds = "Bus Timer Expired";
6399 break;
6400 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006401 {
6402 u16 curr_depth = (u16)(evData0 >> 16);
6403 u8 channel = (u8)(evData0 >> 8);
6404 u8 id = (u8)(evData0);
6405
6406 snprintf(evStr, EVENT_DESCR_STR_SZ,
6407 "Queue Full: channel=%d id=%d depth=%d",
6408 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006409 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006410 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006411 case MPI_EVENT_SAS_SES:
6412 ds = "SAS SES Event";
6413 break;
6414 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6415 ds = "Persistent Table Full";
6416 break;
6417 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006418 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006419 u8 LinkRates = (u8)(evData0 >> 8);
6420 u8 PhyNumber = (u8)(evData0);
6421 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6422 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6423 switch (LinkRates) {
6424 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
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 " Rate Unknown",PhyNumber);
6428 break;
6429 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
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 " Phy Disabled",PhyNumber);
6433 break;
6434 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
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 " Failed Speed Nego",PhyNumber);
6438 break;
6439 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006440 snprintf(evStr, EVENT_DESCR_STR_SZ,
6441 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006442 " Sata OOB Completed",PhyNumber);
6443 break;
6444 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006445 snprintf(evStr, EVENT_DESCR_STR_SZ,
6446 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006447 " Rate 1.5 Gbps",PhyNumber);
6448 break;
6449 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006450 snprintf(evStr, EVENT_DESCR_STR_SZ,
6451 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006452 " Rate 3.0 Gpbs",PhyNumber);
6453 break;
6454 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006455 snprintf(evStr, EVENT_DESCR_STR_SZ,
6456 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006457 break;
6458 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006459 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006460 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006461 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6462 ds = "SAS Discovery Error";
6463 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006464 case MPI_EVENT_IR_RESYNC_UPDATE:
6465 {
6466 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006467 snprintf(evStr, EVENT_DESCR_STR_SZ,
6468 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006469 break;
6470 }
6471 case MPI_EVENT_IR2:
6472 {
6473 u8 ReasonCode = (u8)(evData0 >> 16);
6474 switch (ReasonCode) {
6475 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6476 ds = "IR2: LD State Changed";
6477 break;
6478 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6479 ds = "IR2: PD State Changed";
6480 break;
6481 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6482 ds = "IR2: Bad Block Table Full";
6483 break;
6484 case MPI_EVENT_IR2_RC_PD_INSERTED:
6485 ds = "IR2: PD Inserted";
6486 break;
6487 case MPI_EVENT_IR2_RC_PD_REMOVED:
6488 ds = "IR2: PD Removed";
6489 break;
6490 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6491 ds = "IR2: Foreign CFG Detected";
6492 break;
6493 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6494 ds = "IR2: Rebuild Medium Error";
6495 break;
6496 default:
6497 ds = "IR2";
6498 break;
6499 }
6500 break;
6501 }
6502 case MPI_EVENT_SAS_DISCOVERY:
6503 {
6504 if (evData0)
6505 ds = "SAS Discovery: Start";
6506 else
6507 ds = "SAS Discovery: Stop";
6508 break;
6509 }
6510 case MPI_EVENT_LOG_ENTRY_ADDED:
6511 ds = "SAS Log Entry Added";
6512 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006513
Eric Moorec6c727a2007-01-29 09:44:54 -07006514 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6515 {
6516 u8 phy_num = (u8)(evData0);
6517 u8 port_num = (u8)(evData0 >> 8);
6518 u8 port_width = (u8)(evData0 >> 16);
6519 u8 primative = (u8)(evData0 >> 24);
6520 snprintf(evStr, EVENT_DESCR_STR_SZ,
6521 "SAS Broadcase Primative: phy=%d port=%d "
6522 "width=%d primative=0x%02x",
6523 phy_num, port_num, port_width, primative);
6524 break;
6525 }
6526
6527 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6528 {
6529 u8 reason = (u8)(evData0);
6530 u8 port_num = (u8)(evData0 >> 8);
6531 u16 handle = le16_to_cpu(evData0 >> 16);
6532
6533 snprintf(evStr, EVENT_DESCR_STR_SZ,
6534 "SAS Initiator Device Status Change: reason=0x%02x "
6535 "port=%d handle=0x%04x",
6536 reason, port_num, handle);
6537 break;
6538 }
6539
6540 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6541 {
6542 u8 max_init = (u8)(evData0);
6543 u8 current_init = (u8)(evData0 >> 8);
6544
6545 snprintf(evStr, EVENT_DESCR_STR_SZ,
6546 "SAS Initiator Device Table Overflow: max initiators=%02d "
6547 "current initators=%02d",
6548 max_init, current_init);
6549 break;
6550 }
6551 case MPI_EVENT_SAS_SMP_ERROR:
6552 {
6553 u8 status = (u8)(evData0);
6554 u8 port_num = (u8)(evData0 >> 8);
6555 u8 result = (u8)(evData0 >> 16);
6556
6557 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6558 snprintf(evStr, EVENT_DESCR_STR_SZ,
6559 "SAS SMP Error: port=%d result=0x%02x",
6560 port_num, result);
6561 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6562 snprintf(evStr, EVENT_DESCR_STR_SZ,
6563 "SAS SMP Error: port=%d : CRC Error",
6564 port_num);
6565 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6566 snprintf(evStr, EVENT_DESCR_STR_SZ,
6567 "SAS SMP Error: port=%d : Timeout",
6568 port_num);
6569 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6570 snprintf(evStr, EVENT_DESCR_STR_SZ,
6571 "SAS SMP Error: port=%d : No Destination",
6572 port_num);
6573 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6574 snprintf(evStr, EVENT_DESCR_STR_SZ,
6575 "SAS SMP Error: port=%d : Bad Destination",
6576 port_num);
6577 else
6578 snprintf(evStr, EVENT_DESCR_STR_SZ,
6579 "SAS SMP Error: port=%d : status=0x%02x",
6580 port_num, status);
6581 break;
6582 }
6583
Linus Torvalds1da177e2005-04-16 15:20:36 -07006584 /*
6585 * MPT base "custom" events may be added here...
6586 */
6587 default:
6588 ds = "Unknown";
6589 break;
6590 }
Eric Moore509e5e52006-04-26 13:22:37 -06006591 if (ds)
6592 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593}
6594
6595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006596/**
6597 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598 * @ioc: Pointer to MPT_ADAPTER structure
6599 * @pEventReply: Pointer to EventNotification reply frame
6600 * @evHandlers: Pointer to integer, number of event handlers
6601 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006602 * Routes a received EventNotificationReply to all currently registered
6603 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604 * Returns sum of event handlers return values.
6605 */
6606static int
6607ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
6608{
6609 u16 evDataLen;
6610 u32 evData0 = 0;
6611// u32 evCtx;
6612 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306613 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006614 int r = 0;
6615 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06006616 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617 u8 event;
6618
6619 /*
6620 * Do platform normalization of values
6621 */
6622 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6623// evCtx = le32_to_cpu(pEventReply->EventContext);
6624 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
6625 if (evDataLen) {
6626 evData0 = le32_to_cpu(pEventReply->Data[0]);
6627 }
6628
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006629 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05306630 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07006632 event,
6633 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634
Prakash, Sathya436ace72007-07-24 15:42:08 +05306635#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06006636 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6637 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05306639 devtverboseprintk(ioc, printk(" %08x",
6640 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06006641 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642#endif
6643
6644 /*
6645 * Do general / base driver event processing
6646 */
6647 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648 case MPI_EVENT_EVENT_CHANGE: /* 0A */
6649 if (evDataLen) {
6650 u8 evState = evData0 & 0xFF;
6651
6652 /* CHECKME! What if evState unexpectedly says OFF (0)? */
6653
6654 /* Update EventState field in cached IocFacts */
6655 if (ioc->facts.Function) {
6656 ioc->facts.EventState = evState;
6657 }
6658 }
6659 break;
Moore, Ericece50912006-01-16 18:53:19 -07006660 case MPI_EVENT_INTEGRATED_RAID:
6661 mptbase_raid_process_event_data(ioc,
6662 (MpiEventDataRaid_t *)pEventReply->Data);
6663 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006664 default:
6665 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666 }
6667
6668 /*
6669 * Should this event be logged? Events are written sequentially.
6670 * When buffer is full, start again at the top.
6671 */
6672 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
6673 int idx;
6674
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07006675 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676
6677 ioc->events[idx].event = event;
6678 ioc->events[idx].eventContext = ioc->eventContext;
6679
6680 for (ii = 0; ii < 2; ii++) {
6681 if (ii < evDataLen)
6682 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
6683 else
6684 ioc->events[idx].data[ii] = 0;
6685 }
6686
6687 ioc->eventContext++;
6688 }
6689
6690
6691 /*
6692 * Call each currently registered protocol event handler.
6693 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06006694 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306695 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306696 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306697 ioc->name, cb_idx));
6698 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699 handlers++;
6700 }
6701 }
6702 /* FIXME? Examine results here? */
6703
6704 /*
6705 * If needed, send (a single) EventAck.
6706 */
6707 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306708 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006709 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306711 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 ioc->name, ii));
6713 }
6714 }
6715
6716 *evHandlers = handlers;
6717 return r;
6718}
6719
6720/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006721/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
6723 * @ioc: Pointer to MPT_ADAPTER structure
6724 * @log_info: U32 LogInfo reply word from the IOC
6725 *
Eric Moore4f766dc2006-07-11 17:24:07 -06006726 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727 */
6728static void
6729mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
6730{
Eric Moore7c431e52007-06-13 16:34:36 -06006731 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732
Eric Moore7c431e52007-06-13 16:34:36 -06006733 switch (log_info & 0xFF000000) {
6734 case MPI_IOCLOGINFO_FC_INIT_BASE:
6735 desc = "FCP Initiator";
6736 break;
6737 case MPI_IOCLOGINFO_FC_TARGET_BASE:
6738 desc = "FCP Target";
6739 break;
6740 case MPI_IOCLOGINFO_FC_LAN_BASE:
6741 desc = "LAN";
6742 break;
6743 case MPI_IOCLOGINFO_FC_MSG_BASE:
6744 desc = "MPI Message Layer";
6745 break;
6746 case MPI_IOCLOGINFO_FC_LINK_BASE:
6747 desc = "FC Link";
6748 break;
6749 case MPI_IOCLOGINFO_FC_CTX_BASE:
6750 desc = "Context Manager";
6751 break;
6752 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
6753 desc = "Invalid Field Offset";
6754 break;
6755 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
6756 desc = "State Change Info";
6757 break;
6758 }
6759
6760 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
6761 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762}
6763
6764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006765/**
Moore, Eric335a9412006-01-17 17:06:23 -07006766 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 * @ioc: Pointer to MPT_ADAPTER structure
6768 * @mr: Pointer to MPT reply frame
6769 * @log_info: U32 LogInfo word from the IOC
6770 *
6771 * Refer to lsi/sp_log.h.
6772 */
6773static void
Moore, Eric335a9412006-01-17 17:06:23 -07006774mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775{
6776 u32 info = log_info & 0x00FF0000;
6777 char *desc = "unknown";
6778
6779 switch (info) {
6780 case 0x00010000:
6781 desc = "bug! MID not found";
6782 if (ioc->reload_fw == 0)
6783 ioc->reload_fw++;
6784 break;
6785
6786 case 0x00020000:
6787 desc = "Parity Error";
6788 break;
6789
6790 case 0x00030000:
6791 desc = "ASYNC Outbound Overrun";
6792 break;
6793
6794 case 0x00040000:
6795 desc = "SYNC Offset Error";
6796 break;
6797
6798 case 0x00050000:
6799 desc = "BM Change";
6800 break;
6801
6802 case 0x00060000:
6803 desc = "Msg In Overflow";
6804 break;
6805
6806 case 0x00070000:
6807 desc = "DMA Error";
6808 break;
6809
6810 case 0x00080000:
6811 desc = "Outbound DMA Overrun";
6812 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006813
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814 case 0x00090000:
6815 desc = "Task Management";
6816 break;
6817
6818 case 0x000A0000:
6819 desc = "Device Problem";
6820 break;
6821
6822 case 0x000B0000:
6823 desc = "Invalid Phase Change";
6824 break;
6825
6826 case 0x000C0000:
6827 desc = "Untagged Table Size";
6828 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02006829
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830 }
6831
6832 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
6833}
6834
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006835/* strings for sas loginfo */
6836 static char *originator_str[] = {
6837 "IOP", /* 00h */
6838 "PL", /* 01h */
6839 "IR" /* 02h */
6840 };
6841 static char *iop_code_str[] = {
6842 NULL, /* 00h */
6843 "Invalid SAS Address", /* 01h */
6844 NULL, /* 02h */
6845 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006846 "Diag Message Error", /* 04h */
6847 "Task Terminated", /* 05h */
6848 "Enclosure Management", /* 06h */
6849 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006850 };
6851 static char *pl_code_str[] = {
6852 NULL, /* 00h */
6853 "Open Failure", /* 01h */
6854 "Invalid Scatter Gather List", /* 02h */
6855 "Wrong Relative Offset or Frame Length", /* 03h */
6856 "Frame Transfer Error", /* 04h */
6857 "Transmit Frame Connected Low", /* 05h */
6858 "SATA Non-NCQ RW Error Bit Set", /* 06h */
6859 "SATA Read Log Receive Data Error", /* 07h */
6860 "SATA NCQ Fail All Commands After Error", /* 08h */
6861 "SATA Error in Receive Set Device Bit FIS", /* 09h */
6862 "Receive Frame Invalid Message", /* 0Ah */
6863 "Receive Context Message Valid Error", /* 0Bh */
6864 "Receive Frame Current Frame Error", /* 0Ch */
6865 "SATA Link Down", /* 0Dh */
6866 "Discovery SATA Init W IOS", /* 0Eh */
6867 "Config Invalid Page", /* 0Fh */
6868 "Discovery SATA Init Timeout", /* 10h */
6869 "Reset", /* 11h */
6870 "Abort", /* 12h */
6871 "IO Not Yet Executed", /* 13h */
6872 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006873 "Persistent Reservation Out Not Affiliation "
6874 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07006875 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06006876 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07006877 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006878 NULL, /* 19h */
6879 NULL, /* 1Ah */
6880 NULL, /* 1Bh */
6881 NULL, /* 1Ch */
6882 NULL, /* 1Dh */
6883 NULL, /* 1Eh */
6884 NULL, /* 1Fh */
6885 "Enclosure Management" /* 20h */
6886 };
Eric Moorec6c727a2007-01-29 09:44:54 -07006887 static char *ir_code_str[] = {
6888 "Raid Action Error", /* 00h */
6889 NULL, /* 00h */
6890 NULL, /* 01h */
6891 NULL, /* 02h */
6892 NULL, /* 03h */
6893 NULL, /* 04h */
6894 NULL, /* 05h */
6895 NULL, /* 06h */
6896 NULL /* 07h */
6897 };
6898 static char *raid_sub_code_str[] = {
6899 NULL, /* 00h */
6900 "Volume Creation Failed: Data Passed too "
6901 "Large", /* 01h */
6902 "Volume Creation Failed: Duplicate Volumes "
6903 "Attempted", /* 02h */
6904 "Volume Creation Failed: Max Number "
6905 "Supported Volumes Exceeded", /* 03h */
6906 "Volume Creation Failed: DMA Error", /* 04h */
6907 "Volume Creation Failed: Invalid Volume Type", /* 05h */
6908 "Volume Creation Failed: Error Reading "
6909 "MFG Page 4", /* 06h */
6910 "Volume Creation Failed: Creating Internal "
6911 "Structures", /* 07h */
6912 NULL, /* 08h */
6913 NULL, /* 09h */
6914 NULL, /* 0Ah */
6915 NULL, /* 0Bh */
6916 NULL, /* 0Ch */
6917 NULL, /* 0Dh */
6918 NULL, /* 0Eh */
6919 NULL, /* 0Fh */
6920 "Activation failed: Already Active Volume", /* 10h */
6921 "Activation failed: Unsupported Volume Type", /* 11h */
6922 "Activation failed: Too Many Active Volumes", /* 12h */
6923 "Activation failed: Volume ID in Use", /* 13h */
6924 "Activation failed: Reported Failure", /* 14h */
6925 "Activation failed: Importing a Volume", /* 15h */
6926 NULL, /* 16h */
6927 NULL, /* 17h */
6928 NULL, /* 18h */
6929 NULL, /* 19h */
6930 NULL, /* 1Ah */
6931 NULL, /* 1Bh */
6932 NULL, /* 1Ch */
6933 NULL, /* 1Dh */
6934 NULL, /* 1Eh */
6935 NULL, /* 1Fh */
6936 "Phys Disk failed: Too Many Phys Disks", /* 20h */
6937 "Phys Disk failed: Data Passed too Large", /* 21h */
6938 "Phys Disk failed: DMA Error", /* 22h */
6939 "Phys Disk failed: Invalid <channel:id>", /* 23h */
6940 "Phys Disk failed: Creating Phys Disk Config "
6941 "Page", /* 24h */
6942 NULL, /* 25h */
6943 NULL, /* 26h */
6944 NULL, /* 27h */
6945 NULL, /* 28h */
6946 NULL, /* 29h */
6947 NULL, /* 2Ah */
6948 NULL, /* 2Bh */
6949 NULL, /* 2Ch */
6950 NULL, /* 2Dh */
6951 NULL, /* 2Eh */
6952 NULL, /* 2Fh */
6953 "Compatibility Error: IR Disabled", /* 30h */
6954 "Compatibility Error: Inquiry Comand Failed", /* 31h */
6955 "Compatibility Error: Device not Direct Access "
6956 "Device ", /* 32h */
6957 "Compatibility Error: Removable Device Found", /* 33h */
6958 "Compatibility Error: Device SCSI Version not "
6959 "2 or Higher", /* 34h */
6960 "Compatibility Error: SATA Device, 48 BIT LBA "
6961 "not Supported", /* 35h */
6962 "Compatibility Error: Device doesn't have "
6963 "512 Byte Block Sizes", /* 36h */
6964 "Compatibility Error: Volume Type Check Failed", /* 37h */
6965 "Compatibility Error: Volume Type is "
6966 "Unsupported by FW", /* 38h */
6967 "Compatibility Error: Disk Drive too Small for "
6968 "use in Volume", /* 39h */
6969 "Compatibility Error: Phys Disk for Create "
6970 "Volume not Found", /* 3Ah */
6971 "Compatibility Error: Too Many or too Few "
6972 "Disks for Volume Type", /* 3Bh */
6973 "Compatibility Error: Disk stripe Sizes "
6974 "Must be 64KB", /* 3Ch */
6975 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
6976 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006977
6978/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006979/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006980 * mpt_sas_log_info - Log information returned from SAS IOC.
6981 * @ioc: Pointer to MPT_ADAPTER structure
6982 * @log_info: U32 LogInfo reply word from the IOC
6983 *
6984 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07006985 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006986static void
6987mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
6988{
6989union loginfo_type {
6990 u32 loginfo;
6991 struct {
6992 u32 subcode:16;
6993 u32 code:8;
6994 u32 originator:4;
6995 u32 bus_type:4;
6996 }dw;
6997};
6998 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07006999 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007000 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007001 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007002
7003 sas_loginfo.loginfo = log_info;
7004 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
7005 (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
7006 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007007
7008 originator_desc = originator_str[sas_loginfo.dw.originator];
7009
7010 switch (sas_loginfo.dw.originator) {
7011
7012 case 0: /* IOP */
7013 if (sas_loginfo.dw.code <
7014 sizeof(iop_code_str)/sizeof(char*))
7015 code_desc = iop_code_str[sas_loginfo.dw.code];
7016 break;
7017 case 1: /* PL */
7018 if (sas_loginfo.dw.code <
7019 sizeof(pl_code_str)/sizeof(char*))
7020 code_desc = pl_code_str[sas_loginfo.dw.code];
7021 break;
7022 case 2: /* IR */
7023 if (sas_loginfo.dw.code >=
7024 sizeof(ir_code_str)/sizeof(char*))
7025 break;
7026 code_desc = ir_code_str[sas_loginfo.dw.code];
7027 if (sas_loginfo.dw.subcode >=
7028 sizeof(raid_sub_code_str)/sizeof(char*))
7029 break;
7030 if (sas_loginfo.dw.code == 0)
7031 sub_code_desc =
7032 raid_sub_code_str[sas_loginfo.dw.subcode];
7033 break;
7034 default:
7035 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007036 }
7037
Eric Moorec6c727a2007-01-29 09:44:54 -07007038 if (sub_code_desc != NULL)
7039 printk(MYIOC_s_INFO_FMT
7040 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7041 " SubCode={%s}\n",
7042 ioc->name, log_info, originator_desc, code_desc,
7043 sub_code_desc);
7044 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007045 printk(MYIOC_s_INFO_FMT
7046 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7047 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007048 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007049 sas_loginfo.dw.subcode);
7050 else
7051 printk(MYIOC_s_INFO_FMT
7052 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7053 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007054 ioc->name, log_info, originator_desc,
7055 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007056}
7057
Linus Torvalds1da177e2005-04-16 15:20:36 -07007058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007059/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007060 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7061 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007062 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007063 * @mf: Pointer to MPT request frame
7064 *
7065 * Refer to lsi/mpi.h.
7066 **/
7067static void
7068mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7069{
7070 Config_t *pReq = (Config_t *)mf;
7071 char extend_desc[EVENT_DESCR_STR_SZ];
7072 char *desc = NULL;
7073 u32 form;
7074 u8 page_type;
7075
7076 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7077 page_type = pReq->ExtPageType;
7078 else
7079 page_type = pReq->Header.PageType;
7080
7081 /*
7082 * ignore invalid page messages for GET_NEXT_HANDLE
7083 */
7084 form = le32_to_cpu(pReq->PageAddress);
7085 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7086 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7087 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7088 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7089 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7090 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7091 return;
7092 }
7093 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7094 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7095 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7096 return;
7097 }
7098
7099 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7100 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7101 page_type, pReq->Header.PageNumber, pReq->Action, form);
7102
7103 switch (ioc_status) {
7104
7105 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7106 desc = "Config Page Invalid Action";
7107 break;
7108
7109 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7110 desc = "Config Page Invalid Type";
7111 break;
7112
7113 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7114 desc = "Config Page Invalid Page";
7115 break;
7116
7117 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7118 desc = "Config Page Invalid Data";
7119 break;
7120
7121 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7122 desc = "Config Page No Defaults";
7123 break;
7124
7125 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7126 desc = "Config Page Can't Commit";
7127 break;
7128 }
7129
7130 if (!desc)
7131 return;
7132
Eric Moore29dd3602007-09-14 18:46:51 -06007133 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7134 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007135}
7136
7137/**
7138 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139 * @ioc: Pointer to MPT_ADAPTER structure
7140 * @ioc_status: U32 IOCStatus word from IOC
7141 * @mf: Pointer to MPT request frame
7142 *
7143 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007144 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007146mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147{
7148 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007149 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150
7151 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007152
7153/****************************************************************************/
7154/* Common IOCStatus values for all replies */
7155/****************************************************************************/
7156
Linus Torvalds1da177e2005-04-16 15:20:36 -07007157 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7158 desc = "Invalid Function";
7159 break;
7160
7161 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7162 desc = "Busy";
7163 break;
7164
7165 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7166 desc = "Invalid SGL";
7167 break;
7168
7169 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7170 desc = "Internal Error";
7171 break;
7172
7173 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7174 desc = "Reserved";
7175 break;
7176
7177 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7178 desc = "Insufficient Resources";
7179 break;
7180
7181 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7182 desc = "Invalid Field";
7183 break;
7184
7185 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7186 desc = "Invalid State";
7187 break;
7188
Eric Moorec6c727a2007-01-29 09:44:54 -07007189/****************************************************************************/
7190/* Config IOCStatus values */
7191/****************************************************************************/
7192
Linus Torvalds1da177e2005-04-16 15:20:36 -07007193 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7194 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7195 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7196 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7197 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7198 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007199 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007200 break;
7201
Eric Moorec6c727a2007-01-29 09:44:54 -07007202/****************************************************************************/
7203/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7204/* */
7205/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7206/* */
7207/****************************************************************************/
7208
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007211 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7212 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7213 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7214 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007221 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222 break;
7223
Eric Moorec6c727a2007-01-29 09:44:54 -07007224/****************************************************************************/
7225/* SCSI Target values */
7226/****************************************************************************/
7227
7228 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7229 desc = "Target: Priority IO";
7230 break;
7231
7232 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7233 desc = "Target: Invalid Port";
7234 break;
7235
7236 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7237 desc = "Target Invalid IO Index:";
7238 break;
7239
7240 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7241 desc = "Target: Aborted";
7242 break;
7243
7244 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7245 desc = "Target: No Conn Retryable";
7246 break;
7247
7248 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7249 desc = "Target: No Connection";
7250 break;
7251
7252 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7253 desc = "Target: Transfer Count Mismatch";
7254 break;
7255
7256 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7257 desc = "Target: STS Data not Sent";
7258 break;
7259
7260 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7261 desc = "Target: Data Offset Error";
7262 break;
7263
7264 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7265 desc = "Target: Too Much Write Data";
7266 break;
7267
7268 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7269 desc = "Target: IU Too Short";
7270 break;
7271
7272 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7273 desc = "Target: ACK NAK Timeout";
7274 break;
7275
7276 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7277 desc = "Target: Nak Received";
7278 break;
7279
7280/****************************************************************************/
7281/* Fibre Channel Direct Access values */
7282/****************************************************************************/
7283
7284 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7285 desc = "FC: Aborted";
7286 break;
7287
7288 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7289 desc = "FC: RX ID Invalid";
7290 break;
7291
7292 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7293 desc = "FC: DID Invalid";
7294 break;
7295
7296 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7297 desc = "FC: Node Logged Out";
7298 break;
7299
7300 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7301 desc = "FC: Exchange Canceled";
7302 break;
7303
7304/****************************************************************************/
7305/* LAN values */
7306/****************************************************************************/
7307
7308 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7309 desc = "LAN: Device not Found";
7310 break;
7311
7312 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7313 desc = "LAN: Device Failure";
7314 break;
7315
7316 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7317 desc = "LAN: Transmit Error";
7318 break;
7319
7320 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7321 desc = "LAN: Transmit Aborted";
7322 break;
7323
7324 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7325 desc = "LAN: Receive Error";
7326 break;
7327
7328 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7329 desc = "LAN: Receive Aborted";
7330 break;
7331
7332 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7333 desc = "LAN: Partial Packet";
7334 break;
7335
7336 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7337 desc = "LAN: Canceled";
7338 break;
7339
7340/****************************************************************************/
7341/* Serial Attached SCSI values */
7342/****************************************************************************/
7343
7344 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7345 desc = "SAS: SMP Request Failed";
7346 break;
7347
7348 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7349 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350 break;
7351
7352 default:
7353 desc = "Others";
7354 break;
7355 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007356
7357 if (!desc)
7358 return;
7359
Eric Moore29dd3602007-09-14 18:46:51 -06007360 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7361 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007362}
7363
7364/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007365EXPORT_SYMBOL(mpt_attach);
7366EXPORT_SYMBOL(mpt_detach);
7367#ifdef CONFIG_PM
7368EXPORT_SYMBOL(mpt_resume);
7369EXPORT_SYMBOL(mpt_suspend);
7370#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371EXPORT_SYMBOL(ioc_list);
Linus Torvaldsf7473072005-11-29 14:21:57 -08007372EXPORT_SYMBOL(mpt_proc_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373EXPORT_SYMBOL(mpt_register);
7374EXPORT_SYMBOL(mpt_deregister);
7375EXPORT_SYMBOL(mpt_event_register);
7376EXPORT_SYMBOL(mpt_event_deregister);
7377EXPORT_SYMBOL(mpt_reset_register);
7378EXPORT_SYMBOL(mpt_reset_deregister);
7379EXPORT_SYMBOL(mpt_device_driver_register);
7380EXPORT_SYMBOL(mpt_device_driver_deregister);
7381EXPORT_SYMBOL(mpt_get_msg_frame);
7382EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307383EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007384EXPORT_SYMBOL(mpt_free_msg_frame);
7385EXPORT_SYMBOL(mpt_add_sge);
7386EXPORT_SYMBOL(mpt_send_handshake_request);
7387EXPORT_SYMBOL(mpt_verify_adapter);
7388EXPORT_SYMBOL(mpt_GetIocState);
7389EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390EXPORT_SYMBOL(mpt_HardResetHandler);
7391EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393EXPORT_SYMBOL(mpt_alloc_fw_memory);
7394EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007395EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007396EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007397
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007399/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400 * fusion_init - Fusion MPT base driver initialization routine.
7401 *
7402 * Returns 0 for success, non-zero for failure.
7403 */
7404static int __init
7405fusion_init(void)
7406{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307407 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408
7409 show_mptmod_ver(my_NAME, my_VERSION);
7410 printk(KERN_INFO COPYRIGHT "\n");
7411
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307412 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7413 MptCallbacks[cb_idx] = NULL;
7414 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7415 MptEvHandlers[cb_idx] = NULL;
7416 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007417 }
7418
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007419 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420 * EventNotification handling.
7421 */
7422 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7423
7424 /* Register for hard reset handling callbacks.
7425 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307426 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007427
7428#ifdef CONFIG_PROC_FS
7429 (void) procmpt_create();
7430#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007431 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432}
7433
7434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007435/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007436 * fusion_exit - Perform driver unload cleanup.
7437 *
7438 * This routine frees all resources associated with each MPT adapter
7439 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7440 */
7441static void __exit
7442fusion_exit(void)
7443{
7444
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445 mpt_reset_deregister(mpt_base_index);
7446
7447#ifdef CONFIG_PROC_FS
7448 procmpt_destroy();
7449#endif
7450}
7451
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452module_init(fusion_init);
7453module_exit(fusion_exit);