blob: a66369218c976aaceba4a695019c53dda741c3c0 [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, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 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 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
150
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530151/*
152 * Driver Callback Index's
153 */
154static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
155static u8 last_drv_idx;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
158/*
159 * Forward protos...
160 */
David Howells7d12e782006-10-05 14:55:46 +0100161static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
193static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530194static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
201static int procmpt_summary_read(char *buf, char **start, off_t offset,
202 int request, int *eof, void *data);
203static int procmpt_version_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
210//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
211static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700212static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700214static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600215static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700216static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700217static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int __init fusion_init (void);
221static void __exit fusion_exit (void);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#define CHIPREG_READ32(addr) readl_relaxed(addr)
224#define CHIPREG_READ32_dmasync(addr) readl(addr)
225#define CHIPREG_WRITE32(addr,val) writel(val, addr)
226#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
227#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
228
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600229static void
230pci_disable_io_access(struct pci_dev *pdev)
231{
232 u16 command_reg;
233
234 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
235 command_reg &= ~1;
236 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
237}
238
239static void
240pci_enable_io_access(struct pci_dev *pdev)
241{
242 u16 command_reg;
243
244 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
245 command_reg |= 1;
246 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
247}
248
James Bottomleydb47c2d2007-07-28 13:40:21 -0400249static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
250{
251 int ret = param_set_int(val, kp);
252 MPT_ADAPTER *ioc;
253
254 if (ret)
255 return ret;
256
257 list_for_each_entry(ioc, &ioc_list, list)
258 ioc->debug_level = mpt_debug_level;
259 return 0;
260}
261
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530262/**
263 * mpt_get_cb_idx - obtain cb_idx for registered driver
264 * @dclass: class driver enum
265 *
266 * Returns cb_idx, or zero means it wasn't found
267 **/
268static u8
269mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
270{
271 u8 cb_idx;
272
273 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
274 if (MptDriverClass[cb_idx] == dclass)
275 return cb_idx;
276 return 0;
277}
278
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279/**
280 * mpt_fault_reset_work - work performed on workq after ioc fault
281 * @work: input argument, used to derive ioc
282 *
283**/
284static void
285mpt_fault_reset_work(struct work_struct *work)
286{
287 MPT_ADAPTER *ioc =
288 container_of(work, MPT_ADAPTER, fault_reset_work.work);
289 u32 ioc_raw_state;
290 int rc;
291 unsigned long flags;
292
293 if (ioc->diagPending || !ioc->active)
294 goto out;
295
296 ioc_raw_state = mpt_GetIocState(ioc, 0);
297 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
298 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700299 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530300 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700301 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530302 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
303 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700304 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530305 ioc_raw_state = mpt_GetIocState(ioc, 0);
306 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
307 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
308 "reset (%04xh)\n", ioc->name, ioc_raw_state &
309 MPI_DOORBELL_DATA_MASK);
310 }
311
312 out:
313 /*
314 * Take turns polling alternate controller
315 */
316 if (ioc->alt_ioc)
317 ioc = ioc->alt_ioc;
318
319 /* rearm the timer */
320 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
321 if (ioc->reset_work_q)
322 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
323 msecs_to_jiffies(MPT_POLLING_INTERVAL));
324 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
325}
326
327
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600328/*
329 * Process turbo (context) reply...
330 */
331static void
332mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
333{
334 MPT_FRAME_HDR *mf = NULL;
335 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530336 u16 req_idx = 0;
337 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600338
Prakash, Sathya436ace72007-07-24 15:42:08 +0530339 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600340 ioc->name, pa));
341
342 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
343 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
344 req_idx = pa & 0x0000FFFF;
345 cb_idx = (pa & 0x00FF0000) >> 16;
346 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
347 break;
348 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530349 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600350 /*
351 * Blind set of mf to NULL here was fatal
352 * after lan_reply says "freeme"
353 * Fix sort of combined with an optimization here;
354 * added explicit check for case where lan_reply
355 * was just returning 1 and doing nothing else.
356 * For this case skip the callback, but set up
357 * proper mf value first here:-)
358 */
359 if ((pa & 0x58000000) == 0x58000000) {
360 req_idx = pa & 0x0000FFFF;
361 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
362 mpt_free_msg_frame(ioc, mf);
363 mb();
364 return;
365 break;
366 }
367 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
368 break;
369 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530370 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600371 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
372 break;
373 default:
374 cb_idx = 0;
375 BUG();
376 }
377
378 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530379 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600380 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700382 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600383 goto out;
384 }
385
386 if (MptCallbacks[cb_idx](ioc, mf, mr))
387 mpt_free_msg_frame(ioc, mf);
388 out:
389 mb();
390}
391
392static void
393mpt_reply(MPT_ADAPTER *ioc, u32 pa)
394{
395 MPT_FRAME_HDR *mf;
396 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530397 u16 req_idx;
398 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600399 int freeme;
400
401 u32 reply_dma_low;
402 u16 ioc_stat;
403
404 /* non-TURBO reply! Hmmm, something may be up...
405 * Newest turbo reply mechanism; get address
406 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
407 */
408
409 /* Map DMA address of reply header to cpu address.
410 * pa is 32 bits - but the dma address may be 32 or 64 bits
411 * get offset based only only the low addresses
412 */
413
414 reply_dma_low = (pa <<= 1);
415 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
416 (reply_dma_low - ioc->reply_frames_low_dma));
417
418 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
419 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
420 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
421
Prakash, Sathya436ace72007-07-24 15:42:08 +0530422 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 -0600423 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600424 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600425
426 /* Check/log IOC log info
427 */
428 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
429 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
430 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
431 if (ioc->bus_type == FC)
432 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700433 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700434 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600435 else if (ioc->bus_type == SAS)
436 mpt_sas_log_info(ioc, log_info);
437 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438
Eric Moorec6c727a2007-01-29 09:44:54 -0700439 if (ioc_stat & MPI_IOCSTATUS_MASK)
440 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600441
442 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530443 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600444 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600445 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700446 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600447 freeme = 0;
448 goto out;
449 }
450
451 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
452
453 out:
454 /* Flush (non-TURBO) reply with a WRITE! */
455 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
456
457 if (freeme)
458 mpt_free_msg_frame(ioc, mf);
459 mb();
460}
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800463/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
465 * @irq: irq number (not used)
466 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 *
468 * This routine is registered via the request_irq() kernel API call,
469 * and handles all interrupts generated from a specific MPT adapter
470 * (also referred to as a IO Controller or IOC).
471 * This routine must clear the interrupt from the adapter and does
472 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200473 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 *
475 * This routine handles register-level access of the adapter but
476 * dispatches (calls) a protocol-specific callback routine to handle
477 * the protocol-specific details of the MPT request completion.
478 */
479static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100480mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600483 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
484
485 if (pa == 0xFFFFFFFF)
486 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 /*
489 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600491 do {
492 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600493 mpt_reply(ioc, pa);
494 else
495 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600496 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
497 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 return IRQ_HANDLED;
500}
501
502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800503/**
504 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 * @ioc: Pointer to MPT_ADAPTER structure
506 * @mf: Pointer to original MPT request frame
507 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
508 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800509 * MPT base driver's callback routine; all base driver
510 * "internal" request/reply processing is routed here.
511 * Currently used for EventNotification and EventAck handling.
512 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200513 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 * should be freed, or 0 if it shouldn't.
515 */
516static int
517mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
518{
519 int freereq = 1;
520 u8 func;
521
Prakash, Sathya436ace72007-07-24 15:42:08 +0530522 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
523#ifdef CONFIG_FUSION_LOGGING
524 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
525 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600526 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
527 ioc->name, mf));
528 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530533 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 ioc->name, func));
535
536 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
537 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
538 int evHandlers = 0;
539 int results;
540
541 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
542 if (results != evHandlers) {
543 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530544 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ioc->name, evHandlers, results));
546 }
547
548 /*
549 * Hmmm... It seems that EventNotificationReply is an exception
550 * to the rule of one reply per request.
551 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200552 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200554 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530555 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200556 ioc->name, pEvReply));
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559#ifdef CONFIG_PROC_FS
560// LogEvent(ioc, pEvReply);
561#endif
562
563 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530564 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700566 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 CONFIGPARMS *pCfg;
568 unsigned long flags;
569
Prakash, Sathya436ace72007-07-24 15:42:08 +0530570 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 ioc->name, mf, reply));
572
573 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
574
575 if (pCfg) {
576 /* disable timer and remove from linked list */
577 del_timer(&pCfg->timer);
578
579 spin_lock_irqsave(&ioc->FreeQlock, flags);
580 list_del(&pCfg->linkage);
581 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
582
583 /*
584 * If IOC Status is SUCCESS, save the header
585 * and set the status code to GOOD.
586 */
587 pCfg->status = MPT_CONFIG_ERROR;
588 if (reply) {
589 ConfigReply_t *pReply = (ConfigReply_t *)reply;
590 u16 status;
591
592 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600593 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
594 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 pCfg->status = status;
597 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200598 if ((pReply->Header.PageType &
599 MPI_CONFIG_PAGETYPE_MASK) ==
600 MPI_CONFIG_PAGETYPE_EXTENDED) {
601 pCfg->cfghdr.ehdr->ExtPageLength =
602 le16_to_cpu(pReply->ExtPageLength);
603 pCfg->cfghdr.ehdr->ExtPageType =
604 pReply->ExtPageType;
605 }
606 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
607
608 /* If this is a regular header, save PageLength. */
609 /* LMP Do this better so not using a reserved field! */
610 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
611 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
612 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614 }
615
616 /*
617 * Wake up the original calling thread
618 */
619 pCfg->wait_done = 1;
620 wake_up(&mpt_waitq);
621 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200622 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
623 /* we should be always getting a reply frame */
624 memcpy(ioc->persist_reply_frame, reply,
625 min(MPT_DEFAULT_FRAME_SIZE,
626 4*reply->u.reply.MsgLength));
627 del_timer(&ioc->persist_timer);
628 ioc->persist_wait_done = 1;
629 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 } else {
631 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
632 ioc->name, func);
633 }
634
635 /*
636 * Conditionally tell caller to free the original
637 * EventNotification/EventAck/unexpected request frame!
638 */
639 return freereq;
640}
641
642/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
643/**
644 * mpt_register - Register protocol-specific main callback handler.
645 * @cbfunc: callback function pointer
646 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
647 *
648 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800649 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 * protocol-specific driver must do this before it will be able to
651 * use any IOC resources, such as obtaining request frames.
652 *
653 * NOTES: The SCSI protocol driver currently calls this routine thrice
654 * in order to register separate callbacks; one for "normal" SCSI IO;
655 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
656 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530657 * Returns u8 valued "handle" in the range (and S.O.D. order)
658 * {N,...,7,6,5,...,1} if successful.
659 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
660 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530662u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
664{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530665 u8 cb_idx;
666 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 /*
669 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
670 * (slot/handle 0 is reserved!)
671 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530672 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
673 if (MptCallbacks[cb_idx] == NULL) {
674 MptCallbacks[cb_idx] = cbfunc;
675 MptDriverClass[cb_idx] = dclass;
676 MptEvHandlers[cb_idx] = NULL;
677 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 }
680 }
681
682 return last_drv_idx;
683}
684
685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
686/**
687 * mpt_deregister - Deregister a protocol drivers resources.
688 * @cb_idx: previously registered callback handle
689 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800690 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * module is unloaded.
692 */
693void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530694mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600696 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 MptCallbacks[cb_idx] = NULL;
698 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
699 MptEvHandlers[cb_idx] = NULL;
700
701 last_drv_idx++;
702 }
703}
704
705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
706/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800707 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 * @cb_idx: previously registered (via mpt_register) callback handle
709 * @ev_cbfunc: callback function
710 *
711 * This routine can be called by one or more protocol-specific drivers
712 * if/when they choose to be notified of MPT events.
713 *
714 * Returns 0 for success.
715 */
716int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530717mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600719 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -1;
721
722 MptEvHandlers[cb_idx] = ev_cbfunc;
723 return 0;
724}
725
726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
727/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800728 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 * @cb_idx: previously registered callback handle
730 *
731 * Each protocol-specific driver should call this routine
732 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800733 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 */
735void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530736mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600738 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
740
741 MptEvHandlers[cb_idx] = NULL;
742}
743
744/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
745/**
746 * mpt_reset_register - Register protocol-specific IOC reset handler.
747 * @cb_idx: previously registered (via mpt_register) callback handle
748 * @reset_func: reset function
749 *
750 * This routine can be called by one or more protocol-specific drivers
751 * if/when they choose to be notified of IOC resets.
752 *
753 * Returns 0 for success.
754 */
755int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530756mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530758 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -1;
760
761 MptResetHandlers[cb_idx] = reset_func;
762 return 0;
763}
764
765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
766/**
767 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
768 * @cb_idx: previously registered callback handle
769 *
770 * Each protocol-specific driver should call this routine
771 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800772 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 */
774void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530775mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return;
779
780 MptResetHandlers[cb_idx] = NULL;
781}
782
783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
784/**
785 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800786 * @dd_cbfunc: driver callbacks struct
787 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 */
789int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530790mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600793 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Eric Moore8d6d83e2007-09-14 18:47:40 -0600795 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400796 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
799
800 /* call per pci device probe entry point */
801 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600802 id = ioc->pcidev->driver ?
803 ioc->pcidev->driver->id_table : NULL;
804 if (dd_cbfunc->probe)
805 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
812/**
813 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800814 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 */
816void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530817mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 struct mpt_pci_driver *dd_cbfunc;
820 MPT_ADAPTER *ioc;
821
Eric Moore8d6d83e2007-09-14 18:47:40 -0600822 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return;
824
825 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
826
827 list_for_each_entry(ioc, &ioc_list, list) {
828 if (dd_cbfunc->remove)
829 dd_cbfunc->remove(ioc->pcidev);
830 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 MptDeviceDriverHandlers[cb_idx] = NULL;
833}
834
835
836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
837/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800838 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
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 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800842 * Obtain an MPT request frame from the pool (of 1024) that are
843 * allocated per MPT adapter.
844 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 * Returns pointer to a MPT request frame or %NULL if none are available
846 * or IOC is not active.
847 */
848MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530849mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
851 MPT_FRAME_HDR *mf;
852 unsigned long flags;
853 u16 req_idx; /* Request index */
854
855 /* validate handle and ioc identifier */
856
857#ifdef MFCNT
858 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600859 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
860 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861#endif
862
863 /* If interrupts are not attached, do not return a request frame */
864 if (!ioc->active)
865 return NULL;
866
867 spin_lock_irqsave(&ioc->FreeQlock, flags);
868 if (!list_empty(&ioc->FreeQ)) {
869 int req_offset;
870
871 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
872 u.frame.linkage.list);
873 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200874 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530875 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
877 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500878 req_idx = req_offset / ioc->req_sz;
879 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600881 /* Default, will be changed if necessary in SG generation */
882 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#ifdef MFCNT
884 ioc->mfcnt++;
885#endif
886 }
887 else
888 mf = NULL;
889 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
890
891#ifdef MFCNT
892 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600893 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
894 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
895 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 mfcounter++;
897 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600898 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
899 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900#endif
901
Eric Moore29dd3602007-09-14 18:46:51 -0600902 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
903 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 return mf;
905}
906
907/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
908/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800909 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530910 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 * @ioc: Pointer to MPT adapter structure
912 * @mf: Pointer to MPT request frame
913 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800914 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 * specific MPT adapter.
916 */
917void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530918mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
920 u32 mf_dma_addr;
921 int req_offset;
922 u16 req_idx; /* Request index */
923
924 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530925 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
927 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500928 req_idx = req_offset / ioc->req_sz;
929 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
931
Prakash, Sathya436ace72007-07-24 15:42:08 +0530932 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200934 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600935 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
936 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
937 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
939}
940
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530941/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800942 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530943 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530944 * @ioc: Pointer to MPT adapter structure
945 * @mf: Pointer to MPT request frame
946 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800947 * Send a protocol-specific MPT request frame to an IOC using
948 * hi-priority request queue.
949 *
950 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530951 * specific MPT adapter.
952 **/
953void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530954mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530955{
956 u32 mf_dma_addr;
957 int req_offset;
958 u16 req_idx; /* Request index */
959
960 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530961 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530962 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
963 req_idx = req_offset / ioc->req_sz;
964 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
965 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
966
967 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
968
969 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
970 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
971 ioc->name, mf_dma_addr, req_idx));
972 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
976/**
977 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 * @ioc: Pointer to MPT adapter structure
979 * @mf: Pointer to MPT request frame
980 *
981 * This routine places a MPT request frame back on the MPT adapter's
982 * FreeQ.
983 */
984void
985mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
986{
987 unsigned long flags;
988
989 /* Put Request back on FreeQ! */
990 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200991 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
993#ifdef MFCNT
994 ioc->mfcnt--;
995#endif
996 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
997}
998
999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1000/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301001 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 * @pAddr: virtual address for SGE
1003 * @flagslength: SGE flags and data transfer length
1004 * @dma_addr: Physical address
1005 *
1006 * This routine places a MPT request frame back on the MPT adapter's
1007 * FreeQ.
1008 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301009static void
1010mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301012 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1013 pSge->FlagsLength = cpu_to_le32(flagslength);
1014 pSge->Address = cpu_to_le32(dma_addr);
1015}
1016
1017/**
1018 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1019 * @pAddr: virtual address for SGE
1020 * @flagslength: SGE flags and data transfer length
1021 * @dma_addr: Physical address
1022 *
1023 * This routine places a MPT request frame back on the MPT adapter's
1024 * FreeQ.
1025 **/
1026static void
1027mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1028{
1029 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1030 pSge->Address.Low = cpu_to_le32
1031 (lower_32_bits((unsigned long)(dma_addr)));
1032 pSge->Address.High = cpu_to_le32
1033 (upper_32_bits((unsigned long)dma_addr));
1034 pSge->FlagsLength = cpu_to_le32
1035 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1036}
1037
1038/**
1039 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1040 * (1078 workaround).
1041 * @pAddr: virtual address for SGE
1042 * @flagslength: SGE flags and data transfer length
1043 * @dma_addr: Physical address
1044 *
1045 * This routine places a MPT request frame back on the MPT adapter's
1046 * FreeQ.
1047 **/
1048static void
1049mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1050{
1051 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1052 u32 tmp;
1053
1054 pSge->Address.Low = cpu_to_le32
1055 (lower_32_bits((unsigned long)(dma_addr)));
1056 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1057
1058 /*
1059 * 1078 errata workaround for the 36GB limitation
1060 */
1061 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1062 flagslength |=
1063 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1064 tmp |= (1<<31);
1065 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1066 printk(KERN_DEBUG "1078 P0M2 addressing for "
1067 "addr = 0x%llx len = %d\n",
1068 (unsigned long long)dma_addr,
1069 MPI_SGE_LENGTH(flagslength));
1070 }
1071
1072 pSge->Address.High = cpu_to_le32(tmp);
1073 pSge->FlagsLength = cpu_to_le32(
1074 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1075}
1076
1077/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1078/**
1079 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1080 * @pAddr: virtual address for SGE
1081 * @next: nextChainOffset value (u32's)
1082 * @length: length of next SGL segment
1083 * @dma_addr: Physical address
1084 *
1085 */
1086static void
1087mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1088{
1089 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1090 pChain->Length = cpu_to_le16(length);
1091 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1092 pChain->NextChainOffset = next;
1093 pChain->Address = cpu_to_le32(dma_addr);
1094}
1095
1096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1097/**
1098 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1099 * @pAddr: virtual address for SGE
1100 * @next: nextChainOffset value (u32's)
1101 * @length: length of next SGL segment
1102 * @dma_addr: Physical address
1103 *
1104 */
1105static void
1106mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1107{
1108 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 u32 tmp = dma_addr & 0xFFFFFFFF;
1110
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301111 pChain->Length = cpu_to_le16(length);
1112 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1113 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301115 pChain->NextChainOffset = next;
1116
1117 pChain->Address.Low = cpu_to_le32(tmp);
1118 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1119 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
1122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1123/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001124 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301125 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 * @ioc: Pointer to MPT adapter structure
1127 * @reqBytes: Size of the request in bytes
1128 * @req: Pointer to MPT request frame
1129 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1130 *
1131 * This routine is used exclusively to send MptScsiTaskMgmt
1132 * requests since they are required to be sent via doorbell handshake.
1133 *
1134 * NOTE: It is the callers responsibility to byte-swap fields in the
1135 * request which are greater than 1 byte in size.
1136 *
1137 * Returns 0 for success, non-zero for failure.
1138 */
1139int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301140mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Eric Moorecd2c6192007-01-29 09:47:47 -07001142 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 u8 *req_as_bytes;
1144 int ii;
1145
1146 /* State is known to be good upon entering
1147 * this function so issue the bus reset
1148 * request.
1149 */
1150
1151 /*
1152 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1153 * setting cb_idx/req_idx. But ONLY if this request
1154 * is in proper (pre-alloc'd) request buffer range...
1155 */
1156 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1157 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1158 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1159 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301160 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162
1163 /* Make sure there are no doorbells */
1164 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1167 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1168 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1169
1170 /* Wait for IOC doorbell int */
1171 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1172 return ii;
1173 }
1174
1175 /* Read doorbell and check for active bit */
1176 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1177 return -5;
1178
Eric Moore29dd3602007-09-14 18:46:51 -06001179 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001180 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1183
1184 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1185 return -2;
1186 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 /* Send request via doorbell handshake */
1189 req_as_bytes = (u8 *) req;
1190 for (ii = 0; ii < reqBytes/4; ii++) {
1191 u32 word;
1192
1193 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1194 (req_as_bytes[(ii*4) + 1] << 8) |
1195 (req_as_bytes[(ii*4) + 2] << 16) |
1196 (req_as_bytes[(ii*4) + 3] << 24));
1197 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1198 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1199 r = -3;
1200 break;
1201 }
1202 }
1203
1204 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1205 r = 0;
1206 else
1207 r = -4;
1208
1209 /* Make sure there are no doorbells */
1210 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return r;
1213}
1214
1215/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1216/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001217 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001218 * @ioc: Pointer to MPT adapter structure
1219 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001220 * @sleepFlag: Specifies whether the process can sleep
1221 *
1222 * Provides mechanism for the host driver to control the IOC's
1223 * Host Page Buffer access.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001224 *
1225 * Access Control Value - bits[15:12]
1226 * 0h Reserved
1227 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1228 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1229 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1230 *
1231 * Returns 0 for success, non-zero for failure.
1232 */
1233
1234static int
1235mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1236{
1237 int r = 0;
1238
1239 /* return if in use */
1240 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1241 & MPI_DOORBELL_ACTIVE)
1242 return -1;
1243
1244 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1245
1246 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1247 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1248 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1249 (access_control_value<<12)));
1250
1251 /* Wait for IOC to clear Doorbell Status bit */
1252 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1253 return -2;
1254 }else
1255 return 0;
1256}
1257
1258/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1259/**
1260 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001261 * @ioc: Pointer to pointer to IOC adapter
1262 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001263 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001264 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001265 * Returns 0 for success, non-zero for failure.
1266 */
1267static int
1268mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1269{
1270 char *psge;
1271 int flags_length;
1272 u32 host_page_buffer_sz=0;
1273
1274 if(!ioc->HostPageBuffer) {
1275
1276 host_page_buffer_sz =
1277 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1278
1279 if(!host_page_buffer_sz)
1280 return 0; /* fw doesn't need any host buffers */
1281
1282 /* spin till we get enough memory */
1283 while(host_page_buffer_sz > 0) {
1284
1285 if((ioc->HostPageBuffer = pci_alloc_consistent(
1286 ioc->pcidev,
1287 host_page_buffer_sz,
1288 &ioc->HostPageBuffer_dma)) != NULL) {
1289
Prakash, Sathya436ace72007-07-24 15:42:08 +05301290 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001291 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001292 ioc->name, ioc->HostPageBuffer,
1293 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001294 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001295 ioc->alloc_total += host_page_buffer_sz;
1296 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1297 break;
1298 }
1299
1300 host_page_buffer_sz -= (4*1024);
1301 }
1302 }
1303
1304 if(!ioc->HostPageBuffer) {
1305 printk(MYIOC_s_ERR_FMT
1306 "Failed to alloc memory for host_page_buffer!\n",
1307 ioc->name);
1308 return -999;
1309 }
1310
1311 psge = (char *)&ioc_init->HostPageBufferSGE;
1312 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1313 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1314 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1315 MPI_SGE_FLAGS_HOST_TO_IOC |
1316 MPI_SGE_FLAGS_END_OF_BUFFER;
1317 if (sizeof(dma_addr_t) == sizeof(u64)) {
1318 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1319 }
1320 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1321 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301322 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001323 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1324
1325return 0;
1326}
1327
1328/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1329/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001330 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 * @iocid: IOC unique identifier (integer)
1332 * @iocpp: Pointer to pointer to IOC adapter
1333 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001334 * Given a unique IOC identifier, set pointer to the associated MPT
1335 * adapter structure.
1336 *
1337 * Returns iocid and sets iocpp if iocid is found.
1338 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 */
1340int
1341mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1342{
1343 MPT_ADAPTER *ioc;
1344
1345 list_for_each_entry(ioc,&ioc_list,list) {
1346 if (ioc->id == iocid) {
1347 *iocpp =ioc;
1348 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001351
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 *iocpp = NULL;
1353 return -1;
1354}
1355
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301356/**
1357 * mpt_get_product_name - returns product string
1358 * @vendor: pci vendor id
1359 * @device: pci device id
1360 * @revision: pci revision id
1361 * @prod_name: string returned
1362 *
1363 * Returns product string displayed when driver loads,
1364 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1365 *
1366 **/
1367static void
1368mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1369{
1370 char *product_str = NULL;
1371
1372 if (vendor == PCI_VENDOR_ID_BROCADE) {
1373 switch (device)
1374 {
1375 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1376 switch (revision)
1377 {
1378 case 0x00:
1379 product_str = "BRE040 A0";
1380 break;
1381 case 0x01:
1382 product_str = "BRE040 A1";
1383 break;
1384 default:
1385 product_str = "BRE040";
1386 break;
1387 }
1388 break;
1389 }
1390 goto out;
1391 }
1392
1393 switch (device)
1394 {
1395 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1396 product_str = "LSIFC909 B1";
1397 break;
1398 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1399 product_str = "LSIFC919 B0";
1400 break;
1401 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1402 product_str = "LSIFC929 B0";
1403 break;
1404 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1405 if (revision < 0x80)
1406 product_str = "LSIFC919X A0";
1407 else
1408 product_str = "LSIFC919XL A1";
1409 break;
1410 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1411 if (revision < 0x80)
1412 product_str = "LSIFC929X A0";
1413 else
1414 product_str = "LSIFC929XL A1";
1415 break;
1416 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1417 product_str = "LSIFC939X A1";
1418 break;
1419 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1420 product_str = "LSIFC949X A1";
1421 break;
1422 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1423 switch (revision)
1424 {
1425 case 0x00:
1426 product_str = "LSIFC949E A0";
1427 break;
1428 case 0x01:
1429 product_str = "LSIFC949E A1";
1430 break;
1431 default:
1432 product_str = "LSIFC949E";
1433 break;
1434 }
1435 break;
1436 case MPI_MANUFACTPAGE_DEVID_53C1030:
1437 switch (revision)
1438 {
1439 case 0x00:
1440 product_str = "LSI53C1030 A0";
1441 break;
1442 case 0x01:
1443 product_str = "LSI53C1030 B0";
1444 break;
1445 case 0x03:
1446 product_str = "LSI53C1030 B1";
1447 break;
1448 case 0x07:
1449 product_str = "LSI53C1030 B2";
1450 break;
1451 case 0x08:
1452 product_str = "LSI53C1030 C0";
1453 break;
1454 case 0x80:
1455 product_str = "LSI53C1030T A0";
1456 break;
1457 case 0x83:
1458 product_str = "LSI53C1030T A2";
1459 break;
1460 case 0x87:
1461 product_str = "LSI53C1030T A3";
1462 break;
1463 case 0xc1:
1464 product_str = "LSI53C1020A A1";
1465 break;
1466 default:
1467 product_str = "LSI53C1030";
1468 break;
1469 }
1470 break;
1471 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1472 switch (revision)
1473 {
1474 case 0x03:
1475 product_str = "LSI53C1035 A2";
1476 break;
1477 case 0x04:
1478 product_str = "LSI53C1035 B0";
1479 break;
1480 default:
1481 product_str = "LSI53C1035";
1482 break;
1483 }
1484 break;
1485 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1486 switch (revision)
1487 {
1488 case 0x00:
1489 product_str = "LSISAS1064 A1";
1490 break;
1491 case 0x01:
1492 product_str = "LSISAS1064 A2";
1493 break;
1494 case 0x02:
1495 product_str = "LSISAS1064 A3";
1496 break;
1497 case 0x03:
1498 product_str = "LSISAS1064 A4";
1499 break;
1500 default:
1501 product_str = "LSISAS1064";
1502 break;
1503 }
1504 break;
1505 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1506 switch (revision)
1507 {
1508 case 0x00:
1509 product_str = "LSISAS1064E A0";
1510 break;
1511 case 0x01:
1512 product_str = "LSISAS1064E B0";
1513 break;
1514 case 0x02:
1515 product_str = "LSISAS1064E B1";
1516 break;
1517 case 0x04:
1518 product_str = "LSISAS1064E B2";
1519 break;
1520 case 0x08:
1521 product_str = "LSISAS1064E B3";
1522 break;
1523 default:
1524 product_str = "LSISAS1064E";
1525 break;
1526 }
1527 break;
1528 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1529 switch (revision)
1530 {
1531 case 0x00:
1532 product_str = "LSISAS1068 A0";
1533 break;
1534 case 0x01:
1535 product_str = "LSISAS1068 B0";
1536 break;
1537 case 0x02:
1538 product_str = "LSISAS1068 B1";
1539 break;
1540 default:
1541 product_str = "LSISAS1068";
1542 break;
1543 }
1544 break;
1545 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1546 switch (revision)
1547 {
1548 case 0x00:
1549 product_str = "LSISAS1068E A0";
1550 break;
1551 case 0x01:
1552 product_str = "LSISAS1068E B0";
1553 break;
1554 case 0x02:
1555 product_str = "LSISAS1068E B1";
1556 break;
1557 case 0x04:
1558 product_str = "LSISAS1068E B2";
1559 break;
1560 case 0x08:
1561 product_str = "LSISAS1068E B3";
1562 break;
1563 default:
1564 product_str = "LSISAS1068E";
1565 break;
1566 }
1567 break;
1568 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1569 switch (revision)
1570 {
1571 case 0x00:
1572 product_str = "LSISAS1078 A0";
1573 break;
1574 case 0x01:
1575 product_str = "LSISAS1078 B0";
1576 break;
1577 case 0x02:
1578 product_str = "LSISAS1078 C0";
1579 break;
1580 case 0x03:
1581 product_str = "LSISAS1078 C1";
1582 break;
1583 case 0x04:
1584 product_str = "LSISAS1078 C2";
1585 break;
1586 default:
1587 product_str = "LSISAS1078";
1588 break;
1589 }
1590 break;
1591 }
1592
1593 out:
1594 if (product_str)
1595 sprintf(prod_name, "%s", product_str);
1596}
1597
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301598/**
1599 * mpt_mapresources - map in memory mapped io
1600 * @ioc: Pointer to pointer to IOC adapter
1601 *
1602 **/
1603static int
1604mpt_mapresources(MPT_ADAPTER *ioc)
1605{
1606 u8 __iomem *mem;
1607 int ii;
1608 unsigned long mem_phys;
1609 unsigned long port;
1610 u32 msize;
1611 u32 psize;
1612 u8 revision;
1613 int r = -ENODEV;
1614 struct pci_dev *pdev;
1615
1616 pdev = ioc->pcidev;
1617 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1618 if (pci_enable_device_mem(pdev)) {
1619 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1620 "failed\n", ioc->name);
1621 return r;
1622 }
1623 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1624 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1625 "MEM failed\n", ioc->name);
1626 return r;
1627 }
1628
1629 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1630
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301631 if (sizeof(dma_addr_t) > 4) {
1632 const uint64_t required_mask = dma_get_required_mask
1633 (&pdev->dev);
1634 if (required_mask > DMA_BIT_MASK(32)
1635 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1636 && !pci_set_consistent_dma_mask(pdev,
1637 DMA_BIT_MASK(64))) {
1638 ioc->dma_mask = DMA_BIT_MASK(64);
1639 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1640 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1641 ioc->name));
1642 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1643 && !pci_set_consistent_dma_mask(pdev,
1644 DMA_BIT_MASK(32))) {
1645 ioc->dma_mask = DMA_BIT_MASK(32);
1646 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1647 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1648 ioc->name));
1649 } else {
1650 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1651 ioc->name, pci_name(pdev));
1652 return r;
1653 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301654 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301655 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1656 && !pci_set_consistent_dma_mask(pdev,
1657 DMA_BIT_MASK(32))) {
1658 ioc->dma_mask = DMA_BIT_MASK(32);
1659 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1660 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1661 ioc->name));
1662 } else {
1663 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1664 ioc->name, pci_name(pdev));
1665 return r;
1666 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301667 }
1668
1669 mem_phys = msize = 0;
1670 port = psize = 0;
1671 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1672 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1673 if (psize)
1674 continue;
1675 /* Get I/O space! */
1676 port = pci_resource_start(pdev, ii);
1677 psize = pci_resource_len(pdev, ii);
1678 } else {
1679 if (msize)
1680 continue;
1681 /* Get memmap */
1682 mem_phys = pci_resource_start(pdev, ii);
1683 msize = pci_resource_len(pdev, ii);
1684 }
1685 }
1686 ioc->mem_size = msize;
1687
1688 mem = NULL;
1689 /* Get logical ptr for PciMem0 space */
1690 /*mem = ioremap(mem_phys, msize);*/
1691 mem = ioremap(mem_phys, msize);
1692 if (mem == NULL) {
1693 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1694 " memory!\n", ioc->name);
1695 return -EINVAL;
1696 }
1697 ioc->memmap = mem;
1698 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1699 ioc->name, mem, mem_phys));
1700
1701 ioc->mem_phys = mem_phys;
1702 ioc->chip = (SYSIF_REGS __iomem *)mem;
1703
1704 /* Save Port IO values in case we need to do downloadboot */
1705 ioc->pio_mem_phys = port;
1706 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1707
1708 return 0;
1709}
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001712/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001713 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001715 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 *
1717 * This routine performs all the steps necessary to bring the IOC of
1718 * a MPT adapter to a OPERATIONAL state. This includes registering
1719 * memory regions, registering the interrupt, and allocating request
1720 * and reply memory pools.
1721 *
1722 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1723 * MPT adapter.
1724 *
1725 * Returns 0 for success, non-zero for failure.
1726 *
1727 * TODO: Add support for polled controllers
1728 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001729int
1730mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
1732 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301733 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 u8 revision;
1736 u8 pcixcmd;
1737 static int mpt_ids = 0;
1738#ifdef CONFIG_PROC_FS
1739 struct proc_dir_entry *dent, *ent;
1740#endif
1741
Jesper Juhl56876192007-08-10 14:50:51 -07001742 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1743 if (ioc == NULL) {
1744 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1745 return -ENOMEM;
1746 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301747
Eric Moore29dd3602007-09-14 18:46:51 -06001748 ioc->id = mpt_ids++;
1749 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001750
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301751 /*
1752 * set initial debug level
1753 * (refer to mptdebug.h)
1754 *
1755 */
1756 ioc->debug_level = mpt_debug_level;
1757 if (mpt_debug_level)
1758 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301759
Eric Moore29dd3602007-09-14 18:46:51 -06001760 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001761
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301762 ioc->pcidev = pdev;
1763 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001764 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 return r;
1766 }
1767
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301768 /*
1769 * Setting up proper handlers for scatter gather handling
1770 */
1771 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1772 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1773 ioc->add_sge = &mpt_add_sge_64bit_1078;
1774 else
1775 ioc->add_sge = &mpt_add_sge_64bit;
1776 ioc->add_chain = &mpt_add_chain_64bit;
1777 ioc->sg_addr_size = 8;
1778 } else {
1779 ioc->add_sge = &mpt_add_sge;
1780 ioc->add_chain = &mpt_add_chain;
1781 ioc->sg_addr_size = 4;
1782 }
1783 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 ioc->alloc_total = sizeof(MPT_ADAPTER);
1786 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1787 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 ioc->pcidev = pdev;
1790 ioc->diagPending = 0;
1791 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001792 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
1794 /* Initialize the event logging.
1795 */
1796 ioc->eventTypes = 0; /* None */
1797 ioc->eventContext = 0;
1798 ioc->eventLogSize = 0;
1799 ioc->events = NULL;
1800
1801#ifdef MFCNT
1802 ioc->mfcnt = 0;
1803#endif
1804
1805 ioc->cached_fw = NULL;
1806
1807 /* Initilize SCSI Config Data structure
1808 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001809 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
1811 /* Initialize the running configQ head.
1812 */
1813 INIT_LIST_HEAD(&ioc->configQ);
1814
Michael Reed05e8ec12006-01-13 14:31:54 -06001815 /* Initialize the fc rport list head.
1816 */
1817 INIT_LIST_HEAD(&ioc->fc_rports);
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* Find lookup slot. */
1820 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001821
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301822
1823 /* Initialize workqueue */
1824 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1825 spin_lock_init(&ioc->fault_reset_work_lock);
1826
Kay Sieversaab0de22008-05-02 06:02:41 +02001827 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1828 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301829 ioc->reset_work_q =
1830 create_singlethread_workqueue(ioc->reset_work_q_name);
1831 if (!ioc->reset_work_q) {
1832 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1833 ioc->name);
1834 pci_release_selected_regions(pdev, ioc->bars);
1835 kfree(ioc);
1836 return -ENOMEM;
1837 }
1838
Eric Moore29dd3602007-09-14 18:46:51 -06001839 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1840 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301842 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1843 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1844
1845 switch (pdev->device)
1846 {
1847 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1848 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1849 ioc->errata_flag_1064 = 1;
1850 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1851 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1852 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1853 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301855 break;
1856
1857 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* 929X Chip Fix. Set Split transactions level
1860 * for PCIX. Set MOST bits to zero.
1861 */
1862 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1863 pcixcmd &= 0x8F;
1864 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1865 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 /* 929XL Chip Fix. Set MMRBC to 0x08.
1867 */
1868 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1869 pcixcmd |= 0x08;
1870 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301873 break;
1874
1875 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 /* 919X Chip Fix. Set Split transactions level
1877 * for PCIX. Set MOST bits to zero.
1878 */
1879 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1880 pcixcmd &= 0x8F;
1881 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001882 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883 break;
1884
1885 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 /* 1030 Chip Fix. Disable Split transactions
1887 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1888 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (revision < C0_1030) {
1890 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1891 pcixcmd &= 0x8F;
1892 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1893 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301894
1895 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001896 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301897 break;
1898
1899 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1900 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001901 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301902
1903 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1904 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1905 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001906 ioc->bus_type = SAS;
1907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301909
Kashyap, Desaie3829682009-01-08 14:27:16 +05301910 switch (ioc->bus_type) {
1911
1912 case SAS:
1913 ioc->msi_enable = mpt_msi_enable_sas;
1914 break;
1915
1916 case SPI:
1917 ioc->msi_enable = mpt_msi_enable_spi;
1918 break;
1919
1920 case FC:
1921 ioc->msi_enable = mpt_msi_enable_fc;
1922 break;
1923
1924 default:
1925 ioc->msi_enable = 0;
1926 break;
1927 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001928 if (ioc->errata_flag_1064)
1929 pci_disable_io_access(pdev);
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 spin_lock_init(&ioc->FreeQlock);
1932
1933 /* Disable all! */
1934 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1935 ioc->active = 0;
1936 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1937
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301938 /* Set IOC ptr in the pcidev's driver data. */
1939 pci_set_drvdata(ioc->pcidev, ioc);
1940
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 /* Set lookup ptr. */
1942 list_add_tail(&ioc->list, &ioc_list);
1943
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001944 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 */
1946 mpt_detect_bound_ports(ioc, pdev);
1947
James Bottomleyc92f2222006-03-01 09:02:49 -06001948 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1949 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001950 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1951 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001954 if (ioc->alt_ioc)
1955 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301956 iounmap(ioc->memmap);
1957 if (r != -5)
1958 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301959
1960 destroy_workqueue(ioc->reset_work_q);
1961 ioc->reset_work_q = NULL;
1962
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 kfree(ioc);
1964 pci_set_drvdata(pdev, NULL);
1965 return r;
1966 }
1967
1968 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001969 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301970 if(MptDeviceDriverHandlers[cb_idx] &&
1971 MptDeviceDriverHandlers[cb_idx]->probe) {
1972 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 }
1974 }
1975
1976#ifdef CONFIG_PROC_FS
1977 /*
1978 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1979 */
1980 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1981 if (dent) {
1982 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1983 if (ent) {
1984 ent->read_proc = procmpt_iocinfo_read;
1985 ent->data = ioc;
1986 }
1987 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1988 if (ent) {
1989 ent->read_proc = procmpt_summary_read;
1990 ent->data = ioc;
1991 }
1992 }
1993#endif
1994
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301995 if (!ioc->alt_ioc)
1996 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1997 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return 0;
2000}
2001
2002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002003/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002004 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 */
2007
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002008void
2009mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
2011 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2012 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302013 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302014 unsigned long flags;
2015 struct workqueue_struct *wq;
2016
2017 /*
2018 * Stop polling ioc for fault condition
2019 */
2020 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2021 wq = ioc->reset_work_q;
2022 ioc->reset_work_q = NULL;
2023 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2024 cancel_delayed_work(&ioc->fault_reset_work);
2025 destroy_workqueue(wq);
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2029 remove_proc_entry(pname, NULL);
2030 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2031 remove_proc_entry(pname, NULL);
2032 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2033 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002036 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302037 if(MptDeviceDriverHandlers[cb_idx] &&
2038 MptDeviceDriverHandlers[cb_idx]->remove) {
2039 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
2041 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 /* Disable interrupts! */
2044 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2045
2046 ioc->active = 0;
2047 synchronize_irq(pdev->irq);
2048
2049 /* Clear any lingering interrupt */
2050 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2051
2052 CHIPREG_READ32(&ioc->chip->IntStatus);
2053
2054 mpt_adapter_dispose(ioc);
2055
2056 pci_set_drvdata(pdev, NULL);
2057}
2058
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059/**************************************************************************
2060 * Power Management
2061 */
2062#ifdef CONFIG_PM
2063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002064/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002065 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002066 * @pdev: Pointer to pci_dev structure
2067 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002069int
2070mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071{
2072 u32 device_state;
2073 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302075 device_state = pci_choose_state(pdev, state);
2076 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2077 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2078 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 /* put ioc into READY_STATE */
2081 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2082 printk(MYIOC_s_ERR_FMT
2083 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2084 }
2085
2086 /* disable interrupts */
2087 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2088 ioc->active = 0;
2089
2090 /* Clear any lingering interrupt */
2091 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2092
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302093 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002094 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302095 pci_disable_msi(ioc->pcidev);
2096 ioc->pci_irq = -1;
2097 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302099 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 return 0;
2102}
2103
2104/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002105/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002106 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002107 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002109int
2110mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111{
2112 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2113 u32 device_state = pdev->current_state;
2114 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302115 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002116
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302117 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2118 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2119 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302121 pci_set_power_state(pdev, PCI_D0);
2122 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302124 ioc->pcidev = pdev;
2125 err = mpt_mapresources(ioc);
2126 if (err)
2127 return err;
2128
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302129 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2130 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2131 ioc->add_sge = &mpt_add_sge_64bit_1078;
2132 else
2133 ioc->add_sge = &mpt_add_sge_64bit;
2134 ioc->add_chain = &mpt_add_chain_64bit;
2135 ioc->sg_addr_size = 8;
2136 } else {
2137
2138 ioc->add_sge = &mpt_add_sge;
2139 ioc->add_chain = &mpt_add_chain;
2140 ioc->sg_addr_size = 4;
2141 }
2142 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2143
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302144 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2145 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2146 CHIPREG_READ32(&ioc->chip->Doorbell));
2147
2148 /*
2149 * Errata workaround for SAS pci express:
2150 * Upon returning to the D0 state, the contents of the doorbell will be
2151 * stale data, and this will incorrectly signal to the host driver that
2152 * the firmware is ready to process mpt commands. The workaround is
2153 * to issue a diagnostic reset.
2154 */
2155 if (ioc->bus_type == SAS && (pdev->device ==
2156 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2157 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2158 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2159 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2160 ioc->name);
2161 goto out;
2162 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
2165 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302166 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2167 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2168 CAN_SLEEP);
2169 if (recovery_state != 0)
2170 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2171 "error:[%x]\n", ioc->name, recovery_state);
2172 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302174 "pci-resume: success\n", ioc->name);
2175 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178}
2179#endif
2180
James Bottomley4ff42a62006-05-17 18:06:52 -05002181static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302182mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002183{
2184 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2185 ioc->bus_type != SPI) ||
2186 (MptDriverClass[index] == MPTFC_DRIVER &&
2187 ioc->bus_type != FC) ||
2188 (MptDriverClass[index] == MPTSAS_DRIVER &&
2189 ioc->bus_type != SAS))
2190 /* make sure we only call the relevant reset handler
2191 * for the bus */
2192 return 0;
2193 return (MptResetHandlers[index])(ioc, reset_phase);
2194}
2195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002197/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2199 * @ioc: Pointer to MPT adapter structure
2200 * @reason: Event word / reason
2201 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2202 *
2203 * This routine performs all the steps necessary to bring the IOC
2204 * to a OPERATIONAL state.
2205 *
2206 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2207 * MPT adapter.
2208 *
2209 * Returns:
2210 * 0 for success
2211 * -1 if failed to get board READY
2212 * -2 if READY but IOCFacts Failed
2213 * -3 if READY but PrimeIOCFifos Failed
2214 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302215 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302216 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 */
2218static int
2219mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2220{
2221 int hard_reset_done = 0;
2222 int alt_ioc_ready = 0;
2223 int hard;
2224 int rc=0;
2225 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302226 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 int handlers;
2228 int ret = 0;
2229 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002230 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302231 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Eric Moore29dd3602007-09-14 18:46:51 -06002233 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2234 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
2236 /* Disable reply interrupts (also blocks FreeQ) */
2237 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2238 ioc->active = 0;
2239
2240 if (ioc->alt_ioc) {
2241 if (ioc->alt_ioc->active)
2242 reset_alt_ioc_active = 1;
2243
2244 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2245 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2246 ioc->alt_ioc->active = 0;
2247 }
2248
2249 hard = 1;
2250 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2251 hard = 0;
2252
2253 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2254 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002255 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2256 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
2258 if (reset_alt_ioc_active && ioc->alt_ioc) {
2259 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002260 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2261 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002262 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 ioc->alt_ioc->active = 1;
2264 }
2265
2266 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002267 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269 return -1;
2270 }
2271
2272 /* hard_reset_done = 0 if a soft reset was performed
2273 * and 1 if a hard reset was performed.
2274 */
2275 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2276 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2277 alt_ioc_ready = 1;
2278 else
Eric Moore29dd3602007-09-14 18:46:51 -06002279 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 }
2281
2282 for (ii=0; ii<5; ii++) {
2283 /* Get IOC facts! Allow 5 retries */
2284 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2285 break;
2286 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002290 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2291 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 ret = -2;
2293 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2294 MptDisplayIocCapabilities(ioc);
2295 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 if (alt_ioc_ready) {
2298 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302299 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002300 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 /* Retry - alt IOC was initialized once
2302 */
2303 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2304 }
2305 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302306 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002307 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 alt_ioc_ready = 0;
2309 reset_alt_ioc_active = 0;
2310 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2311 MptDisplayIocCapabilities(ioc->alt_ioc);
2312 }
2313 }
2314
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302315 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2316 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2317 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2318 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2319 IORESOURCE_IO);
2320 if (pci_enable_device(ioc->pcidev))
2321 return -5;
2322 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2323 "mpt"))
2324 return -5;
2325 }
2326
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002327 /*
2328 * Device is reset now. It must have de-asserted the interrupt line
2329 * (if it was asserted) and it should be safe to register for the
2330 * interrupt now.
2331 */
2332 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2333 ioc->pci_irq = -1;
2334 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302335 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002336 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002337 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302338 else
2339 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002340 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002341 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002342 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002343 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002344 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302345 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002346 pci_disable_msi(ioc->pcidev);
2347 return -EBUSY;
2348 }
2349 irq_allocated = 1;
2350 ioc->pci_irq = ioc->pcidev->irq;
2351 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002352 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2353 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 }
2355 }
2356
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 /* Prime reply & request queues!
2358 * (mucho alloc's) Must be done prior to
2359 * init as upper addresses are needed for init.
2360 * If fails, continue with alt-ioc processing
2361 */
2362 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2363 ret = -3;
2364
2365 /* May need to check/upload firmware & data here!
2366 * If fails, continue with alt-ioc processing
2367 */
2368 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2369 ret = -4;
2370// NEW!
2371 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002372 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2373 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 alt_ioc_ready = 0;
2375 reset_alt_ioc_active = 0;
2376 }
2377
2378 if (alt_ioc_ready) {
2379 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2380 alt_ioc_ready = 0;
2381 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002382 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2383 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 }
2385 }
2386
2387 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2388 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302389 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002390 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
2392 /* Controller is not operational, cannot do upload
2393 */
2394 if (ret == 0) {
2395 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002396 if (rc == 0) {
2397 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2398 /*
2399 * Maintain only one pointer to FW memory
2400 * so there will not be two attempt to
2401 * downloadboot onboard dual function
2402 * chips (mpt_adapter_disable,
2403 * mpt_diag_reset)
2404 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302405 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002406 "mpt_upload: alt_%s has cached_fw=%p \n",
2407 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302408 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002409 }
2410 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002411 printk(MYIOC_s_WARN_FMT
2412 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302413 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 }
2416 }
2417 }
2418
2419 if (ret == 0) {
2420 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002421 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 ioc->active = 1;
2423 }
2424
2425 if (reset_alt_ioc_active && ioc->alt_ioc) {
2426 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002427 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2428 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002429 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 ioc->alt_ioc->active = 1;
2431 }
2432
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002433 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 * and EventAck handling.
2435 */
2436 if ((ret == 0) && (!ioc->facts.EventState))
2437 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2438
2439 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2440 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2441
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002442 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2444 * recursive scenario; GetLanConfigPages times out, timer expired
2445 * routine calls HardResetHandler, which calls into here again,
2446 * and we try GetLanConfigPages again...
2447 */
2448 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002449
2450 /*
2451 * Initalize link list for inactive raid volumes.
2452 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002453 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002454 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2455
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002456 if (ioc->bus_type == SAS) {
2457
2458 /* clear persistency table */
2459 if(ioc->facts.IOCExceptions &
2460 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2461 ret = mptbase_sas_persist_operation(ioc,
2462 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2463 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002464 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002465 }
2466
2467 /* Find IM volumes
2468 */
2469 mpt_findImVolumes(ioc);
2470
2471 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2473 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2474 /*
2475 * Pre-fetch the ports LAN MAC address!
2476 * (LANPage1_t stuff)
2477 */
2478 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302479 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2480 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002481 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2482 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302483
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 } else {
2486 /* Get NVRAM and adapter maximums from SPP 0 and 2
2487 */
2488 mpt_GetScsiPortSettings(ioc, 0);
2489
2490 /* Get version and length of SDP 1
2491 */
2492 mpt_readScsiDevicePageHeaders(ioc, 0);
2493
2494 /* Find IM volumes
2495 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002496 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 mpt_findImVolumes(ioc);
2498
2499 /* Check, and possibly reset, the coalescing value
2500 */
2501 mpt_read_ioc_pg_1(ioc);
2502
2503 mpt_read_ioc_pg_4(ioc);
2504 }
2505
2506 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302507 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
2509
2510 /*
2511 * Call each currently registered protocol IOC reset handler
2512 * with post-reset indication.
2513 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2514 * MptResetHandlers[] registered yet.
2515 */
2516 if (hard_reset_done) {
2517 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302518 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2519 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302520 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002521 "Calling IOC post_reset handler #%d\n",
2522 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302523 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 handlers++;
2525 }
2526
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302527 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302528 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002529 "Calling IOC post_reset handler #%d\n",
2530 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302531 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 handlers++;
2533 }
2534 }
2535 /* FIXME? Examine results here? */
2536 }
2537
Eric Moore0ccdb002006-07-11 17:33:13 -06002538 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002539 if ((ret != 0) && irq_allocated) {
2540 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302541 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002542 pci_disable_msi(ioc->pcidev);
2543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 return ret;
2545}
2546
2547/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002548/**
2549 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 * @ioc: Pointer to MPT adapter structure
2551 * @pdev: Pointer to (struct pci_dev) structure
2552 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002553 * Search for PCI bus/dev_function which matches
2554 * PCI bus/dev_function (+/-1) for newly discovered 929,
2555 * 929X, 1030 or 1035.
2556 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2558 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2559 */
2560static void
2561mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2562{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002563 struct pci_dev *peer=NULL;
2564 unsigned int slot = PCI_SLOT(pdev->devfn);
2565 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 MPT_ADAPTER *ioc_srch;
2567
Prakash, Sathya436ace72007-07-24 15:42:08 +05302568 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002569 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002570 ioc->name, pci_name(pdev), pdev->bus->number,
2571 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002572
2573 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2574 if (!peer) {
2575 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2576 if (!peer)
2577 return;
2578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 list_for_each_entry(ioc_srch, &ioc_list, list) {
2581 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002582 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 /* Paranoia checks */
2584 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002585 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002586 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 break;
2588 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002589 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002590 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 break;
2592 }
Eric Moore29dd3602007-09-14 18:46:51 -06002593 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002594 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 ioc_srch->alt_ioc = ioc;
2596 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 }
2598 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002599 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600}
2601
2602/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002603/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002605 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 */
2607static void
2608mpt_adapter_disable(MPT_ADAPTER *ioc)
2609{
2610 int sz;
2611 int ret;
2612
2613 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302614 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002615 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302616 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2617 ioc->cached_fw, CAN_SLEEP)) < 0) {
2618 printk(MYIOC_s_WARN_FMT
2619 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002620 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 }
2622 }
2623
2624 /* Disable adapter interrupts! */
2625 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2626 ioc->active = 0;
2627 /* Clear any lingering interrupt */
2628 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2629
2630 if (ioc->alloc != NULL) {
2631 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002632 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2633 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 pci_free_consistent(ioc->pcidev, sz,
2635 ioc->alloc, ioc->alloc_dma);
2636 ioc->reply_frames = NULL;
2637 ioc->req_frames = NULL;
2638 ioc->alloc = NULL;
2639 ioc->alloc_total -= sz;
2640 }
2641
2642 if (ioc->sense_buf_pool != NULL) {
2643 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2644 pci_free_consistent(ioc->pcidev, sz,
2645 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2646 ioc->sense_buf_pool = NULL;
2647 ioc->alloc_total -= sz;
2648 }
2649
2650 if (ioc->events != NULL){
2651 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2652 kfree(ioc->events);
2653 ioc->events = NULL;
2654 ioc->alloc_total -= sz;
2655 }
2656
Prakash, Sathya984621b2008-01-11 14:42:17 +05302657 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002659 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002660 mpt_inactive_raid_list_free(ioc);
2661 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002662 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002663 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002664 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
2666 if (ioc->spi_data.pIocPg4 != NULL) {
2667 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302668 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 ioc->spi_data.pIocPg4,
2670 ioc->spi_data.IocPg4_dma);
2671 ioc->spi_data.pIocPg4 = NULL;
2672 ioc->alloc_total -= sz;
2673 }
2674
2675 if (ioc->ReqToChain != NULL) {
2676 kfree(ioc->ReqToChain);
2677 kfree(ioc->RequestNB);
2678 ioc->ReqToChain = NULL;
2679 }
2680
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002681 kfree(ioc->ChainToChain);
2682 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002683
2684 if (ioc->HostPageBuffer != NULL) {
2685 if((ret = mpt_host_page_access_control(ioc,
2686 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002687 printk(MYIOC_s_ERR_FMT
2688 "host page buffers free failed (%d)!\n",
2689 ioc->name, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002690 }
Eric Moore29dd3602007-09-14 18:46:51 -06002691 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002692 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2693 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002694 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002695 ioc->HostPageBuffer = NULL;
2696 ioc->HostPageBuffer_sz = 0;
2697 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699}
2700
2701/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002702/**
2703 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 * @ioc: Pointer to MPT adapter structure
2705 *
2706 * This routine unregisters h/w resources and frees all alloc'd memory
2707 * associated with a MPT adapter structure.
2708 */
2709static void
2710mpt_adapter_dispose(MPT_ADAPTER *ioc)
2711{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002712 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002714 if (ioc == NULL)
2715 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002717 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002719 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002721 if (ioc->pci_irq != -1) {
2722 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302723 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002724 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002725 ioc->pci_irq = -1;
2726 }
2727
2728 if (ioc->memmap != NULL) {
2729 iounmap(ioc->memmap);
2730 ioc->memmap = NULL;
2731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302733 pci_disable_device(ioc->pcidev);
2734 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2735
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002737 if (ioc->mtrr_reg > 0) {
2738 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002739 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741#endif
2742
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002743 /* Zap the adapter lookup ptr! */
2744 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002746 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002747 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2748 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002749
2750 if (ioc->alt_ioc)
2751 ioc->alt_ioc->alt_ioc = NULL;
2752
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002753 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754}
2755
2756/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002757/**
2758 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 * @ioc: Pointer to MPT adapter structure
2760 */
2761static void
2762MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2763{
2764 int i = 0;
2765
2766 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302767 if (ioc->prod_name)
2768 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 printk("Capabilities={");
2770
2771 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2772 printk("Initiator");
2773 i++;
2774 }
2775
2776 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2777 printk("%sTarget", i ? "," : "");
2778 i++;
2779 }
2780
2781 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2782 printk("%sLAN", i ? "," : "");
2783 i++;
2784 }
2785
2786#if 0
2787 /*
2788 * This would probably evoke more questions than it's worth
2789 */
2790 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2791 printk("%sLogBusAddr", i ? "," : "");
2792 i++;
2793 }
2794#endif
2795
2796 printk("}\n");
2797}
2798
2799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002800/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2802 * @ioc: Pointer to MPT_ADAPTER structure
2803 * @force: Force hard KickStart of IOC
2804 * @sleepFlag: Specifies whether the process can sleep
2805 *
2806 * Returns:
2807 * 1 - DIAG reset and READY
2808 * 0 - READY initially OR soft reset and READY
2809 * -1 - Any failure on KickStart
2810 * -2 - Msg Unit Reset Failed
2811 * -3 - IO Unit Reset Failed
2812 * -4 - IOC owned by a PEER
2813 */
2814static int
2815MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2816{
2817 u32 ioc_state;
2818 int statefault = 0;
2819 int cntdn;
2820 int hard_reset_done = 0;
2821 int r;
2822 int ii;
2823 int whoinit;
2824
2825 /* Get current [raw] IOC state */
2826 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002827 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
2829 /*
2830 * Check to see if IOC got left/stuck in doorbell handshake
2831 * grip of death. If so, hard reset the IOC.
2832 */
2833 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2834 statefault = 1;
2835 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2836 ioc->name);
2837 }
2838
2839 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002840 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 return 0;
2842
2843 /*
2844 * Check to see if IOC is in FAULT state.
2845 */
2846 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2847 statefault = 2;
2848 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002849 ioc->name);
2850 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2851 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 }
2853
2854 /*
2855 * Hmmm... Did it get left operational?
2856 */
2857 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302858 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 ioc->name));
2860
2861 /* Check WhoInit.
2862 * If PCI Peer, exit.
2863 * Else, if no fault conditions are present, issue a MessageUnitReset
2864 * Else, fall through to KickStart case
2865 */
2866 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002867 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2868 "whoinit 0x%x statefault %d force %d\n",
2869 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 if (whoinit == MPI_WHOINIT_PCI_PEER)
2871 return -4;
2872 else {
2873 if ((statefault == 0 ) && (force == 0)) {
2874 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2875 return 0;
2876 }
2877 statefault = 3;
2878 }
2879 }
2880
2881 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2882 if (hard_reset_done < 0)
2883 return -1;
2884
2885 /*
2886 * Loop here waiting for IOC to come READY.
2887 */
2888 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002889 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
2891 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2892 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2893 /*
2894 * BIOS or previous driver load left IOC in OP state.
2895 * Reset messaging FIFOs.
2896 */
2897 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2898 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2899 return -2;
2900 }
2901 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2902 /*
2903 * Something is wrong. Try to get IOC back
2904 * to a known state.
2905 */
2906 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2907 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2908 return -3;
2909 }
2910 }
2911
2912 ii++; cntdn--;
2913 if (!cntdn) {
2914 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2915 ioc->name, (int)((ii+5)/HZ));
2916 return -ETIME;
2917 }
2918
2919 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002920 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 } else {
2922 mdelay (1); /* 1 msec delay */
2923 }
2924
2925 }
2926
2927 if (statefault < 3) {
2928 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2929 ioc->name,
2930 statefault==1 ? "stuck handshake" : "IOC FAULT");
2931 }
2932
2933 return hard_reset_done;
2934}
2935
2936/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002937/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 * mpt_GetIocState - Get the current state of a MPT adapter.
2939 * @ioc: Pointer to MPT_ADAPTER structure
2940 * @cooked: Request raw or cooked IOC state
2941 *
2942 * Returns all IOC Doorbell register bits if cooked==0, else just the
2943 * Doorbell bits in MPI_IOC_STATE_MASK.
2944 */
2945u32
2946mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2947{
2948 u32 s, sc;
2949
2950 /* Get! */
2951 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 sc = s & MPI_IOC_STATE_MASK;
2953
2954 /* Save! */
2955 ioc->last_state = sc;
2956
2957 return cooked ? sc : s;
2958}
2959
2960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002961/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 * GetIocFacts - Send IOCFacts request to MPT adapter.
2963 * @ioc: Pointer to MPT_ADAPTER structure
2964 * @sleepFlag: Specifies whether the process can sleep
2965 * @reason: If recovery, only update facts.
2966 *
2967 * Returns 0 for success, non-zero for failure.
2968 */
2969static int
2970GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2971{
2972 IOCFacts_t get_facts;
2973 IOCFactsReply_t *facts;
2974 int r;
2975 int req_sz;
2976 int reply_sz;
2977 int sz;
2978 u32 status, vv;
2979 u8 shiftFactor=1;
2980
2981 /* IOC *must* NOT be in RESET state! */
2982 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002983 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2984 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 return -44;
2986 }
2987
2988 facts = &ioc->facts;
2989
2990 /* Destination (reply area)... */
2991 reply_sz = sizeof(*facts);
2992 memset(facts, 0, reply_sz);
2993
2994 /* Request area (get_facts on the stack right now!) */
2995 req_sz = sizeof(get_facts);
2996 memset(&get_facts, 0, req_sz);
2997
2998 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2999 /* Assert: All other get_facts fields are zero! */
3000
Prakash, Sathya436ace72007-07-24 15:42:08 +05303001 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003002 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 ioc->name, req_sz, reply_sz));
3004
3005 /* No non-zero fields in the get_facts request are greater than
3006 * 1 byte in size, so we can just fire it off as is.
3007 */
3008 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3009 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3010 if (r != 0)
3011 return r;
3012
3013 /*
3014 * Now byte swap (GRRR) the necessary fields before any further
3015 * inspection of reply contents.
3016 *
3017 * But need to do some sanity checks on MsgLength (byte) field
3018 * to make sure we don't zero IOC's req_sz!
3019 */
3020 /* Did we get a valid reply? */
3021 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3022 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3023 /*
3024 * If not been here, done that, save off first WhoInit value
3025 */
3026 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3027 ioc->FirstWhoInit = facts->WhoInit;
3028 }
3029
3030 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3031 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3032 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3033 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3034 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003035 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 /* CHECKME! IOCStatus, IOCLogInfo */
3037
3038 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3039 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3040
3041 /*
3042 * FC f/w version changed between 1.1 and 1.2
3043 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3044 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3045 */
3046 if (facts->MsgVersion < 0x0102) {
3047 /*
3048 * Handle old FC f/w style, convert to new...
3049 */
3050 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3051 facts->FWVersion.Word =
3052 ((oldv<<12) & 0xFF000000) |
3053 ((oldv<<8) & 0x000FFF00);
3054 } else
3055 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3056
3057 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003058 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3059 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3060 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 facts->CurrentHostMfaHighAddr =
3062 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3063 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3064 facts->CurrentSenseBufferHighAddr =
3065 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3066 facts->CurReplyFrameSize =
3067 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003068 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
3070 /*
3071 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3072 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3073 * to 14 in MPI-1.01.0x.
3074 */
3075 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3076 facts->MsgVersion > 0x0100) {
3077 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3078 }
3079
3080 sz = facts->FWImageSize;
3081 if ( sz & 0x01 )
3082 sz += 1;
3083 if ( sz & 0x02 )
3084 sz += 2;
3085 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003086
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 if (!facts->RequestFrameSize) {
3088 /* Something is wrong! */
3089 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3090 ioc->name);
3091 return -55;
3092 }
3093
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003094 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 vv = ((63 / (sz * 4)) + 1) & 0x03;
3096 ioc->NB_for_64_byte_frame = vv;
3097 while ( sz )
3098 {
3099 shiftFactor++;
3100 sz = sz >> 1;
3101 }
3102 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303103 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003104 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3105 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003106
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3108 /*
3109 * Set values for this IOC's request & reply frame sizes,
3110 * and request & reply queue depths...
3111 */
3112 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3113 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3114 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3115 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3116
Prakash, Sathya436ace72007-07-24 15:42:08 +05303117 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303119 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 ioc->name, ioc->req_sz, ioc->req_depth));
3121
3122 /* Get port facts! */
3123 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3124 return r;
3125 }
3126 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003127 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3129 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3130 RequestFrameSize)/sizeof(u32)));
3131 return -66;
3132 }
3133
3134 return 0;
3135}
3136
3137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003138/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 * GetPortFacts - Send PortFacts request to MPT adapter.
3140 * @ioc: Pointer to MPT_ADAPTER structure
3141 * @portnum: Port number
3142 * @sleepFlag: Specifies whether the process can sleep
3143 *
3144 * Returns 0 for success, non-zero for failure.
3145 */
3146static int
3147GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3148{
3149 PortFacts_t get_pfacts;
3150 PortFactsReply_t *pfacts;
3151 int ii;
3152 int req_sz;
3153 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003154 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156 /* IOC *must* NOT be in RESET state! */
3157 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003158 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3159 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 return -4;
3161 }
3162
3163 pfacts = &ioc->pfacts[portnum];
3164
3165 /* Destination (reply area)... */
3166 reply_sz = sizeof(*pfacts);
3167 memset(pfacts, 0, reply_sz);
3168
3169 /* Request area (get_pfacts on the stack right now!) */
3170 req_sz = sizeof(get_pfacts);
3171 memset(&get_pfacts, 0, req_sz);
3172
3173 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3174 get_pfacts.PortNumber = portnum;
3175 /* Assert: All other get_pfacts fields are zero! */
3176
Prakash, Sathya436ace72007-07-24 15:42:08 +05303177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 ioc->name, portnum));
3179
3180 /* No non-zero fields in the get_pfacts request are greater than
3181 * 1 byte in size, so we can just fire it off as is.
3182 */
3183 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3184 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3185 if (ii != 0)
3186 return ii;
3187
3188 /* Did we get a valid reply? */
3189
3190 /* Now byte swap the necessary fields in the response. */
3191 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3192 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3193 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3194 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3195 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3196 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3197 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3198 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3199 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3200
Eric Moore793955f2007-01-29 09:42:20 -07003201 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3202 pfacts->MaxDevices;
3203 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3204 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3205
3206 /*
3207 * Place all the devices on channels
3208 *
3209 * (for debuging)
3210 */
3211 if (mpt_channel_mapping) {
3212 ioc->devices_per_bus = 1;
3213 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3214 }
3215
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 return 0;
3217}
3218
3219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003220/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 * SendIocInit - Send IOCInit request to MPT adapter.
3222 * @ioc: Pointer to MPT_ADAPTER structure
3223 * @sleepFlag: Specifies whether the process can sleep
3224 *
3225 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3226 *
3227 * Returns 0 for success, non-zero for failure.
3228 */
3229static int
3230SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3231{
3232 IOCInit_t ioc_init;
3233 MPIDefaultReply_t init_reply;
3234 u32 state;
3235 int r;
3236 int count;
3237 int cntdn;
3238
3239 memset(&ioc_init, 0, sizeof(ioc_init));
3240 memset(&init_reply, 0, sizeof(init_reply));
3241
3242 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3243 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3244
3245 /* If we are in a recovery mode and we uploaded the FW image,
3246 * then this pointer is not NULL. Skip the upload a second time.
3247 * Set this flag if cached_fw set for either IOC.
3248 */
3249 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3250 ioc->upload_fw = 1;
3251 else
3252 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303253 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3255
Eric Moore793955f2007-01-29 09:42:20 -07003256 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3257 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303258 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003259 ioc->name, ioc->facts.MsgVersion));
3260 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3261 // set MsgVersion and HeaderVersion host driver was built with
3262 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3263 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003265 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3266 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3267 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3268 return -99;
3269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3271
3272 if (sizeof(dma_addr_t) == sizeof(u64)) {
3273 /* Save the upper 32-bits of the request
3274 * (reply) and sense buffers.
3275 */
3276 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3277 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3278 } else {
3279 /* Force 32-bit addressing */
3280 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3281 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3282 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003283
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3285 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003286 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3287 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
Prakash, Sathya436ace72007-07-24 15:42:08 +05303289 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 ioc->name, &ioc_init));
3291
3292 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3293 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003294 if (r != 0) {
3295 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
3299 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003300 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 */
3302
Prakash, Sathya436ace72007-07-24 15:42:08 +05303303 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003305
3306 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3307 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310
3311 /* YIKES! SUPER IMPORTANT!!!
3312 * Poll IocState until _OPERATIONAL while IOC is doing
3313 * LoopInit and TargetDiscovery!
3314 */
3315 count = 0;
3316 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3317 state = mpt_GetIocState(ioc, 1);
3318 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3319 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003320 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 } else {
3322 mdelay(1);
3323 }
3324
3325 if (!cntdn) {
3326 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3327 ioc->name, (int)((count+5)/HZ));
3328 return -9;
3329 }
3330
3331 state = mpt_GetIocState(ioc, 1);
3332 count++;
3333 }
Eric Moore29dd3602007-09-14 18:46:51 -06003334 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 ioc->name, count));
3336
Eric Mooreba856d32006-07-11 17:34:01 -06003337 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 return r;
3339}
3340
3341/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003342/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 * SendPortEnable - Send PortEnable request to MPT adapter port.
3344 * @ioc: Pointer to MPT_ADAPTER structure
3345 * @portnum: Port number to enable
3346 * @sleepFlag: Specifies whether the process can sleep
3347 *
3348 * Send PortEnable to bring IOC to OPERATIONAL state.
3349 *
3350 * Returns 0 for success, non-zero for failure.
3351 */
3352static int
3353SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3354{
3355 PortEnable_t port_enable;
3356 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003357 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 int req_sz;
3359 int reply_sz;
3360
3361 /* Destination... */
3362 reply_sz = sizeof(MPIDefaultReply_t);
3363 memset(&reply_buf, 0, reply_sz);
3364
3365 req_sz = sizeof(PortEnable_t);
3366 memset(&port_enable, 0, req_sz);
3367
3368 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3369 port_enable.PortNumber = portnum;
3370/* port_enable.ChainOffset = 0; */
3371/* port_enable.MsgFlags = 0; */
3372/* port_enable.MsgContext = 0; */
3373
Prakash, Sathya436ace72007-07-24 15:42:08 +05303374 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 ioc->name, portnum, &port_enable));
3376
3377 /* RAID FW may take a long time to enable
3378 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003379 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003380 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3381 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3382 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003383 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003384 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3385 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3386 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003388 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389}
3390
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003391/**
3392 * mpt_alloc_fw_memory - allocate firmware memory
3393 * @ioc: Pointer to MPT_ADAPTER structure
3394 * @size: total FW bytes
3395 *
3396 * If memory has already been allocated, the same (cached) value
3397 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303398 *
3399 * Return 0 if successfull, or non-zero for failure
3400 **/
3401int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3403{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303404 int rc;
3405
3406 if (ioc->cached_fw) {
3407 rc = 0; /* use already allocated memory */
3408 goto out;
3409 }
3410 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3412 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303413 rc = 0;
3414 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303416 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3417 if (!ioc->cached_fw) {
3418 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3419 ioc->name);
3420 rc = -1;
3421 } else {
3422 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3423 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3424 ioc->alloc_total += size;
3425 rc = 0;
3426 }
3427 out:
3428 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303430
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003431/**
3432 * mpt_free_fw_memory - free firmware memory
3433 * @ioc: Pointer to MPT_ADAPTER structure
3434 *
3435 * If alt_img is NULL, delete from ioc structure.
3436 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303437 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438void
3439mpt_free_fw_memory(MPT_ADAPTER *ioc)
3440{
3441 int sz;
3442
Prakash, Sathya984621b2008-01-11 14:42:17 +05303443 if (!ioc->cached_fw)
3444 return;
3445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303447 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3448 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003449 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303450 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452}
3453
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003455/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3457 * @ioc: Pointer to MPT_ADAPTER structure
3458 * @sleepFlag: Specifies whether the process can sleep
3459 *
3460 * Returns 0 for success, >0 for handshake failure
3461 * <0 for fw upload failure.
3462 *
3463 * Remark: If bound IOC and a successful FWUpload was performed
3464 * on the bound IOC, the second image is discarded
3465 * and memory is free'd. Both channels must upload to prevent
3466 * IOC from running in degraded mode.
3467 */
3468static int
3469mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3470{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 u8 reply[sizeof(FWUploadReply_t)];
3472 FWUpload_t *prequest;
3473 FWUploadReply_t *preply;
3474 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 u32 flagsLength;
3476 int ii, sz, reply_sz;
3477 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303478 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 /* If the image size is 0, we are done.
3480 */
3481 if ((sz = ioc->facts.FWImageSize) == 0)
3482 return 0;
3483
Prakash, Sathya984621b2008-01-11 14:42:17 +05303484 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3485 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
Eric Moore29dd3602007-09-14 18:46:51 -06003487 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3488 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003489
Eric Moorebc6e0892007-09-29 10:16:28 -06003490 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3491 kzalloc(ioc->req_sz, GFP_KERNEL);
3492 if (!prequest) {
3493 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3494 "while allocating memory \n", ioc->name));
3495 mpt_free_fw_memory(ioc);
3496 return -ENOMEM;
3497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498
Eric Moorebc6e0892007-09-29 10:16:28 -06003499 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
3501 reply_sz = sizeof(reply);
3502 memset(preply, 0, reply_sz);
3503
3504 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3505 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3506
3507 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3508 ptcsge->DetailsLength = 12;
3509 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3510 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003511 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303514 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3515 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3516 ioc->SGE_size;
3517 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3518 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3519 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003520 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303522 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3523 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
Eric Moore29dd3602007-09-14 18:46:51 -06003525 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526
3527 cmdStatus = -EFAULT;
3528 if (ii == 0) {
3529 /* Handshake transfer was complete and successful.
3530 * Check the Reply Frame.
3531 */
3532 int status, transfer_sz;
3533 status = le16_to_cpu(preply->IOCStatus);
3534 if (status == MPI_IOCSTATUS_SUCCESS) {
3535 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3536 if (transfer_sz == sz)
3537 cmdStatus = 0;
3538 }
3539 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303540 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 ioc->name, cmdStatus));
3542
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003543
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 if (cmdStatus) {
3545
Prakash, Sathya436ace72007-07-24 15:42:08 +05303546 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 ioc->name));
3548 mpt_free_fw_memory(ioc);
3549 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003550 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
3552 return cmdStatus;
3553}
3554
3555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003556/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 * mpt_downloadboot - DownloadBoot code
3558 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003559 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 * @sleepFlag: Specifies whether the process can sleep
3561 *
3562 * FwDownloadBoot requires Programmed IO access.
3563 *
3564 * Returns 0 for success
3565 * -1 FW Image size is 0
3566 * -2 No valid cached_fw Pointer
3567 * <0 for fw upload failure.
3568 */
3569static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003570mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 MpiExtImageHeader_t *pExtImage;
3573 u32 fwSize;
3574 u32 diag0val;
3575 int count;
3576 u32 *ptrFw;
3577 u32 diagRwData;
3578 u32 nextImage;
3579 u32 load_addr;
3580 u32 ioc_state=0;
3581
Prakash, Sathya436ace72007-07-24 15:42:08 +05303582 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003583 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003584
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3586 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3587 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3588 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3589 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3590 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3591
3592 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3593
3594 /* wait 1 msec */
3595 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003596 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 } else {
3598 mdelay (1);
3599 }
3600
3601 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3602 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3603
3604 for (count = 0; count < 30; count ++) {
3605 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3606 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303607 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 ioc->name, count));
3609 break;
3610 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003611 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003613 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003615 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 }
3617 }
3618
3619 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303620 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003621 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 ioc->name, diag0val));
3623 return -3;
3624 }
3625
3626 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3629 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3632
3633 /* Set the DiagRwEn and Disable ARM bits */
3634 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 fwSize = (pFwHeader->ImageSize + 3)/4;
3637 ptrFw = (u32 *) pFwHeader;
3638
3639 /* Write the LoadStartAddress to the DiagRw Address Register
3640 * using Programmed IO
3641 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003642 if (ioc->errata_flag_1064)
3643 pci_enable_io_access(ioc->pcidev);
3644
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303646 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 ioc->name, pFwHeader->LoadStartAddress));
3648
Prakash, Sathya436ace72007-07-24 15:42:08 +05303649 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 ioc->name, fwSize*4, ptrFw));
3651 while (fwSize--) {
3652 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3653 }
3654
3655 nextImage = pFwHeader->NextImageHeaderOffset;
3656 while (nextImage) {
3657 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3658
3659 load_addr = pExtImage->LoadStartAddress;
3660
3661 fwSize = (pExtImage->ImageSize + 3) >> 2;
3662 ptrFw = (u32 *)pExtImage;
3663
Prakash, Sathya436ace72007-07-24 15:42:08 +05303664 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 +02003665 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3667
3668 while (fwSize--) {
3669 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3670 }
3671 nextImage = pExtImage->NextImageHeaderOffset;
3672 }
3673
3674 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303675 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3677
3678 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303679 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3681
3682 /* Clear the internal flash bad bit - autoincrementing register,
3683 * so must do two writes.
3684 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003685 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003686 /*
3687 * 1030 and 1035 H/W errata, workaround to access
3688 * the ClearFlashBadSignatureBit
3689 */
3690 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3691 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3692 diagRwData |= 0x40000000;
3693 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3694 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3695
3696 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3697 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3698 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3699 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3700
3701 /* wait 1 msec */
3702 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003703 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003704 } else {
3705 mdelay (1);
3706 }
3707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003709 if (ioc->errata_flag_1064)
3710 pci_disable_io_access(ioc->pcidev);
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303713 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003714 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003716 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303717 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 ioc->name, diag0val));
3719 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3720
3721 /* Write 0xFF to reset the sequencer */
3722 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3723
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003724 if (ioc->bus_type == SAS) {
3725 ioc_state = mpt_GetIocState(ioc, 0);
3726 if ( (GetIocFacts(ioc, sleepFlag,
3727 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303728 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003729 ioc->name, ioc_state));
3730 return -EFAULT;
3731 }
3732 }
3733
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 for (count=0; count<HZ*20; count++) {
3735 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303736 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3737 "downloadboot successful! (count=%d) IocState=%x\n",
3738 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003739 if (ioc->bus_type == SAS) {
3740 return 0;
3741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303743 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3744 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 ioc->name));
3746 return -EFAULT;
3747 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303748 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3749 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 ioc->name));
3751 return 0;
3752 }
3753 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003754 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 } else {
3756 mdelay (10);
3757 }
3758 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303759 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3760 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 return -EFAULT;
3762}
3763
3764/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003765/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 * KickStart - Perform hard reset of MPT adapter.
3767 * @ioc: Pointer to MPT_ADAPTER structure
3768 * @force: Force hard reset
3769 * @sleepFlag: Specifies whether the process can sleep
3770 *
3771 * This routine places MPT adapter in diagnostic mode via the
3772 * WriteSequence register, and then performs a hard reset of adapter
3773 * via the Diagnostic register.
3774 *
3775 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3776 * or NO_SLEEP (interrupt thread, use mdelay)
3777 * force - 1 if doorbell active, board fault state
3778 * board operational, IOC_RECOVERY or
3779 * IOC_BRINGUP and there is an alt_ioc.
3780 * 0 else
3781 *
3782 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003783 * 1 - hard reset, READY
3784 * 0 - no reset due to History bit, READY
3785 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 * OR reset but failed to come READY
3787 * -2 - no reset, could not enter DIAG mode
3788 * -3 - reset but bad FW bit
3789 */
3790static int
3791KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3792{
3793 int hard_reset_done = 0;
3794 u32 ioc_state=0;
3795 int cnt,cntdn;
3796
Eric Moore29dd3602007-09-14 18:46:51 -06003797 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003798 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 /* Always issue a Msg Unit Reset first. This will clear some
3800 * SCSI bus hang conditions.
3801 */
3802 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3803
3804 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003805 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 } else {
3807 mdelay (1000);
3808 }
3809 }
3810
3811 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3812 if (hard_reset_done < 0)
3813 return hard_reset_done;
3814
Prakash, Sathya436ace72007-07-24 15:42:08 +05303815 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003816 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
3818 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3819 for (cnt=0; cnt<cntdn; cnt++) {
3820 ioc_state = mpt_GetIocState(ioc, 1);
3821 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303822 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 ioc->name, cnt));
3824 return hard_reset_done;
3825 }
3826 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003827 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 } else {
3829 mdelay (10);
3830 }
3831 }
3832
Eric Moore29dd3602007-09-14 18:46:51 -06003833 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3834 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 return -1;
3836}
3837
3838/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003839/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 * mpt_diag_reset - Perform hard reset of the adapter.
3841 * @ioc: Pointer to MPT_ADAPTER structure
3842 * @ignore: Set if to honor and clear to ignore
3843 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003844 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 * else set to NO_SLEEP (use mdelay instead)
3846 *
3847 * This routine places the adapter in diagnostic mode via the
3848 * WriteSequence register and then performs a hard reset of adapter
3849 * via the Diagnostic register. Adapter should be in ready state
3850 * upon successful completion.
3851 *
3852 * Returns: 1 hard reset successful
3853 * 0 no reset performed because reset history bit set
3854 * -2 enabling diagnostic mode failed
3855 * -3 diagnostic reset failed
3856 */
3857static int
3858mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3859{
3860 u32 diag0val;
3861 u32 doorbell;
3862 int hard_reset_done = 0;
3863 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303865 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
Eric Moorecd2c6192007-01-29 09:47:47 -07003867 /* Clear any existing interrupts */
3868 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3869
Eric Moore87cf8982006-06-27 16:09:26 -06003870 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303871 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003872 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003873 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3874 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3875 if (sleepFlag == CAN_SLEEP)
3876 msleep(1);
3877 else
3878 mdelay(1);
3879
3880 for (count = 0; count < 60; count ++) {
3881 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3882 doorbell &= MPI_IOC_STATE_MASK;
3883
Prakash, Sathya436ace72007-07-24 15:42:08 +05303884 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003885 "looking for READY STATE: doorbell=%x"
3886 " count=%d\n",
3887 ioc->name, doorbell, count));
3888 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003889 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003890 }
3891
3892 /* wait 1 sec */
3893 if (sleepFlag == CAN_SLEEP)
3894 msleep(1000);
3895 else
3896 mdelay(1000);
3897 }
3898 return -1;
3899 }
3900
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 /* Use "Diagnostic reset" method! (only thing available!) */
3902 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3903
Prakash, Sathya436ace72007-07-24 15:42:08 +05303904 if (ioc->debug_level & MPT_DEBUG) {
3905 if (ioc->alt_ioc)
3906 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3907 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
3911 /* Do the reset if we are told to ignore the reset history
3912 * or if the reset history is 0
3913 */
3914 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3915 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3916 /* Write magic sequence to WriteSequence register
3917 * Loop until in diagnostic mode
3918 */
3919 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3920 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3921 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3922 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3923 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3924 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3925
3926 /* wait 100 msec */
3927 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003928 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 } else {
3930 mdelay (100);
3931 }
3932
3933 count++;
3934 if (count > 20) {
3935 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3936 ioc->name, diag0val);
3937 return -2;
3938
3939 }
3940
3941 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3942
Prakash, Sathya436ace72007-07-24 15:42:08 +05303943 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 ioc->name, diag0val));
3945 }
3946
Prakash, Sathya436ace72007-07-24 15:42:08 +05303947 if (ioc->debug_level & MPT_DEBUG) {
3948 if (ioc->alt_ioc)
3949 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3950 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 /*
3954 * Disable the ARM (Bug fix)
3955 *
3956 */
3957 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003958 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959
3960 /*
3961 * Now hit the reset bit in the Diagnostic register
3962 * (THE BIG HAMMER!) (Clears DRWE bit).
3963 */
3964 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3965 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303966 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 ioc->name));
3968
3969 /*
3970 * Call each currently registered protocol IOC reset handler
3971 * with pre-reset indication.
3972 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3973 * MptResetHandlers[] registered yet.
3974 */
3975 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303976 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 int r = 0;
3978
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303979 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3980 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303981 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3982 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303983 ioc->name, cb_idx));
3984 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303986 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3987 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303988 ioc->name, ioc->alt_ioc->name, cb_idx));
3989 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 }
3991 }
3992 }
3993 /* FIXME? Examine results here? */
3994 }
3995
Eric Moore0ccdb002006-07-11 17:33:13 -06003996 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303997 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003998 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303999 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4000 else
4001 cached_fw = NULL;
4002 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 /* If the DownloadBoot operation fails, the
4004 * IOC will be left unusable. This is a fatal error
4005 * case. _diag_reset will return < 0
4006 */
4007 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304008 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4010 break;
4011 }
4012
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304014 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 /* wait 1 sec */
4016 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004017 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 } else {
4019 mdelay (1000);
4020 }
4021 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304022 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004023 printk(MYIOC_s_WARN_FMT
4024 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 }
4026
4027 } else {
4028 /* Wait for FW to reload and for board
4029 * to go to the READY state.
4030 * Maximum wait is 60 seconds.
4031 * If fail, no error will check again
4032 * with calling program.
4033 */
4034 for (count = 0; count < 60; count ++) {
4035 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4036 doorbell &= MPI_IOC_STATE_MASK;
4037
4038 if (doorbell == MPI_IOC_STATE_READY) {
4039 break;
4040 }
4041
4042 /* wait 1 sec */
4043 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004044 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 } else {
4046 mdelay (1000);
4047 }
4048 }
4049 }
4050 }
4051
4052 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304053 if (ioc->debug_level & MPT_DEBUG) {
4054 if (ioc->alt_ioc)
4055 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4056 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4057 ioc->name, diag0val, diag1val));
4058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059
4060 /* Clear RESET_HISTORY bit! Place board in the
4061 * diagnostic mode to update the diag register.
4062 */
4063 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4064 count = 0;
4065 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4066 /* Write magic sequence to WriteSequence register
4067 * Loop until in diagnostic mode
4068 */
4069 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4070 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4071 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4072 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4073 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4074 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4075
4076 /* wait 100 msec */
4077 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004078 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 } else {
4080 mdelay (100);
4081 }
4082
4083 count++;
4084 if (count > 20) {
4085 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4086 ioc->name, diag0val);
4087 break;
4088 }
4089 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4090 }
4091 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4092 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4093 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4094 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4095 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4096 ioc->name);
4097 }
4098
4099 /* Disable Diagnostic Mode
4100 */
4101 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4102
4103 /* Check FW reload status flags.
4104 */
4105 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4106 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4107 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4108 ioc->name, diag0val);
4109 return -3;
4110 }
4111
Prakash, Sathya436ace72007-07-24 15:42:08 +05304112 if (ioc->debug_level & MPT_DEBUG) {
4113 if (ioc->alt_ioc)
4114 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4115 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
4119 /*
4120 * Reset flag that says we've enabled event notification
4121 */
4122 ioc->facts.EventState = 0;
4123
4124 if (ioc->alt_ioc)
4125 ioc->alt_ioc->facts.EventState = 0;
4126
4127 return hard_reset_done;
4128}
4129
4130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004131/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 * SendIocReset - Send IOCReset request to MPT adapter.
4133 * @ioc: Pointer to MPT_ADAPTER structure
4134 * @reset_type: reset type, expected values are
4135 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004136 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 *
4138 * Send IOCReset request to the MPT adapter.
4139 *
4140 * Returns 0 for success, non-zero for failure.
4141 */
4142static int
4143SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4144{
4145 int r;
4146 u32 state;
4147 int cntdn, count;
4148
Prakash, Sathya436ace72007-07-24 15:42:08 +05304149 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 ioc->name, reset_type));
4151 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4152 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4153 return r;
4154
4155 /* FW ACK'd request, wait for READY state
4156 */
4157 count = 0;
4158 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4159
4160 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4161 cntdn--;
4162 count++;
4163 if (!cntdn) {
4164 if (sleepFlag != CAN_SLEEP)
4165 count *= 10;
4166
Eric Moore29dd3602007-09-14 18:46:51 -06004167 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4168 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 return -ETIME;
4170 }
4171
4172 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004173 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 } else {
4175 mdelay (1); /* 1 msec delay */
4176 }
4177 }
4178
4179 /* TODO!
4180 * Cleanup all event stuff for this IOC; re-issue EventNotification
4181 * request if needed.
4182 */
4183 if (ioc->facts.Function)
4184 ioc->facts.EventState = 0;
4185
4186 return 0;
4187}
4188
4189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004190/**
4191 * initChainBuffers - Allocate memory for and initialize chain buffers
4192 * @ioc: Pointer to MPT_ADAPTER structure
4193 *
4194 * Allocates memory for and initializes chain buffers,
4195 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 */
4197static int
4198initChainBuffers(MPT_ADAPTER *ioc)
4199{
4200 u8 *mem;
4201 int sz, ii, num_chain;
4202 int scale, num_sge, numSGE;
4203
4204 /* ReqToChain size must equal the req_depth
4205 * index = req_idx
4206 */
4207 if (ioc->ReqToChain == NULL) {
4208 sz = ioc->req_depth * sizeof(int);
4209 mem = kmalloc(sz, GFP_ATOMIC);
4210 if (mem == NULL)
4211 return -1;
4212
4213 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304214 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 ioc->name, mem, sz));
4216 mem = kmalloc(sz, GFP_ATOMIC);
4217 if (mem == NULL)
4218 return -1;
4219
4220 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304221 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 ioc->name, mem, sz));
4223 }
4224 for (ii = 0; ii < ioc->req_depth; ii++) {
4225 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4226 }
4227
4228 /* ChainToChain size must equal the total number
4229 * of chain buffers to be allocated.
4230 * index = chain_idx
4231 *
4232 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004233 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 *
4235 * num_sge = num sge in request frame + last chain buffer
4236 * scale = num sge per chain buffer if no chain element
4237 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304238 scale = ioc->req_sz / ioc->SGE_size;
4239 if (ioc->sg_addr_size == sizeof(u64))
4240 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304242 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304244 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304246 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304248 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4249 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304251 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 ioc->name, num_sge, numSGE));
4253
4254 if ( numSGE > MPT_SCSI_SG_DEPTH )
4255 numSGE = MPT_SCSI_SG_DEPTH;
4256
4257 num_chain = 1;
4258 while (numSGE - num_sge > 0) {
4259 num_chain++;
4260 num_sge += (scale - 1);
4261 }
4262 num_chain++;
4263
Prakash, Sathya436ace72007-07-24 15:42:08 +05304264 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 ioc->name, numSGE, num_sge, num_chain));
4266
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004267 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 num_chain *= MPT_SCSI_CAN_QUEUE;
4269 else
4270 num_chain *= MPT_FC_CAN_QUEUE;
4271
4272 ioc->num_chain = num_chain;
4273
4274 sz = num_chain * sizeof(int);
4275 if (ioc->ChainToChain == NULL) {
4276 mem = kmalloc(sz, GFP_ATOMIC);
4277 if (mem == NULL)
4278 return -1;
4279
4280 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304281 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 ioc->name, mem, sz));
4283 } else {
4284 mem = (u8 *) ioc->ChainToChain;
4285 }
4286 memset(mem, 0xFF, sz);
4287 return num_chain;
4288}
4289
4290/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004291/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4293 * @ioc: Pointer to MPT_ADAPTER structure
4294 *
4295 * This routine allocates memory for the MPT reply and request frame
4296 * pools (if necessary), and primes the IOC reply FIFO with
4297 * reply frames.
4298 *
4299 * Returns 0 for success, non-zero for failure.
4300 */
4301static int
4302PrimeIocFifos(MPT_ADAPTER *ioc)
4303{
4304 MPT_FRAME_HDR *mf;
4305 unsigned long flags;
4306 dma_addr_t alloc_dma;
4307 u8 *mem;
4308 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304309 u64 dma_mask;
4310
4311 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
4313 /* Prime reply FIFO... */
4314
4315 if (ioc->reply_frames == NULL) {
4316 if ( (num_chain = initChainBuffers(ioc)) < 0)
4317 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304318 /*
4319 * 1078 errata workaround for the 36GB limitation
4320 */
4321 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4322 ioc->dma_mask > DMA_35BIT_MASK) {
4323 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4324 && !pci_set_consistent_dma_mask(ioc->pcidev,
4325 DMA_BIT_MASK(32))) {
4326 dma_mask = DMA_35BIT_MASK;
4327 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4328 "setting 35 bit addressing for "
4329 "Request/Reply/Chain and Sense Buffers\n",
4330 ioc->name));
4331 } else {
4332 /*Reseting DMA mask to 64 bit*/
4333 pci_set_dma_mask(ioc->pcidev,
4334 DMA_BIT_MASK(64));
4335 pci_set_consistent_dma_mask(ioc->pcidev,
4336 DMA_BIT_MASK(64));
4337
4338 printk(MYIOC_s_ERR_FMT
4339 "failed setting 35 bit addressing for "
4340 "Request/Reply/Chain and Sense Buffers\n",
4341 ioc->name);
4342 return -1;
4343 }
4344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
4346 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304347 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304349 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 ioc->name, reply_sz, reply_sz));
4351
4352 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304353 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304355 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 ioc->name, sz, sz));
4357 total_size += sz;
4358
4359 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304360 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304362 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 ioc->name, sz, sz, num_chain));
4364
4365 total_size += sz;
4366 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4367 if (mem == NULL) {
4368 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4369 ioc->name);
4370 goto out_fail;
4371 }
4372
Prakash, Sathya436ace72007-07-24 15:42:08 +05304373 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4375
4376 memset(mem, 0, total_size);
4377 ioc->alloc_total += total_size;
4378 ioc->alloc = mem;
4379 ioc->alloc_dma = alloc_dma;
4380 ioc->alloc_sz = total_size;
4381 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4382 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4383
Prakash, Sathya436ace72007-07-24 15:42:08 +05304384 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004385 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 alloc_dma += reply_sz;
4388 mem += reply_sz;
4389
4390 /* Request FIFO - WE manage this! */
4391
4392 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4393 ioc->req_frames_dma = alloc_dma;
4394
Prakash, Sathya436ace72007-07-24 15:42:08 +05304395 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 ioc->name, mem, (void *)(ulong)alloc_dma));
4397
4398 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4399
4400#if defined(CONFIG_MTRR) && 0
4401 /*
4402 * Enable Write Combining MTRR for IOC's memory region.
4403 * (at least as much as we can; "size and base must be
4404 * multiples of 4 kiB"
4405 */
4406 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4407 sz,
4408 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304409 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 ioc->name, ioc->req_frames_dma, sz));
4411#endif
4412
4413 for (i = 0; i < ioc->req_depth; i++) {
4414 alloc_dma += ioc->req_sz;
4415 mem += ioc->req_sz;
4416 }
4417
4418 ioc->ChainBuffer = mem;
4419 ioc->ChainBufferDMA = alloc_dma;
4420
Prakash, Sathya436ace72007-07-24 15:42:08 +05304421 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4423
4424 /* Initialize the free chain Q.
4425 */
4426
4427 INIT_LIST_HEAD(&ioc->FreeChainQ);
4428
4429 /* Post the chain buffers to the FreeChainQ.
4430 */
4431 mem = (u8 *)ioc->ChainBuffer;
4432 for (i=0; i < num_chain; i++) {
4433 mf = (MPT_FRAME_HDR *) mem;
4434 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4435 mem += ioc->req_sz;
4436 }
4437
4438 /* Initialize Request frames linked list
4439 */
4440 alloc_dma = ioc->req_frames_dma;
4441 mem = (u8 *) ioc->req_frames;
4442
4443 spin_lock_irqsave(&ioc->FreeQlock, flags);
4444 INIT_LIST_HEAD(&ioc->FreeQ);
4445 for (i = 0; i < ioc->req_depth; i++) {
4446 mf = (MPT_FRAME_HDR *) mem;
4447
4448 /* Queue REQUESTs *internally*! */
4449 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4450
4451 mem += ioc->req_sz;
4452 }
4453 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4454
4455 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4456 ioc->sense_buf_pool =
4457 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4458 if (ioc->sense_buf_pool == NULL) {
4459 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4460 ioc->name);
4461 goto out_fail;
4462 }
4463
4464 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4465 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304466 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4468
4469 }
4470
4471 /* Post Reply frames to FIFO
4472 */
4473 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304474 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4476
4477 for (i = 0; i < ioc->reply_depth; i++) {
4478 /* Write each address to the IOC! */
4479 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4480 alloc_dma += ioc->reply_sz;
4481 }
4482
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304483 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4484 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4485 ioc->dma_mask))
4486 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4487 "restoring 64 bit addressing\n", ioc->name));
4488
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 return 0;
4490
4491out_fail:
4492 if (ioc->alloc != NULL) {
4493 sz = ioc->alloc_sz;
4494 pci_free_consistent(ioc->pcidev,
4495 sz,
4496 ioc->alloc, ioc->alloc_dma);
4497 ioc->reply_frames = NULL;
4498 ioc->req_frames = NULL;
4499 ioc->alloc_total -= sz;
4500 }
4501 if (ioc->sense_buf_pool != NULL) {
4502 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4503 pci_free_consistent(ioc->pcidev,
4504 sz,
4505 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4506 ioc->sense_buf_pool = NULL;
4507 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304508
4509 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4510 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4511 DMA_BIT_MASK(64)))
4512 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4513 "restoring 64 bit addressing\n", ioc->name));
4514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 return -1;
4516}
4517
4518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4519/**
4520 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4521 * from IOC via doorbell handshake method.
4522 * @ioc: Pointer to MPT_ADAPTER structure
4523 * @reqBytes: Size of the request in bytes
4524 * @req: Pointer to MPT request frame
4525 * @replyBytes: Expected size of the reply in bytes
4526 * @u16reply: Pointer to area where reply should be written
4527 * @maxwait: Max wait time for a reply (in seconds)
4528 * @sleepFlag: Specifies whether the process can sleep
4529 *
4530 * NOTES: It is the callers responsibility to byte-swap fields in the
4531 * request which are greater than 1 byte in size. It is also the
4532 * callers responsibility to byte-swap response fields which are
4533 * greater than 1 byte in size.
4534 *
4535 * Returns 0 for success, non-zero for failure.
4536 */
4537static int
4538mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004539 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
4541 MPIDefaultReply_t *mptReply;
4542 int failcnt = 0;
4543 int t;
4544
4545 /*
4546 * Get ready to cache a handshake reply
4547 */
4548 ioc->hs_reply_idx = 0;
4549 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4550 mptReply->MsgLength = 0;
4551
4552 /*
4553 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4554 * then tell IOC that we want to handshake a request of N words.
4555 * (WRITE u32val to Doorbell reg).
4556 */
4557 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4558 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4559 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4560 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4561
4562 /*
4563 * Wait for IOC's doorbell handshake int
4564 */
4565 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4566 failcnt++;
4567
Prakash, Sathya436ace72007-07-24 15:42:08 +05304568 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4570
4571 /* Read doorbell and check for active bit */
4572 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4573 return -1;
4574
4575 /*
4576 * Clear doorbell int (WRITE 0 to IntStatus reg),
4577 * then wait for IOC to ACKnowledge that it's ready for
4578 * our handshake request.
4579 */
4580 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4581 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4582 failcnt++;
4583
4584 if (!failcnt) {
4585 int ii;
4586 u8 *req_as_bytes = (u8 *) req;
4587
4588 /*
4589 * Stuff request words via doorbell handshake,
4590 * with ACK from IOC for each.
4591 */
4592 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4593 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4594 (req_as_bytes[(ii*4) + 1] << 8) |
4595 (req_as_bytes[(ii*4) + 2] << 16) |
4596 (req_as_bytes[(ii*4) + 3] << 24));
4597
4598 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4599 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4600 failcnt++;
4601 }
4602
Prakash, Sathya436ace72007-07-24 15:42:08 +05304603 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004604 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605
Prakash, Sathya436ace72007-07-24 15:42:08 +05304606 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4608
4609 /*
4610 * Wait for completion of doorbell handshake reply from the IOC
4611 */
4612 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4613 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004614
Prakash, Sathya436ace72007-07-24 15:42:08 +05304615 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4617
4618 /*
4619 * Copy out the cached reply...
4620 */
4621 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4622 u16reply[ii] = ioc->hs_reply[ii];
4623 } else {
4624 return -99;
4625 }
4626
4627 return -failcnt;
4628}
4629
4630/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004631/**
4632 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 * @ioc: Pointer to MPT_ADAPTER structure
4634 * @howlong: How long to wait (in seconds)
4635 * @sleepFlag: Specifies whether the process can sleep
4636 *
4637 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004638 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4639 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 *
4641 * Returns a negative value on failure, else wait loop count.
4642 */
4643static int
4644WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4645{
4646 int cntdn;
4647 int count = 0;
4648 u32 intstat=0;
4649
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004650 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
4652 if (sleepFlag == CAN_SLEEP) {
4653 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004654 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4656 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4657 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 count++;
4659 }
4660 } else {
4661 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004662 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4664 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4665 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 count++;
4667 }
4668 }
4669
4670 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304671 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 ioc->name, count));
4673 return count;
4674 }
4675
4676 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4677 ioc->name, count, intstat);
4678 return -1;
4679}
4680
4681/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004682/**
4683 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 * @ioc: Pointer to MPT_ADAPTER structure
4685 * @howlong: How long to wait (in seconds)
4686 * @sleepFlag: Specifies whether the process can sleep
4687 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004688 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4689 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 *
4691 * Returns a negative value on failure, else wait loop count.
4692 */
4693static int
4694WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4695{
4696 int cntdn;
4697 int count = 0;
4698 u32 intstat=0;
4699
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004700 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 if (sleepFlag == CAN_SLEEP) {
4702 while (--cntdn) {
4703 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4704 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4705 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004706 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 count++;
4708 }
4709 } else {
4710 while (--cntdn) {
4711 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4712 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4713 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004714 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 count++;
4716 }
4717 }
4718
4719 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304720 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 ioc->name, count, howlong));
4722 return count;
4723 }
4724
4725 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4726 ioc->name, count, intstat);
4727 return -1;
4728}
4729
4730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004731/**
4732 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 * @ioc: Pointer to MPT_ADAPTER structure
4734 * @howlong: How long to wait (in seconds)
4735 * @sleepFlag: Specifies whether the process can sleep
4736 *
4737 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4738 * Reply is cached to IOC private area large enough to hold a maximum
4739 * of 128 bytes of reply data.
4740 *
4741 * Returns a negative value on failure, else size of reply in WORDS.
4742 */
4743static int
4744WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4745{
4746 int u16cnt = 0;
4747 int failcnt = 0;
4748 int t;
4749 u16 *hs_reply = ioc->hs_reply;
4750 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4751 u16 hword;
4752
4753 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4754
4755 /*
4756 * Get first two u16's so we can look at IOC's intended reply MsgLength
4757 */
4758 u16cnt=0;
4759 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4760 failcnt++;
4761 } else {
4762 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4763 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4764 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4765 failcnt++;
4766 else {
4767 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4768 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4769 }
4770 }
4771
Prakash, Sathya436ace72007-07-24 15:42:08 +05304772 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004773 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4775
4776 /*
4777 * If no error (and IOC said MsgLength is > 0), piece together
4778 * reply 16 bits at a time.
4779 */
4780 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4781 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4782 failcnt++;
4783 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4784 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004785 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 hs_reply[u16cnt] = hword;
4787 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4788 }
4789
4790 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4791 failcnt++;
4792 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4793
4794 if (failcnt) {
4795 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4796 ioc->name);
4797 return -failcnt;
4798 }
4799#if 0
4800 else if (u16cnt != (2 * mptReply->MsgLength)) {
4801 return -101;
4802 }
4803 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4804 return -102;
4805 }
4806#endif
4807
Prakash, Sathya436ace72007-07-24 15:42:08 +05304808 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004809 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
Prakash, Sathya436ace72007-07-24 15:42:08 +05304811 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 ioc->name, t, u16cnt/2));
4813 return u16cnt/2;
4814}
4815
4816/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004817/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 * GetLanConfigPages - Fetch LANConfig pages.
4819 * @ioc: Pointer to MPT_ADAPTER structure
4820 *
4821 * Return: 0 for success
4822 * -ENOMEM if no memory available
4823 * -EPERM if not allowed due to ISR context
4824 * -EAGAIN if no msg frames currently available
4825 * -EFAULT for non-successful reply or no reply (timeout)
4826 */
4827static int
4828GetLanConfigPages(MPT_ADAPTER *ioc)
4829{
4830 ConfigPageHeader_t hdr;
4831 CONFIGPARMS cfg;
4832 LANPage0_t *ppage0_alloc;
4833 dma_addr_t page0_dma;
4834 LANPage1_t *ppage1_alloc;
4835 dma_addr_t page1_dma;
4836 int rc = 0;
4837 int data_sz;
4838 int copy_sz;
4839
4840 /* Get LAN Page 0 header */
4841 hdr.PageVersion = 0;
4842 hdr.PageLength = 0;
4843 hdr.PageNumber = 0;
4844 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004845 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 cfg.physAddr = -1;
4847 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4848 cfg.dir = 0;
4849 cfg.pageAddr = 0;
4850 cfg.timeout = 0;
4851
4852 if ((rc = mpt_config(ioc, &cfg)) != 0)
4853 return rc;
4854
4855 if (hdr.PageLength > 0) {
4856 data_sz = hdr.PageLength * 4;
4857 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4858 rc = -ENOMEM;
4859 if (ppage0_alloc) {
4860 memset((u8 *)ppage0_alloc, 0, data_sz);
4861 cfg.physAddr = page0_dma;
4862 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4863
4864 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4865 /* save the data */
4866 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4867 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4868
4869 }
4870
4871 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4872
4873 /* FIXME!
4874 * Normalize endianness of structure data,
4875 * by byte-swapping all > 1 byte fields!
4876 */
4877
4878 }
4879
4880 if (rc)
4881 return rc;
4882 }
4883
4884 /* Get LAN Page 1 header */
4885 hdr.PageVersion = 0;
4886 hdr.PageLength = 0;
4887 hdr.PageNumber = 1;
4888 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004889 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 cfg.physAddr = -1;
4891 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4892 cfg.dir = 0;
4893 cfg.pageAddr = 0;
4894
4895 if ((rc = mpt_config(ioc, &cfg)) != 0)
4896 return rc;
4897
4898 if (hdr.PageLength == 0)
4899 return 0;
4900
4901 data_sz = hdr.PageLength * 4;
4902 rc = -ENOMEM;
4903 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4904 if (ppage1_alloc) {
4905 memset((u8 *)ppage1_alloc, 0, data_sz);
4906 cfg.physAddr = page1_dma;
4907 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4908
4909 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4910 /* save the data */
4911 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4912 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4913 }
4914
4915 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4916
4917 /* FIXME!
4918 * Normalize endianness of structure data,
4919 * by byte-swapping all > 1 byte fields!
4920 */
4921
4922 }
4923
4924 return rc;
4925}
4926
4927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004928/**
4929 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004930 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004931 * @persist_opcode: see below
4932 *
4933 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4934 * devices not currently present.
4935 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4936 *
4937 * NOTE: Don't use not this function during interrupt time.
4938 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004939 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004940 */
4941
4942/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4943int
4944mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4945{
4946 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4947 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4948 MPT_FRAME_HDR *mf = NULL;
4949 MPIHeader_t *mpi_hdr;
4950
4951
4952 /* insure garbage is not sent to fw */
4953 switch(persist_opcode) {
4954
4955 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4956 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4957 break;
4958
4959 default:
4960 return -1;
4961 break;
4962 }
4963
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004964 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004965
4966 /* Get a MF for this command.
4967 */
4968 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004969 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004970 return -1;
4971 }
4972
4973 mpi_hdr = (MPIHeader_t *) mf;
4974 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4975 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4976 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4977 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4978 sasIoUnitCntrReq->Operation = persist_opcode;
4979
4980 init_timer(&ioc->persist_timer);
4981 ioc->persist_timer.data = (unsigned long) ioc;
4982 ioc->persist_timer.function = mpt_timer_expired;
4983 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
4984 ioc->persist_wait_done=0;
4985 add_timer(&ioc->persist_timer);
4986 mpt_put_msg_frame(mpt_base_index, ioc, mf);
4987 wait_event(mpt_waitq, ioc->persist_wait_done);
4988
4989 sasIoUnitCntrReply =
4990 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
4991 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
4992 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004993 __func__,
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004994 sasIoUnitCntrReply->IOCStatus,
4995 sasIoUnitCntrReply->IOCLogInfo);
4996 return -1;
4997 }
4998
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004999 printk("%s: success\n",__func__);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005000 return 0;
5001}
5002
5003/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005004
5005static void
5006mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5007 MpiEventDataRaid_t * pRaidEventData)
5008{
5009 int volume;
5010 int reason;
5011 int disk;
5012 int status;
5013 int flags;
5014 int state;
5015
5016 volume = pRaidEventData->VolumeID;
5017 reason = pRaidEventData->ReasonCode;
5018 disk = pRaidEventData->PhysDiskNum;
5019 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5020 flags = (status >> 0) & 0xff;
5021 state = (status >> 8) & 0xff;
5022
5023 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5024 return;
5025 }
5026
5027 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5028 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5029 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005030 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5031 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005032 } else {
5033 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5034 ioc->name, volume);
5035 }
5036
5037 switch(reason) {
5038 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5039 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5040 ioc->name);
5041 break;
5042
5043 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5044
5045 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5046 ioc->name);
5047 break;
5048
5049 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5050 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5051 ioc->name);
5052 break;
5053
5054 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5055 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5056 ioc->name,
5057 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5058 ? "optimal"
5059 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5060 ? "degraded"
5061 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5062 ? "failed"
5063 : "state unknown",
5064 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5065 ? ", enabled" : "",
5066 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5067 ? ", quiesced" : "",
5068 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5069 ? ", resync in progress" : "" );
5070 break;
5071
5072 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5073 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5074 ioc->name, disk);
5075 break;
5076
5077 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5078 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5079 ioc->name);
5080 break;
5081
5082 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5083 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5084 ioc->name);
5085 break;
5086
5087 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5088 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5089 ioc->name);
5090 break;
5091
5092 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5093 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5094 ioc->name,
5095 state == MPI_PHYSDISK0_STATUS_ONLINE
5096 ? "online"
5097 : state == MPI_PHYSDISK0_STATUS_MISSING
5098 ? "missing"
5099 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5100 ? "not compatible"
5101 : state == MPI_PHYSDISK0_STATUS_FAILED
5102 ? "failed"
5103 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5104 ? "initializing"
5105 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5106 ? "offline requested"
5107 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5108 ? "failed requested"
5109 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5110 ? "offline"
5111 : "state unknown",
5112 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5113 ? ", out of sync" : "",
5114 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5115 ? ", quiesced" : "" );
5116 break;
5117
5118 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5119 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5120 ioc->name, disk);
5121 break;
5122
5123 case MPI_EVENT_RAID_RC_SMART_DATA:
5124 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5125 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5126 break;
5127
5128 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5129 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5130 ioc->name, disk);
5131 break;
5132 }
5133}
5134
5135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005136/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5138 * @ioc: Pointer to MPT_ADAPTER structure
5139 *
5140 * Returns: 0 for success
5141 * -ENOMEM if no memory available
5142 * -EPERM if not allowed due to ISR context
5143 * -EAGAIN if no msg frames currently available
5144 * -EFAULT for non-successful reply or no reply (timeout)
5145 */
5146static int
5147GetIoUnitPage2(MPT_ADAPTER *ioc)
5148{
5149 ConfigPageHeader_t hdr;
5150 CONFIGPARMS cfg;
5151 IOUnitPage2_t *ppage_alloc;
5152 dma_addr_t page_dma;
5153 int data_sz;
5154 int rc;
5155
5156 /* Get the page header */
5157 hdr.PageVersion = 0;
5158 hdr.PageLength = 0;
5159 hdr.PageNumber = 2;
5160 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005161 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 cfg.physAddr = -1;
5163 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5164 cfg.dir = 0;
5165 cfg.pageAddr = 0;
5166 cfg.timeout = 0;
5167
5168 if ((rc = mpt_config(ioc, &cfg)) != 0)
5169 return rc;
5170
5171 if (hdr.PageLength == 0)
5172 return 0;
5173
5174 /* Read the config page */
5175 data_sz = hdr.PageLength * 4;
5176 rc = -ENOMEM;
5177 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5178 if (ppage_alloc) {
5179 memset((u8 *)ppage_alloc, 0, data_sz);
5180 cfg.physAddr = page_dma;
5181 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5182
5183 /* If Good, save data */
5184 if ((rc = mpt_config(ioc, &cfg)) == 0)
5185 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5186
5187 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5188 }
5189
5190 return rc;
5191}
5192
5193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005194/**
5195 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 * @ioc: Pointer to a Adapter Strucutre
5197 * @portnum: IOC port number
5198 *
5199 * Return: -EFAULT if read of config page header fails
5200 * or if no nvram
5201 * If read of SCSI Port Page 0 fails,
5202 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5203 * Adapter settings: async, narrow
5204 * Return 1
5205 * If read of SCSI Port Page 2 fails,
5206 * Adapter settings valid
5207 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5208 * Return 1
5209 * Else
5210 * Both valid
5211 * Return 0
5212 * CHECK - what type of locking mechanisms should be used????
5213 */
5214static int
5215mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5216{
5217 u8 *pbuf;
5218 dma_addr_t buf_dma;
5219 CONFIGPARMS cfg;
5220 ConfigPageHeader_t header;
5221 int ii;
5222 int data, rc = 0;
5223
5224 /* Allocate memory
5225 */
5226 if (!ioc->spi_data.nvram) {
5227 int sz;
5228 u8 *mem;
5229 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5230 mem = kmalloc(sz, GFP_ATOMIC);
5231 if (mem == NULL)
5232 return -EFAULT;
5233
5234 ioc->spi_data.nvram = (int *) mem;
5235
Prakash, Sathya436ace72007-07-24 15:42:08 +05305236 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 ioc->name, ioc->spi_data.nvram, sz));
5238 }
5239
5240 /* Invalidate NVRAM information
5241 */
5242 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5243 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5244 }
5245
5246 /* Read SPP0 header, allocate memory, then read page.
5247 */
5248 header.PageVersion = 0;
5249 header.PageLength = 0;
5250 header.PageNumber = 0;
5251 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005252 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 cfg.physAddr = -1;
5254 cfg.pageAddr = portnum;
5255 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5256 cfg.dir = 0;
5257 cfg.timeout = 0; /* use default */
5258 if (mpt_config(ioc, &cfg) != 0)
5259 return -EFAULT;
5260
5261 if (header.PageLength > 0) {
5262 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5263 if (pbuf) {
5264 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5265 cfg.physAddr = buf_dma;
5266 if (mpt_config(ioc, &cfg) != 0) {
5267 ioc->spi_data.maxBusWidth = MPT_NARROW;
5268 ioc->spi_data.maxSyncOffset = 0;
5269 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5270 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5271 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305272 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5273 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005274 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 } else {
5276 /* Save the Port Page 0 data
5277 */
5278 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5279 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5280 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5281
5282 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5283 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005284 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5285 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 ioc->name, pPP0->Capabilities));
5287 }
5288 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5289 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5290 if (data) {
5291 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5292 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5293 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305294 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5295 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005296 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 } else {
5298 ioc->spi_data.maxSyncOffset = 0;
5299 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5300 }
5301
5302 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5303
5304 /* Update the minSyncFactor based on bus type.
5305 */
5306 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5307 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5308
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005309 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305311 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5312 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005313 ioc->name, ioc->spi_data.minSyncFactor));
5314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 }
5316 }
5317 if (pbuf) {
5318 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5319 }
5320 }
5321 }
5322
5323 /* SCSI Port Page 2 - Read the header then the page.
5324 */
5325 header.PageVersion = 0;
5326 header.PageLength = 0;
5327 header.PageNumber = 2;
5328 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005329 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 cfg.physAddr = -1;
5331 cfg.pageAddr = portnum;
5332 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5333 cfg.dir = 0;
5334 if (mpt_config(ioc, &cfg) != 0)
5335 return -EFAULT;
5336
5337 if (header.PageLength > 0) {
5338 /* Allocate memory and read SCSI Port Page 2
5339 */
5340 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5341 if (pbuf) {
5342 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5343 cfg.physAddr = buf_dma;
5344 if (mpt_config(ioc, &cfg) != 0) {
5345 /* Nvram data is left with INVALID mark
5346 */
5347 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005348 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5349
5350 /* This is an ATTO adapter, read Page2 accordingly
5351 */
5352 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5353 ATTODeviceInfo_t *pdevice = NULL;
5354 u16 ATTOFlags;
5355
5356 /* Save the Port Page 2 data
5357 * (reformat into a 32bit quantity)
5358 */
5359 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5360 pdevice = &pPP2->DeviceSettings[ii];
5361 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5362 data = 0;
5363
5364 /* Translate ATTO device flags to LSI format
5365 */
5366 if (ATTOFlags & ATTOFLAG_DISC)
5367 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5368 if (ATTOFlags & ATTOFLAG_ID_ENB)
5369 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5370 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5371 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5372 if (ATTOFlags & ATTOFLAG_TAGGED)
5373 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5374 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5375 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5376
5377 data = (data << 16) | (pdevice->Period << 8) | 10;
5378 ioc->spi_data.nvram[ii] = data;
5379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 } else {
5381 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5382 MpiDeviceInfo_t *pdevice = NULL;
5383
Moore, Ericd8e925d2006-01-16 18:53:06 -07005384 /*
5385 * Save "Set to Avoid SCSI Bus Resets" flag
5386 */
5387 ioc->spi_data.bus_reset =
5388 (le32_to_cpu(pPP2->PortFlags) &
5389 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5390 0 : 1 ;
5391
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 /* Save the Port Page 2 data
5393 * (reformat into a 32bit quantity)
5394 */
5395 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5396 ioc->spi_data.PortFlags = data;
5397 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5398 pdevice = &pPP2->DeviceSettings[ii];
5399 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5400 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5401 ioc->spi_data.nvram[ii] = data;
5402 }
5403 }
5404
5405 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5406 }
5407 }
5408
5409 /* Update Adapter limits with those from NVRAM
5410 * Comment: Don't need to do this. Target performance
5411 * parameters will never exceed the adapters limits.
5412 */
5413
5414 return rc;
5415}
5416
5417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005418/**
5419 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 * @ioc: Pointer to a Adapter Strucutre
5421 * @portnum: IOC port number
5422 *
5423 * Return: -EFAULT if read of config page header fails
5424 * or 0 if success.
5425 */
5426static int
5427mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5428{
5429 CONFIGPARMS cfg;
5430 ConfigPageHeader_t header;
5431
5432 /* Read the SCSI Device Page 1 header
5433 */
5434 header.PageVersion = 0;
5435 header.PageLength = 0;
5436 header.PageNumber = 1;
5437 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005438 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 cfg.physAddr = -1;
5440 cfg.pageAddr = portnum;
5441 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5442 cfg.dir = 0;
5443 cfg.timeout = 0;
5444 if (mpt_config(ioc, &cfg) != 0)
5445 return -EFAULT;
5446
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005447 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5448 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449
5450 header.PageVersion = 0;
5451 header.PageLength = 0;
5452 header.PageNumber = 0;
5453 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5454 if (mpt_config(ioc, &cfg) != 0)
5455 return -EFAULT;
5456
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005457 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5458 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
Prakash, Sathya436ace72007-07-24 15:42:08 +05305460 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5462
Prakash, Sathya436ace72007-07-24 15:42:08 +05305463 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5465 return 0;
5466}
5467
Eric Mooreb506ade2007-01-29 09:45:37 -07005468/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005469 * mpt_inactive_raid_list_free - This clears this link list.
5470 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005471 **/
5472static void
5473mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5474{
5475 struct inactive_raid_component_info *component_info, *pNext;
5476
5477 if (list_empty(&ioc->raid_data.inactive_list))
5478 return;
5479
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005480 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005481 list_for_each_entry_safe(component_info, pNext,
5482 &ioc->raid_data.inactive_list, list) {
5483 list_del(&component_info->list);
5484 kfree(component_info);
5485 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005486 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005487}
5488
5489/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005490 * 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 -07005491 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005492 * @ioc : pointer to per adapter structure
5493 * @channel : volume channel
5494 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005495 **/
5496static void
5497mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5498{
5499 CONFIGPARMS cfg;
5500 ConfigPageHeader_t hdr;
5501 dma_addr_t dma_handle;
5502 pRaidVolumePage0_t buffer = NULL;
5503 int i;
5504 RaidPhysDiskPage0_t phys_disk;
5505 struct inactive_raid_component_info *component_info;
5506 int handle_inactive_volumes;
5507
5508 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5509 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5510 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5511 cfg.pageAddr = (channel << 8) + id;
5512 cfg.cfghdr.hdr = &hdr;
5513 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5514
5515 if (mpt_config(ioc, &cfg) != 0)
5516 goto out;
5517
5518 if (!hdr.PageLength)
5519 goto out;
5520
5521 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5522 &dma_handle);
5523
5524 if (!buffer)
5525 goto out;
5526
5527 cfg.physAddr = dma_handle;
5528 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5529
5530 if (mpt_config(ioc, &cfg) != 0)
5531 goto out;
5532
5533 if (!buffer->NumPhysDisks)
5534 goto out;
5535
5536 handle_inactive_volumes =
5537 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5538 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5539 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5540 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5541
5542 if (!handle_inactive_volumes)
5543 goto out;
5544
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005545 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005546 for (i = 0; i < buffer->NumPhysDisks; i++) {
5547 if(mpt_raid_phys_disk_pg0(ioc,
5548 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5549 continue;
5550
5551 if ((component_info = kmalloc(sizeof (*component_info),
5552 GFP_KERNEL)) == NULL)
5553 continue;
5554
5555 component_info->volumeID = id;
5556 component_info->volumeBus = channel;
5557 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5558 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5559 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5560 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5561
5562 list_add_tail(&component_info->list,
5563 &ioc->raid_data.inactive_list);
5564 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005565 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005566
5567 out:
5568 if (buffer)
5569 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5570 dma_handle);
5571}
5572
5573/**
5574 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5575 * @ioc: Pointer to a Adapter Structure
5576 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5577 * @phys_disk: requested payload data returned
5578 *
5579 * Return:
5580 * 0 on success
5581 * -EFAULT if read of config page header fails or data pointer not NULL
5582 * -ENOMEM if pci_alloc failed
5583 **/
5584int
5585mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5586{
5587 CONFIGPARMS cfg;
5588 ConfigPageHeader_t hdr;
5589 dma_addr_t dma_handle;
5590 pRaidPhysDiskPage0_t buffer = NULL;
5591 int rc;
5592
5593 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5594 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5595
5596 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5597 cfg.cfghdr.hdr = &hdr;
5598 cfg.physAddr = -1;
5599 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5600
5601 if (mpt_config(ioc, &cfg) != 0) {
5602 rc = -EFAULT;
5603 goto out;
5604 }
5605
5606 if (!hdr.PageLength) {
5607 rc = -EFAULT;
5608 goto out;
5609 }
5610
5611 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5612 &dma_handle);
5613
5614 if (!buffer) {
5615 rc = -ENOMEM;
5616 goto out;
5617 }
5618
5619 cfg.physAddr = dma_handle;
5620 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5621 cfg.pageAddr = phys_disk_num;
5622
5623 if (mpt_config(ioc, &cfg) != 0) {
5624 rc = -EFAULT;
5625 goto out;
5626 }
5627
5628 rc = 0;
5629 memcpy(phys_disk, buffer, sizeof(*buffer));
5630 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5631
5632 out:
5633
5634 if (buffer)
5635 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5636 dma_handle);
5637
5638 return rc;
5639}
5640
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641/**
5642 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5643 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 *
5645 * Return:
5646 * 0 on success
5647 * -EFAULT if read of config page header fails or data pointer not NULL
5648 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005649 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650int
5651mpt_findImVolumes(MPT_ADAPTER *ioc)
5652{
5653 IOCPage2_t *pIoc2;
5654 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 dma_addr_t ioc2_dma;
5656 CONFIGPARMS cfg;
5657 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 int rc = 0;
5659 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005660 int i;
5661
5662 if (!ioc->ir_firmware)
5663 return 0;
5664
5665 /* Free the old page
5666 */
5667 kfree(ioc->raid_data.pIocPg2);
5668 ioc->raid_data.pIocPg2 = NULL;
5669 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
5671 /* Read IOCP2 header then the page.
5672 */
5673 header.PageVersion = 0;
5674 header.PageLength = 0;
5675 header.PageNumber = 2;
5676 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005677 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 cfg.physAddr = -1;
5679 cfg.pageAddr = 0;
5680 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5681 cfg.dir = 0;
5682 cfg.timeout = 0;
5683 if (mpt_config(ioc, &cfg) != 0)
5684 return -EFAULT;
5685
5686 if (header.PageLength == 0)
5687 return -EFAULT;
5688
5689 iocpage2sz = header.PageLength * 4;
5690 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5691 if (!pIoc2)
5692 return -ENOMEM;
5693
5694 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5695 cfg.physAddr = ioc2_dma;
5696 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005697 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Eric Mooreb506ade2007-01-29 09:45:37 -07005699 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5700 if (!mem)
5701 goto out;
5702
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005704 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705
Eric Mooreb506ade2007-01-29 09:45:37 -07005706 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Eric Mooreb506ade2007-01-29 09:45:37 -07005708 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5709 mpt_inactive_raid_volumes(ioc,
5710 pIoc2->RaidVolume[i].VolumeBus,
5711 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712
Eric Mooreb506ade2007-01-29 09:45:37 -07005713 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5715
5716 return rc;
5717}
5718
Moore, Ericc972c702006-03-14 09:14:06 -07005719static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5721{
5722 IOCPage3_t *pIoc3;
5723 u8 *mem;
5724 CONFIGPARMS cfg;
5725 ConfigPageHeader_t header;
5726 dma_addr_t ioc3_dma;
5727 int iocpage3sz = 0;
5728
5729 /* Free the old page
5730 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005731 kfree(ioc->raid_data.pIocPg3);
5732 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733
5734 /* There is at least one physical disk.
5735 * Read and save IOC Page 3
5736 */
5737 header.PageVersion = 0;
5738 header.PageLength = 0;
5739 header.PageNumber = 3;
5740 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005741 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 cfg.physAddr = -1;
5743 cfg.pageAddr = 0;
5744 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5745 cfg.dir = 0;
5746 cfg.timeout = 0;
5747 if (mpt_config(ioc, &cfg) != 0)
5748 return 0;
5749
5750 if (header.PageLength == 0)
5751 return 0;
5752
5753 /* Read Header good, alloc memory
5754 */
5755 iocpage3sz = header.PageLength * 4;
5756 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5757 if (!pIoc3)
5758 return 0;
5759
5760 /* Read the Page and save the data
5761 * into malloc'd memory.
5762 */
5763 cfg.physAddr = ioc3_dma;
5764 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5765 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005766 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 if (mem) {
5768 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005769 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 }
5771 }
5772
5773 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5774
5775 return 0;
5776}
5777
5778static void
5779mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5780{
5781 IOCPage4_t *pIoc4;
5782 CONFIGPARMS cfg;
5783 ConfigPageHeader_t header;
5784 dma_addr_t ioc4_dma;
5785 int iocpage4sz;
5786
5787 /* Read and save IOC Page 4
5788 */
5789 header.PageVersion = 0;
5790 header.PageLength = 0;
5791 header.PageNumber = 4;
5792 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005793 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 cfg.physAddr = -1;
5795 cfg.pageAddr = 0;
5796 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5797 cfg.dir = 0;
5798 cfg.timeout = 0;
5799 if (mpt_config(ioc, &cfg) != 0)
5800 return;
5801
5802 if (header.PageLength == 0)
5803 return;
5804
5805 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5806 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5807 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5808 if (!pIoc4)
5809 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005810 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 } else {
5812 ioc4_dma = ioc->spi_data.IocPg4_dma;
5813 iocpage4sz = ioc->spi_data.IocPg4Sz;
5814 }
5815
5816 /* Read the Page into dma memory.
5817 */
5818 cfg.physAddr = ioc4_dma;
5819 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5820 if (mpt_config(ioc, &cfg) == 0) {
5821 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5822 ioc->spi_data.IocPg4_dma = ioc4_dma;
5823 ioc->spi_data.IocPg4Sz = iocpage4sz;
5824 } else {
5825 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5826 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005827 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 }
5829}
5830
5831static void
5832mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5833{
5834 IOCPage1_t *pIoc1;
5835 CONFIGPARMS cfg;
5836 ConfigPageHeader_t header;
5837 dma_addr_t ioc1_dma;
5838 int iocpage1sz = 0;
5839 u32 tmp;
5840
5841 /* Check the Coalescing Timeout in IOC Page 1
5842 */
5843 header.PageVersion = 0;
5844 header.PageLength = 0;
5845 header.PageNumber = 1;
5846 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005847 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 cfg.physAddr = -1;
5849 cfg.pageAddr = 0;
5850 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5851 cfg.dir = 0;
5852 cfg.timeout = 0;
5853 if (mpt_config(ioc, &cfg) != 0)
5854 return;
5855
5856 if (header.PageLength == 0)
5857 return;
5858
5859 /* Read Header good, alloc memory
5860 */
5861 iocpage1sz = header.PageLength * 4;
5862 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5863 if (!pIoc1)
5864 return;
5865
5866 /* Read the Page and check coalescing timeout
5867 */
5868 cfg.physAddr = ioc1_dma;
5869 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5870 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305871
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5873 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5874 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5875
Prakash, Sathya436ace72007-07-24 15:42:08 +05305876 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 ioc->name, tmp));
5878
5879 if (tmp > MPT_COALESCING_TIMEOUT) {
5880 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5881
5882 /* Write NVRAM and current
5883 */
5884 cfg.dir = 1;
5885 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5886 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305887 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 ioc->name, MPT_COALESCING_TIMEOUT));
5889
5890 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5891 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305892 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5893 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 ioc->name, MPT_COALESCING_TIMEOUT));
5895 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305896 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5897 "Reset NVRAM Coalescing Timeout Failed\n",
5898 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 }
5900
5901 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305902 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5903 "Reset of Current Coalescing Timeout Failed!\n",
5904 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 }
5906 }
5907
5908 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305909 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 }
5911 }
5912
5913 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5914
5915 return;
5916}
5917
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305918static void
5919mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5920{
5921 CONFIGPARMS cfg;
5922 ConfigPageHeader_t hdr;
5923 dma_addr_t buf_dma;
5924 ManufacturingPage0_t *pbuf = NULL;
5925
5926 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5927 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5928
5929 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5930 cfg.cfghdr.hdr = &hdr;
5931 cfg.physAddr = -1;
5932 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5933 cfg.timeout = 10;
5934
5935 if (mpt_config(ioc, &cfg) != 0)
5936 goto out;
5937
5938 if (!cfg.cfghdr.hdr->PageLength)
5939 goto out;
5940
5941 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5942 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5943 if (!pbuf)
5944 goto out;
5945
5946 cfg.physAddr = buf_dma;
5947
5948 if (mpt_config(ioc, &cfg) != 0)
5949 goto out;
5950
5951 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5952 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5953 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5954
5955 out:
5956
5957 if (pbuf)
5958 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5959}
5960
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005962/**
5963 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 * @ioc: Pointer to MPT_ADAPTER structure
5965 * @EvSwitch: Event switch flags
5966 */
5967static int
5968SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
5969{
5970 EventNotification_t *evnp;
5971
5972 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
5973 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305974 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 ioc->name));
5976 return 0;
5977 }
5978 memset(evnp, 0, sizeof(*evnp));
5979
Prakash, Sathya436ace72007-07-24 15:42:08 +05305980 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981
5982 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5983 evnp->ChainOffset = 0;
5984 evnp->MsgFlags = 0;
5985 evnp->Switch = EvSwitch;
5986
5987 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
5988
5989 return 0;
5990}
5991
5992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5993/**
5994 * SendEventAck - Send EventAck request to MPT adapter.
5995 * @ioc: Pointer to MPT_ADAPTER structure
5996 * @evnp: Pointer to original EventNotification request
5997 */
5998static int
5999SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6000{
6001 EventAck_t *pAck;
6002
6003 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306004 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07006005 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 return -1;
6007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
Prakash, Sathya436ace72007-07-24 15:42:08 +05306009 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
6011 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6012 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006013 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006015 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 pAck->Event = evnp->Event;
6017 pAck->EventContext = evnp->EventContext;
6018
6019 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6020
6021 return 0;
6022}
6023
6024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6025/**
6026 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006027 * @ioc: Pointer to an adapter structure
6028 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 * action, page address, direction, physical address
6030 * and pointer to a configuration page header
6031 * Page header is updated.
6032 *
6033 * Returns 0 for success
6034 * -EPERM if not allowed due to ISR context
6035 * -EAGAIN if no msg frames currently available
6036 * -EFAULT for non-successful reply or no reply (timeout)
6037 */
6038int
6039mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6040{
6041 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006042 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 MPT_FRAME_HDR *mf;
6044 unsigned long flags;
6045 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006046 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 int in_isr;
6048
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006049 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 * to be in ISR context, because that is fatal!
6051 */
6052 in_isr = in_interrupt();
6053 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306054 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 ioc->name));
6056 return -EPERM;
6057 }
6058
6059 /* Get and Populate a free Frame
6060 */
6061 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306062 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 ioc->name));
6064 return -EAGAIN;
6065 }
6066 pReq = (Config_t *)mf;
6067 pReq->Action = pCfg->action;
6068 pReq->Reserved = 0;
6069 pReq->ChainOffset = 0;
6070 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006071
6072 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 pReq->ExtPageLength = 0;
6074 pReq->ExtPageType = 0;
6075 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006076
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 for (ii=0; ii < 8; ii++)
6078 pReq->Reserved2[ii] = 0;
6079
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006080 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6081 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6082 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6083 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6084
6085 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6086 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6087 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6088 pReq->ExtPageType = pExtHdr->ExtPageType;
6089 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6090
6091 /* Page Length must be treated as a reserved field for the extended header. */
6092 pReq->Header.PageLength = 0;
6093 }
6094
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6096
6097 /* Add a SGE to the config request.
6098 */
6099 if (pCfg->dir)
6100 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6101 else
6102 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6103
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006104 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6105 flagsLength |= pExtHdr->ExtPageLength * 4;
6106
Prakash, Sathya436ace72007-07-24 15:42:08 +05306107 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 +02006108 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
6109 }
6110 else {
6111 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
6112
Prakash, Sathya436ace72007-07-24 15:42:08 +05306113 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 +02006114 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
6115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306117 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 /* Append pCfg pointer to end of mf
6120 */
6121 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
6122
6123 /* Initalize the timer
6124 */
Eric Parisb298cec2009-04-21 12:24:54 -07006125 init_timer_on_stack(&pCfg->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 pCfg->timer.data = (unsigned long) ioc;
6127 pCfg->timer.function = mpt_timer_expired;
6128 pCfg->wait_done = 0;
6129
6130 /* Set the timer; ensure 10 second minimum */
6131 if (pCfg->timeout < 10)
6132 pCfg->timer.expires = jiffies + HZ*10;
6133 else
6134 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
6135
6136 /* Add to end of Q, set timer and then issue this command */
6137 spin_lock_irqsave(&ioc->FreeQlock, flags);
6138 list_add_tail(&pCfg->linkage, &ioc->configQ);
6139 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6140
6141 add_timer(&pCfg->timer);
6142 mpt_put_msg_frame(mpt_base_index, ioc, mf);
6143 wait_event(mpt_waitq, pCfg->wait_done);
6144
6145 /* mf has been freed - do not access */
6146
6147 rc = pCfg->status;
6148
6149 return rc;
6150}
6151
6152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006153/**
6154 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 * Used only internal config functionality.
6156 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
6157 */
6158static void
6159mpt_timer_expired(unsigned long data)
6160{
6161 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
6162
Prakash, Sathya436ace72007-07-24 15:42:08 +05306163 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164
6165 /* Perform a FW reload */
6166 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
6167 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
6168
6169 /* No more processing.
6170 * Hard reset clean-up will wake up
6171 * process and free all resources.
6172 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05306173 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
6175 return;
6176}
6177
6178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006179/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180 * mpt_ioc_reset - Base cleanup for hard reset
6181 * @ioc: Pointer to the adapter structure
6182 * @reset_phase: Indicates pre- or post-reset functionality
6183 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006184 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 */
6186static int
6187mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6188{
6189 CONFIGPARMS *pCfg;
6190 unsigned long flags;
6191
Eric Moore29dd3602007-09-14 18:46:51 -06006192 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6193 ": IOC %s_reset routed to MPT base driver!\n",
6194 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
6195 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196
6197 if (reset_phase == MPT_IOC_SETUP_RESET) {
6198 ;
6199 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6200 /* If the internal config Q is not empty -
6201 * delete timer. MF resources will be freed when
6202 * the FIFO's are primed.
6203 */
6204 spin_lock_irqsave(&ioc->FreeQlock, flags);
6205 list_for_each_entry(pCfg, &ioc->configQ, linkage)
6206 del_timer(&pCfg->timer);
6207 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6208
6209 } else {
6210 CONFIGPARMS *pNext;
6211
6212 /* Search the configQ for internal commands.
6213 * Flush the Q, and wake up all suspended threads.
6214 */
6215 spin_lock_irqsave(&ioc->FreeQlock, flags);
6216 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
6217 list_del(&pCfg->linkage);
6218
6219 pCfg->status = MPT_CONFIG_ERROR;
6220 pCfg->wait_done = 1;
6221 wake_up(&mpt_waitq);
6222 }
6223 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6224 }
6225
6226 return 1; /* currently means nothing really */
6227}
6228
6229
6230#ifdef CONFIG_PROC_FS /* { */
6231/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6232/*
6233 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6234 */
6235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006236/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6238 *
6239 * Returns 0 for success, non-zero for failure.
6240 */
6241static int
6242procmpt_create(void)
6243{
6244 struct proc_dir_entry *ent;
6245
6246 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6247 if (mpt_proc_root_dir == NULL)
6248 return -ENOTDIR;
6249
6250 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6251 if (ent)
6252 ent->read_proc = procmpt_summary_read;
6253
6254 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6255 if (ent)
6256 ent->read_proc = procmpt_version_read;
6257
6258 return 0;
6259}
6260
6261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006262/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6264 *
6265 * Returns 0 for success, non-zero for failure.
6266 */
6267static void
6268procmpt_destroy(void)
6269{
6270 remove_proc_entry("version", mpt_proc_root_dir);
6271 remove_proc_entry("summary", mpt_proc_root_dir);
6272 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6273}
6274
6275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006276/**
6277 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278 * @buf: Pointer to area to write information
6279 * @start: Pointer to start pointer
6280 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006281 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 * @eof: Pointer to EOF integer
6283 * @data: Pointer
6284 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006285 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 * Returns number of characters written to process performing the read.
6287 */
6288static int
6289procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6290{
6291 MPT_ADAPTER *ioc;
6292 char *out = buf;
6293 int len;
6294
6295 if (data) {
6296 int more = 0;
6297
6298 ioc = data;
6299 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6300
6301 out += more;
6302 } else {
6303 list_for_each_entry(ioc, &ioc_list, list) {
6304 int more = 0;
6305
6306 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6307
6308 out += more;
6309 if ((out-buf) >= request)
6310 break;
6311 }
6312 }
6313
6314 len = out - buf;
6315
6316 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6317}
6318
6319/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006320/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 * procmpt_version_read - Handle read request from /proc/mpt/version.
6322 * @buf: Pointer to area to write information
6323 * @start: Pointer to start pointer
6324 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006325 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 * @eof: Pointer to EOF integer
6327 * @data: Pointer
6328 *
6329 * Returns number of characters written to process performing the read.
6330 */
6331static int
6332procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6333{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306334 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006335 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 char *drvname;
6337 int len;
6338
6339 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6340 len += sprintf(buf+len, " Fusion MPT base driver\n");
6341
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006342 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006343 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306345 if (MptCallbacks[cb_idx]) {
6346 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006347 case MPTSPI_DRIVER:
6348 if (!scsi++) drvname = "SPI host";
6349 break;
6350 case MPTFC_DRIVER:
6351 if (!fc++) drvname = "FC host";
6352 break;
6353 case MPTSAS_DRIVER:
6354 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 break;
6356 case MPTLAN_DRIVER:
6357 if (!lan++) drvname = "LAN";
6358 break;
6359 case MPTSTM_DRIVER:
6360 if (!targ++) drvname = "SCSI target";
6361 break;
6362 case MPTCTL_DRIVER:
6363 if (!ctl++) drvname = "ioctl";
6364 break;
6365 }
6366
6367 if (drvname)
6368 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6369 }
6370 }
6371
6372 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6373}
6374
6375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006376/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6378 * @buf: Pointer to area to write information
6379 * @start: Pointer to start pointer
6380 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006381 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 * @eof: Pointer to EOF integer
6383 * @data: Pointer
6384 *
6385 * Returns number of characters written to process performing the read.
6386 */
6387static int
6388procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6389{
6390 MPT_ADAPTER *ioc = data;
6391 int len;
6392 char expVer[32];
6393 int sz;
6394 int p;
6395
6396 mpt_get_fw_exp_ver(expVer, ioc);
6397
6398 len = sprintf(buf, "%s:", ioc->name);
6399 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6400 len += sprintf(buf+len, " (f/w download boot flag set)");
6401// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6402// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6403
6404 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6405 ioc->facts.ProductID,
6406 ioc->prod_name);
6407 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6408 if (ioc->facts.FWImageSize)
6409 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6410 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6411 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6412 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6413
6414 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6415 ioc->facts.CurrentHostMfaHighAddr);
6416 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6417 ioc->facts.CurrentSenseBufferHighAddr);
6418
6419 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6420 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6421
6422 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6423 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6424 /*
6425 * Rounding UP to nearest 4-kB boundary here...
6426 */
6427 sz = (ioc->req_sz * ioc->req_depth) + 128;
6428 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6429 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6430 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6431 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6432 4*ioc->facts.RequestFrameSize,
6433 ioc->facts.GlobalCredits);
6434
6435 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6436 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6437 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6438 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6439 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6440 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6441 ioc->facts.CurReplyFrameSize,
6442 ioc->facts.ReplyQueueDepth);
6443
6444 len += sprintf(buf+len, " MaxDevices = %d\n",
6445 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6446 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6447
6448 /* per-port info */
6449 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6450 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6451 p+1,
6452 ioc->facts.NumberOfPorts);
6453 if (ioc->bus_type == FC) {
6454 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6455 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6456 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6457 a[5], a[4], a[3], a[2], a[1], a[0]);
6458 }
6459 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6460 ioc->fc_port_page0[p].WWNN.High,
6461 ioc->fc_port_page0[p].WWNN.Low,
6462 ioc->fc_port_page0[p].WWPN.High,
6463 ioc->fc_port_page0[p].WWPN.Low);
6464 }
6465 }
6466
6467 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6468}
6469
6470#endif /* CONFIG_PROC_FS } */
6471
6472/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6473static void
6474mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6475{
6476 buf[0] ='\0';
6477 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6478 sprintf(buf, " (Exp %02d%02d)",
6479 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6480 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6481
6482 /* insider hack! */
6483 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6484 strcat(buf, " [MDBG]");
6485 }
6486}
6487
6488/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6489/**
6490 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6491 * @ioc: Pointer to MPT_ADAPTER structure
6492 * @buffer: Pointer to buffer where IOC summary info should be written
6493 * @size: Pointer to number of bytes we wrote (set by this routine)
6494 * @len: Offset at which to start writing in buffer
6495 * @showlan: Display LAN stuff?
6496 *
6497 * This routine writes (english readable) ASCII text, which represents
6498 * a summary of IOC information, to a buffer.
6499 */
6500void
6501mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6502{
6503 char expVer[32];
6504 int y;
6505
6506 mpt_get_fw_exp_ver(expVer, ioc);
6507
6508 /*
6509 * Shorter summary of attached ioc's...
6510 */
6511 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6512 ioc->name,
6513 ioc->prod_name,
6514 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6515 ioc->facts.FWVersion.Word,
6516 expVer,
6517 ioc->facts.NumberOfPorts,
6518 ioc->req_depth);
6519
6520 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6521 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6522 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6523 a[5], a[4], a[3], a[2], a[1], a[0]);
6524 }
6525
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527
6528 if (!ioc->active)
6529 y += sprintf(buffer+len+y, " (disabled)");
6530
6531 y += sprintf(buffer+len+y, "\n");
6532
6533 *size = y;
6534}
6535
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306536
6537/**
6538 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6539 * the kernel
6540 * @ioc: Pointer to MPT_ADAPTER structure
6541 *
6542 **/
6543void
6544mpt_halt_firmware(MPT_ADAPTER *ioc)
6545{
6546 u32 ioc_raw_state;
6547
6548 ioc_raw_state = mpt_GetIocState(ioc, 0);
6549
6550 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6551 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6552 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6553 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6554 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6555 } else {
6556 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6557 panic("%s: Firmware is halted due to command timeout\n",
6558 ioc->name);
6559 }
6560}
6561EXPORT_SYMBOL(mpt_halt_firmware);
6562
Linus Torvalds1da177e2005-04-16 15:20:36 -07006563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6564/*
6565 * Reset Handling
6566 */
6567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6568/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006569 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570 * @ioc: Pointer to MPT_ADAPTER structure
6571 * @sleepFlag: Indicates if sleep or schedule must be called.
6572 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006573 * Issues SCSI Task Management call based on input arg values.
6574 * If TaskMgmt fails, returns associated SCSI request.
6575 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006576 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6577 * or a non-interrupt thread. In the former, must not call schedule().
6578 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006579 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580 * FW reload/initialization failed.
6581 *
6582 * Returns 0 for SUCCESS or -1 if FAILED.
6583 */
6584int
6585mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6586{
6587 int rc;
6588 unsigned long flags;
6589
Prakash, Sathya436ace72007-07-24 15:42:08 +05306590 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591#ifdef MFCNT
6592 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6593 printk("MF count 0x%x !\n", ioc->mfcnt);
6594#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306595 if (mpt_fwfault_debug)
6596 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597
6598 /* Reset the adapter. Prevent more than 1 call to
6599 * mpt_do_ioc_recovery at any instant in time.
6600 */
6601 spin_lock_irqsave(&ioc->diagLock, flags);
6602 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6603 spin_unlock_irqrestore(&ioc->diagLock, flags);
6604 return 0;
6605 } else {
6606 ioc->diagPending = 1;
6607 }
6608 spin_unlock_irqrestore(&ioc->diagLock, flags);
6609
6610 /* FIXME: If do_ioc_recovery fails, repeat....
6611 */
6612
6613 /* The SCSI driver needs to adjust timeouts on all current
6614 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006615 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 * For all other protocol drivers, this is a no-op.
6617 */
6618 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306619 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 int r = 0;
6621
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306622 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6623 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306624 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306625 ioc->name, cb_idx));
6626 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306628 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306629 ioc->name, ioc->alt_ioc->name, cb_idx));
6630 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 }
6632 }
6633 }
6634 }
6635
6636 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006637 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638 }
6639 ioc->reload_fw = 0;
6640 if (ioc->alt_ioc)
6641 ioc->alt_ioc->reload_fw = 0;
6642
6643 spin_lock_irqsave(&ioc->diagLock, flags);
6644 ioc->diagPending = 0;
6645 if (ioc->alt_ioc)
6646 ioc->alt_ioc->diagPending = 0;
6647 spin_unlock_irqrestore(&ioc->diagLock, flags);
6648
Prakash, Sathya436ace72007-07-24 15:42:08 +05306649 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006650
6651 return rc;
6652}
6653
6654/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006655static void
6656EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006657{
Eric Moore509e5e52006-04-26 13:22:37 -06006658 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
6660 switch(event) {
6661 case MPI_EVENT_NONE:
6662 ds = "None";
6663 break;
6664 case MPI_EVENT_LOG_DATA:
6665 ds = "Log Data";
6666 break;
6667 case MPI_EVENT_STATE_CHANGE:
6668 ds = "State Change";
6669 break;
6670 case MPI_EVENT_UNIT_ATTENTION:
6671 ds = "Unit Attention";
6672 break;
6673 case MPI_EVENT_IOC_BUS_RESET:
6674 ds = "IOC Bus Reset";
6675 break;
6676 case MPI_EVENT_EXT_BUS_RESET:
6677 ds = "External Bus Reset";
6678 break;
6679 case MPI_EVENT_RESCAN:
6680 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681 break;
6682 case MPI_EVENT_LINK_STATUS_CHANGE:
6683 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6684 ds = "Link Status(FAILURE) Change";
6685 else
6686 ds = "Link Status(ACTIVE) Change";
6687 break;
6688 case MPI_EVENT_LOOP_STATE_CHANGE:
6689 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6690 ds = "Loop State(LIP) Change";
6691 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006692 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006693 else
Eric Moore509e5e52006-04-26 13:22:37 -06006694 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 break;
6696 case MPI_EVENT_LOGOUT:
6697 ds = "Logout";
6698 break;
6699 case MPI_EVENT_EVENT_CHANGE:
6700 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006701 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006703 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704 break;
6705 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006706 {
6707 u8 ReasonCode = (u8)(evData0 >> 16);
6708 switch (ReasonCode) {
6709 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6710 ds = "Integrated Raid: Volume Created";
6711 break;
6712 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6713 ds = "Integrated Raid: Volume Deleted";
6714 break;
6715 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6716 ds = "Integrated Raid: Volume Settings Changed";
6717 break;
6718 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6719 ds = "Integrated Raid: Volume Status Changed";
6720 break;
6721 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6722 ds = "Integrated Raid: Volume Physdisk Changed";
6723 break;
6724 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6725 ds = "Integrated Raid: Physdisk Created";
6726 break;
6727 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6728 ds = "Integrated Raid: Physdisk Deleted";
6729 break;
6730 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6731 ds = "Integrated Raid: Physdisk Settings Changed";
6732 break;
6733 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6734 ds = "Integrated Raid: Physdisk Status Changed";
6735 break;
6736 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6737 ds = "Integrated Raid: Domain Validation Needed";
6738 break;
6739 case MPI_EVENT_RAID_RC_SMART_DATA :
6740 ds = "Integrated Raid; Smart Data";
6741 break;
6742 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6743 ds = "Integrated Raid: Replace Action Started";
6744 break;
6745 default:
6746 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006748 }
6749 break;
6750 }
6751 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6752 ds = "SCSI Device Status Change";
6753 break;
6754 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6755 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006756 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006757 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006758 u8 ReasonCode = (u8)(evData0 >> 16);
6759 switch (ReasonCode) {
6760 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006761 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006762 "SAS Device Status Change: Added: "
6763 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006764 break;
6765 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006766 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006767 "SAS Device Status Change: Deleted: "
6768 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006769 break;
6770 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006771 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006772 "SAS Device Status Change: SMART Data: "
6773 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006774 break;
6775 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006776 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006777 "SAS Device Status Change: No Persistancy: "
6778 "id=%d channel=%d", id, channel);
6779 break;
6780 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6781 snprintf(evStr, EVENT_DESCR_STR_SZ,
6782 "SAS Device Status Change: Unsupported Device "
6783 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006784 break;
6785 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6786 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006787 "SAS Device Status Change: Internal Device "
6788 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006789 break;
6790 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6791 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006792 "SAS Device Status Change: Internal Task "
6793 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006794 break;
6795 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6796 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006797 "SAS Device Status Change: Internal Abort "
6798 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006799 break;
6800 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6801 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006802 "SAS Device Status Change: Internal Clear "
6803 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006804 break;
6805 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6806 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006807 "SAS Device Status Change: Internal Query "
6808 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006809 break;
6810 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006811 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006812 "SAS Device Status Change: Unknown: "
6813 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006814 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006815 }
6816 break;
6817 }
6818 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6819 ds = "Bus Timer Expired";
6820 break;
6821 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006822 {
6823 u16 curr_depth = (u16)(evData0 >> 16);
6824 u8 channel = (u8)(evData0 >> 8);
6825 u8 id = (u8)(evData0);
6826
6827 snprintf(evStr, EVENT_DESCR_STR_SZ,
6828 "Queue Full: channel=%d id=%d depth=%d",
6829 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006830 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006831 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006832 case MPI_EVENT_SAS_SES:
6833 ds = "SAS SES Event";
6834 break;
6835 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6836 ds = "Persistent Table Full";
6837 break;
6838 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006839 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006840 u8 LinkRates = (u8)(evData0 >> 8);
6841 u8 PhyNumber = (u8)(evData0);
6842 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6843 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6844 switch (LinkRates) {
6845 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006846 snprintf(evStr, EVENT_DESCR_STR_SZ,
6847 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006848 " Rate Unknown",PhyNumber);
6849 break;
6850 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006851 snprintf(evStr, EVENT_DESCR_STR_SZ,
6852 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006853 " Phy Disabled",PhyNumber);
6854 break;
6855 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006856 snprintf(evStr, EVENT_DESCR_STR_SZ,
6857 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006858 " Failed Speed Nego",PhyNumber);
6859 break;
6860 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006861 snprintf(evStr, EVENT_DESCR_STR_SZ,
6862 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006863 " Sata OOB Completed",PhyNumber);
6864 break;
6865 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006866 snprintf(evStr, EVENT_DESCR_STR_SZ,
6867 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006868 " Rate 1.5 Gbps",PhyNumber);
6869 break;
6870 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006871 snprintf(evStr, EVENT_DESCR_STR_SZ,
6872 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006873 " Rate 3.0 Gpbs",PhyNumber);
6874 break;
6875 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006876 snprintf(evStr, EVENT_DESCR_STR_SZ,
6877 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006878 break;
6879 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006880 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006881 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006882 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6883 ds = "SAS Discovery Error";
6884 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006885 case MPI_EVENT_IR_RESYNC_UPDATE:
6886 {
6887 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006888 snprintf(evStr, EVENT_DESCR_STR_SZ,
6889 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006890 break;
6891 }
6892 case MPI_EVENT_IR2:
6893 {
6894 u8 ReasonCode = (u8)(evData0 >> 16);
6895 switch (ReasonCode) {
6896 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6897 ds = "IR2: LD State Changed";
6898 break;
6899 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6900 ds = "IR2: PD State Changed";
6901 break;
6902 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6903 ds = "IR2: Bad Block Table Full";
6904 break;
6905 case MPI_EVENT_IR2_RC_PD_INSERTED:
6906 ds = "IR2: PD Inserted";
6907 break;
6908 case MPI_EVENT_IR2_RC_PD_REMOVED:
6909 ds = "IR2: PD Removed";
6910 break;
6911 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6912 ds = "IR2: Foreign CFG Detected";
6913 break;
6914 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6915 ds = "IR2: Rebuild Medium Error";
6916 break;
6917 default:
6918 ds = "IR2";
6919 break;
6920 }
6921 break;
6922 }
6923 case MPI_EVENT_SAS_DISCOVERY:
6924 {
6925 if (evData0)
6926 ds = "SAS Discovery: Start";
6927 else
6928 ds = "SAS Discovery: Stop";
6929 break;
6930 }
6931 case MPI_EVENT_LOG_ENTRY_ADDED:
6932 ds = "SAS Log Entry Added";
6933 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006934
Eric Moorec6c727a2007-01-29 09:44:54 -07006935 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6936 {
6937 u8 phy_num = (u8)(evData0);
6938 u8 port_num = (u8)(evData0 >> 8);
6939 u8 port_width = (u8)(evData0 >> 16);
6940 u8 primative = (u8)(evData0 >> 24);
6941 snprintf(evStr, EVENT_DESCR_STR_SZ,
6942 "SAS Broadcase Primative: phy=%d port=%d "
6943 "width=%d primative=0x%02x",
6944 phy_num, port_num, port_width, primative);
6945 break;
6946 }
6947
6948 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
6949 {
6950 u8 reason = (u8)(evData0);
6951 u8 port_num = (u8)(evData0 >> 8);
6952 u16 handle = le16_to_cpu(evData0 >> 16);
6953
6954 snprintf(evStr, EVENT_DESCR_STR_SZ,
6955 "SAS Initiator Device Status Change: reason=0x%02x "
6956 "port=%d handle=0x%04x",
6957 reason, port_num, handle);
6958 break;
6959 }
6960
6961 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
6962 {
6963 u8 max_init = (u8)(evData0);
6964 u8 current_init = (u8)(evData0 >> 8);
6965
6966 snprintf(evStr, EVENT_DESCR_STR_SZ,
6967 "SAS Initiator Device Table Overflow: max initiators=%02d "
6968 "current initators=%02d",
6969 max_init, current_init);
6970 break;
6971 }
6972 case MPI_EVENT_SAS_SMP_ERROR:
6973 {
6974 u8 status = (u8)(evData0);
6975 u8 port_num = (u8)(evData0 >> 8);
6976 u8 result = (u8)(evData0 >> 16);
6977
6978 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
6979 snprintf(evStr, EVENT_DESCR_STR_SZ,
6980 "SAS SMP Error: port=%d result=0x%02x",
6981 port_num, result);
6982 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
6983 snprintf(evStr, EVENT_DESCR_STR_SZ,
6984 "SAS SMP Error: port=%d : CRC Error",
6985 port_num);
6986 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
6987 snprintf(evStr, EVENT_DESCR_STR_SZ,
6988 "SAS SMP Error: port=%d : Timeout",
6989 port_num);
6990 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
6991 snprintf(evStr, EVENT_DESCR_STR_SZ,
6992 "SAS SMP Error: port=%d : No Destination",
6993 port_num);
6994 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
6995 snprintf(evStr, EVENT_DESCR_STR_SZ,
6996 "SAS SMP Error: port=%d : Bad Destination",
6997 port_num);
6998 else
6999 snprintf(evStr, EVENT_DESCR_STR_SZ,
7000 "SAS SMP Error: port=%d : status=0x%02x",
7001 port_num, status);
7002 break;
7003 }
7004
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005 /*
7006 * MPT base "custom" events may be added here...
7007 */
7008 default:
7009 ds = "Unknown";
7010 break;
7011 }
Eric Moore509e5e52006-04-26 13:22:37 -06007012 if (ds)
7013 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014}
7015
7016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007017/**
7018 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007019 * @ioc: Pointer to MPT_ADAPTER structure
7020 * @pEventReply: Pointer to EventNotification reply frame
7021 * @evHandlers: Pointer to integer, number of event handlers
7022 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007023 * Routes a received EventNotificationReply to all currently registered
7024 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025 * Returns sum of event handlers return values.
7026 */
7027static int
7028ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7029{
7030 u16 evDataLen;
7031 u32 evData0 = 0;
7032// u32 evCtx;
7033 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307034 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007035 int r = 0;
7036 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007037 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007038 u8 event;
7039
7040 /*
7041 * Do platform normalization of values
7042 */
7043 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7044// evCtx = le32_to_cpu(pEventReply->EventContext);
7045 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7046 if (evDataLen) {
7047 evData0 = le32_to_cpu(pEventReply->Data[0]);
7048 }
7049
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007050 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307051 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007052 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007053 event,
7054 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007055
Prakash, Sathya436ace72007-07-24 15:42:08 +05307056#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007057 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7058 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307060 devtverboseprintk(ioc, printk(" %08x",
7061 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007062 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063#endif
7064
7065 /*
7066 * Do general / base driver event processing
7067 */
7068 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7070 if (evDataLen) {
7071 u8 evState = evData0 & 0xFF;
7072
7073 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7074
7075 /* Update EventState field in cached IocFacts */
7076 if (ioc->facts.Function) {
7077 ioc->facts.EventState = evState;
7078 }
7079 }
7080 break;
Moore, Ericece50912006-01-16 18:53:19 -07007081 case MPI_EVENT_INTEGRATED_RAID:
7082 mptbase_raid_process_event_data(ioc,
7083 (MpiEventDataRaid_t *)pEventReply->Data);
7084 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007085 default:
7086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087 }
7088
7089 /*
7090 * Should this event be logged? Events are written sequentially.
7091 * When buffer is full, start again at the top.
7092 */
7093 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7094 int idx;
7095
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007096 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097
7098 ioc->events[idx].event = event;
7099 ioc->events[idx].eventContext = ioc->eventContext;
7100
7101 for (ii = 0; ii < 2; ii++) {
7102 if (ii < evDataLen)
7103 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7104 else
7105 ioc->events[idx].data[ii] = 0;
7106 }
7107
7108 ioc->eventContext++;
7109 }
7110
7111
7112 /*
7113 * Call each currently registered protocol event handler.
7114 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007115 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307116 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307117 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307118 ioc->name, cb_idx));
7119 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120 handlers++;
7121 }
7122 }
7123 /* FIXME? Examine results here? */
7124
7125 /*
7126 * If needed, send (a single) EventAck.
7127 */
7128 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307129 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007130 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307132 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133 ioc->name, ii));
7134 }
7135 }
7136
7137 *evHandlers = handlers;
7138 return r;
7139}
7140
7141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007142/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7144 * @ioc: Pointer to MPT_ADAPTER structure
7145 * @log_info: U32 LogInfo reply word from the IOC
7146 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007147 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007148 */
7149static void
7150mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7151{
Eric Moore7c431e52007-06-13 16:34:36 -06007152 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153
Eric Moore7c431e52007-06-13 16:34:36 -06007154 switch (log_info & 0xFF000000) {
7155 case MPI_IOCLOGINFO_FC_INIT_BASE:
7156 desc = "FCP Initiator";
7157 break;
7158 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7159 desc = "FCP Target";
7160 break;
7161 case MPI_IOCLOGINFO_FC_LAN_BASE:
7162 desc = "LAN";
7163 break;
7164 case MPI_IOCLOGINFO_FC_MSG_BASE:
7165 desc = "MPI Message Layer";
7166 break;
7167 case MPI_IOCLOGINFO_FC_LINK_BASE:
7168 desc = "FC Link";
7169 break;
7170 case MPI_IOCLOGINFO_FC_CTX_BASE:
7171 desc = "Context Manager";
7172 break;
7173 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7174 desc = "Invalid Field Offset";
7175 break;
7176 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7177 desc = "State Change Info";
7178 break;
7179 }
7180
7181 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7182 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183}
7184
7185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007186/**
Moore, Eric335a9412006-01-17 17:06:23 -07007187 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189 * @log_info: U32 LogInfo word from the IOC
7190 *
7191 * Refer to lsi/sp_log.h.
7192 */
7193static void
Moore, Eric335a9412006-01-17 17:06:23 -07007194mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195{
7196 u32 info = log_info & 0x00FF0000;
7197 char *desc = "unknown";
7198
7199 switch (info) {
7200 case 0x00010000:
7201 desc = "bug! MID not found";
7202 if (ioc->reload_fw == 0)
7203 ioc->reload_fw++;
7204 break;
7205
7206 case 0x00020000:
7207 desc = "Parity Error";
7208 break;
7209
7210 case 0x00030000:
7211 desc = "ASYNC Outbound Overrun";
7212 break;
7213
7214 case 0x00040000:
7215 desc = "SYNC Offset Error";
7216 break;
7217
7218 case 0x00050000:
7219 desc = "BM Change";
7220 break;
7221
7222 case 0x00060000:
7223 desc = "Msg In Overflow";
7224 break;
7225
7226 case 0x00070000:
7227 desc = "DMA Error";
7228 break;
7229
7230 case 0x00080000:
7231 desc = "Outbound DMA Overrun";
7232 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007233
Linus Torvalds1da177e2005-04-16 15:20:36 -07007234 case 0x00090000:
7235 desc = "Task Management";
7236 break;
7237
7238 case 0x000A0000:
7239 desc = "Device Problem";
7240 break;
7241
7242 case 0x000B0000:
7243 desc = "Invalid Phase Change";
7244 break;
7245
7246 case 0x000C0000:
7247 desc = "Untagged Table Size";
7248 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007249
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250 }
7251
7252 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7253}
7254
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007255/* strings for sas loginfo */
7256 static char *originator_str[] = {
7257 "IOP", /* 00h */
7258 "PL", /* 01h */
7259 "IR" /* 02h */
7260 };
7261 static char *iop_code_str[] = {
7262 NULL, /* 00h */
7263 "Invalid SAS Address", /* 01h */
7264 NULL, /* 02h */
7265 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007266 "Diag Message Error", /* 04h */
7267 "Task Terminated", /* 05h */
7268 "Enclosure Management", /* 06h */
7269 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007270 };
7271 static char *pl_code_str[] = {
7272 NULL, /* 00h */
7273 "Open Failure", /* 01h */
7274 "Invalid Scatter Gather List", /* 02h */
7275 "Wrong Relative Offset or Frame Length", /* 03h */
7276 "Frame Transfer Error", /* 04h */
7277 "Transmit Frame Connected Low", /* 05h */
7278 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7279 "SATA Read Log Receive Data Error", /* 07h */
7280 "SATA NCQ Fail All Commands After Error", /* 08h */
7281 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7282 "Receive Frame Invalid Message", /* 0Ah */
7283 "Receive Context Message Valid Error", /* 0Bh */
7284 "Receive Frame Current Frame Error", /* 0Ch */
7285 "SATA Link Down", /* 0Dh */
7286 "Discovery SATA Init W IOS", /* 0Eh */
7287 "Config Invalid Page", /* 0Fh */
7288 "Discovery SATA Init Timeout", /* 10h */
7289 "Reset", /* 11h */
7290 "Abort", /* 12h */
7291 "IO Not Yet Executed", /* 13h */
7292 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007293 "Persistent Reservation Out Not Affiliation "
7294 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007295 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007296 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007297 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007298 NULL, /* 19h */
7299 NULL, /* 1Ah */
7300 NULL, /* 1Bh */
7301 NULL, /* 1Ch */
7302 NULL, /* 1Dh */
7303 NULL, /* 1Eh */
7304 NULL, /* 1Fh */
7305 "Enclosure Management" /* 20h */
7306 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007307 static char *ir_code_str[] = {
7308 "Raid Action Error", /* 00h */
7309 NULL, /* 00h */
7310 NULL, /* 01h */
7311 NULL, /* 02h */
7312 NULL, /* 03h */
7313 NULL, /* 04h */
7314 NULL, /* 05h */
7315 NULL, /* 06h */
7316 NULL /* 07h */
7317 };
7318 static char *raid_sub_code_str[] = {
7319 NULL, /* 00h */
7320 "Volume Creation Failed: Data Passed too "
7321 "Large", /* 01h */
7322 "Volume Creation Failed: Duplicate Volumes "
7323 "Attempted", /* 02h */
7324 "Volume Creation Failed: Max Number "
7325 "Supported Volumes Exceeded", /* 03h */
7326 "Volume Creation Failed: DMA Error", /* 04h */
7327 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7328 "Volume Creation Failed: Error Reading "
7329 "MFG Page 4", /* 06h */
7330 "Volume Creation Failed: Creating Internal "
7331 "Structures", /* 07h */
7332 NULL, /* 08h */
7333 NULL, /* 09h */
7334 NULL, /* 0Ah */
7335 NULL, /* 0Bh */
7336 NULL, /* 0Ch */
7337 NULL, /* 0Dh */
7338 NULL, /* 0Eh */
7339 NULL, /* 0Fh */
7340 "Activation failed: Already Active Volume", /* 10h */
7341 "Activation failed: Unsupported Volume Type", /* 11h */
7342 "Activation failed: Too Many Active Volumes", /* 12h */
7343 "Activation failed: Volume ID in Use", /* 13h */
7344 "Activation failed: Reported Failure", /* 14h */
7345 "Activation failed: Importing a Volume", /* 15h */
7346 NULL, /* 16h */
7347 NULL, /* 17h */
7348 NULL, /* 18h */
7349 NULL, /* 19h */
7350 NULL, /* 1Ah */
7351 NULL, /* 1Bh */
7352 NULL, /* 1Ch */
7353 NULL, /* 1Dh */
7354 NULL, /* 1Eh */
7355 NULL, /* 1Fh */
7356 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7357 "Phys Disk failed: Data Passed too Large", /* 21h */
7358 "Phys Disk failed: DMA Error", /* 22h */
7359 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7360 "Phys Disk failed: Creating Phys Disk Config "
7361 "Page", /* 24h */
7362 NULL, /* 25h */
7363 NULL, /* 26h */
7364 NULL, /* 27h */
7365 NULL, /* 28h */
7366 NULL, /* 29h */
7367 NULL, /* 2Ah */
7368 NULL, /* 2Bh */
7369 NULL, /* 2Ch */
7370 NULL, /* 2Dh */
7371 NULL, /* 2Eh */
7372 NULL, /* 2Fh */
7373 "Compatibility Error: IR Disabled", /* 30h */
7374 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7375 "Compatibility Error: Device not Direct Access "
7376 "Device ", /* 32h */
7377 "Compatibility Error: Removable Device Found", /* 33h */
7378 "Compatibility Error: Device SCSI Version not "
7379 "2 or Higher", /* 34h */
7380 "Compatibility Error: SATA Device, 48 BIT LBA "
7381 "not Supported", /* 35h */
7382 "Compatibility Error: Device doesn't have "
7383 "512 Byte Block Sizes", /* 36h */
7384 "Compatibility Error: Volume Type Check Failed", /* 37h */
7385 "Compatibility Error: Volume Type is "
7386 "Unsupported by FW", /* 38h */
7387 "Compatibility Error: Disk Drive too Small for "
7388 "use in Volume", /* 39h */
7389 "Compatibility Error: Phys Disk for Create "
7390 "Volume not Found", /* 3Ah */
7391 "Compatibility Error: Too Many or too Few "
7392 "Disks for Volume Type", /* 3Bh */
7393 "Compatibility Error: Disk stripe Sizes "
7394 "Must be 64KB", /* 3Ch */
7395 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7396 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007397
7398/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007399/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007400 * mpt_sas_log_info - Log information returned from SAS IOC.
7401 * @ioc: Pointer to MPT_ADAPTER structure
7402 * @log_info: U32 LogInfo reply word from the IOC
7403 *
7404 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007405 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007406static void
7407mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7408{
7409union loginfo_type {
7410 u32 loginfo;
7411 struct {
7412 u32 subcode:16;
7413 u32 code:8;
7414 u32 originator:4;
7415 u32 bus_type:4;
7416 }dw;
7417};
7418 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007419 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007420 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007421 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007422
7423 sas_loginfo.loginfo = log_info;
7424 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007425 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007426 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007427
7428 originator_desc = originator_str[sas_loginfo.dw.originator];
7429
7430 switch (sas_loginfo.dw.originator) {
7431
7432 case 0: /* IOP */
7433 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007434 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007435 code_desc = iop_code_str[sas_loginfo.dw.code];
7436 break;
7437 case 1: /* PL */
7438 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007439 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007440 code_desc = pl_code_str[sas_loginfo.dw.code];
7441 break;
7442 case 2: /* IR */
7443 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007444 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007445 break;
7446 code_desc = ir_code_str[sas_loginfo.dw.code];
7447 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007448 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007449 break;
7450 if (sas_loginfo.dw.code == 0)
7451 sub_code_desc =
7452 raid_sub_code_str[sas_loginfo.dw.subcode];
7453 break;
7454 default:
7455 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007456 }
7457
Eric Moorec6c727a2007-01-29 09:44:54 -07007458 if (sub_code_desc != NULL)
7459 printk(MYIOC_s_INFO_FMT
7460 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7461 " SubCode={%s}\n",
7462 ioc->name, log_info, originator_desc, code_desc,
7463 sub_code_desc);
7464 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007465 printk(MYIOC_s_INFO_FMT
7466 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7467 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007468 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007469 sas_loginfo.dw.subcode);
7470 else
7471 printk(MYIOC_s_INFO_FMT
7472 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7473 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007474 ioc->name, log_info, originator_desc,
7475 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007476}
7477
Linus Torvalds1da177e2005-04-16 15:20:36 -07007478/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007479/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007480 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7481 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007482 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007483 * @mf: Pointer to MPT request frame
7484 *
7485 * Refer to lsi/mpi.h.
7486 **/
7487static void
7488mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7489{
7490 Config_t *pReq = (Config_t *)mf;
7491 char extend_desc[EVENT_DESCR_STR_SZ];
7492 char *desc = NULL;
7493 u32 form;
7494 u8 page_type;
7495
7496 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7497 page_type = pReq->ExtPageType;
7498 else
7499 page_type = pReq->Header.PageType;
7500
7501 /*
7502 * ignore invalid page messages for GET_NEXT_HANDLE
7503 */
7504 form = le32_to_cpu(pReq->PageAddress);
7505 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7506 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7507 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7508 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7509 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7510 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7511 return;
7512 }
7513 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7514 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7515 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7516 return;
7517 }
7518
7519 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7520 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7521 page_type, pReq->Header.PageNumber, pReq->Action, form);
7522
7523 switch (ioc_status) {
7524
7525 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7526 desc = "Config Page Invalid Action";
7527 break;
7528
7529 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7530 desc = "Config Page Invalid Type";
7531 break;
7532
7533 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7534 desc = "Config Page Invalid Page";
7535 break;
7536
7537 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7538 desc = "Config Page Invalid Data";
7539 break;
7540
7541 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7542 desc = "Config Page No Defaults";
7543 break;
7544
7545 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7546 desc = "Config Page Can't Commit";
7547 break;
7548 }
7549
7550 if (!desc)
7551 return;
7552
Eric Moore29dd3602007-09-14 18:46:51 -06007553 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7554 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007555}
7556
7557/**
7558 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007559 * @ioc: Pointer to MPT_ADAPTER structure
7560 * @ioc_status: U32 IOCStatus word from IOC
7561 * @mf: Pointer to MPT request frame
7562 *
7563 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007564 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007566mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567{
7568 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007569 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007570
7571 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007572
7573/****************************************************************************/
7574/* Common IOCStatus values for all replies */
7575/****************************************************************************/
7576
Linus Torvalds1da177e2005-04-16 15:20:36 -07007577 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7578 desc = "Invalid Function";
7579 break;
7580
7581 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7582 desc = "Busy";
7583 break;
7584
7585 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7586 desc = "Invalid SGL";
7587 break;
7588
7589 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7590 desc = "Internal Error";
7591 break;
7592
7593 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7594 desc = "Reserved";
7595 break;
7596
7597 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7598 desc = "Insufficient Resources";
7599 break;
7600
7601 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7602 desc = "Invalid Field";
7603 break;
7604
7605 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7606 desc = "Invalid State";
7607 break;
7608
Eric Moorec6c727a2007-01-29 09:44:54 -07007609/****************************************************************************/
7610/* Config IOCStatus values */
7611/****************************************************************************/
7612
Linus Torvalds1da177e2005-04-16 15:20:36 -07007613 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7614 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7615 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7616 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7617 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7618 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007619 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620 break;
7621
Eric Moorec6c727a2007-01-29 09:44:54 -07007622/****************************************************************************/
7623/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7624/* */
7625/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7626/* */
7627/****************************************************************************/
7628
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007631 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7632 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7633 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7634 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007641 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 break;
7643
Eric Moorec6c727a2007-01-29 09:44:54 -07007644/****************************************************************************/
7645/* SCSI Target values */
7646/****************************************************************************/
7647
7648 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7649 desc = "Target: Priority IO";
7650 break;
7651
7652 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7653 desc = "Target: Invalid Port";
7654 break;
7655
7656 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7657 desc = "Target Invalid IO Index:";
7658 break;
7659
7660 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7661 desc = "Target: Aborted";
7662 break;
7663
7664 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7665 desc = "Target: No Conn Retryable";
7666 break;
7667
7668 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7669 desc = "Target: No Connection";
7670 break;
7671
7672 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7673 desc = "Target: Transfer Count Mismatch";
7674 break;
7675
7676 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7677 desc = "Target: STS Data not Sent";
7678 break;
7679
7680 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7681 desc = "Target: Data Offset Error";
7682 break;
7683
7684 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7685 desc = "Target: Too Much Write Data";
7686 break;
7687
7688 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7689 desc = "Target: IU Too Short";
7690 break;
7691
7692 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7693 desc = "Target: ACK NAK Timeout";
7694 break;
7695
7696 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7697 desc = "Target: Nak Received";
7698 break;
7699
7700/****************************************************************************/
7701/* Fibre Channel Direct Access values */
7702/****************************************************************************/
7703
7704 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7705 desc = "FC: Aborted";
7706 break;
7707
7708 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7709 desc = "FC: RX ID Invalid";
7710 break;
7711
7712 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7713 desc = "FC: DID Invalid";
7714 break;
7715
7716 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7717 desc = "FC: Node Logged Out";
7718 break;
7719
7720 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7721 desc = "FC: Exchange Canceled";
7722 break;
7723
7724/****************************************************************************/
7725/* LAN values */
7726/****************************************************************************/
7727
7728 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7729 desc = "LAN: Device not Found";
7730 break;
7731
7732 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7733 desc = "LAN: Device Failure";
7734 break;
7735
7736 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7737 desc = "LAN: Transmit Error";
7738 break;
7739
7740 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7741 desc = "LAN: Transmit Aborted";
7742 break;
7743
7744 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7745 desc = "LAN: Receive Error";
7746 break;
7747
7748 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7749 desc = "LAN: Receive Aborted";
7750 break;
7751
7752 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7753 desc = "LAN: Partial Packet";
7754 break;
7755
7756 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7757 desc = "LAN: Canceled";
7758 break;
7759
7760/****************************************************************************/
7761/* Serial Attached SCSI values */
7762/****************************************************************************/
7763
7764 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7765 desc = "SAS: SMP Request Failed";
7766 break;
7767
7768 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7769 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007770 break;
7771
7772 default:
7773 desc = "Others";
7774 break;
7775 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007776
7777 if (!desc)
7778 return;
7779
Eric Moore29dd3602007-09-14 18:46:51 -06007780 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7781 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782}
7783
7784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007785EXPORT_SYMBOL(mpt_attach);
7786EXPORT_SYMBOL(mpt_detach);
7787#ifdef CONFIG_PM
7788EXPORT_SYMBOL(mpt_resume);
7789EXPORT_SYMBOL(mpt_suspend);
7790#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007791EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792EXPORT_SYMBOL(mpt_register);
7793EXPORT_SYMBOL(mpt_deregister);
7794EXPORT_SYMBOL(mpt_event_register);
7795EXPORT_SYMBOL(mpt_event_deregister);
7796EXPORT_SYMBOL(mpt_reset_register);
7797EXPORT_SYMBOL(mpt_reset_deregister);
7798EXPORT_SYMBOL(mpt_device_driver_register);
7799EXPORT_SYMBOL(mpt_device_driver_deregister);
7800EXPORT_SYMBOL(mpt_get_msg_frame);
7801EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307802EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007803EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007804EXPORT_SYMBOL(mpt_send_handshake_request);
7805EXPORT_SYMBOL(mpt_verify_adapter);
7806EXPORT_SYMBOL(mpt_GetIocState);
7807EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808EXPORT_SYMBOL(mpt_HardResetHandler);
7809EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007810EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811EXPORT_SYMBOL(mpt_alloc_fw_memory);
7812EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007813EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007814EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007815
Linus Torvalds1da177e2005-04-16 15:20:36 -07007816/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007817/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007818 * fusion_init - Fusion MPT base driver initialization routine.
7819 *
7820 * Returns 0 for success, non-zero for failure.
7821 */
7822static int __init
7823fusion_init(void)
7824{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307825 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007826
7827 show_mptmod_ver(my_NAME, my_VERSION);
7828 printk(KERN_INFO COPYRIGHT "\n");
7829
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307830 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7831 MptCallbacks[cb_idx] = NULL;
7832 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7833 MptEvHandlers[cb_idx] = NULL;
7834 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007835 }
7836
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007837 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838 * EventNotification handling.
7839 */
7840 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7841
7842 /* Register for hard reset handling callbacks.
7843 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307844 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007845
7846#ifdef CONFIG_PROC_FS
7847 (void) procmpt_create();
7848#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007849 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007850}
7851
7852/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007853/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854 * fusion_exit - Perform driver unload cleanup.
7855 *
7856 * This routine frees all resources associated with each MPT adapter
7857 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7858 */
7859static void __exit
7860fusion_exit(void)
7861{
7862
Linus Torvalds1da177e2005-04-16 15:20:36 -07007863 mpt_reset_deregister(mpt_base_index);
7864
7865#ifdef CONFIG_PROC_FS
7866 procmpt_destroy();
7867#endif
7868}
7869
Linus Torvalds1da177e2005-04-16 15:20:36 -07007870module_init(fusion_init);
7871module_exit(fusion_exit);