blob: 0d2fb0eb34b9a144c0f35792fa6508c3acafbaff [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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
196 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200198static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
199static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201#ifdef CONFIG_PROC_FS
202static int procmpt_summary_read(char *buf, char **start, off_t offset,
203 int request, int *eof, void *data);
204static int procmpt_version_read(char *buf, char **start, off_t offset,
205 int request, int *eof, void *data);
206static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
207 int request, int *eof, void *data);
208#endif
209static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
210
211//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530212static int ProcessEventNotification(MPT_ADAPTER *ioc,
213 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700214static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700216static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600217static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700218static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700219static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static int __init fusion_init (void);
223static void __exit fusion_exit (void);
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225#define CHIPREG_READ32(addr) readl_relaxed(addr)
226#define CHIPREG_READ32_dmasync(addr) readl(addr)
227#define CHIPREG_WRITE32(addr,val) writel(val, addr)
228#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
229#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
230
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600231static void
232pci_disable_io_access(struct pci_dev *pdev)
233{
234 u16 command_reg;
235
236 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
237 command_reg &= ~1;
238 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
239}
240
241static void
242pci_enable_io_access(struct pci_dev *pdev)
243{
244 u16 command_reg;
245
246 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
247 command_reg |= 1;
248 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
249}
250
James Bottomleydb47c2d2007-07-28 13:40:21 -0400251static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
252{
253 int ret = param_set_int(val, kp);
254 MPT_ADAPTER *ioc;
255
256 if (ret)
257 return ret;
258
259 list_for_each_entry(ioc, &ioc_list, list)
260 ioc->debug_level = mpt_debug_level;
261 return 0;
262}
263
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264/**
265 * mpt_get_cb_idx - obtain cb_idx for registered driver
266 * @dclass: class driver enum
267 *
268 * Returns cb_idx, or zero means it wasn't found
269 **/
270static u8
271mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
272{
273 u8 cb_idx;
274
275 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
276 if (MptDriverClass[cb_idx] == dclass)
277 return cb_idx;
278 return 0;
279}
280
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530281/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530282 * mpt_is_discovery_complete - determine if discovery has completed
283 * @ioc: per adatper instance
284 *
285 * Returns 1 when discovery completed, else zero.
286 */
287static int
288mpt_is_discovery_complete(MPT_ADAPTER *ioc)
289{
290 ConfigExtendedPageHeader_t hdr;
291 CONFIGPARMS cfg;
292 SasIOUnitPage0_t *buffer;
293 dma_addr_t dma_handle;
294 int rc = 0;
295
296 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
297 memset(&cfg, 0, sizeof(CONFIGPARMS));
298 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
299 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
300 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
301 cfg.cfghdr.ehdr = &hdr;
302 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
303
304 if ((mpt_config(ioc, &cfg)))
305 goto out;
306 if (!hdr.ExtPageLength)
307 goto out;
308
309 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
310 &dma_handle);
311 if (!buffer)
312 goto out;
313
314 cfg.physAddr = dma_handle;
315 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
316
317 if ((mpt_config(ioc, &cfg)))
318 goto out_free_consistent;
319
320 if (!(buffer->PhyData[0].PortFlags &
321 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
322 rc = 1;
323
324 out_free_consistent:
325 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
326 buffer, dma_handle);
327 out:
328 return rc;
329}
330
331/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530332 * mpt_fault_reset_work - work performed on workq after ioc fault
333 * @work: input argument, used to derive ioc
334 *
335**/
336static void
337mpt_fault_reset_work(struct work_struct *work)
338{
339 MPT_ADAPTER *ioc =
340 container_of(work, MPT_ADAPTER, fault_reset_work.work);
341 u32 ioc_raw_state;
342 int rc;
343 unsigned long flags;
344
345 if (ioc->diagPending || !ioc->active)
346 goto out;
347
348 ioc_raw_state = mpt_GetIocState(ioc, 0);
349 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
350 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700351 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700353 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530354 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
355 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700356 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530357 ioc_raw_state = mpt_GetIocState(ioc, 0);
358 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
359 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
360 "reset (%04xh)\n", ioc->name, ioc_raw_state &
361 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530362 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
363 if ((mpt_is_discovery_complete(ioc))) {
364 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
365 "discovery_quiesce_io flag\n", ioc->name));
366 ioc->sas_discovery_quiesce_io = 0;
367 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530368 }
369
370 out:
371 /*
372 * Take turns polling alternate controller
373 */
374 if (ioc->alt_ioc)
375 ioc = ioc->alt_ioc;
376
377 /* rearm the timer */
378 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
379 if (ioc->reset_work_q)
380 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
381 msecs_to_jiffies(MPT_POLLING_INTERVAL));
382 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
383}
384
385
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600386/*
387 * Process turbo (context) reply...
388 */
389static void
390mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
391{
392 MPT_FRAME_HDR *mf = NULL;
393 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530394 u16 req_idx = 0;
395 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600396
Prakash, Sathya436ace72007-07-24 15:42:08 +0530397 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600398 ioc->name, pa));
399
400 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
401 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
402 req_idx = pa & 0x0000FFFF;
403 cb_idx = (pa & 0x00FF0000) >> 16;
404 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
405 break;
406 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530407 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600408 /*
409 * Blind set of mf to NULL here was fatal
410 * after lan_reply says "freeme"
411 * Fix sort of combined with an optimization here;
412 * added explicit check for case where lan_reply
413 * was just returning 1 and doing nothing else.
414 * For this case skip the callback, but set up
415 * proper mf value first here:-)
416 */
417 if ((pa & 0x58000000) == 0x58000000) {
418 req_idx = pa & 0x0000FFFF;
419 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
420 mpt_free_msg_frame(ioc, mf);
421 mb();
422 return;
423 break;
424 }
425 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
426 break;
427 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530428 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600429 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
430 break;
431 default:
432 cb_idx = 0;
433 BUG();
434 }
435
436 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530437 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600438 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700440 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600441 goto out;
442 }
443
444 if (MptCallbacks[cb_idx](ioc, mf, mr))
445 mpt_free_msg_frame(ioc, mf);
446 out:
447 mb();
448}
449
450static void
451mpt_reply(MPT_ADAPTER *ioc, u32 pa)
452{
453 MPT_FRAME_HDR *mf;
454 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530455 u16 req_idx;
456 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600457 int freeme;
458
459 u32 reply_dma_low;
460 u16 ioc_stat;
461
462 /* non-TURBO reply! Hmmm, something may be up...
463 * Newest turbo reply mechanism; get address
464 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
465 */
466
467 /* Map DMA address of reply header to cpu address.
468 * pa is 32 bits - but the dma address may be 32 or 64 bits
469 * get offset based only only the low addresses
470 */
471
472 reply_dma_low = (pa <<= 1);
473 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
474 (reply_dma_low - ioc->reply_frames_low_dma));
475
476 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
477 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
478 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
479
Prakash, Sathya436ace72007-07-24 15:42:08 +0530480 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 -0600481 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600482 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600483
484 /* Check/log IOC log info
485 */
486 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
487 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
488 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
489 if (ioc->bus_type == FC)
490 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700491 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700492 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600493 else if (ioc->bus_type == SAS)
494 mpt_sas_log_info(ioc, log_info);
495 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600496
Eric Moorec6c727a2007-01-29 09:44:54 -0700497 if (ioc_stat & MPI_IOCSTATUS_MASK)
498 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600499
500 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530501 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600502 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600503 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700504 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600505 freeme = 0;
506 goto out;
507 }
508
509 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
510
511 out:
512 /* Flush (non-TURBO) reply with a WRITE! */
513 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
514
515 if (freeme)
516 mpt_free_msg_frame(ioc, mf);
517 mb();
518}
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800521/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
523 * @irq: irq number (not used)
524 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 *
526 * This routine is registered via the request_irq() kernel API call,
527 * and handles all interrupts generated from a specific MPT adapter
528 * (also referred to as a IO Controller or IOC).
529 * This routine must clear the interrupt from the adapter and does
530 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200531 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 *
533 * This routine handles register-level access of the adapter but
534 * dispatches (calls) a protocol-specific callback routine to handle
535 * the protocol-specific details of the MPT request completion.
536 */
537static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100538mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600540 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600541 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
542
543 if (pa == 0xFFFFFFFF)
544 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 /*
547 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600549 do {
550 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600551 mpt_reply(ioc, pa);
552 else
553 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600554 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
555 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 return IRQ_HANDLED;
558}
559
560/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800561/**
562 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 * @ioc: Pointer to MPT_ADAPTER structure
564 * @mf: Pointer to original MPT request frame
565 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
566 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800567 * MPT base driver's callback routine; all base driver
568 * "internal" request/reply processing is routed here.
569 * Currently used for EventNotification and EventAck handling.
570 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200571 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 * should be freed, or 0 if it shouldn't.
573 */
574static int
575mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
576{
577 int freereq = 1;
578 u8 func;
579
Prakash, Sathya436ace72007-07-24 15:42:08 +0530580 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
581#ifdef CONFIG_FUSION_LOGGING
582 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
583 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600584 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
585 ioc->name, mf));
586 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200588#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530591 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 ioc->name, func));
593
594 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
595 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
596 int evHandlers = 0;
597 int results;
598
599 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
600 if (results != evHandlers) {
601 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530602 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 ioc->name, evHandlers, results));
604 }
605
606 /*
607 * Hmmm... It seems that EventNotificationReply is an exception
608 * to the rule of one reply per request.
609 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200610 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200612 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530613 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200614 ioc->name, pEvReply));
615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617#ifdef CONFIG_PROC_FS
618// LogEvent(ioc, pEvReply);
619#endif
620
621 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530622 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700624 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 CONFIGPARMS *pCfg;
626 unsigned long flags;
627
Prakash, Sathya436ace72007-07-24 15:42:08 +0530628 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 ioc->name, mf, reply));
630
631 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
632
633 if (pCfg) {
634 /* disable timer and remove from linked list */
635 del_timer(&pCfg->timer);
636
637 spin_lock_irqsave(&ioc->FreeQlock, flags);
638 list_del(&pCfg->linkage);
639 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
640
641 /*
642 * If IOC Status is SUCCESS, save the header
643 * and set the status code to GOOD.
644 */
645 pCfg->status = MPT_CONFIG_ERROR;
646 if (reply) {
647 ConfigReply_t *pReply = (ConfigReply_t *)reply;
648 u16 status;
649
650 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600651 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
652 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 pCfg->status = status;
655 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200656 if ((pReply->Header.PageType &
657 MPI_CONFIG_PAGETYPE_MASK) ==
658 MPI_CONFIG_PAGETYPE_EXTENDED) {
659 pCfg->cfghdr.ehdr->ExtPageLength =
660 le16_to_cpu(pReply->ExtPageLength);
661 pCfg->cfghdr.ehdr->ExtPageType =
662 pReply->ExtPageType;
663 }
664 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
665
666 /* If this is a regular header, save PageLength. */
667 /* LMP Do this better so not using a reserved field! */
668 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
669 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
670 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
672 }
673
674 /*
675 * Wake up the original calling thread
676 */
677 pCfg->wait_done = 1;
678 wake_up(&mpt_waitq);
679 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200680 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
681 /* we should be always getting a reply frame */
682 memcpy(ioc->persist_reply_frame, reply,
683 min(MPT_DEFAULT_FRAME_SIZE,
684 4*reply->u.reply.MsgLength));
685 del_timer(&ioc->persist_timer);
686 ioc->persist_wait_done = 1;
687 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 } else {
689 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
690 ioc->name, func);
691 }
692
693 /*
694 * Conditionally tell caller to free the original
695 * EventNotification/EventAck/unexpected request frame!
696 */
697 return freereq;
698}
699
700/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
701/**
702 * mpt_register - Register protocol-specific main callback handler.
703 * @cbfunc: callback function pointer
704 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
705 *
706 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800707 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 * protocol-specific driver must do this before it will be able to
709 * use any IOC resources, such as obtaining request frames.
710 *
711 * NOTES: The SCSI protocol driver currently calls this routine thrice
712 * in order to register separate callbacks; one for "normal" SCSI IO;
713 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
714 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530715 * Returns u8 valued "handle" in the range (and S.O.D. order)
716 * {N,...,7,6,5,...,1} if successful.
717 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
718 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
722{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530723 u8 cb_idx;
724 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /*
727 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
728 * (slot/handle 0 is reserved!)
729 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530730 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
731 if (MptCallbacks[cb_idx] == NULL) {
732 MptCallbacks[cb_idx] = cbfunc;
733 MptDriverClass[cb_idx] = dclass;
734 MptEvHandlers[cb_idx] = NULL;
735 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 break;
737 }
738 }
739
740 return last_drv_idx;
741}
742
743/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
744/**
745 * mpt_deregister - Deregister a protocol drivers resources.
746 * @cb_idx: previously registered callback handle
747 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800748 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 * module is unloaded.
750 */
751void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530752mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600754 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 MptCallbacks[cb_idx] = NULL;
756 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
757 MptEvHandlers[cb_idx] = NULL;
758
759 last_drv_idx++;
760 }
761}
762
763/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
764/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800765 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 * @cb_idx: previously registered (via mpt_register) callback handle
767 * @ev_cbfunc: callback function
768 *
769 * This routine can be called by one or more protocol-specific drivers
770 * if/when they choose to be notified of MPT events.
771 *
772 * Returns 0 for success.
773 */
774int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530775mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600777 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return -1;
779
780 MptEvHandlers[cb_idx] = ev_cbfunc;
781 return 0;
782}
783
784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
785/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800786 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 * @cb_idx: previously registered callback handle
788 *
789 * Each protocol-specific driver should call this routine
790 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800791 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 */
793void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530794mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600796 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 return;
798
799 MptEvHandlers[cb_idx] = NULL;
800}
801
802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
803/**
804 * mpt_reset_register - Register protocol-specific IOC reset handler.
805 * @cb_idx: previously registered (via mpt_register) callback handle
806 * @reset_func: reset function
807 *
808 * This routine can be called by one or more protocol-specific drivers
809 * if/when they choose to be notified of IOC resets.
810 *
811 * Returns 0 for success.
812 */
813int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530814mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530816 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return -1;
818
819 MptResetHandlers[cb_idx] = reset_func;
820 return 0;
821}
822
823/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
824/**
825 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
826 * @cb_idx: previously registered callback handle
827 *
828 * Each protocol-specific driver should call this routine
829 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800830 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 */
832void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530835 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 return;
837
838 MptResetHandlers[cb_idx] = NULL;
839}
840
841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
842/**
843 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800844 * @dd_cbfunc: driver callbacks struct
845 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 */
847int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530848mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
850 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600851 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Eric Moore8d6d83e2007-09-14 18:47:40 -0600853 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400854 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
856 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
857
858 /* call per pci device probe entry point */
859 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600860 id = ioc->pcidev->driver ?
861 ioc->pcidev->driver->id_table : NULL;
862 if (dd_cbfunc->probe)
863 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
865
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400866 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867}
868
869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
870/**
871 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800872 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 */
874void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530875mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 struct mpt_pci_driver *dd_cbfunc;
878 MPT_ADAPTER *ioc;
879
Eric Moore8d6d83e2007-09-14 18:47:40 -0600880 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return;
882
883 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
884
885 list_for_each_entry(ioc, &ioc_list, list) {
886 if (dd_cbfunc->remove)
887 dd_cbfunc->remove(ioc->pcidev);
888 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 MptDeviceDriverHandlers[cb_idx] = NULL;
891}
892
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800896 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530897 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 * @ioc: Pointer to MPT adapter structure
899 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800900 * Obtain an MPT request frame from the pool (of 1024) that are
901 * allocated per MPT adapter.
902 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 * Returns pointer to a MPT request frame or %NULL if none are available
904 * or IOC is not active.
905 */
906MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530907mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
909 MPT_FRAME_HDR *mf;
910 unsigned long flags;
911 u16 req_idx; /* Request index */
912
913 /* validate handle and ioc identifier */
914
915#ifdef MFCNT
916 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600917 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
918 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919#endif
920
921 /* If interrupts are not attached, do not return a request frame */
922 if (!ioc->active)
923 return NULL;
924
925 spin_lock_irqsave(&ioc->FreeQlock, flags);
926 if (!list_empty(&ioc->FreeQ)) {
927 int req_offset;
928
929 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
930 u.frame.linkage.list);
931 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200932 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530933 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
935 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500936 req_idx = req_offset / ioc->req_sz;
937 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600939 /* Default, will be changed if necessary in SG generation */
940 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941#ifdef MFCNT
942 ioc->mfcnt++;
943#endif
944 }
945 else
946 mf = NULL;
947 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
948
949#ifdef MFCNT
950 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600951 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
952 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
953 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 mfcounter++;
955 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600956 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
957 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958#endif
959
Eric Moore29dd3602007-09-14 18:46:51 -0600960 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
961 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return mf;
963}
964
965/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
966/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800967 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530968 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 * @ioc: Pointer to MPT adapter structure
970 * @mf: Pointer to MPT request frame
971 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800972 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 * specific MPT adapter.
974 */
975void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530976mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 u32 mf_dma_addr;
979 int req_offset;
980 u16 req_idx; /* Request index */
981
982 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530983 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
985 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500986 req_idx = req_offset / ioc->req_sz;
987 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
989
Prakash, Sathya436ace72007-07-24 15:42:08 +0530990 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200992 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600993 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
994 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
995 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
997}
998
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530999/**
Randy Dunlap7105a382008-02-29 22:03:27 -08001000 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301001 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301002 * @ioc: Pointer to MPT adapter structure
1003 * @mf: Pointer to MPT request frame
1004 *
Randy Dunlap7105a382008-02-29 22:03:27 -08001005 * Send a protocol-specific MPT request frame to an IOC using
1006 * hi-priority request queue.
1007 *
1008 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301009 * specific MPT adapter.
1010 **/
1011void
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301012mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301013{
1014 u32 mf_dma_addr;
1015 int req_offset;
1016 u16 req_idx; /* Request index */
1017
1018 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301019 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301020 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
1021 req_idx = req_offset / ioc->req_sz;
1022 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
1023 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
1024
1025 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
1026
1027 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
1028 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
1029 ioc->name, mf_dma_addr, req_idx));
1030 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
1031}
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1034/**
1035 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 * @ioc: Pointer to MPT adapter structure
1037 * @mf: Pointer to MPT request frame
1038 *
1039 * This routine places a MPT request frame back on the MPT adapter's
1040 * FreeQ.
1041 */
1042void
1043mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
1044{
1045 unsigned long flags;
1046
1047 /* Put Request back on FreeQ! */
1048 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001049 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
1051#ifdef MFCNT
1052 ioc->mfcnt--;
1053#endif
1054 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1055}
1056
1057/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1058/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301059 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 * @pAddr: virtual address for SGE
1061 * @flagslength: SGE flags and data transfer length
1062 * @dma_addr: Physical address
1063 *
1064 * This routine places a MPT request frame back on the MPT adapter's
1065 * FreeQ.
1066 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301067static void
1068mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301070 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1071 pSge->FlagsLength = cpu_to_le32(flagslength);
1072 pSge->Address = cpu_to_le32(dma_addr);
1073}
1074
1075/**
1076 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1077 * @pAddr: virtual address for SGE
1078 * @flagslength: SGE flags and data transfer length
1079 * @dma_addr: Physical address
1080 *
1081 * This routine places a MPT request frame back on the MPT adapter's
1082 * FreeQ.
1083 **/
1084static void
1085mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1086{
1087 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1088 pSge->Address.Low = cpu_to_le32
1089 (lower_32_bits((unsigned long)(dma_addr)));
1090 pSge->Address.High = cpu_to_le32
1091 (upper_32_bits((unsigned long)dma_addr));
1092 pSge->FlagsLength = cpu_to_le32
1093 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1094}
1095
1096/**
1097 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1098 * (1078 workaround).
1099 * @pAddr: virtual address for SGE
1100 * @flagslength: SGE flags and data transfer length
1101 * @dma_addr: Physical address
1102 *
1103 * This routine places a MPT request frame back on the MPT adapter's
1104 * FreeQ.
1105 **/
1106static void
1107mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1108{
1109 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1110 u32 tmp;
1111
1112 pSge->Address.Low = cpu_to_le32
1113 (lower_32_bits((unsigned long)(dma_addr)));
1114 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1115
1116 /*
1117 * 1078 errata workaround for the 36GB limitation
1118 */
1119 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1120 flagslength |=
1121 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1122 tmp |= (1<<31);
1123 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1124 printk(KERN_DEBUG "1078 P0M2 addressing for "
1125 "addr = 0x%llx len = %d\n",
1126 (unsigned long long)dma_addr,
1127 MPI_SGE_LENGTH(flagslength));
1128 }
1129
1130 pSge->Address.High = cpu_to_le32(tmp);
1131 pSge->FlagsLength = cpu_to_le32(
1132 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1133}
1134
1135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1136/**
1137 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1138 * @pAddr: virtual address for SGE
1139 * @next: nextChainOffset value (u32's)
1140 * @length: length of next SGL segment
1141 * @dma_addr: Physical address
1142 *
1143 */
1144static void
1145mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1146{
1147 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1148 pChain->Length = cpu_to_le16(length);
1149 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1150 pChain->NextChainOffset = next;
1151 pChain->Address = cpu_to_le32(dma_addr);
1152}
1153
1154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1155/**
1156 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1157 * @pAddr: virtual address for SGE
1158 * @next: nextChainOffset value (u32's)
1159 * @length: length of next SGL segment
1160 * @dma_addr: Physical address
1161 *
1162 */
1163static void
1164mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1165{
1166 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 u32 tmp = dma_addr & 0xFFFFFFFF;
1168
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301169 pChain->Length = cpu_to_le16(length);
1170 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1171 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301173 pChain->NextChainOffset = next;
1174
1175 pChain->Address.Low = cpu_to_le32(tmp);
1176 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1177 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
1180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1181/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001182 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301183 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 * @ioc: Pointer to MPT adapter structure
1185 * @reqBytes: Size of the request in bytes
1186 * @req: Pointer to MPT request frame
1187 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1188 *
1189 * This routine is used exclusively to send MptScsiTaskMgmt
1190 * requests since they are required to be sent via doorbell handshake.
1191 *
1192 * NOTE: It is the callers responsibility to byte-swap fields in the
1193 * request which are greater than 1 byte in size.
1194 *
1195 * Returns 0 for success, non-zero for failure.
1196 */
1197int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301198mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
Eric Moorecd2c6192007-01-29 09:47:47 -07001200 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 u8 *req_as_bytes;
1202 int ii;
1203
1204 /* State is known to be good upon entering
1205 * this function so issue the bus reset
1206 * request.
1207 */
1208
1209 /*
1210 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1211 * setting cb_idx/req_idx. But ONLY if this request
1212 * is in proper (pre-alloc'd) request buffer range...
1213 */
1214 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1215 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1216 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1217 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301218 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 }
1220
1221 /* Make sure there are no doorbells */
1222 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1225 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1226 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1227
1228 /* Wait for IOC doorbell int */
1229 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1230 return ii;
1231 }
1232
1233 /* Read doorbell and check for active bit */
1234 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1235 return -5;
1236
Eric Moore29dd3602007-09-14 18:46:51 -06001237 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001238 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1241
1242 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1243 return -2;
1244 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* Send request via doorbell handshake */
1247 req_as_bytes = (u8 *) req;
1248 for (ii = 0; ii < reqBytes/4; ii++) {
1249 u32 word;
1250
1251 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1252 (req_as_bytes[(ii*4) + 1] << 8) |
1253 (req_as_bytes[(ii*4) + 2] << 16) |
1254 (req_as_bytes[(ii*4) + 3] << 24));
1255 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1256 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1257 r = -3;
1258 break;
1259 }
1260 }
1261
1262 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1263 r = 0;
1264 else
1265 r = -4;
1266
1267 /* Make sure there are no doorbells */
1268 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001269
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 return r;
1271}
1272
1273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1274/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001275 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001276 * @ioc: Pointer to MPT adapter structure
1277 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001278 * @sleepFlag: Specifies whether the process can sleep
1279 *
1280 * Provides mechanism for the host driver to control the IOC's
1281 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001282 *
1283 * Access Control Value - bits[15:12]
1284 * 0h Reserved
1285 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1286 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1287 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1288 *
1289 * Returns 0 for success, non-zero for failure.
1290 */
1291
1292static int
1293mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1294{
1295 int r = 0;
1296
1297 /* return if in use */
1298 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1299 & MPI_DOORBELL_ACTIVE)
1300 return -1;
1301
1302 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1303
1304 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1305 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1306 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1307 (access_control_value<<12)));
1308
1309 /* Wait for IOC to clear Doorbell Status bit */
1310 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1311 return -2;
1312 }else
1313 return 0;
1314}
1315
1316/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1317/**
1318 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001319 * @ioc: Pointer to pointer to IOC adapter
1320 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001321 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001322 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001323 * Returns 0 for success, non-zero for failure.
1324 */
1325static int
1326mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1327{
1328 char *psge;
1329 int flags_length;
1330 u32 host_page_buffer_sz=0;
1331
1332 if(!ioc->HostPageBuffer) {
1333
1334 host_page_buffer_sz =
1335 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1336
1337 if(!host_page_buffer_sz)
1338 return 0; /* fw doesn't need any host buffers */
1339
1340 /* spin till we get enough memory */
1341 while(host_page_buffer_sz > 0) {
1342
1343 if((ioc->HostPageBuffer = pci_alloc_consistent(
1344 ioc->pcidev,
1345 host_page_buffer_sz,
1346 &ioc->HostPageBuffer_dma)) != NULL) {
1347
Prakash, Sathya436ace72007-07-24 15:42:08 +05301348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001349 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001350 ioc->name, ioc->HostPageBuffer,
1351 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001352 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001353 ioc->alloc_total += host_page_buffer_sz;
1354 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1355 break;
1356 }
1357
1358 host_page_buffer_sz -= (4*1024);
1359 }
1360 }
1361
1362 if(!ioc->HostPageBuffer) {
1363 printk(MYIOC_s_ERR_FMT
1364 "Failed to alloc memory for host_page_buffer!\n",
1365 ioc->name);
1366 return -999;
1367 }
1368
1369 psge = (char *)&ioc_init->HostPageBufferSGE;
1370 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1371 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1372 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1373 MPI_SGE_FLAGS_HOST_TO_IOC |
1374 MPI_SGE_FLAGS_END_OF_BUFFER;
1375 if (sizeof(dma_addr_t) == sizeof(u64)) {
1376 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1377 }
1378 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1379 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301380 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001381 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1382
1383return 0;
1384}
1385
1386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1387/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001388 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 * @iocid: IOC unique identifier (integer)
1390 * @iocpp: Pointer to pointer to IOC adapter
1391 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001392 * Given a unique IOC identifier, set pointer to the associated MPT
1393 * adapter structure.
1394 *
1395 * Returns iocid and sets iocpp if iocid is found.
1396 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 */
1398int
1399mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1400{
1401 MPT_ADAPTER *ioc;
1402
1403 list_for_each_entry(ioc,&ioc_list,list) {
1404 if (ioc->id == iocid) {
1405 *iocpp =ioc;
1406 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 *iocpp = NULL;
1411 return -1;
1412}
1413
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301414/**
1415 * mpt_get_product_name - returns product string
1416 * @vendor: pci vendor id
1417 * @device: pci device id
1418 * @revision: pci revision id
1419 * @prod_name: string returned
1420 *
1421 * Returns product string displayed when driver loads,
1422 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1423 *
1424 **/
1425static void
1426mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1427{
1428 char *product_str = NULL;
1429
1430 if (vendor == PCI_VENDOR_ID_BROCADE) {
1431 switch (device)
1432 {
1433 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1434 switch (revision)
1435 {
1436 case 0x00:
1437 product_str = "BRE040 A0";
1438 break;
1439 case 0x01:
1440 product_str = "BRE040 A1";
1441 break;
1442 default:
1443 product_str = "BRE040";
1444 break;
1445 }
1446 break;
1447 }
1448 goto out;
1449 }
1450
1451 switch (device)
1452 {
1453 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1454 product_str = "LSIFC909 B1";
1455 break;
1456 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1457 product_str = "LSIFC919 B0";
1458 break;
1459 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1460 product_str = "LSIFC929 B0";
1461 break;
1462 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1463 if (revision < 0x80)
1464 product_str = "LSIFC919X A0";
1465 else
1466 product_str = "LSIFC919XL A1";
1467 break;
1468 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1469 if (revision < 0x80)
1470 product_str = "LSIFC929X A0";
1471 else
1472 product_str = "LSIFC929XL A1";
1473 break;
1474 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1475 product_str = "LSIFC939X A1";
1476 break;
1477 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1478 product_str = "LSIFC949X A1";
1479 break;
1480 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1481 switch (revision)
1482 {
1483 case 0x00:
1484 product_str = "LSIFC949E A0";
1485 break;
1486 case 0x01:
1487 product_str = "LSIFC949E A1";
1488 break;
1489 default:
1490 product_str = "LSIFC949E";
1491 break;
1492 }
1493 break;
1494 case MPI_MANUFACTPAGE_DEVID_53C1030:
1495 switch (revision)
1496 {
1497 case 0x00:
1498 product_str = "LSI53C1030 A0";
1499 break;
1500 case 0x01:
1501 product_str = "LSI53C1030 B0";
1502 break;
1503 case 0x03:
1504 product_str = "LSI53C1030 B1";
1505 break;
1506 case 0x07:
1507 product_str = "LSI53C1030 B2";
1508 break;
1509 case 0x08:
1510 product_str = "LSI53C1030 C0";
1511 break;
1512 case 0x80:
1513 product_str = "LSI53C1030T A0";
1514 break;
1515 case 0x83:
1516 product_str = "LSI53C1030T A2";
1517 break;
1518 case 0x87:
1519 product_str = "LSI53C1030T A3";
1520 break;
1521 case 0xc1:
1522 product_str = "LSI53C1020A A1";
1523 break;
1524 default:
1525 product_str = "LSI53C1030";
1526 break;
1527 }
1528 break;
1529 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1530 switch (revision)
1531 {
1532 case 0x03:
1533 product_str = "LSI53C1035 A2";
1534 break;
1535 case 0x04:
1536 product_str = "LSI53C1035 B0";
1537 break;
1538 default:
1539 product_str = "LSI53C1035";
1540 break;
1541 }
1542 break;
1543 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1544 switch (revision)
1545 {
1546 case 0x00:
1547 product_str = "LSISAS1064 A1";
1548 break;
1549 case 0x01:
1550 product_str = "LSISAS1064 A2";
1551 break;
1552 case 0x02:
1553 product_str = "LSISAS1064 A3";
1554 break;
1555 case 0x03:
1556 product_str = "LSISAS1064 A4";
1557 break;
1558 default:
1559 product_str = "LSISAS1064";
1560 break;
1561 }
1562 break;
1563 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1564 switch (revision)
1565 {
1566 case 0x00:
1567 product_str = "LSISAS1064E A0";
1568 break;
1569 case 0x01:
1570 product_str = "LSISAS1064E B0";
1571 break;
1572 case 0x02:
1573 product_str = "LSISAS1064E B1";
1574 break;
1575 case 0x04:
1576 product_str = "LSISAS1064E B2";
1577 break;
1578 case 0x08:
1579 product_str = "LSISAS1064E B3";
1580 break;
1581 default:
1582 product_str = "LSISAS1064E";
1583 break;
1584 }
1585 break;
1586 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1587 switch (revision)
1588 {
1589 case 0x00:
1590 product_str = "LSISAS1068 A0";
1591 break;
1592 case 0x01:
1593 product_str = "LSISAS1068 B0";
1594 break;
1595 case 0x02:
1596 product_str = "LSISAS1068 B1";
1597 break;
1598 default:
1599 product_str = "LSISAS1068";
1600 break;
1601 }
1602 break;
1603 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1604 switch (revision)
1605 {
1606 case 0x00:
1607 product_str = "LSISAS1068E A0";
1608 break;
1609 case 0x01:
1610 product_str = "LSISAS1068E B0";
1611 break;
1612 case 0x02:
1613 product_str = "LSISAS1068E B1";
1614 break;
1615 case 0x04:
1616 product_str = "LSISAS1068E B2";
1617 break;
1618 case 0x08:
1619 product_str = "LSISAS1068E B3";
1620 break;
1621 default:
1622 product_str = "LSISAS1068E";
1623 break;
1624 }
1625 break;
1626 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1627 switch (revision)
1628 {
1629 case 0x00:
1630 product_str = "LSISAS1078 A0";
1631 break;
1632 case 0x01:
1633 product_str = "LSISAS1078 B0";
1634 break;
1635 case 0x02:
1636 product_str = "LSISAS1078 C0";
1637 break;
1638 case 0x03:
1639 product_str = "LSISAS1078 C1";
1640 break;
1641 case 0x04:
1642 product_str = "LSISAS1078 C2";
1643 break;
1644 default:
1645 product_str = "LSISAS1078";
1646 break;
1647 }
1648 break;
1649 }
1650
1651 out:
1652 if (product_str)
1653 sprintf(prod_name, "%s", product_str);
1654}
1655
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301656/**
1657 * mpt_mapresources - map in memory mapped io
1658 * @ioc: Pointer to pointer to IOC adapter
1659 *
1660 **/
1661static int
1662mpt_mapresources(MPT_ADAPTER *ioc)
1663{
1664 u8 __iomem *mem;
1665 int ii;
1666 unsigned long mem_phys;
1667 unsigned long port;
1668 u32 msize;
1669 u32 psize;
1670 u8 revision;
1671 int r = -ENODEV;
1672 struct pci_dev *pdev;
1673
1674 pdev = ioc->pcidev;
1675 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1676 if (pci_enable_device_mem(pdev)) {
1677 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1678 "failed\n", ioc->name);
1679 return r;
1680 }
1681 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1682 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1683 "MEM failed\n", ioc->name);
1684 return r;
1685 }
1686
1687 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1688
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301689 if (sizeof(dma_addr_t) > 4) {
1690 const uint64_t required_mask = dma_get_required_mask
1691 (&pdev->dev);
1692 if (required_mask > DMA_BIT_MASK(32)
1693 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1694 && !pci_set_consistent_dma_mask(pdev,
1695 DMA_BIT_MASK(64))) {
1696 ioc->dma_mask = DMA_BIT_MASK(64);
1697 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1698 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1699 ioc->name));
1700 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1701 && !pci_set_consistent_dma_mask(pdev,
1702 DMA_BIT_MASK(32))) {
1703 ioc->dma_mask = DMA_BIT_MASK(32);
1704 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1705 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1706 ioc->name));
1707 } else {
1708 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1709 ioc->name, pci_name(pdev));
1710 return r;
1711 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301712 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301713 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1714 && !pci_set_consistent_dma_mask(pdev,
1715 DMA_BIT_MASK(32))) {
1716 ioc->dma_mask = DMA_BIT_MASK(32);
1717 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1718 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1719 ioc->name));
1720 } else {
1721 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1722 ioc->name, pci_name(pdev));
1723 return r;
1724 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301725 }
1726
1727 mem_phys = msize = 0;
1728 port = psize = 0;
1729 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1730 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1731 if (psize)
1732 continue;
1733 /* Get I/O space! */
1734 port = pci_resource_start(pdev, ii);
1735 psize = pci_resource_len(pdev, ii);
1736 } else {
1737 if (msize)
1738 continue;
1739 /* Get memmap */
1740 mem_phys = pci_resource_start(pdev, ii);
1741 msize = pci_resource_len(pdev, ii);
1742 }
1743 }
1744 ioc->mem_size = msize;
1745
1746 mem = NULL;
1747 /* Get logical ptr for PciMem0 space */
1748 /*mem = ioremap(mem_phys, msize);*/
1749 mem = ioremap(mem_phys, msize);
1750 if (mem == NULL) {
1751 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1752 " memory!\n", ioc->name);
1753 return -EINVAL;
1754 }
1755 ioc->memmap = mem;
1756 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1757 ioc->name, mem, mem_phys));
1758
1759 ioc->mem_phys = mem_phys;
1760 ioc->chip = (SYSIF_REGS __iomem *)mem;
1761
1762 /* Save Port IO values in case we need to do downloadboot */
1763 ioc->pio_mem_phys = port;
1764 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1765
1766 return 0;
1767}
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001770/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001771 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001773 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 *
1775 * This routine performs all the steps necessary to bring the IOC of
1776 * a MPT adapter to a OPERATIONAL state. This includes registering
1777 * memory regions, registering the interrupt, and allocating request
1778 * and reply memory pools.
1779 *
1780 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1781 * MPT adapter.
1782 *
1783 * Returns 0 for success, non-zero for failure.
1784 *
1785 * TODO: Add support for polled controllers
1786 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001787int
1788mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
1790 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301791 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 u8 revision;
1794 u8 pcixcmd;
1795 static int mpt_ids = 0;
1796#ifdef CONFIG_PROC_FS
1797 struct proc_dir_entry *dent, *ent;
1798#endif
1799
Jesper Juhl56876192007-08-10 14:50:51 -07001800 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1801 if (ioc == NULL) {
1802 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1803 return -ENOMEM;
1804 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301805
Eric Moore29dd3602007-09-14 18:46:51 -06001806 ioc->id = mpt_ids++;
1807 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001808
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301809 /*
1810 * set initial debug level
1811 * (refer to mptdebug.h)
1812 *
1813 */
1814 ioc->debug_level = mpt_debug_level;
1815 if (mpt_debug_level)
1816 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301817
Eric Moore29dd3602007-09-14 18:46:51 -06001818 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001819
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301820 ioc->pcidev = pdev;
1821 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001822 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 return r;
1824 }
1825
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301826 /*
1827 * Setting up proper handlers for scatter gather handling
1828 */
1829 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1830 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1831 ioc->add_sge = &mpt_add_sge_64bit_1078;
1832 else
1833 ioc->add_sge = &mpt_add_sge_64bit;
1834 ioc->add_chain = &mpt_add_chain_64bit;
1835 ioc->sg_addr_size = 8;
1836 } else {
1837 ioc->add_sge = &mpt_add_sge;
1838 ioc->add_chain = &mpt_add_chain;
1839 ioc->sg_addr_size = 4;
1840 }
1841 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 ioc->alloc_total = sizeof(MPT_ADAPTER);
1844 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1845 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 ioc->pcidev = pdev;
1848 ioc->diagPending = 0;
1849 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001850 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 /* Initialize the event logging.
1853 */
1854 ioc->eventTypes = 0; /* None */
1855 ioc->eventContext = 0;
1856 ioc->eventLogSize = 0;
1857 ioc->events = NULL;
1858
1859#ifdef MFCNT
1860 ioc->mfcnt = 0;
1861#endif
1862
1863 ioc->cached_fw = NULL;
1864
1865 /* Initilize SCSI Config Data structure
1866 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001867 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869 /* Initialize the running configQ head.
1870 */
1871 INIT_LIST_HEAD(&ioc->configQ);
1872
Michael Reed05e8ec12006-01-13 14:31:54 -06001873 /* Initialize the fc rport list head.
1874 */
1875 INIT_LIST_HEAD(&ioc->fc_rports);
1876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 /* Find lookup slot. */
1878 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001879
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301880
1881 /* Initialize workqueue */
1882 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1883 spin_lock_init(&ioc->fault_reset_work_lock);
1884
Kay Sieversaab0de22008-05-02 06:02:41 +02001885 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1886 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301887 ioc->reset_work_q =
1888 create_singlethread_workqueue(ioc->reset_work_q_name);
1889 if (!ioc->reset_work_q) {
1890 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1891 ioc->name);
1892 pci_release_selected_regions(pdev, ioc->bars);
1893 kfree(ioc);
1894 return -ENOMEM;
1895 }
1896
Eric Moore29dd3602007-09-14 18:46:51 -06001897 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1898 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301900 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1901 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1902
1903 switch (pdev->device)
1904 {
1905 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1906 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1907 ioc->errata_flag_1064 = 1;
1908 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1909 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1910 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1911 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301913 break;
1914
1915 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 /* 929X Chip Fix. Set Split transactions level
1918 * for PCIX. Set MOST bits to zero.
1919 */
1920 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1921 pcixcmd &= 0x8F;
1922 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1923 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 /* 929XL Chip Fix. Set MMRBC to 0x08.
1925 */
1926 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1927 pcixcmd |= 0x08;
1928 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301931 break;
1932
1933 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 /* 919X Chip Fix. Set Split transactions level
1935 * for PCIX. Set MOST bits to zero.
1936 */
1937 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1938 pcixcmd &= 0x8F;
1939 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001940 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301941 break;
1942
1943 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 /* 1030 Chip Fix. Disable Split transactions
1945 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1946 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 if (revision < C0_1030) {
1948 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1949 pcixcmd &= 0x8F;
1950 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1951 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301952
1953 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001954 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301955 break;
1956
1957 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1958 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001959 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301960
1961 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1962 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1963 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001964 ioc->bus_type = SAS;
1965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301967
Kashyap, Desaie3829682009-01-08 14:27:16 +05301968 switch (ioc->bus_type) {
1969
1970 case SAS:
1971 ioc->msi_enable = mpt_msi_enable_sas;
1972 break;
1973
1974 case SPI:
1975 ioc->msi_enable = mpt_msi_enable_spi;
1976 break;
1977
1978 case FC:
1979 ioc->msi_enable = mpt_msi_enable_fc;
1980 break;
1981
1982 default:
1983 ioc->msi_enable = 0;
1984 break;
1985 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001986 if (ioc->errata_flag_1064)
1987 pci_disable_io_access(pdev);
1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 spin_lock_init(&ioc->FreeQlock);
1990
1991 /* Disable all! */
1992 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1993 ioc->active = 0;
1994 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1995
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301996 /* Set IOC ptr in the pcidev's driver data. */
1997 pci_set_drvdata(ioc->pcidev, ioc);
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 /* Set lookup ptr. */
2000 list_add_tail(&ioc->list, &ioc_list);
2001
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002002 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 */
2004 mpt_detect_bound_ports(ioc, pdev);
2005
James Bottomleyc92f2222006-03-01 09:02:49 -06002006 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2007 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06002008 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
2009 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06002010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07002012 if (ioc->alt_ioc)
2013 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302014 iounmap(ioc->memmap);
2015 if (r != -5)
2016 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302017
2018 destroy_workqueue(ioc->reset_work_q);
2019 ioc->reset_work_q = NULL;
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 kfree(ioc);
2022 pci_set_drvdata(pdev, NULL);
2023 return r;
2024 }
2025
2026 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002027 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302028 if(MptDeviceDriverHandlers[cb_idx] &&
2029 MptDeviceDriverHandlers[cb_idx]->probe) {
2030 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 }
2032 }
2033
2034#ifdef CONFIG_PROC_FS
2035 /*
2036 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
2037 */
2038 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
2039 if (dent) {
2040 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
2041 if (ent) {
2042 ent->read_proc = procmpt_iocinfo_read;
2043 ent->data = ioc;
2044 }
2045 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
2046 if (ent) {
2047 ent->read_proc = procmpt_summary_read;
2048 ent->data = ioc;
2049 }
2050 }
2051#endif
2052
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302053 if (!ioc->alt_ioc)
2054 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
2055 msecs_to_jiffies(MPT_POLLING_INTERVAL));
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return 0;
2058}
2059
2060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002061/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002062 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 */
2065
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002066void
2067mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068{
2069 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2070 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302071 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302072 unsigned long flags;
2073 struct workqueue_struct *wq;
2074
2075 /*
2076 * Stop polling ioc for fault condition
2077 */
2078 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2079 wq = ioc->reset_work_q;
2080 ioc->reset_work_q = NULL;
2081 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2082 cancel_delayed_work(&ioc->fault_reset_work);
2083 destroy_workqueue(wq);
2084
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
2086 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2087 remove_proc_entry(pname, NULL);
2088 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2089 remove_proc_entry(pname, NULL);
2090 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2091 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002092
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002094 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302095 if(MptDeviceDriverHandlers[cb_idx] &&
2096 MptDeviceDriverHandlers[cb_idx]->remove) {
2097 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 }
2099 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002100
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 /* Disable interrupts! */
2102 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2103
2104 ioc->active = 0;
2105 synchronize_irq(pdev->irq);
2106
2107 /* Clear any lingering interrupt */
2108 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2109
2110 CHIPREG_READ32(&ioc->chip->IntStatus);
2111
2112 mpt_adapter_dispose(ioc);
2113
2114 pci_set_drvdata(pdev, NULL);
2115}
2116
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117/**************************************************************************
2118 * Power Management
2119 */
2120#ifdef CONFIG_PM
2121/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002122/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002123 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002124 * @pdev: Pointer to pci_dev structure
2125 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002127int
2128mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129{
2130 u32 device_state;
2131 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302133 device_state = pci_choose_state(pdev, state);
2134 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2135 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2136 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 /* put ioc into READY_STATE */
2139 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2140 printk(MYIOC_s_ERR_FMT
2141 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2142 }
2143
2144 /* disable interrupts */
2145 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2146 ioc->active = 0;
2147
2148 /* Clear any lingering interrupt */
2149 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2150
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302151 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002152 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302153 pci_disable_msi(ioc->pcidev);
2154 ioc->pci_irq = -1;
2155 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302157 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return 0;
2160}
2161
2162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002163/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002164 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002165 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002167int
2168mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169{
2170 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2171 u32 device_state = pdev->current_state;
2172 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302173 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002174
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302175 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2176 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2177 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302179 pci_set_power_state(pdev, PCI_D0);
2180 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302182 ioc->pcidev = pdev;
2183 err = mpt_mapresources(ioc);
2184 if (err)
2185 return err;
2186
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302187 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2188 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2189 ioc->add_sge = &mpt_add_sge_64bit_1078;
2190 else
2191 ioc->add_sge = &mpt_add_sge_64bit;
2192 ioc->add_chain = &mpt_add_chain_64bit;
2193 ioc->sg_addr_size = 8;
2194 } else {
2195
2196 ioc->add_sge = &mpt_add_sge;
2197 ioc->add_chain = &mpt_add_chain;
2198 ioc->sg_addr_size = 4;
2199 }
2200 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2201
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302202 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2203 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2204 CHIPREG_READ32(&ioc->chip->Doorbell));
2205
2206 /*
2207 * Errata workaround for SAS pci express:
2208 * Upon returning to the D0 state, the contents of the doorbell will be
2209 * stale data, and this will incorrectly signal to the host driver that
2210 * the firmware is ready to process mpt commands. The workaround is
2211 * to issue a diagnostic reset.
2212 */
2213 if (ioc->bus_type == SAS && (pdev->device ==
2214 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2215 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2216 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2217 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2218 ioc->name);
2219 goto out;
2220 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
2223 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302224 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2225 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2226 CAN_SLEEP);
2227 if (recovery_state != 0)
2228 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2229 "error:[%x]\n", ioc->name, recovery_state);
2230 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302232 "pci-resume: success\n", ioc->name);
2233 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302235
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236}
2237#endif
2238
James Bottomley4ff42a62006-05-17 18:06:52 -05002239static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302240mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002241{
2242 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2243 ioc->bus_type != SPI) ||
2244 (MptDriverClass[index] == MPTFC_DRIVER &&
2245 ioc->bus_type != FC) ||
2246 (MptDriverClass[index] == MPTSAS_DRIVER &&
2247 ioc->bus_type != SAS))
2248 /* make sure we only call the relevant reset handler
2249 * for the bus */
2250 return 0;
2251 return (MptResetHandlers[index])(ioc, reset_phase);
2252}
2253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002255/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2257 * @ioc: Pointer to MPT adapter structure
2258 * @reason: Event word / reason
2259 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2260 *
2261 * This routine performs all the steps necessary to bring the IOC
2262 * to a OPERATIONAL state.
2263 *
2264 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2265 * MPT adapter.
2266 *
2267 * Returns:
2268 * 0 for success
2269 * -1 if failed to get board READY
2270 * -2 if READY but IOCFacts Failed
2271 * -3 if READY but PrimeIOCFifos Failed
2272 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302273 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302274 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 */
2276static int
2277mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2278{
2279 int hard_reset_done = 0;
2280 int alt_ioc_ready = 0;
2281 int hard;
2282 int rc=0;
2283 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302284 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 int handlers;
2286 int ret = 0;
2287 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002288 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302289 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Eric Moore29dd3602007-09-14 18:46:51 -06002291 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2292 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
2294 /* Disable reply interrupts (also blocks FreeQ) */
2295 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2296 ioc->active = 0;
2297
2298 if (ioc->alt_ioc) {
2299 if (ioc->alt_ioc->active)
2300 reset_alt_ioc_active = 1;
2301
2302 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2303 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2304 ioc->alt_ioc->active = 0;
2305 }
2306
2307 hard = 1;
2308 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2309 hard = 0;
2310
2311 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2312 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002313 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2314 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
2316 if (reset_alt_ioc_active && ioc->alt_ioc) {
2317 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002318 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2319 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002320 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 ioc->alt_ioc->active = 1;
2322 }
2323
2324 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002325 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 }
2327 return -1;
2328 }
2329
2330 /* hard_reset_done = 0 if a soft reset was performed
2331 * and 1 if a hard reset was performed.
2332 */
2333 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2334 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2335 alt_ioc_ready = 1;
2336 else
Eric Moore29dd3602007-09-14 18:46:51 -06002337 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339
2340 for (ii=0; ii<5; ii++) {
2341 /* Get IOC facts! Allow 5 retries */
2342 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2343 break;
2344 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2349 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 ret = -2;
2351 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2352 MptDisplayIocCapabilities(ioc);
2353 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 if (alt_ioc_ready) {
2356 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302357 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002358 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 /* Retry - alt IOC was initialized once
2360 */
2361 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2362 }
2363 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302364 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002365 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 alt_ioc_ready = 0;
2367 reset_alt_ioc_active = 0;
2368 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2369 MptDisplayIocCapabilities(ioc->alt_ioc);
2370 }
2371 }
2372
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302373 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2374 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2375 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2376 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2377 IORESOURCE_IO);
2378 if (pci_enable_device(ioc->pcidev))
2379 return -5;
2380 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2381 "mpt"))
2382 return -5;
2383 }
2384
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002385 /*
2386 * Device is reset now. It must have de-asserted the interrupt line
2387 * (if it was asserted) and it should be safe to register for the
2388 * interrupt now.
2389 */
2390 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2391 ioc->pci_irq = -1;
2392 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302393 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002394 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002395 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302396 else
2397 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002398 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002399 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002400 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002401 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002402 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302403 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002404 pci_disable_msi(ioc->pcidev);
2405 return -EBUSY;
2406 }
2407 irq_allocated = 1;
2408 ioc->pci_irq = ioc->pcidev->irq;
2409 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002410 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2411 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002412 }
2413 }
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* Prime reply & request queues!
2416 * (mucho alloc's) Must be done prior to
2417 * init as upper addresses are needed for init.
2418 * If fails, continue with alt-ioc processing
2419 */
2420 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2421 ret = -3;
2422
2423 /* May need to check/upload firmware & data here!
2424 * If fails, continue with alt-ioc processing
2425 */
2426 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2427 ret = -4;
2428// NEW!
2429 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002430 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2431 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 alt_ioc_ready = 0;
2433 reset_alt_ioc_active = 0;
2434 }
2435
2436 if (alt_ioc_ready) {
2437 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2438 alt_ioc_ready = 0;
2439 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002440 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2441 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 }
2443 }
2444
2445 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2446 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302447 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002448 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 /* Controller is not operational, cannot do upload
2451 */
2452 if (ret == 0) {
2453 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002454 if (rc == 0) {
2455 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2456 /*
2457 * Maintain only one pointer to FW memory
2458 * so there will not be two attempt to
2459 * downloadboot onboard dual function
2460 * chips (mpt_adapter_disable,
2461 * mpt_diag_reset)
2462 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302463 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002464 "mpt_upload: alt_%s has cached_fw=%p \n",
2465 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302466 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002467 }
2468 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002469 printk(MYIOC_s_WARN_FMT
2470 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302471 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 }
2474 }
2475 }
2476
Kashyap, Desaifd761752009-05-29 16:39:06 +05302477 /* Enable MPT base driver management of EventNotification
2478 * and EventAck handling.
2479 */
2480 if ((ret == 0) && (!ioc->facts.EventState)) {
2481 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2482 "SendEventNotification\n",
2483 ioc->name));
2484 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2485 }
2486
2487 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2488 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2489
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 if (ret == 0) {
2491 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002492 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 ioc->active = 1;
2494 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302495 if (rc == 0) { /* alt ioc */
2496 if (reset_alt_ioc_active && ioc->alt_ioc) {
2497 /* (re)Enable alt-IOC! (reply interrupt) */
2498 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2499 "reply irq re-enabled\n",
2500 ioc->alt_ioc->name));
2501 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2502 MPI_HIM_DIM);
2503 ioc->alt_ioc->active = 1;
2504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
2506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002508 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2510 * recursive scenario; GetLanConfigPages times out, timer expired
2511 * routine calls HardResetHandler, which calls into here again,
2512 * and we try GetLanConfigPages again...
2513 */
2514 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002515
2516 /*
2517 * Initalize link list for inactive raid volumes.
2518 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002519 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002520 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2521
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002522 if (ioc->bus_type == SAS) {
2523
2524 /* clear persistency table */
2525 if(ioc->facts.IOCExceptions &
2526 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2527 ret = mptbase_sas_persist_operation(ioc,
2528 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2529 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002530 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002531 }
2532
2533 /* Find IM volumes
2534 */
2535 mpt_findImVolumes(ioc);
2536
2537 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2539 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2540 /*
2541 * Pre-fetch the ports LAN MAC address!
2542 * (LANPage1_t stuff)
2543 */
2544 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302545 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2546 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002547 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2548 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302549
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551 } else {
2552 /* Get NVRAM and adapter maximums from SPP 0 and 2
2553 */
2554 mpt_GetScsiPortSettings(ioc, 0);
2555
2556 /* Get version and length of SDP 1
2557 */
2558 mpt_readScsiDevicePageHeaders(ioc, 0);
2559
2560 /* Find IM volumes
2561 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002562 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 mpt_findImVolumes(ioc);
2564
2565 /* Check, and possibly reset, the coalescing value
2566 */
2567 mpt_read_ioc_pg_1(ioc);
2568
2569 mpt_read_ioc_pg_4(ioc);
2570 }
2571
2572 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302573 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 }
2575
2576 /*
2577 * Call each currently registered protocol IOC reset handler
2578 * with post-reset indication.
2579 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2580 * MptResetHandlers[] registered yet.
2581 */
2582 if (hard_reset_done) {
2583 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302584 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2585 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302586 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002587 "Calling IOC post_reset handler #%d\n",
2588 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302589 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 handlers++;
2591 }
2592
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302593 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302594 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002595 "Calling IOC post_reset handler #%d\n",
2596 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302597 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 handlers++;
2599 }
2600 }
2601 /* FIXME? Examine results here? */
2602 }
2603
Eric Moore0ccdb002006-07-11 17:33:13 -06002604 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002605 if ((ret != 0) && irq_allocated) {
2606 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302607 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002608 pci_disable_msi(ioc->pcidev);
2609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 return ret;
2611}
2612
2613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002614/**
2615 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 * @ioc: Pointer to MPT adapter structure
2617 * @pdev: Pointer to (struct pci_dev) structure
2618 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002619 * Search for PCI bus/dev_function which matches
2620 * PCI bus/dev_function (+/-1) for newly discovered 929,
2621 * 929X, 1030 or 1035.
2622 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2624 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2625 */
2626static void
2627mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2628{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002629 struct pci_dev *peer=NULL;
2630 unsigned int slot = PCI_SLOT(pdev->devfn);
2631 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 MPT_ADAPTER *ioc_srch;
2633
Prakash, Sathya436ace72007-07-24 15:42:08 +05302634 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002635 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002636 ioc->name, pci_name(pdev), pdev->bus->number,
2637 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002638
2639 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2640 if (!peer) {
2641 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2642 if (!peer)
2643 return;
2644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 list_for_each_entry(ioc_srch, &ioc_list, list) {
2647 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002648 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 /* Paranoia checks */
2650 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002651 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002652 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 break;
2654 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002655 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002656 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 break;
2658 }
Eric Moore29dd3602007-09-14 18:46:51 -06002659 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002660 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 ioc_srch->alt_ioc = ioc;
2662 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 }
2664 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002665 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666}
2667
2668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002669/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002671 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 */
2673static void
2674mpt_adapter_disable(MPT_ADAPTER *ioc)
2675{
2676 int sz;
2677 int ret;
2678
2679 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302680 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002681 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302682 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2683 ioc->cached_fw, CAN_SLEEP)) < 0) {
2684 printk(MYIOC_s_WARN_FMT
2685 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002686 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 }
2688 }
2689
2690 /* Disable adapter interrupts! */
2691 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2692 ioc->active = 0;
2693 /* Clear any lingering interrupt */
2694 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2695
2696 if (ioc->alloc != NULL) {
2697 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002698 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2699 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 pci_free_consistent(ioc->pcidev, sz,
2701 ioc->alloc, ioc->alloc_dma);
2702 ioc->reply_frames = NULL;
2703 ioc->req_frames = NULL;
2704 ioc->alloc = NULL;
2705 ioc->alloc_total -= sz;
2706 }
2707
2708 if (ioc->sense_buf_pool != NULL) {
2709 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2710 pci_free_consistent(ioc->pcidev, sz,
2711 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2712 ioc->sense_buf_pool = NULL;
2713 ioc->alloc_total -= sz;
2714 }
2715
2716 if (ioc->events != NULL){
2717 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2718 kfree(ioc->events);
2719 ioc->events = NULL;
2720 ioc->alloc_total -= sz;
2721 }
2722
Prakash, Sathya984621b2008-01-11 14:42:17 +05302723 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002725 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002726 mpt_inactive_raid_list_free(ioc);
2727 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002728 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002729 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002730 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732 if (ioc->spi_data.pIocPg4 != NULL) {
2733 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302734 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 ioc->spi_data.pIocPg4,
2736 ioc->spi_data.IocPg4_dma);
2737 ioc->spi_data.pIocPg4 = NULL;
2738 ioc->alloc_total -= sz;
2739 }
2740
2741 if (ioc->ReqToChain != NULL) {
2742 kfree(ioc->ReqToChain);
2743 kfree(ioc->RequestNB);
2744 ioc->ReqToChain = NULL;
2745 }
2746
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002747 kfree(ioc->ChainToChain);
2748 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002749
2750 if (ioc->HostPageBuffer != NULL) {
2751 if((ret = mpt_host_page_access_control(ioc,
2752 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002753 printk(MYIOC_s_ERR_FMT
2754 "host page buffers free failed (%d)!\n",
2755 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002756 }
Eric Moore29dd3602007-09-14 18:46:51 -06002757 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002758 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2759 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002760 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002761 ioc->HostPageBuffer = NULL;
2762 ioc->HostPageBuffer_sz = 0;
2763 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765}
2766
2767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002768/**
2769 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 * @ioc: Pointer to MPT adapter structure
2771 *
2772 * This routine unregisters h/w resources and frees all alloc'd memory
2773 * associated with a MPT adapter structure.
2774 */
2775static void
2776mpt_adapter_dispose(MPT_ADAPTER *ioc)
2777{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002778 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 if (ioc == NULL)
2781 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002783 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002785 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002787 if (ioc->pci_irq != -1) {
2788 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302789 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002790 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002791 ioc->pci_irq = -1;
2792 }
2793
2794 if (ioc->memmap != NULL) {
2795 iounmap(ioc->memmap);
2796 ioc->memmap = NULL;
2797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302799 pci_disable_device(ioc->pcidev);
2800 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002803 if (ioc->mtrr_reg > 0) {
2804 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002805 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807#endif
2808
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002809 /* Zap the adapter lookup ptr! */
2810 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002812 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002813 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2814 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002815
2816 if (ioc->alt_ioc)
2817 ioc->alt_ioc->alt_ioc = NULL;
2818
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002819 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820}
2821
2822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002823/**
2824 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 * @ioc: Pointer to MPT adapter structure
2826 */
2827static void
2828MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2829{
2830 int i = 0;
2831
2832 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302833 if (ioc->prod_name)
2834 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 printk("Capabilities={");
2836
2837 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2838 printk("Initiator");
2839 i++;
2840 }
2841
2842 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2843 printk("%sTarget", i ? "," : "");
2844 i++;
2845 }
2846
2847 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2848 printk("%sLAN", i ? "," : "");
2849 i++;
2850 }
2851
2852#if 0
2853 /*
2854 * This would probably evoke more questions than it's worth
2855 */
2856 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2857 printk("%sLogBusAddr", i ? "," : "");
2858 i++;
2859 }
2860#endif
2861
2862 printk("}\n");
2863}
2864
2865/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002866/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2868 * @ioc: Pointer to MPT_ADAPTER structure
2869 * @force: Force hard KickStart of IOC
2870 * @sleepFlag: Specifies whether the process can sleep
2871 *
2872 * Returns:
2873 * 1 - DIAG reset and READY
2874 * 0 - READY initially OR soft reset and READY
2875 * -1 - Any failure on KickStart
2876 * -2 - Msg Unit Reset Failed
2877 * -3 - IO Unit Reset Failed
2878 * -4 - IOC owned by a PEER
2879 */
2880static int
2881MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2882{
2883 u32 ioc_state;
2884 int statefault = 0;
2885 int cntdn;
2886 int hard_reset_done = 0;
2887 int r;
2888 int ii;
2889 int whoinit;
2890
2891 /* Get current [raw] IOC state */
2892 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002893 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 /*
2896 * Check to see if IOC got left/stuck in doorbell handshake
2897 * grip of death. If so, hard reset the IOC.
2898 */
2899 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2900 statefault = 1;
2901 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2902 ioc->name);
2903 }
2904
2905 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002906 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 return 0;
2908
2909 /*
2910 * Check to see if IOC is in FAULT state.
2911 */
2912 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2913 statefault = 2;
2914 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002915 ioc->name);
2916 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2917 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 }
2919
2920 /*
2921 * Hmmm... Did it get left operational?
2922 */
2923 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302924 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 ioc->name));
2926
2927 /* Check WhoInit.
2928 * If PCI Peer, exit.
2929 * Else, if no fault conditions are present, issue a MessageUnitReset
2930 * Else, fall through to KickStart case
2931 */
2932 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002933 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2934 "whoinit 0x%x statefault %d force %d\n",
2935 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 if (whoinit == MPI_WHOINIT_PCI_PEER)
2937 return -4;
2938 else {
2939 if ((statefault == 0 ) && (force == 0)) {
2940 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2941 return 0;
2942 }
2943 statefault = 3;
2944 }
2945 }
2946
2947 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2948 if (hard_reset_done < 0)
2949 return -1;
2950
2951 /*
2952 * Loop here waiting for IOC to come READY.
2953 */
2954 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002955 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
2957 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2958 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2959 /*
2960 * BIOS or previous driver load left IOC in OP state.
2961 * Reset messaging FIFOs.
2962 */
2963 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2964 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2965 return -2;
2966 }
2967 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2968 /*
2969 * Something is wrong. Try to get IOC back
2970 * to a known state.
2971 */
2972 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2973 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2974 return -3;
2975 }
2976 }
2977
2978 ii++; cntdn--;
2979 if (!cntdn) {
2980 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2981 ioc->name, (int)((ii+5)/HZ));
2982 return -ETIME;
2983 }
2984
2985 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002986 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 } else {
2988 mdelay (1); /* 1 msec delay */
2989 }
2990
2991 }
2992
2993 if (statefault < 3) {
2994 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2995 ioc->name,
2996 statefault==1 ? "stuck handshake" : "IOC FAULT");
2997 }
2998
2999 return hard_reset_done;
3000}
3001
3002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003003/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 * mpt_GetIocState - Get the current state of a MPT adapter.
3005 * @ioc: Pointer to MPT_ADAPTER structure
3006 * @cooked: Request raw or cooked IOC state
3007 *
3008 * Returns all IOC Doorbell register bits if cooked==0, else just the
3009 * Doorbell bits in MPI_IOC_STATE_MASK.
3010 */
3011u32
3012mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3013{
3014 u32 s, sc;
3015
3016 /* Get! */
3017 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 sc = s & MPI_IOC_STATE_MASK;
3019
3020 /* Save! */
3021 ioc->last_state = sc;
3022
3023 return cooked ? sc : s;
3024}
3025
3026/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003027/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 * GetIocFacts - Send IOCFacts request to MPT adapter.
3029 * @ioc: Pointer to MPT_ADAPTER structure
3030 * @sleepFlag: Specifies whether the process can sleep
3031 * @reason: If recovery, only update facts.
3032 *
3033 * Returns 0 for success, non-zero for failure.
3034 */
3035static int
3036GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3037{
3038 IOCFacts_t get_facts;
3039 IOCFactsReply_t *facts;
3040 int r;
3041 int req_sz;
3042 int reply_sz;
3043 int sz;
3044 u32 status, vv;
3045 u8 shiftFactor=1;
3046
3047 /* IOC *must* NOT be in RESET state! */
3048 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003049 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
3050 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 return -44;
3052 }
3053
3054 facts = &ioc->facts;
3055
3056 /* Destination (reply area)... */
3057 reply_sz = sizeof(*facts);
3058 memset(facts, 0, reply_sz);
3059
3060 /* Request area (get_facts on the stack right now!) */
3061 req_sz = sizeof(get_facts);
3062 memset(&get_facts, 0, req_sz);
3063
3064 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3065 /* Assert: All other get_facts fields are zero! */
3066
Prakash, Sathya436ace72007-07-24 15:42:08 +05303067 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003068 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 ioc->name, req_sz, reply_sz));
3070
3071 /* No non-zero fields in the get_facts request are greater than
3072 * 1 byte in size, so we can just fire it off as is.
3073 */
3074 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3075 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3076 if (r != 0)
3077 return r;
3078
3079 /*
3080 * Now byte swap (GRRR) the necessary fields before any further
3081 * inspection of reply contents.
3082 *
3083 * But need to do some sanity checks on MsgLength (byte) field
3084 * to make sure we don't zero IOC's req_sz!
3085 */
3086 /* Did we get a valid reply? */
3087 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3088 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3089 /*
3090 * If not been here, done that, save off first WhoInit value
3091 */
3092 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3093 ioc->FirstWhoInit = facts->WhoInit;
3094 }
3095
3096 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3097 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3098 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3099 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3100 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003101 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 /* CHECKME! IOCStatus, IOCLogInfo */
3103
3104 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3105 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3106
3107 /*
3108 * FC f/w version changed between 1.1 and 1.2
3109 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3110 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3111 */
3112 if (facts->MsgVersion < 0x0102) {
3113 /*
3114 * Handle old FC f/w style, convert to new...
3115 */
3116 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3117 facts->FWVersion.Word =
3118 ((oldv<<12) & 0xFF000000) |
3119 ((oldv<<8) & 0x000FFF00);
3120 } else
3121 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3122
3123 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003124 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3125 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3126 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 facts->CurrentHostMfaHighAddr =
3128 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3129 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3130 facts->CurrentSenseBufferHighAddr =
3131 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3132 facts->CurReplyFrameSize =
3133 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003134 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
3136 /*
3137 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3138 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3139 * to 14 in MPI-1.01.0x.
3140 */
3141 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3142 facts->MsgVersion > 0x0100) {
3143 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3144 }
3145
3146 sz = facts->FWImageSize;
3147 if ( sz & 0x01 )
3148 sz += 1;
3149 if ( sz & 0x02 )
3150 sz += 2;
3151 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003152
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 if (!facts->RequestFrameSize) {
3154 /* Something is wrong! */
3155 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3156 ioc->name);
3157 return -55;
3158 }
3159
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003160 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 vv = ((63 / (sz * 4)) + 1) & 0x03;
3162 ioc->NB_for_64_byte_frame = vv;
3163 while ( sz )
3164 {
3165 shiftFactor++;
3166 sz = sz >> 1;
3167 }
3168 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303169 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003170 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3171 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3174 /*
3175 * Set values for this IOC's request & reply frame sizes,
3176 * and request & reply queue depths...
3177 */
3178 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3179 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3180 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3181 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3182
Prakash, Sathya436ace72007-07-24 15:42:08 +05303183 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303185 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 ioc->name, ioc->req_sz, ioc->req_depth));
3187
3188 /* Get port facts! */
3189 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3190 return r;
3191 }
3192 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003193 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3195 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3196 RequestFrameSize)/sizeof(u32)));
3197 return -66;
3198 }
3199
3200 return 0;
3201}
3202
3203/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003204/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 * GetPortFacts - Send PortFacts request to MPT adapter.
3206 * @ioc: Pointer to MPT_ADAPTER structure
3207 * @portnum: Port number
3208 * @sleepFlag: Specifies whether the process can sleep
3209 *
3210 * Returns 0 for success, non-zero for failure.
3211 */
3212static int
3213GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3214{
3215 PortFacts_t get_pfacts;
3216 PortFactsReply_t *pfacts;
3217 int ii;
3218 int req_sz;
3219 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003220 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 /* IOC *must* NOT be in RESET state! */
3223 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003224 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3225 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 return -4;
3227 }
3228
3229 pfacts = &ioc->pfacts[portnum];
3230
3231 /* Destination (reply area)... */
3232 reply_sz = sizeof(*pfacts);
3233 memset(pfacts, 0, reply_sz);
3234
3235 /* Request area (get_pfacts on the stack right now!) */
3236 req_sz = sizeof(get_pfacts);
3237 memset(&get_pfacts, 0, req_sz);
3238
3239 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3240 get_pfacts.PortNumber = portnum;
3241 /* Assert: All other get_pfacts fields are zero! */
3242
Prakash, Sathya436ace72007-07-24 15:42:08 +05303243 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 ioc->name, portnum));
3245
3246 /* No non-zero fields in the get_pfacts request are greater than
3247 * 1 byte in size, so we can just fire it off as is.
3248 */
3249 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3250 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3251 if (ii != 0)
3252 return ii;
3253
3254 /* Did we get a valid reply? */
3255
3256 /* Now byte swap the necessary fields in the response. */
3257 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3258 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3259 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3260 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3261 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3262 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3263 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3264 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3265 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3266
Eric Moore793955f2007-01-29 09:42:20 -07003267 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3268 pfacts->MaxDevices;
3269 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3270 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3271
3272 /*
3273 * Place all the devices on channels
3274 *
3275 * (for debuging)
3276 */
3277 if (mpt_channel_mapping) {
3278 ioc->devices_per_bus = 1;
3279 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3280 }
3281
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 return 0;
3283}
3284
3285/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003286/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 * SendIocInit - Send IOCInit request to MPT adapter.
3288 * @ioc: Pointer to MPT_ADAPTER structure
3289 * @sleepFlag: Specifies whether the process can sleep
3290 *
3291 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3292 *
3293 * Returns 0 for success, non-zero for failure.
3294 */
3295static int
3296SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3297{
3298 IOCInit_t ioc_init;
3299 MPIDefaultReply_t init_reply;
3300 u32 state;
3301 int r;
3302 int count;
3303 int cntdn;
3304
3305 memset(&ioc_init, 0, sizeof(ioc_init));
3306 memset(&init_reply, 0, sizeof(init_reply));
3307
3308 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3309 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3310
3311 /* If we are in a recovery mode and we uploaded the FW image,
3312 * then this pointer is not NULL. Skip the upload a second time.
3313 * Set this flag if cached_fw set for either IOC.
3314 */
3315 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3316 ioc->upload_fw = 1;
3317 else
3318 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303319 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3321
Eric Moore793955f2007-01-29 09:42:20 -07003322 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3323 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303324 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003325 ioc->name, ioc->facts.MsgVersion));
3326 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3327 // set MsgVersion and HeaderVersion host driver was built with
3328 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3329 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003331 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3332 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3333 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3334 return -99;
3335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3337
3338 if (sizeof(dma_addr_t) == sizeof(u64)) {
3339 /* Save the upper 32-bits of the request
3340 * (reply) and sense buffers.
3341 */
3342 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3343 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3344 } else {
3345 /* Force 32-bit addressing */
3346 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3347 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3348 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003349
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3351 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003352 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3353 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
Prakash, Sathya436ace72007-07-24 15:42:08 +05303355 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 ioc->name, &ioc_init));
3357
3358 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3359 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003360 if (r != 0) {
3361 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
3365 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003366 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 */
3368
Prakash, Sathya436ace72007-07-24 15:42:08 +05303369 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003371
3372 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3373 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
3377 /* YIKES! SUPER IMPORTANT!!!
3378 * Poll IocState until _OPERATIONAL while IOC is doing
3379 * LoopInit and TargetDiscovery!
3380 */
3381 count = 0;
3382 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3383 state = mpt_GetIocState(ioc, 1);
3384 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3385 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003386 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 } else {
3388 mdelay(1);
3389 }
3390
3391 if (!cntdn) {
3392 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3393 ioc->name, (int)((count+5)/HZ));
3394 return -9;
3395 }
3396
3397 state = mpt_GetIocState(ioc, 1);
3398 count++;
3399 }
Eric Moore29dd3602007-09-14 18:46:51 -06003400 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 ioc->name, count));
3402
Eric Mooreba856d32006-07-11 17:34:01 -06003403 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 return r;
3405}
3406
3407/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003408/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 * SendPortEnable - Send PortEnable request to MPT adapter port.
3410 * @ioc: Pointer to MPT_ADAPTER structure
3411 * @portnum: Port number to enable
3412 * @sleepFlag: Specifies whether the process can sleep
3413 *
3414 * Send PortEnable to bring IOC to OPERATIONAL state.
3415 *
3416 * Returns 0 for success, non-zero for failure.
3417 */
3418static int
3419SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3420{
3421 PortEnable_t port_enable;
3422 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003423 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 int req_sz;
3425 int reply_sz;
3426
3427 /* Destination... */
3428 reply_sz = sizeof(MPIDefaultReply_t);
3429 memset(&reply_buf, 0, reply_sz);
3430
3431 req_sz = sizeof(PortEnable_t);
3432 memset(&port_enable, 0, req_sz);
3433
3434 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3435 port_enable.PortNumber = portnum;
3436/* port_enable.ChainOffset = 0; */
3437/* port_enable.MsgFlags = 0; */
3438/* port_enable.MsgContext = 0; */
3439
Prakash, Sathya436ace72007-07-24 15:42:08 +05303440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 ioc->name, portnum, &port_enable));
3442
3443 /* RAID FW may take a long time to enable
3444 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003445 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003446 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3447 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3448 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003449 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003450 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3451 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3452 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003454 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455}
3456
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003457/**
3458 * mpt_alloc_fw_memory - allocate firmware memory
3459 * @ioc: Pointer to MPT_ADAPTER structure
3460 * @size: total FW bytes
3461 *
3462 * If memory has already been allocated, the same (cached) value
3463 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303464 *
3465 * Return 0 if successfull, or non-zero for failure
3466 **/
3467int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3469{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303470 int rc;
3471
3472 if (ioc->cached_fw) {
3473 rc = 0; /* use already allocated memory */
3474 goto out;
3475 }
3476 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3478 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303479 rc = 0;
3480 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303482 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3483 if (!ioc->cached_fw) {
3484 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3485 ioc->name);
3486 rc = -1;
3487 } else {
3488 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3489 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3490 ioc->alloc_total += size;
3491 rc = 0;
3492 }
3493 out:
3494 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303496
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003497/**
3498 * mpt_free_fw_memory - free firmware memory
3499 * @ioc: Pointer to MPT_ADAPTER structure
3500 *
3501 * If alt_img is NULL, delete from ioc structure.
3502 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303503 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504void
3505mpt_free_fw_memory(MPT_ADAPTER *ioc)
3506{
3507 int sz;
3508
Prakash, Sathya984621b2008-01-11 14:42:17 +05303509 if (!ioc->cached_fw)
3510 return;
3511
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303513 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3514 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003515 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303516 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518}
3519
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003521/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3523 * @ioc: Pointer to MPT_ADAPTER structure
3524 * @sleepFlag: Specifies whether the process can sleep
3525 *
3526 * Returns 0 for success, >0 for handshake failure
3527 * <0 for fw upload failure.
3528 *
3529 * Remark: If bound IOC and a successful FWUpload was performed
3530 * on the bound IOC, the second image is discarded
3531 * and memory is free'd. Both channels must upload to prevent
3532 * IOC from running in degraded mode.
3533 */
3534static int
3535mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3536{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 u8 reply[sizeof(FWUploadReply_t)];
3538 FWUpload_t *prequest;
3539 FWUploadReply_t *preply;
3540 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 u32 flagsLength;
3542 int ii, sz, reply_sz;
3543 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303544 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 /* If the image size is 0, we are done.
3546 */
3547 if ((sz = ioc->facts.FWImageSize) == 0)
3548 return 0;
3549
Prakash, Sathya984621b2008-01-11 14:42:17 +05303550 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3551 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
Eric Moore29dd3602007-09-14 18:46:51 -06003553 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3554 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003555
Eric Moorebc6e0892007-09-29 10:16:28 -06003556 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3557 kzalloc(ioc->req_sz, GFP_KERNEL);
3558 if (!prequest) {
3559 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3560 "while allocating memory \n", ioc->name));
3561 mpt_free_fw_memory(ioc);
3562 return -ENOMEM;
3563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
Eric Moorebc6e0892007-09-29 10:16:28 -06003565 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567 reply_sz = sizeof(reply);
3568 memset(preply, 0, reply_sz);
3569
3570 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3571 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3572
3573 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3574 ptcsge->DetailsLength = 12;
3575 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3576 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003577 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303580 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3581 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3582 ioc->SGE_size;
3583 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3584 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3585 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003586 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303588 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3589 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Eric Moore29dd3602007-09-14 18:46:51 -06003591 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
3593 cmdStatus = -EFAULT;
3594 if (ii == 0) {
3595 /* Handshake transfer was complete and successful.
3596 * Check the Reply Frame.
3597 */
3598 int status, transfer_sz;
3599 status = le16_to_cpu(preply->IOCStatus);
3600 if (status == MPI_IOCSTATUS_SUCCESS) {
3601 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3602 if (transfer_sz == sz)
3603 cmdStatus = 0;
3604 }
3605 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303606 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 ioc->name, cmdStatus));
3608
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003609
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 if (cmdStatus) {
3611
Prakash, Sathya436ace72007-07-24 15:42:08 +05303612 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 ioc->name));
3614 mpt_free_fw_memory(ioc);
3615 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003616 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
3618 return cmdStatus;
3619}
3620
3621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003622/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 * mpt_downloadboot - DownloadBoot code
3624 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003625 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 * @sleepFlag: Specifies whether the process can sleep
3627 *
3628 * FwDownloadBoot requires Programmed IO access.
3629 *
3630 * Returns 0 for success
3631 * -1 FW Image size is 0
3632 * -2 No valid cached_fw Pointer
3633 * <0 for fw upload failure.
3634 */
3635static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003636mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 MpiExtImageHeader_t *pExtImage;
3639 u32 fwSize;
3640 u32 diag0val;
3641 int count;
3642 u32 *ptrFw;
3643 u32 diagRwData;
3644 u32 nextImage;
3645 u32 load_addr;
3646 u32 ioc_state=0;
3647
Prakash, Sathya436ace72007-07-24 15:42:08 +05303648 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003649 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3652 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3653 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3654 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3655 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3656 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3657
3658 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3659
3660 /* wait 1 msec */
3661 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003662 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 } else {
3664 mdelay (1);
3665 }
3666
3667 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3668 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3669
3670 for (count = 0; count < 30; count ++) {
3671 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3672 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303673 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 ioc->name, count));
3675 break;
3676 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003677 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003679 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003681 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 }
3683 }
3684
3685 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303686 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003687 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 ioc->name, diag0val));
3689 return -3;
3690 }
3691
3692 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3693 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3694 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3695 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3696 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3697 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3698
3699 /* Set the DiagRwEn and Disable ARM bits */
3700 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 fwSize = (pFwHeader->ImageSize + 3)/4;
3703 ptrFw = (u32 *) pFwHeader;
3704
3705 /* Write the LoadStartAddress to the DiagRw Address Register
3706 * using Programmed IO
3707 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003708 if (ioc->errata_flag_1064)
3709 pci_enable_io_access(ioc->pcidev);
3710
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303712 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 ioc->name, pFwHeader->LoadStartAddress));
3714
Prakash, Sathya436ace72007-07-24 15:42:08 +05303715 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 ioc->name, fwSize*4, ptrFw));
3717 while (fwSize--) {
3718 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3719 }
3720
3721 nextImage = pFwHeader->NextImageHeaderOffset;
3722 while (nextImage) {
3723 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3724
3725 load_addr = pExtImage->LoadStartAddress;
3726
3727 fwSize = (pExtImage->ImageSize + 3) >> 2;
3728 ptrFw = (u32 *)pExtImage;
3729
Prakash, Sathya436ace72007-07-24 15:42:08 +05303730 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 +02003731 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3733
3734 while (fwSize--) {
3735 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3736 }
3737 nextImage = pExtImage->NextImageHeaderOffset;
3738 }
3739
3740 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303741 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3743
3744 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303745 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3747
3748 /* Clear the internal flash bad bit - autoincrementing register,
3749 * so must do two writes.
3750 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003751 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003752 /*
3753 * 1030 and 1035 H/W errata, workaround to access
3754 * the ClearFlashBadSignatureBit
3755 */
3756 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3757 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3758 diagRwData |= 0x40000000;
3759 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3760 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3761
3762 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3763 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3764 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3765 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3766
3767 /* wait 1 msec */
3768 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003769 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003770 } else {
3771 mdelay (1);
3772 }
3773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003775 if (ioc->errata_flag_1064)
3776 pci_disable_io_access(ioc->pcidev);
3777
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303779 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003780 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003782 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303783 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 ioc->name, diag0val));
3785 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3786
3787 /* Write 0xFF to reset the sequencer */
3788 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3789
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003790 if (ioc->bus_type == SAS) {
3791 ioc_state = mpt_GetIocState(ioc, 0);
3792 if ( (GetIocFacts(ioc, sleepFlag,
3793 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303794 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003795 ioc->name, ioc_state));
3796 return -EFAULT;
3797 }
3798 }
3799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 for (count=0; count<HZ*20; count++) {
3801 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303802 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3803 "downloadboot successful! (count=%d) IocState=%x\n",
3804 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003805 if (ioc->bus_type == SAS) {
3806 return 0;
3807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303809 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3810 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 ioc->name));
3812 return -EFAULT;
3813 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303814 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3815 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 ioc->name));
3817 return 0;
3818 }
3819 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003820 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 } else {
3822 mdelay (10);
3823 }
3824 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303825 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3826 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 return -EFAULT;
3828}
3829
3830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003831/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 * KickStart - Perform hard reset of MPT adapter.
3833 * @ioc: Pointer to MPT_ADAPTER structure
3834 * @force: Force hard reset
3835 * @sleepFlag: Specifies whether the process can sleep
3836 *
3837 * This routine places MPT adapter in diagnostic mode via the
3838 * WriteSequence register, and then performs a hard reset of adapter
3839 * via the Diagnostic register.
3840 *
3841 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3842 * or NO_SLEEP (interrupt thread, use mdelay)
3843 * force - 1 if doorbell active, board fault state
3844 * board operational, IOC_RECOVERY or
3845 * IOC_BRINGUP and there is an alt_ioc.
3846 * 0 else
3847 *
3848 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003849 * 1 - hard reset, READY
3850 * 0 - no reset due to History bit, READY
3851 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 * OR reset but failed to come READY
3853 * -2 - no reset, could not enter DIAG mode
3854 * -3 - reset but bad FW bit
3855 */
3856static int
3857KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3858{
3859 int hard_reset_done = 0;
3860 u32 ioc_state=0;
3861 int cnt,cntdn;
3862
Eric Moore29dd3602007-09-14 18:46:51 -06003863 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003864 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 /* Always issue a Msg Unit Reset first. This will clear some
3866 * SCSI bus hang conditions.
3867 */
3868 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3869
3870 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003871 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 } else {
3873 mdelay (1000);
3874 }
3875 }
3876
3877 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3878 if (hard_reset_done < 0)
3879 return hard_reset_done;
3880
Prakash, Sathya436ace72007-07-24 15:42:08 +05303881 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003882 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
3884 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3885 for (cnt=0; cnt<cntdn; cnt++) {
3886 ioc_state = mpt_GetIocState(ioc, 1);
3887 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303888 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 ioc->name, cnt));
3890 return hard_reset_done;
3891 }
3892 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003893 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 } else {
3895 mdelay (10);
3896 }
3897 }
3898
Eric Moore29dd3602007-09-14 18:46:51 -06003899 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3900 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 return -1;
3902}
3903
3904/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003905/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 * mpt_diag_reset - Perform hard reset of the adapter.
3907 * @ioc: Pointer to MPT_ADAPTER structure
3908 * @ignore: Set if to honor and clear to ignore
3909 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003910 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 * else set to NO_SLEEP (use mdelay instead)
3912 *
3913 * This routine places the adapter in diagnostic mode via the
3914 * WriteSequence register and then performs a hard reset of adapter
3915 * via the Diagnostic register. Adapter should be in ready state
3916 * upon successful completion.
3917 *
3918 * Returns: 1 hard reset successful
3919 * 0 no reset performed because reset history bit set
3920 * -2 enabling diagnostic mode failed
3921 * -3 diagnostic reset failed
3922 */
3923static int
3924mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3925{
3926 u32 diag0val;
3927 u32 doorbell;
3928 int hard_reset_done = 0;
3929 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303931 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
Eric Moorecd2c6192007-01-29 09:47:47 -07003933 /* Clear any existing interrupts */
3934 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3935
Eric Moore87cf8982006-06-27 16:09:26 -06003936 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303937 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003938 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003939 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3940 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3941 if (sleepFlag == CAN_SLEEP)
3942 msleep(1);
3943 else
3944 mdelay(1);
3945
3946 for (count = 0; count < 60; count ++) {
3947 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3948 doorbell &= MPI_IOC_STATE_MASK;
3949
Prakash, Sathya436ace72007-07-24 15:42:08 +05303950 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003951 "looking for READY STATE: doorbell=%x"
3952 " count=%d\n",
3953 ioc->name, doorbell, count));
3954 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003955 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003956 }
3957
3958 /* wait 1 sec */
3959 if (sleepFlag == CAN_SLEEP)
3960 msleep(1000);
3961 else
3962 mdelay(1000);
3963 }
3964 return -1;
3965 }
3966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 /* Use "Diagnostic reset" method! (only thing available!) */
3968 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3969
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 if (ioc->debug_level & MPT_DEBUG) {
3971 if (ioc->alt_ioc)
3972 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3973 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977 /* Do the reset if we are told to ignore the reset history
3978 * or if the reset history is 0
3979 */
3980 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3981 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3982 /* Write magic sequence to WriteSequence register
3983 * Loop until in diagnostic mode
3984 */
3985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3988 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3989 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3990 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3991
3992 /* wait 100 msec */
3993 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003994 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 } else {
3996 mdelay (100);
3997 }
3998
3999 count++;
4000 if (count > 20) {
4001 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4002 ioc->name, diag0val);
4003 return -2;
4004
4005 }
4006
4007 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4008
Prakash, Sathya436ace72007-07-24 15:42:08 +05304009 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 ioc->name, diag0val));
4011 }
4012
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 if (ioc->debug_level & MPT_DEBUG) {
4014 if (ioc->alt_ioc)
4015 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 /*
4020 * Disable the ARM (Bug fix)
4021 *
4022 */
4023 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004024 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025
4026 /*
4027 * Now hit the reset bit in the Diagnostic register
4028 * (THE BIG HAMMER!) (Clears DRWE bit).
4029 */
4030 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4031 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304032 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 ioc->name));
4034
4035 /*
4036 * Call each currently registered protocol IOC reset handler
4037 * with pre-reset indication.
4038 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4039 * MptResetHandlers[] registered yet.
4040 */
4041 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304042 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 int r = 0;
4044
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304045 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4046 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304047 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4048 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304049 ioc->name, cb_idx));
4050 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304052 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4053 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304054 ioc->name, ioc->alt_ioc->name, cb_idx));
4055 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 }
4057 }
4058 }
4059 /* FIXME? Examine results here? */
4060 }
4061
Eric Moore0ccdb002006-07-11 17:33:13 -06004062 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304063 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004064 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304065 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4066 else
4067 cached_fw = NULL;
4068 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 /* If the DownloadBoot operation fails, the
4070 * IOC will be left unusable. This is a fatal error
4071 * case. _diag_reset will return < 0
4072 */
4073 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304074 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4076 break;
4077 }
4078
Prakash, Sathya436ace72007-07-24 15:42:08 +05304079 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304080 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 /* wait 1 sec */
4082 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004083 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 } else {
4085 mdelay (1000);
4086 }
4087 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304088 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004089 printk(MYIOC_s_WARN_FMT
4090 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 }
4092
4093 } else {
4094 /* Wait for FW to reload and for board
4095 * to go to the READY state.
4096 * Maximum wait is 60 seconds.
4097 * If fail, no error will check again
4098 * with calling program.
4099 */
4100 for (count = 0; count < 60; count ++) {
4101 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4102 doorbell &= MPI_IOC_STATE_MASK;
4103
4104 if (doorbell == MPI_IOC_STATE_READY) {
4105 break;
4106 }
4107
4108 /* wait 1 sec */
4109 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004110 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 } else {
4112 mdelay (1000);
4113 }
4114 }
4115 }
4116 }
4117
4118 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304119 if (ioc->debug_level & MPT_DEBUG) {
4120 if (ioc->alt_ioc)
4121 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4122 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4123 ioc->name, diag0val, diag1val));
4124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
4126 /* Clear RESET_HISTORY bit! Place board in the
4127 * diagnostic mode to update the diag register.
4128 */
4129 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4130 count = 0;
4131 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4132 /* Write magic sequence to WriteSequence register
4133 * Loop until in diagnostic mode
4134 */
4135 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4136 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4137 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4138 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4139 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4140 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4141
4142 /* wait 100 msec */
4143 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004144 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 } else {
4146 mdelay (100);
4147 }
4148
4149 count++;
4150 if (count > 20) {
4151 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4152 ioc->name, diag0val);
4153 break;
4154 }
4155 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4156 }
4157 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4158 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4159 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4160 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4161 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4162 ioc->name);
4163 }
4164
4165 /* Disable Diagnostic Mode
4166 */
4167 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4168
4169 /* Check FW reload status flags.
4170 */
4171 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4172 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4173 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4174 ioc->name, diag0val);
4175 return -3;
4176 }
4177
Prakash, Sathya436ace72007-07-24 15:42:08 +05304178 if (ioc->debug_level & MPT_DEBUG) {
4179 if (ioc->alt_ioc)
4180 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4181 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
4185 /*
4186 * Reset flag that says we've enabled event notification
4187 */
4188 ioc->facts.EventState = 0;
4189
4190 if (ioc->alt_ioc)
4191 ioc->alt_ioc->facts.EventState = 0;
4192
4193 return hard_reset_done;
4194}
4195
4196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004197/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 * SendIocReset - Send IOCReset request to MPT adapter.
4199 * @ioc: Pointer to MPT_ADAPTER structure
4200 * @reset_type: reset type, expected values are
4201 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004202 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 *
4204 * Send IOCReset request to the MPT adapter.
4205 *
4206 * Returns 0 for success, non-zero for failure.
4207 */
4208static int
4209SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4210{
4211 int r;
4212 u32 state;
4213 int cntdn, count;
4214
Prakash, Sathya436ace72007-07-24 15:42:08 +05304215 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 ioc->name, reset_type));
4217 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4218 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4219 return r;
4220
4221 /* FW ACK'd request, wait for READY state
4222 */
4223 count = 0;
4224 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4225
4226 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4227 cntdn--;
4228 count++;
4229 if (!cntdn) {
4230 if (sleepFlag != CAN_SLEEP)
4231 count *= 10;
4232
Eric Moore29dd3602007-09-14 18:46:51 -06004233 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4234 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 return -ETIME;
4236 }
4237
4238 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004239 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 } else {
4241 mdelay (1); /* 1 msec delay */
4242 }
4243 }
4244
4245 /* TODO!
4246 * Cleanup all event stuff for this IOC; re-issue EventNotification
4247 * request if needed.
4248 */
4249 if (ioc->facts.Function)
4250 ioc->facts.EventState = 0;
4251
4252 return 0;
4253}
4254
4255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004256/**
4257 * initChainBuffers - Allocate memory for and initialize chain buffers
4258 * @ioc: Pointer to MPT_ADAPTER structure
4259 *
4260 * Allocates memory for and initializes chain buffers,
4261 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 */
4263static int
4264initChainBuffers(MPT_ADAPTER *ioc)
4265{
4266 u8 *mem;
4267 int sz, ii, num_chain;
4268 int scale, num_sge, numSGE;
4269
4270 /* ReqToChain size must equal the req_depth
4271 * index = req_idx
4272 */
4273 if (ioc->ReqToChain == NULL) {
4274 sz = ioc->req_depth * sizeof(int);
4275 mem = kmalloc(sz, GFP_ATOMIC);
4276 if (mem == NULL)
4277 return -1;
4278
4279 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304280 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 ioc->name, mem, sz));
4282 mem = kmalloc(sz, GFP_ATOMIC);
4283 if (mem == NULL)
4284 return -1;
4285
4286 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304287 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 ioc->name, mem, sz));
4289 }
4290 for (ii = 0; ii < ioc->req_depth; ii++) {
4291 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4292 }
4293
4294 /* ChainToChain size must equal the total number
4295 * of chain buffers to be allocated.
4296 * index = chain_idx
4297 *
4298 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004299 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 *
4301 * num_sge = num sge in request frame + last chain buffer
4302 * scale = num sge per chain buffer if no chain element
4303 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304304 scale = ioc->req_sz / ioc->SGE_size;
4305 if (ioc->sg_addr_size == sizeof(u64))
4306 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304308 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304310 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304312 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304314 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4315 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304317 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 ioc->name, num_sge, numSGE));
4319
4320 if ( numSGE > MPT_SCSI_SG_DEPTH )
4321 numSGE = MPT_SCSI_SG_DEPTH;
4322
4323 num_chain = 1;
4324 while (numSGE - num_sge > 0) {
4325 num_chain++;
4326 num_sge += (scale - 1);
4327 }
4328 num_chain++;
4329
Prakash, Sathya436ace72007-07-24 15:42:08 +05304330 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 ioc->name, numSGE, num_sge, num_chain));
4332
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004333 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 num_chain *= MPT_SCSI_CAN_QUEUE;
4335 else
4336 num_chain *= MPT_FC_CAN_QUEUE;
4337
4338 ioc->num_chain = num_chain;
4339
4340 sz = num_chain * sizeof(int);
4341 if (ioc->ChainToChain == NULL) {
4342 mem = kmalloc(sz, GFP_ATOMIC);
4343 if (mem == NULL)
4344 return -1;
4345
4346 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304347 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 ioc->name, mem, sz));
4349 } else {
4350 mem = (u8 *) ioc->ChainToChain;
4351 }
4352 memset(mem, 0xFF, sz);
4353 return num_chain;
4354}
4355
4356/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004357/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4359 * @ioc: Pointer to MPT_ADAPTER structure
4360 *
4361 * This routine allocates memory for the MPT reply and request frame
4362 * pools (if necessary), and primes the IOC reply FIFO with
4363 * reply frames.
4364 *
4365 * Returns 0 for success, non-zero for failure.
4366 */
4367static int
4368PrimeIocFifos(MPT_ADAPTER *ioc)
4369{
4370 MPT_FRAME_HDR *mf;
4371 unsigned long flags;
4372 dma_addr_t alloc_dma;
4373 u8 *mem;
4374 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304375 u64 dma_mask;
4376
4377 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
4379 /* Prime reply FIFO... */
4380
4381 if (ioc->reply_frames == NULL) {
4382 if ( (num_chain = initChainBuffers(ioc)) < 0)
4383 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304384 /*
4385 * 1078 errata workaround for the 36GB limitation
4386 */
4387 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4388 ioc->dma_mask > DMA_35BIT_MASK) {
4389 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4390 && !pci_set_consistent_dma_mask(ioc->pcidev,
4391 DMA_BIT_MASK(32))) {
4392 dma_mask = DMA_35BIT_MASK;
4393 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4394 "setting 35 bit addressing for "
4395 "Request/Reply/Chain and Sense Buffers\n",
4396 ioc->name));
4397 } else {
4398 /*Reseting DMA mask to 64 bit*/
4399 pci_set_dma_mask(ioc->pcidev,
4400 DMA_BIT_MASK(64));
4401 pci_set_consistent_dma_mask(ioc->pcidev,
4402 DMA_BIT_MASK(64));
4403
4404 printk(MYIOC_s_ERR_FMT
4405 "failed setting 35 bit addressing for "
4406 "Request/Reply/Chain and Sense Buffers\n",
4407 ioc->name);
4408 return -1;
4409 }
4410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411
4412 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 ioc->name, reply_sz, reply_sz));
4417
4418 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304419 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304421 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 ioc->name, sz, sz));
4423 total_size += sz;
4424
4425 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304428 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 ioc->name, sz, sz, num_chain));
4430
4431 total_size += sz;
4432 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4433 if (mem == NULL) {
4434 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4435 ioc->name);
4436 goto out_fail;
4437 }
4438
Prakash, Sathya436ace72007-07-24 15:42:08 +05304439 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4441
4442 memset(mem, 0, total_size);
4443 ioc->alloc_total += total_size;
4444 ioc->alloc = mem;
4445 ioc->alloc_dma = alloc_dma;
4446 ioc->alloc_sz = total_size;
4447 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4448 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4449
Prakash, Sathya436ace72007-07-24 15:42:08 +05304450 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004451 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 alloc_dma += reply_sz;
4454 mem += reply_sz;
4455
4456 /* Request FIFO - WE manage this! */
4457
4458 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4459 ioc->req_frames_dma = alloc_dma;
4460
Prakash, Sathya436ace72007-07-24 15:42:08 +05304461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 ioc->name, mem, (void *)(ulong)alloc_dma));
4463
4464 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4465
4466#if defined(CONFIG_MTRR) && 0
4467 /*
4468 * Enable Write Combining MTRR for IOC's memory region.
4469 * (at least as much as we can; "size and base must be
4470 * multiples of 4 kiB"
4471 */
4472 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4473 sz,
4474 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304475 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 ioc->name, ioc->req_frames_dma, sz));
4477#endif
4478
4479 for (i = 0; i < ioc->req_depth; i++) {
4480 alloc_dma += ioc->req_sz;
4481 mem += ioc->req_sz;
4482 }
4483
4484 ioc->ChainBuffer = mem;
4485 ioc->ChainBufferDMA = alloc_dma;
4486
Prakash, Sathya436ace72007-07-24 15:42:08 +05304487 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4489
4490 /* Initialize the free chain Q.
4491 */
4492
4493 INIT_LIST_HEAD(&ioc->FreeChainQ);
4494
4495 /* Post the chain buffers to the FreeChainQ.
4496 */
4497 mem = (u8 *)ioc->ChainBuffer;
4498 for (i=0; i < num_chain; i++) {
4499 mf = (MPT_FRAME_HDR *) mem;
4500 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4501 mem += ioc->req_sz;
4502 }
4503
4504 /* Initialize Request frames linked list
4505 */
4506 alloc_dma = ioc->req_frames_dma;
4507 mem = (u8 *) ioc->req_frames;
4508
4509 spin_lock_irqsave(&ioc->FreeQlock, flags);
4510 INIT_LIST_HEAD(&ioc->FreeQ);
4511 for (i = 0; i < ioc->req_depth; i++) {
4512 mf = (MPT_FRAME_HDR *) mem;
4513
4514 /* Queue REQUESTs *internally*! */
4515 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4516
4517 mem += ioc->req_sz;
4518 }
4519 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4520
4521 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4522 ioc->sense_buf_pool =
4523 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4524 if (ioc->sense_buf_pool == NULL) {
4525 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4526 ioc->name);
4527 goto out_fail;
4528 }
4529
4530 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4531 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304532 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4534
4535 }
4536
4537 /* Post Reply frames to FIFO
4538 */
4539 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304540 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4542
4543 for (i = 0; i < ioc->reply_depth; i++) {
4544 /* Write each address to the IOC! */
4545 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4546 alloc_dma += ioc->reply_sz;
4547 }
4548
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304549 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4550 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4551 ioc->dma_mask))
4552 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4553 "restoring 64 bit addressing\n", ioc->name));
4554
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 return 0;
4556
4557out_fail:
4558 if (ioc->alloc != NULL) {
4559 sz = ioc->alloc_sz;
4560 pci_free_consistent(ioc->pcidev,
4561 sz,
4562 ioc->alloc, ioc->alloc_dma);
4563 ioc->reply_frames = NULL;
4564 ioc->req_frames = NULL;
4565 ioc->alloc_total -= sz;
4566 }
4567 if (ioc->sense_buf_pool != NULL) {
4568 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4569 pci_free_consistent(ioc->pcidev,
4570 sz,
4571 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4572 ioc->sense_buf_pool = NULL;
4573 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304574
4575 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4576 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4577 DMA_BIT_MASK(64)))
4578 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4579 "restoring 64 bit addressing\n", ioc->name));
4580
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 return -1;
4582}
4583
4584/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4585/**
4586 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4587 * from IOC via doorbell handshake method.
4588 * @ioc: Pointer to MPT_ADAPTER structure
4589 * @reqBytes: Size of the request in bytes
4590 * @req: Pointer to MPT request frame
4591 * @replyBytes: Expected size of the reply in bytes
4592 * @u16reply: Pointer to area where reply should be written
4593 * @maxwait: Max wait time for a reply (in seconds)
4594 * @sleepFlag: Specifies whether the process can sleep
4595 *
4596 * NOTES: It is the callers responsibility to byte-swap fields in the
4597 * request which are greater than 1 byte in size. It is also the
4598 * callers responsibility to byte-swap response fields which are
4599 * greater than 1 byte in size.
4600 *
4601 * Returns 0 for success, non-zero for failure.
4602 */
4603static int
4604mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004605 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606{
4607 MPIDefaultReply_t *mptReply;
4608 int failcnt = 0;
4609 int t;
4610
4611 /*
4612 * Get ready to cache a handshake reply
4613 */
4614 ioc->hs_reply_idx = 0;
4615 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4616 mptReply->MsgLength = 0;
4617
4618 /*
4619 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4620 * then tell IOC that we want to handshake a request of N words.
4621 * (WRITE u32val to Doorbell reg).
4622 */
4623 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4624 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4625 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4626 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4627
4628 /*
4629 * Wait for IOC's doorbell handshake int
4630 */
4631 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4632 failcnt++;
4633
Prakash, Sathya436ace72007-07-24 15:42:08 +05304634 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4636
4637 /* Read doorbell and check for active bit */
4638 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4639 return -1;
4640
4641 /*
4642 * Clear doorbell int (WRITE 0 to IntStatus reg),
4643 * then wait for IOC to ACKnowledge that it's ready for
4644 * our handshake request.
4645 */
4646 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4647 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4648 failcnt++;
4649
4650 if (!failcnt) {
4651 int ii;
4652 u8 *req_as_bytes = (u8 *) req;
4653
4654 /*
4655 * Stuff request words via doorbell handshake,
4656 * with ACK from IOC for each.
4657 */
4658 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4659 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4660 (req_as_bytes[(ii*4) + 1] << 8) |
4661 (req_as_bytes[(ii*4) + 2] << 16) |
4662 (req_as_bytes[(ii*4) + 3] << 24));
4663
4664 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4665 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4666 failcnt++;
4667 }
4668
Prakash, Sathya436ace72007-07-24 15:42:08 +05304669 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004670 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671
Prakash, Sathya436ace72007-07-24 15:42:08 +05304672 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4674
4675 /*
4676 * Wait for completion of doorbell handshake reply from the IOC
4677 */
4678 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4679 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004680
Prakash, Sathya436ace72007-07-24 15:42:08 +05304681 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4683
4684 /*
4685 * Copy out the cached reply...
4686 */
4687 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4688 u16reply[ii] = ioc->hs_reply[ii];
4689 } else {
4690 return -99;
4691 }
4692
4693 return -failcnt;
4694}
4695
4696/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004697/**
4698 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 * @ioc: Pointer to MPT_ADAPTER structure
4700 * @howlong: How long to wait (in seconds)
4701 * @sleepFlag: Specifies whether the process can sleep
4702 *
4703 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004704 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4705 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 *
4707 * Returns a negative value on failure, else wait loop count.
4708 */
4709static int
4710WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4711{
4712 int cntdn;
4713 int count = 0;
4714 u32 intstat=0;
4715
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004716 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717
4718 if (sleepFlag == CAN_SLEEP) {
4719 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004720 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4722 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4723 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 count++;
4725 }
4726 } else {
4727 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004728 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4730 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4731 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 count++;
4733 }
4734 }
4735
4736 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304737 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 ioc->name, count));
4739 return count;
4740 }
4741
4742 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4743 ioc->name, count, intstat);
4744 return -1;
4745}
4746
4747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004748/**
4749 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 * @ioc: Pointer to MPT_ADAPTER structure
4751 * @howlong: How long to wait (in seconds)
4752 * @sleepFlag: Specifies whether the process can sleep
4753 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004754 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4755 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 *
4757 * Returns a negative value on failure, else wait loop count.
4758 */
4759static int
4760WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4761{
4762 int cntdn;
4763 int count = 0;
4764 u32 intstat=0;
4765
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004766 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 if (sleepFlag == CAN_SLEEP) {
4768 while (--cntdn) {
4769 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4770 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4771 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004772 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 count++;
4774 }
4775 } else {
4776 while (--cntdn) {
4777 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4778 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4779 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004780 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 count++;
4782 }
4783 }
4784
4785 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304786 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 ioc->name, count, howlong));
4788 return count;
4789 }
4790
4791 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4792 ioc->name, count, intstat);
4793 return -1;
4794}
4795
4796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004797/**
4798 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 * @ioc: Pointer to MPT_ADAPTER structure
4800 * @howlong: How long to wait (in seconds)
4801 * @sleepFlag: Specifies whether the process can sleep
4802 *
4803 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4804 * Reply is cached to IOC private area large enough to hold a maximum
4805 * of 128 bytes of reply data.
4806 *
4807 * Returns a negative value on failure, else size of reply in WORDS.
4808 */
4809static int
4810WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4811{
4812 int u16cnt = 0;
4813 int failcnt = 0;
4814 int t;
4815 u16 *hs_reply = ioc->hs_reply;
4816 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4817 u16 hword;
4818
4819 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4820
4821 /*
4822 * Get first two u16's so we can look at IOC's intended reply MsgLength
4823 */
4824 u16cnt=0;
4825 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4826 failcnt++;
4827 } else {
4828 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4829 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4830 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4831 failcnt++;
4832 else {
4833 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4834 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4835 }
4836 }
4837
Prakash, Sathya436ace72007-07-24 15:42:08 +05304838 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004839 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4841
4842 /*
4843 * If no error (and IOC said MsgLength is > 0), piece together
4844 * reply 16 bits at a time.
4845 */
4846 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4847 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4848 failcnt++;
4849 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4850 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004851 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 hs_reply[u16cnt] = hword;
4853 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4854 }
4855
4856 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4857 failcnt++;
4858 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4859
4860 if (failcnt) {
4861 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4862 ioc->name);
4863 return -failcnt;
4864 }
4865#if 0
4866 else if (u16cnt != (2 * mptReply->MsgLength)) {
4867 return -101;
4868 }
4869 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4870 return -102;
4871 }
4872#endif
4873
Prakash, Sathya436ace72007-07-24 15:42:08 +05304874 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004875 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
Prakash, Sathya436ace72007-07-24 15:42:08 +05304877 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 ioc->name, t, u16cnt/2));
4879 return u16cnt/2;
4880}
4881
4882/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004883/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 * GetLanConfigPages - Fetch LANConfig pages.
4885 * @ioc: Pointer to MPT_ADAPTER structure
4886 *
4887 * Return: 0 for success
4888 * -ENOMEM if no memory available
4889 * -EPERM if not allowed due to ISR context
4890 * -EAGAIN if no msg frames currently available
4891 * -EFAULT for non-successful reply or no reply (timeout)
4892 */
4893static int
4894GetLanConfigPages(MPT_ADAPTER *ioc)
4895{
4896 ConfigPageHeader_t hdr;
4897 CONFIGPARMS cfg;
4898 LANPage0_t *ppage0_alloc;
4899 dma_addr_t page0_dma;
4900 LANPage1_t *ppage1_alloc;
4901 dma_addr_t page1_dma;
4902 int rc = 0;
4903 int data_sz;
4904 int copy_sz;
4905
4906 /* Get LAN Page 0 header */
4907 hdr.PageVersion = 0;
4908 hdr.PageLength = 0;
4909 hdr.PageNumber = 0;
4910 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004911 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 cfg.physAddr = -1;
4913 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4914 cfg.dir = 0;
4915 cfg.pageAddr = 0;
4916 cfg.timeout = 0;
4917
4918 if ((rc = mpt_config(ioc, &cfg)) != 0)
4919 return rc;
4920
4921 if (hdr.PageLength > 0) {
4922 data_sz = hdr.PageLength * 4;
4923 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4924 rc = -ENOMEM;
4925 if (ppage0_alloc) {
4926 memset((u8 *)ppage0_alloc, 0, data_sz);
4927 cfg.physAddr = page0_dma;
4928 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4929
4930 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4931 /* save the data */
4932 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4933 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4934
4935 }
4936
4937 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4938
4939 /* FIXME!
4940 * Normalize endianness of structure data,
4941 * by byte-swapping all > 1 byte fields!
4942 */
4943
4944 }
4945
4946 if (rc)
4947 return rc;
4948 }
4949
4950 /* Get LAN Page 1 header */
4951 hdr.PageVersion = 0;
4952 hdr.PageLength = 0;
4953 hdr.PageNumber = 1;
4954 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004955 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 cfg.physAddr = -1;
4957 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4958 cfg.dir = 0;
4959 cfg.pageAddr = 0;
4960
4961 if ((rc = mpt_config(ioc, &cfg)) != 0)
4962 return rc;
4963
4964 if (hdr.PageLength == 0)
4965 return 0;
4966
4967 data_sz = hdr.PageLength * 4;
4968 rc = -ENOMEM;
4969 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4970 if (ppage1_alloc) {
4971 memset((u8 *)ppage1_alloc, 0, data_sz);
4972 cfg.physAddr = page1_dma;
4973 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4974
4975 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4976 /* save the data */
4977 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4978 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4979 }
4980
4981 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4982
4983 /* FIXME!
4984 * Normalize endianness of structure data,
4985 * by byte-swapping all > 1 byte fields!
4986 */
4987
4988 }
4989
4990 return rc;
4991}
4992
4993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004994/**
4995 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004996 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004997 * @persist_opcode: see below
4998 *
4999 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5000 * devices not currently present.
5001 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5002 *
5003 * NOTE: Don't use not this function during interrupt time.
5004 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005005 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005006 */
5007
5008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5009int
5010mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5011{
5012 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5013 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5014 MPT_FRAME_HDR *mf = NULL;
5015 MPIHeader_t *mpi_hdr;
5016
5017
5018 /* insure garbage is not sent to fw */
5019 switch(persist_opcode) {
5020
5021 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5022 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5023 break;
5024
5025 default:
5026 return -1;
5027 break;
5028 }
5029
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005030 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005031
5032 /* Get a MF for this command.
5033 */
5034 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005035 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005036 return -1;
5037 }
5038
5039 mpi_hdr = (MPIHeader_t *) mf;
5040 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5041 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5042 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5043 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5044 sasIoUnitCntrReq->Operation = persist_opcode;
5045
5046 init_timer(&ioc->persist_timer);
5047 ioc->persist_timer.data = (unsigned long) ioc;
5048 ioc->persist_timer.function = mpt_timer_expired;
5049 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
5050 ioc->persist_wait_done=0;
5051 add_timer(&ioc->persist_timer);
5052 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5053 wait_event(mpt_waitq, ioc->persist_wait_done);
5054
5055 sasIoUnitCntrReply =
5056 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
5057 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5058 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005059 __func__,
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005060 sasIoUnitCntrReply->IOCStatus,
5061 sasIoUnitCntrReply->IOCLogInfo);
5062 return -1;
5063 }
5064
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005065 printk("%s: success\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005066 return 0;
5067}
5068
5069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005070
5071static void
5072mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5073 MpiEventDataRaid_t * pRaidEventData)
5074{
5075 int volume;
5076 int reason;
5077 int disk;
5078 int status;
5079 int flags;
5080 int state;
5081
5082 volume = pRaidEventData->VolumeID;
5083 reason = pRaidEventData->ReasonCode;
5084 disk = pRaidEventData->PhysDiskNum;
5085 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5086 flags = (status >> 0) & 0xff;
5087 state = (status >> 8) & 0xff;
5088
5089 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5090 return;
5091 }
5092
5093 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5094 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5095 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005096 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5097 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005098 } else {
5099 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5100 ioc->name, volume);
5101 }
5102
5103 switch(reason) {
5104 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5105 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5106 ioc->name);
5107 break;
5108
5109 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5110
5111 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5112 ioc->name);
5113 break;
5114
5115 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5116 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5117 ioc->name);
5118 break;
5119
5120 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5121 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5122 ioc->name,
5123 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5124 ? "optimal"
5125 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5126 ? "degraded"
5127 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5128 ? "failed"
5129 : "state unknown",
5130 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5131 ? ", enabled" : "",
5132 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5133 ? ", quiesced" : "",
5134 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5135 ? ", resync in progress" : "" );
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5139 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5140 ioc->name, disk);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5144 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5145 ioc->name);
5146 break;
5147
5148 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5149 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5150 ioc->name);
5151 break;
5152
5153 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5154 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5155 ioc->name);
5156 break;
5157
5158 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5159 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5160 ioc->name,
5161 state == MPI_PHYSDISK0_STATUS_ONLINE
5162 ? "online"
5163 : state == MPI_PHYSDISK0_STATUS_MISSING
5164 ? "missing"
5165 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5166 ? "not compatible"
5167 : state == MPI_PHYSDISK0_STATUS_FAILED
5168 ? "failed"
5169 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5170 ? "initializing"
5171 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5172 ? "offline requested"
5173 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5174 ? "failed requested"
5175 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5176 ? "offline"
5177 : "state unknown",
5178 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5179 ? ", out of sync" : "",
5180 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5181 ? ", quiesced" : "" );
5182 break;
5183
5184 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5185 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5186 ioc->name, disk);
5187 break;
5188
5189 case MPI_EVENT_RAID_RC_SMART_DATA:
5190 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5191 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5192 break;
5193
5194 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5195 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5196 ioc->name, disk);
5197 break;
5198 }
5199}
5200
5201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005202/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5204 * @ioc: Pointer to MPT_ADAPTER structure
5205 *
5206 * Returns: 0 for success
5207 * -ENOMEM if no memory available
5208 * -EPERM if not allowed due to ISR context
5209 * -EAGAIN if no msg frames currently available
5210 * -EFAULT for non-successful reply or no reply (timeout)
5211 */
5212static int
5213GetIoUnitPage2(MPT_ADAPTER *ioc)
5214{
5215 ConfigPageHeader_t hdr;
5216 CONFIGPARMS cfg;
5217 IOUnitPage2_t *ppage_alloc;
5218 dma_addr_t page_dma;
5219 int data_sz;
5220 int rc;
5221
5222 /* Get the page header */
5223 hdr.PageVersion = 0;
5224 hdr.PageLength = 0;
5225 hdr.PageNumber = 2;
5226 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005227 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 cfg.physAddr = -1;
5229 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5230 cfg.dir = 0;
5231 cfg.pageAddr = 0;
5232 cfg.timeout = 0;
5233
5234 if ((rc = mpt_config(ioc, &cfg)) != 0)
5235 return rc;
5236
5237 if (hdr.PageLength == 0)
5238 return 0;
5239
5240 /* Read the config page */
5241 data_sz = hdr.PageLength * 4;
5242 rc = -ENOMEM;
5243 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5244 if (ppage_alloc) {
5245 memset((u8 *)ppage_alloc, 0, data_sz);
5246 cfg.physAddr = page_dma;
5247 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5248
5249 /* If Good, save data */
5250 if ((rc = mpt_config(ioc, &cfg)) == 0)
5251 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5252
5253 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5254 }
5255
5256 return rc;
5257}
5258
5259/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005260/**
5261 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 * @ioc: Pointer to a Adapter Strucutre
5263 * @portnum: IOC port number
5264 *
5265 * Return: -EFAULT if read of config page header fails
5266 * or if no nvram
5267 * If read of SCSI Port Page 0 fails,
5268 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5269 * Adapter settings: async, narrow
5270 * Return 1
5271 * If read of SCSI Port Page 2 fails,
5272 * Adapter settings valid
5273 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5274 * Return 1
5275 * Else
5276 * Both valid
5277 * Return 0
5278 * CHECK - what type of locking mechanisms should be used????
5279 */
5280static int
5281mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5282{
5283 u8 *pbuf;
5284 dma_addr_t buf_dma;
5285 CONFIGPARMS cfg;
5286 ConfigPageHeader_t header;
5287 int ii;
5288 int data, rc = 0;
5289
5290 /* Allocate memory
5291 */
5292 if (!ioc->spi_data.nvram) {
5293 int sz;
5294 u8 *mem;
5295 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5296 mem = kmalloc(sz, GFP_ATOMIC);
5297 if (mem == NULL)
5298 return -EFAULT;
5299
5300 ioc->spi_data.nvram = (int *) mem;
5301
Prakash, Sathya436ace72007-07-24 15:42:08 +05305302 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 ioc->name, ioc->spi_data.nvram, sz));
5304 }
5305
5306 /* Invalidate NVRAM information
5307 */
5308 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5309 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5310 }
5311
5312 /* Read SPP0 header, allocate memory, then read page.
5313 */
5314 header.PageVersion = 0;
5315 header.PageLength = 0;
5316 header.PageNumber = 0;
5317 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005318 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 cfg.physAddr = -1;
5320 cfg.pageAddr = portnum;
5321 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5322 cfg.dir = 0;
5323 cfg.timeout = 0; /* use default */
5324 if (mpt_config(ioc, &cfg) != 0)
5325 return -EFAULT;
5326
5327 if (header.PageLength > 0) {
5328 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5329 if (pbuf) {
5330 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5331 cfg.physAddr = buf_dma;
5332 if (mpt_config(ioc, &cfg) != 0) {
5333 ioc->spi_data.maxBusWidth = MPT_NARROW;
5334 ioc->spi_data.maxSyncOffset = 0;
5335 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5336 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5337 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305338 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5339 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005340 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 } else {
5342 /* Save the Port Page 0 data
5343 */
5344 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5345 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5346 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5347
5348 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5349 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005350 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5351 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 ioc->name, pPP0->Capabilities));
5353 }
5354 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5355 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5356 if (data) {
5357 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5358 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5359 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305360 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5361 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005362 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 } else {
5364 ioc->spi_data.maxSyncOffset = 0;
5365 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5366 }
5367
5368 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5369
5370 /* Update the minSyncFactor based on bus type.
5371 */
5372 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5373 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5374
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005375 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305377 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5378 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005379 ioc->name, ioc->spi_data.minSyncFactor));
5380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 }
5382 }
5383 if (pbuf) {
5384 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5385 }
5386 }
5387 }
5388
5389 /* SCSI Port Page 2 - Read the header then the page.
5390 */
5391 header.PageVersion = 0;
5392 header.PageLength = 0;
5393 header.PageNumber = 2;
5394 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005395 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 cfg.physAddr = -1;
5397 cfg.pageAddr = portnum;
5398 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5399 cfg.dir = 0;
5400 if (mpt_config(ioc, &cfg) != 0)
5401 return -EFAULT;
5402
5403 if (header.PageLength > 0) {
5404 /* Allocate memory and read SCSI Port Page 2
5405 */
5406 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5407 if (pbuf) {
5408 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5409 cfg.physAddr = buf_dma;
5410 if (mpt_config(ioc, &cfg) != 0) {
5411 /* Nvram data is left with INVALID mark
5412 */
5413 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005414 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5415
5416 /* This is an ATTO adapter, read Page2 accordingly
5417 */
5418 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5419 ATTODeviceInfo_t *pdevice = NULL;
5420 u16 ATTOFlags;
5421
5422 /* Save the Port Page 2 data
5423 * (reformat into a 32bit quantity)
5424 */
5425 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5426 pdevice = &pPP2->DeviceSettings[ii];
5427 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5428 data = 0;
5429
5430 /* Translate ATTO device flags to LSI format
5431 */
5432 if (ATTOFlags & ATTOFLAG_DISC)
5433 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5434 if (ATTOFlags & ATTOFLAG_ID_ENB)
5435 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5436 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5437 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5438 if (ATTOFlags & ATTOFLAG_TAGGED)
5439 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5440 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5441 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5442
5443 data = (data << 16) | (pdevice->Period << 8) | 10;
5444 ioc->spi_data.nvram[ii] = data;
5445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 } else {
5447 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5448 MpiDeviceInfo_t *pdevice = NULL;
5449
Moore, Ericd8e925d2006-01-16 18:53:06 -07005450 /*
5451 * Save "Set to Avoid SCSI Bus Resets" flag
5452 */
5453 ioc->spi_data.bus_reset =
5454 (le32_to_cpu(pPP2->PortFlags) &
5455 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5456 0 : 1 ;
5457
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 /* Save the Port Page 2 data
5459 * (reformat into a 32bit quantity)
5460 */
5461 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5462 ioc->spi_data.PortFlags = data;
5463 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5464 pdevice = &pPP2->DeviceSettings[ii];
5465 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5466 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5467 ioc->spi_data.nvram[ii] = data;
5468 }
5469 }
5470
5471 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5472 }
5473 }
5474
5475 /* Update Adapter limits with those from NVRAM
5476 * Comment: Don't need to do this. Target performance
5477 * parameters will never exceed the adapters limits.
5478 */
5479
5480 return rc;
5481}
5482
5483/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005484/**
5485 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 * @ioc: Pointer to a Adapter Strucutre
5487 * @portnum: IOC port number
5488 *
5489 * Return: -EFAULT if read of config page header fails
5490 * or 0 if success.
5491 */
5492static int
5493mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5494{
5495 CONFIGPARMS cfg;
5496 ConfigPageHeader_t header;
5497
5498 /* Read the SCSI Device Page 1 header
5499 */
5500 header.PageVersion = 0;
5501 header.PageLength = 0;
5502 header.PageNumber = 1;
5503 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005504 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 cfg.physAddr = -1;
5506 cfg.pageAddr = portnum;
5507 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5508 cfg.dir = 0;
5509 cfg.timeout = 0;
5510 if (mpt_config(ioc, &cfg) != 0)
5511 return -EFAULT;
5512
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005513 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5514 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
5516 header.PageVersion = 0;
5517 header.PageLength = 0;
5518 header.PageNumber = 0;
5519 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5520 if (mpt_config(ioc, &cfg) != 0)
5521 return -EFAULT;
5522
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005523 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5524 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
Prakash, Sathya436ace72007-07-24 15:42:08 +05305526 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5528
Prakash, Sathya436ace72007-07-24 15:42:08 +05305529 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5531 return 0;
5532}
5533
Eric Mooreb506ade2007-01-29 09:45:37 -07005534/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005535 * mpt_inactive_raid_list_free - This clears this link list.
5536 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005537 **/
5538static void
5539mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5540{
5541 struct inactive_raid_component_info *component_info, *pNext;
5542
5543 if (list_empty(&ioc->raid_data.inactive_list))
5544 return;
5545
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005546 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005547 list_for_each_entry_safe(component_info, pNext,
5548 &ioc->raid_data.inactive_list, list) {
5549 list_del(&component_info->list);
5550 kfree(component_info);
5551 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005552 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005553}
5554
5555/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005556 * 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 -07005557 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005558 * @ioc : pointer to per adapter structure
5559 * @channel : volume channel
5560 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005561 **/
5562static void
5563mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5564{
5565 CONFIGPARMS cfg;
5566 ConfigPageHeader_t hdr;
5567 dma_addr_t dma_handle;
5568 pRaidVolumePage0_t buffer = NULL;
5569 int i;
5570 RaidPhysDiskPage0_t phys_disk;
5571 struct inactive_raid_component_info *component_info;
5572 int handle_inactive_volumes;
5573
5574 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5575 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5576 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5577 cfg.pageAddr = (channel << 8) + id;
5578 cfg.cfghdr.hdr = &hdr;
5579 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5580
5581 if (mpt_config(ioc, &cfg) != 0)
5582 goto out;
5583
5584 if (!hdr.PageLength)
5585 goto out;
5586
5587 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5588 &dma_handle);
5589
5590 if (!buffer)
5591 goto out;
5592
5593 cfg.physAddr = dma_handle;
5594 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5595
5596 if (mpt_config(ioc, &cfg) != 0)
5597 goto out;
5598
5599 if (!buffer->NumPhysDisks)
5600 goto out;
5601
5602 handle_inactive_volumes =
5603 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5604 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5605 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5606 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5607
5608 if (!handle_inactive_volumes)
5609 goto out;
5610
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005611 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005612 for (i = 0; i < buffer->NumPhysDisks; i++) {
5613 if(mpt_raid_phys_disk_pg0(ioc,
5614 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5615 continue;
5616
5617 if ((component_info = kmalloc(sizeof (*component_info),
5618 GFP_KERNEL)) == NULL)
5619 continue;
5620
5621 component_info->volumeID = id;
5622 component_info->volumeBus = channel;
5623 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5624 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5625 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5626 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5627
5628 list_add_tail(&component_info->list,
5629 &ioc->raid_data.inactive_list);
5630 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005631 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005632
5633 out:
5634 if (buffer)
5635 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5636 dma_handle);
5637}
5638
5639/**
5640 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5641 * @ioc: Pointer to a Adapter Structure
5642 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5643 * @phys_disk: requested payload data returned
5644 *
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
5649 **/
5650int
5651mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5652{
5653 CONFIGPARMS cfg;
5654 ConfigPageHeader_t hdr;
5655 dma_addr_t dma_handle;
5656 pRaidPhysDiskPage0_t buffer = NULL;
5657 int rc;
5658
5659 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5660 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5661
5662 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5663 cfg.cfghdr.hdr = &hdr;
5664 cfg.physAddr = -1;
5665 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5666
5667 if (mpt_config(ioc, &cfg) != 0) {
5668 rc = -EFAULT;
5669 goto out;
5670 }
5671
5672 if (!hdr.PageLength) {
5673 rc = -EFAULT;
5674 goto out;
5675 }
5676
5677 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5678 &dma_handle);
5679
5680 if (!buffer) {
5681 rc = -ENOMEM;
5682 goto out;
5683 }
5684
5685 cfg.physAddr = dma_handle;
5686 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5687 cfg.pageAddr = phys_disk_num;
5688
5689 if (mpt_config(ioc, &cfg) != 0) {
5690 rc = -EFAULT;
5691 goto out;
5692 }
5693
5694 rc = 0;
5695 memcpy(phys_disk, buffer, sizeof(*buffer));
5696 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5697
5698 out:
5699
5700 if (buffer)
5701 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5702 dma_handle);
5703
5704 return rc;
5705}
5706
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707/**
5708 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5709 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 *
5711 * Return:
5712 * 0 on success
5713 * -EFAULT if read of config page header fails or data pointer not NULL
5714 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005715 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716int
5717mpt_findImVolumes(MPT_ADAPTER *ioc)
5718{
5719 IOCPage2_t *pIoc2;
5720 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 dma_addr_t ioc2_dma;
5722 CONFIGPARMS cfg;
5723 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 int rc = 0;
5725 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005726 int i;
5727
5728 if (!ioc->ir_firmware)
5729 return 0;
5730
5731 /* Free the old page
5732 */
5733 kfree(ioc->raid_data.pIocPg2);
5734 ioc->raid_data.pIocPg2 = NULL;
5735 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736
5737 /* Read IOCP2 header then the page.
5738 */
5739 header.PageVersion = 0;
5740 header.PageLength = 0;
5741 header.PageNumber = 2;
5742 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005743 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 cfg.physAddr = -1;
5745 cfg.pageAddr = 0;
5746 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5747 cfg.dir = 0;
5748 cfg.timeout = 0;
5749 if (mpt_config(ioc, &cfg) != 0)
5750 return -EFAULT;
5751
5752 if (header.PageLength == 0)
5753 return -EFAULT;
5754
5755 iocpage2sz = header.PageLength * 4;
5756 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5757 if (!pIoc2)
5758 return -ENOMEM;
5759
5760 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5761 cfg.physAddr = ioc2_dma;
5762 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005763 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764
Eric Mooreb506ade2007-01-29 09:45:37 -07005765 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5766 if (!mem)
5767 goto out;
5768
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005770 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771
Eric Mooreb506ade2007-01-29 09:45:37 -07005772 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Eric Mooreb506ade2007-01-29 09:45:37 -07005774 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5775 mpt_inactive_raid_volumes(ioc,
5776 pIoc2->RaidVolume[i].VolumeBus,
5777 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
Eric Mooreb506ade2007-01-29 09:45:37 -07005779 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5781
5782 return rc;
5783}
5784
Moore, Ericc972c702006-03-14 09:14:06 -07005785static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5787{
5788 IOCPage3_t *pIoc3;
5789 u8 *mem;
5790 CONFIGPARMS cfg;
5791 ConfigPageHeader_t header;
5792 dma_addr_t ioc3_dma;
5793 int iocpage3sz = 0;
5794
5795 /* Free the old page
5796 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005797 kfree(ioc->raid_data.pIocPg3);
5798 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
5800 /* There is at least one physical disk.
5801 * Read and save IOC Page 3
5802 */
5803 header.PageVersion = 0;
5804 header.PageLength = 0;
5805 header.PageNumber = 3;
5806 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005807 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 cfg.physAddr = -1;
5809 cfg.pageAddr = 0;
5810 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5811 cfg.dir = 0;
5812 cfg.timeout = 0;
5813 if (mpt_config(ioc, &cfg) != 0)
5814 return 0;
5815
5816 if (header.PageLength == 0)
5817 return 0;
5818
5819 /* Read Header good, alloc memory
5820 */
5821 iocpage3sz = header.PageLength * 4;
5822 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5823 if (!pIoc3)
5824 return 0;
5825
5826 /* Read the Page and save the data
5827 * into malloc'd memory.
5828 */
5829 cfg.physAddr = ioc3_dma;
5830 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5831 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005832 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 if (mem) {
5834 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005835 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 }
5837 }
5838
5839 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5840
5841 return 0;
5842}
5843
5844static void
5845mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5846{
5847 IOCPage4_t *pIoc4;
5848 CONFIGPARMS cfg;
5849 ConfigPageHeader_t header;
5850 dma_addr_t ioc4_dma;
5851 int iocpage4sz;
5852
5853 /* Read and save IOC Page 4
5854 */
5855 header.PageVersion = 0;
5856 header.PageLength = 0;
5857 header.PageNumber = 4;
5858 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005859 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 cfg.physAddr = -1;
5861 cfg.pageAddr = 0;
5862 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5863 cfg.dir = 0;
5864 cfg.timeout = 0;
5865 if (mpt_config(ioc, &cfg) != 0)
5866 return;
5867
5868 if (header.PageLength == 0)
5869 return;
5870
5871 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5872 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5873 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5874 if (!pIoc4)
5875 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005876 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 } else {
5878 ioc4_dma = ioc->spi_data.IocPg4_dma;
5879 iocpage4sz = ioc->spi_data.IocPg4Sz;
5880 }
5881
5882 /* Read the Page into dma memory.
5883 */
5884 cfg.physAddr = ioc4_dma;
5885 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5886 if (mpt_config(ioc, &cfg) == 0) {
5887 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5888 ioc->spi_data.IocPg4_dma = ioc4_dma;
5889 ioc->spi_data.IocPg4Sz = iocpage4sz;
5890 } else {
5891 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5892 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005893 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 }
5895}
5896
5897static void
5898mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5899{
5900 IOCPage1_t *pIoc1;
5901 CONFIGPARMS cfg;
5902 ConfigPageHeader_t header;
5903 dma_addr_t ioc1_dma;
5904 int iocpage1sz = 0;
5905 u32 tmp;
5906
5907 /* Check the Coalescing Timeout in IOC Page 1
5908 */
5909 header.PageVersion = 0;
5910 header.PageLength = 0;
5911 header.PageNumber = 1;
5912 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005913 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 cfg.physAddr = -1;
5915 cfg.pageAddr = 0;
5916 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5917 cfg.dir = 0;
5918 cfg.timeout = 0;
5919 if (mpt_config(ioc, &cfg) != 0)
5920 return;
5921
5922 if (header.PageLength == 0)
5923 return;
5924
5925 /* Read Header good, alloc memory
5926 */
5927 iocpage1sz = header.PageLength * 4;
5928 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5929 if (!pIoc1)
5930 return;
5931
5932 /* Read the Page and check coalescing timeout
5933 */
5934 cfg.physAddr = ioc1_dma;
5935 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5936 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305937
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5939 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5940 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5941
Prakash, Sathya436ace72007-07-24 15:42:08 +05305942 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 ioc->name, tmp));
5944
5945 if (tmp > MPT_COALESCING_TIMEOUT) {
5946 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5947
5948 /* Write NVRAM and current
5949 */
5950 cfg.dir = 1;
5951 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5952 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305953 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 ioc->name, MPT_COALESCING_TIMEOUT));
5955
5956 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5957 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305958 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5959 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 ioc->name, MPT_COALESCING_TIMEOUT));
5961 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305962 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5963 "Reset NVRAM Coalescing Timeout Failed\n",
5964 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 }
5966
5967 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305968 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5969 "Reset of Current Coalescing Timeout Failed!\n",
5970 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 }
5972 }
5973
5974 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305975 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 }
5977 }
5978
5979 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5980
5981 return;
5982}
5983
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305984static void
5985mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5986{
5987 CONFIGPARMS cfg;
5988 ConfigPageHeader_t hdr;
5989 dma_addr_t buf_dma;
5990 ManufacturingPage0_t *pbuf = NULL;
5991
5992 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5993 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5994
5995 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5996 cfg.cfghdr.hdr = &hdr;
5997 cfg.physAddr = -1;
5998 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5999 cfg.timeout = 10;
6000
6001 if (mpt_config(ioc, &cfg) != 0)
6002 goto out;
6003
6004 if (!cfg.cfghdr.hdr->PageLength)
6005 goto out;
6006
6007 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6008 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6009 if (!pbuf)
6010 goto out;
6011
6012 cfg.physAddr = buf_dma;
6013
6014 if (mpt_config(ioc, &cfg) != 0)
6015 goto out;
6016
6017 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6018 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6019 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6020
6021 out:
6022
6023 if (pbuf)
6024 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6025}
6026
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006028/**
6029 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030 * @ioc: Pointer to MPT_ADAPTER structure
6031 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306032 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 */
6034static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306035SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306037 EventNotification_t evn;
6038 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
Kashyap, Desaifd761752009-05-29 16:39:06 +05306040 memset(&evn, 0, sizeof(EventNotification_t));
6041 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042
Kashyap, Desaifd761752009-05-29 16:39:06 +05306043 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6044 evn.Switch = EvSwitch;
6045 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046
Kashyap, Desaifd761752009-05-29 16:39:06 +05306047 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6048 "Sending EventNotification (%d) request %p\n",
6049 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
Kashyap, Desaifd761752009-05-29 16:39:06 +05306051 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6052 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6053 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054}
6055
6056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6057/**
6058 * SendEventAck - Send EventAck request to MPT adapter.
6059 * @ioc: Pointer to MPT_ADAPTER structure
6060 * @evnp: Pointer to original EventNotification request
6061 */
6062static int
6063SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6064{
6065 EventAck_t *pAck;
6066
6067 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306068 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07006069 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 return -1;
6071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072
Prakash, Sathya436ace72007-07-24 15:42:08 +05306073 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074
6075 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6076 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006077 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006079 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 pAck->Event = evnp->Event;
6081 pAck->EventContext = evnp->EventContext;
6082
6083 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6084
6085 return 0;
6086}
6087
6088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6089/**
6090 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006091 * @ioc: Pointer to an adapter structure
6092 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 * action, page address, direction, physical address
6094 * and pointer to a configuration page header
6095 * Page header is updated.
6096 *
6097 * Returns 0 for success
6098 * -EPERM if not allowed due to ISR context
6099 * -EAGAIN if no msg frames currently available
6100 * -EFAULT for non-successful reply or no reply (timeout)
6101 */
6102int
6103mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6104{
6105 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006106 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 MPT_FRAME_HDR *mf;
6108 unsigned long flags;
6109 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006110 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 int in_isr;
6112
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006113 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114 * to be in ISR context, because that is fatal!
6115 */
6116 in_isr = in_interrupt();
6117 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306118 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 ioc->name));
6120 return -EPERM;
6121 }
6122
6123 /* Get and Populate a free Frame
6124 */
6125 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306126 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 ioc->name));
6128 return -EAGAIN;
6129 }
6130 pReq = (Config_t *)mf;
6131 pReq->Action = pCfg->action;
6132 pReq->Reserved = 0;
6133 pReq->ChainOffset = 0;
6134 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006135
6136 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 pReq->ExtPageLength = 0;
6138 pReq->ExtPageType = 0;
6139 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006140
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 for (ii=0; ii < 8; ii++)
6142 pReq->Reserved2[ii] = 0;
6143
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006144 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6145 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6146 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6147 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6148
6149 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6150 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6151 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6152 pReq->ExtPageType = pExtHdr->ExtPageType;
6153 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6154
6155 /* Page Length must be treated as a reserved field for the extended header. */
6156 pReq->Header.PageLength = 0;
6157 }
6158
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6160
6161 /* Add a SGE to the config request.
6162 */
6163 if (pCfg->dir)
6164 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6165 else
6166 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6167
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006168 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6169 flagsLength |= pExtHdr->ExtPageLength * 4;
6170
Prakash, Sathya436ace72007-07-24 15:42:08 +05306171 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 +02006172 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
6173 }
6174 else {
6175 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
6176
Prakash, Sathya436ace72007-07-24 15:42:08 +05306177 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 +02006178 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
6179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306181 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183 /* Append pCfg pointer to end of mf
6184 */
6185 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
6186
6187 /* Initalize the timer
6188 */
Eric Parisb298cec2009-04-21 12:24:54 -07006189 init_timer_on_stack(&pCfg->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 pCfg->timer.data = (unsigned long) ioc;
6191 pCfg->timer.function = mpt_timer_expired;
6192 pCfg->wait_done = 0;
6193
6194 /* Set the timer; ensure 10 second minimum */
6195 if (pCfg->timeout < 10)
6196 pCfg->timer.expires = jiffies + HZ*10;
6197 else
6198 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
6199
6200 /* Add to end of Q, set timer and then issue this command */
6201 spin_lock_irqsave(&ioc->FreeQlock, flags);
6202 list_add_tail(&pCfg->linkage, &ioc->configQ);
6203 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6204
6205 add_timer(&pCfg->timer);
6206 mpt_put_msg_frame(mpt_base_index, ioc, mf);
6207 wait_event(mpt_waitq, pCfg->wait_done);
6208
6209 /* mf has been freed - do not access */
6210
6211 rc = pCfg->status;
6212
6213 return rc;
6214}
6215
6216/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006217/**
6218 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 * Used only internal config functionality.
6220 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
6221 */
6222static void
6223mpt_timer_expired(unsigned long data)
6224{
6225 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
6226
Prakash, Sathya436ace72007-07-24 15:42:08 +05306227 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
6229 /* Perform a FW reload */
6230 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
6231 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
6232
6233 /* No more processing.
6234 * Hard reset clean-up will wake up
6235 * process and free all resources.
6236 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05306237 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238
6239 return;
6240}
6241
6242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006243/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 * mpt_ioc_reset - Base cleanup for hard reset
6245 * @ioc: Pointer to the adapter structure
6246 * @reset_phase: Indicates pre- or post-reset functionality
6247 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006248 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249 */
6250static int
6251mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6252{
6253 CONFIGPARMS *pCfg;
6254 unsigned long flags;
6255
Eric Moore29dd3602007-09-14 18:46:51 -06006256 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6257 ": IOC %s_reset routed to MPT base driver!\n",
6258 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
6259 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
6261 if (reset_phase == MPT_IOC_SETUP_RESET) {
6262 ;
6263 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6264 /* If the internal config Q is not empty -
6265 * delete timer. MF resources will be freed when
6266 * the FIFO's are primed.
6267 */
6268 spin_lock_irqsave(&ioc->FreeQlock, flags);
6269 list_for_each_entry(pCfg, &ioc->configQ, linkage)
6270 del_timer(&pCfg->timer);
6271 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6272
6273 } else {
6274 CONFIGPARMS *pNext;
6275
6276 /* Search the configQ for internal commands.
6277 * Flush the Q, and wake up all suspended threads.
6278 */
6279 spin_lock_irqsave(&ioc->FreeQlock, flags);
6280 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
6281 list_del(&pCfg->linkage);
6282
6283 pCfg->status = MPT_CONFIG_ERROR;
6284 pCfg->wait_done = 1;
6285 wake_up(&mpt_waitq);
6286 }
6287 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6288 }
6289
6290 return 1; /* currently means nothing really */
6291}
6292
6293
6294#ifdef CONFIG_PROC_FS /* { */
6295/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6296/*
6297 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6298 */
6299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006300/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6302 *
6303 * Returns 0 for success, non-zero for failure.
6304 */
6305static int
6306procmpt_create(void)
6307{
6308 struct proc_dir_entry *ent;
6309
6310 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6311 if (mpt_proc_root_dir == NULL)
6312 return -ENOTDIR;
6313
6314 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6315 if (ent)
6316 ent->read_proc = procmpt_summary_read;
6317
6318 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6319 if (ent)
6320 ent->read_proc = procmpt_version_read;
6321
6322 return 0;
6323}
6324
6325/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006326/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6328 *
6329 * Returns 0 for success, non-zero for failure.
6330 */
6331static void
6332procmpt_destroy(void)
6333{
6334 remove_proc_entry("version", mpt_proc_root_dir);
6335 remove_proc_entry("summary", mpt_proc_root_dir);
6336 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6337}
6338
6339/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006340/**
6341 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 * @buf: Pointer to area to write information
6343 * @start: Pointer to start pointer
6344 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006345 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 * @eof: Pointer to EOF integer
6347 * @data: Pointer
6348 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006349 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 * Returns number of characters written to process performing the read.
6351 */
6352static int
6353procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6354{
6355 MPT_ADAPTER *ioc;
6356 char *out = buf;
6357 int len;
6358
6359 if (data) {
6360 int more = 0;
6361
6362 ioc = data;
6363 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6364
6365 out += more;
6366 } else {
6367 list_for_each_entry(ioc, &ioc_list, list) {
6368 int more = 0;
6369
6370 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6371
6372 out += more;
6373 if ((out-buf) >= request)
6374 break;
6375 }
6376 }
6377
6378 len = out - buf;
6379
6380 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6381}
6382
6383/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006384/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 * procmpt_version_read - Handle read request from /proc/mpt/version.
6386 * @buf: Pointer to area to write information
6387 * @start: Pointer to start pointer
6388 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006389 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390 * @eof: Pointer to EOF integer
6391 * @data: Pointer
6392 *
6393 * Returns number of characters written to process performing the read.
6394 */
6395static int
6396procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6397{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306398 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006399 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400 char *drvname;
6401 int len;
6402
6403 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6404 len += sprintf(buf+len, " Fusion MPT base driver\n");
6405
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006406 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006407 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306409 if (MptCallbacks[cb_idx]) {
6410 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006411 case MPTSPI_DRIVER:
6412 if (!scsi++) drvname = "SPI host";
6413 break;
6414 case MPTFC_DRIVER:
6415 if (!fc++) drvname = "FC host";
6416 break;
6417 case MPTSAS_DRIVER:
6418 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 break;
6420 case MPTLAN_DRIVER:
6421 if (!lan++) drvname = "LAN";
6422 break;
6423 case MPTSTM_DRIVER:
6424 if (!targ++) drvname = "SCSI target";
6425 break;
6426 case MPTCTL_DRIVER:
6427 if (!ctl++) drvname = "ioctl";
6428 break;
6429 }
6430
6431 if (drvname)
6432 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6433 }
6434 }
6435
6436 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6437}
6438
6439/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006440/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6442 * @buf: Pointer to area to write information
6443 * @start: Pointer to start pointer
6444 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006445 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 * @eof: Pointer to EOF integer
6447 * @data: Pointer
6448 *
6449 * Returns number of characters written to process performing the read.
6450 */
6451static int
6452procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6453{
6454 MPT_ADAPTER *ioc = data;
6455 int len;
6456 char expVer[32];
6457 int sz;
6458 int p;
6459
6460 mpt_get_fw_exp_ver(expVer, ioc);
6461
6462 len = sprintf(buf, "%s:", ioc->name);
6463 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6464 len += sprintf(buf+len, " (f/w download boot flag set)");
6465// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6466// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6467
6468 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6469 ioc->facts.ProductID,
6470 ioc->prod_name);
6471 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6472 if (ioc->facts.FWImageSize)
6473 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6474 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6475 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6476 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6477
6478 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6479 ioc->facts.CurrentHostMfaHighAddr);
6480 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6481 ioc->facts.CurrentSenseBufferHighAddr);
6482
6483 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6484 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6485
6486 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6487 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6488 /*
6489 * Rounding UP to nearest 4-kB boundary here...
6490 */
6491 sz = (ioc->req_sz * ioc->req_depth) + 128;
6492 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6493 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6494 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6495 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6496 4*ioc->facts.RequestFrameSize,
6497 ioc->facts.GlobalCredits);
6498
6499 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6500 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6501 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6502 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6503 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6504 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6505 ioc->facts.CurReplyFrameSize,
6506 ioc->facts.ReplyQueueDepth);
6507
6508 len += sprintf(buf+len, " MaxDevices = %d\n",
6509 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6510 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6511
6512 /* per-port info */
6513 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6514 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6515 p+1,
6516 ioc->facts.NumberOfPorts);
6517 if (ioc->bus_type == FC) {
6518 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6519 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6520 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6521 a[5], a[4], a[3], a[2], a[1], a[0]);
6522 }
6523 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6524 ioc->fc_port_page0[p].WWNN.High,
6525 ioc->fc_port_page0[p].WWNN.Low,
6526 ioc->fc_port_page0[p].WWPN.High,
6527 ioc->fc_port_page0[p].WWPN.Low);
6528 }
6529 }
6530
6531 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6532}
6533
6534#endif /* CONFIG_PROC_FS } */
6535
6536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6537static void
6538mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6539{
6540 buf[0] ='\0';
6541 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6542 sprintf(buf, " (Exp %02d%02d)",
6543 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6544 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6545
6546 /* insider hack! */
6547 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6548 strcat(buf, " [MDBG]");
6549 }
6550}
6551
6552/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6553/**
6554 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6555 * @ioc: Pointer to MPT_ADAPTER structure
6556 * @buffer: Pointer to buffer where IOC summary info should be written
6557 * @size: Pointer to number of bytes we wrote (set by this routine)
6558 * @len: Offset at which to start writing in buffer
6559 * @showlan: Display LAN stuff?
6560 *
6561 * This routine writes (english readable) ASCII text, which represents
6562 * a summary of IOC information, to a buffer.
6563 */
6564void
6565mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6566{
6567 char expVer[32];
6568 int y;
6569
6570 mpt_get_fw_exp_ver(expVer, ioc);
6571
6572 /*
6573 * Shorter summary of attached ioc's...
6574 */
6575 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6576 ioc->name,
6577 ioc->prod_name,
6578 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6579 ioc->facts.FWVersion.Word,
6580 expVer,
6581 ioc->facts.NumberOfPorts,
6582 ioc->req_depth);
6583
6584 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6585 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6586 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6587 a[5], a[4], a[3], a[2], a[1], a[0]);
6588 }
6589
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591
6592 if (!ioc->active)
6593 y += sprintf(buffer+len+y, " (disabled)");
6594
6595 y += sprintf(buffer+len+y, "\n");
6596
6597 *size = y;
6598}
6599
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306600
6601/**
6602 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6603 * the kernel
6604 * @ioc: Pointer to MPT_ADAPTER structure
6605 *
6606 **/
6607void
6608mpt_halt_firmware(MPT_ADAPTER *ioc)
6609{
6610 u32 ioc_raw_state;
6611
6612 ioc_raw_state = mpt_GetIocState(ioc, 0);
6613
6614 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6615 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6616 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6617 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6618 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6619 } else {
6620 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6621 panic("%s: Firmware is halted due to command timeout\n",
6622 ioc->name);
6623 }
6624}
6625EXPORT_SYMBOL(mpt_halt_firmware);
6626
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6628/*
6629 * Reset Handling
6630 */
6631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6632/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006633 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634 * @ioc: Pointer to MPT_ADAPTER structure
6635 * @sleepFlag: Indicates if sleep or schedule must be called.
6636 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006637 * Issues SCSI Task Management call based on input arg values.
6638 * If TaskMgmt fails, returns associated SCSI request.
6639 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6641 * or a non-interrupt thread. In the former, must not call schedule().
6642 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006643 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644 * FW reload/initialization failed.
6645 *
6646 * Returns 0 for SUCCESS or -1 if FAILED.
6647 */
6648int
6649mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6650{
6651 int rc;
6652 unsigned long flags;
6653
Prakash, Sathya436ace72007-07-24 15:42:08 +05306654 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655#ifdef MFCNT
6656 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6657 printk("MF count 0x%x !\n", ioc->mfcnt);
6658#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306659 if (mpt_fwfault_debug)
6660 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661
6662 /* Reset the adapter. Prevent more than 1 call to
6663 * mpt_do_ioc_recovery at any instant in time.
6664 */
6665 spin_lock_irqsave(&ioc->diagLock, flags);
6666 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6667 spin_unlock_irqrestore(&ioc->diagLock, flags);
6668 return 0;
6669 } else {
6670 ioc->diagPending = 1;
6671 }
6672 spin_unlock_irqrestore(&ioc->diagLock, flags);
6673
6674 /* FIXME: If do_ioc_recovery fails, repeat....
6675 */
6676
6677 /* The SCSI driver needs to adjust timeouts on all current
6678 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006679 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680 * For all other protocol drivers, this is a no-op.
6681 */
6682 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306683 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684 int r = 0;
6685
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306686 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6687 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306688 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306689 ioc->name, cb_idx));
6690 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306692 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306693 ioc->name, ioc->alt_ioc->name, cb_idx));
6694 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 }
6696 }
6697 }
6698 }
6699
6700 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006701 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 }
6703 ioc->reload_fw = 0;
6704 if (ioc->alt_ioc)
6705 ioc->alt_ioc->reload_fw = 0;
6706
6707 spin_lock_irqsave(&ioc->diagLock, flags);
6708 ioc->diagPending = 0;
6709 if (ioc->alt_ioc)
6710 ioc->alt_ioc->diagPending = 0;
6711 spin_unlock_irqrestore(&ioc->diagLock, flags);
6712
Prakash, Sathya436ace72007-07-24 15:42:08 +05306713 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714
6715 return rc;
6716}
6717
6718/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006719static void
6720EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721{
Eric Moore509e5e52006-04-26 13:22:37 -06006722 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723
6724 switch(event) {
6725 case MPI_EVENT_NONE:
6726 ds = "None";
6727 break;
6728 case MPI_EVENT_LOG_DATA:
6729 ds = "Log Data";
6730 break;
6731 case MPI_EVENT_STATE_CHANGE:
6732 ds = "State Change";
6733 break;
6734 case MPI_EVENT_UNIT_ATTENTION:
6735 ds = "Unit Attention";
6736 break;
6737 case MPI_EVENT_IOC_BUS_RESET:
6738 ds = "IOC Bus Reset";
6739 break;
6740 case MPI_EVENT_EXT_BUS_RESET:
6741 ds = "External Bus Reset";
6742 break;
6743 case MPI_EVENT_RESCAN:
6744 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745 break;
6746 case MPI_EVENT_LINK_STATUS_CHANGE:
6747 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6748 ds = "Link Status(FAILURE) Change";
6749 else
6750 ds = "Link Status(ACTIVE) Change";
6751 break;
6752 case MPI_EVENT_LOOP_STATE_CHANGE:
6753 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6754 ds = "Loop State(LIP) Change";
6755 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006756 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757 else
Eric Moore509e5e52006-04-26 13:22:37 -06006758 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759 break;
6760 case MPI_EVENT_LOGOUT:
6761 ds = "Logout";
6762 break;
6763 case MPI_EVENT_EVENT_CHANGE:
6764 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006765 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006767 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768 break;
6769 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006770 {
6771 u8 ReasonCode = (u8)(evData0 >> 16);
6772 switch (ReasonCode) {
6773 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6774 ds = "Integrated Raid: Volume Created";
6775 break;
6776 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6777 ds = "Integrated Raid: Volume Deleted";
6778 break;
6779 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6780 ds = "Integrated Raid: Volume Settings Changed";
6781 break;
6782 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6783 ds = "Integrated Raid: Volume Status Changed";
6784 break;
6785 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6786 ds = "Integrated Raid: Volume Physdisk Changed";
6787 break;
6788 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6789 ds = "Integrated Raid: Physdisk Created";
6790 break;
6791 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6792 ds = "Integrated Raid: Physdisk Deleted";
6793 break;
6794 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6795 ds = "Integrated Raid: Physdisk Settings Changed";
6796 break;
6797 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6798 ds = "Integrated Raid: Physdisk Status Changed";
6799 break;
6800 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6801 ds = "Integrated Raid: Domain Validation Needed";
6802 break;
6803 case MPI_EVENT_RAID_RC_SMART_DATA :
6804 ds = "Integrated Raid; Smart Data";
6805 break;
6806 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6807 ds = "Integrated Raid: Replace Action Started";
6808 break;
6809 default:
6810 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006812 }
6813 break;
6814 }
6815 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6816 ds = "SCSI Device Status Change";
6817 break;
6818 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6819 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006820 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006821 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006822 u8 ReasonCode = (u8)(evData0 >> 16);
6823 switch (ReasonCode) {
6824 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006825 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006826 "SAS Device Status Change: Added: "
6827 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006828 break;
6829 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006830 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006831 "SAS Device Status Change: Deleted: "
6832 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006833 break;
6834 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006835 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006836 "SAS Device Status Change: SMART Data: "
6837 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006838 break;
6839 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006840 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006841 "SAS Device Status Change: No Persistancy: "
6842 "id=%d channel=%d", id, channel);
6843 break;
6844 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6845 snprintf(evStr, EVENT_DESCR_STR_SZ,
6846 "SAS Device Status Change: Unsupported Device "
6847 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006848 break;
6849 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6850 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006851 "SAS Device Status Change: Internal Device "
6852 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006853 break;
6854 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6855 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006856 "SAS Device Status Change: Internal Task "
6857 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006858 break;
6859 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6860 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006861 "SAS Device Status Change: Internal Abort "
6862 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006863 break;
6864 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6865 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006866 "SAS Device Status Change: Internal Clear "
6867 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006868 break;
6869 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6870 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006871 "SAS Device Status Change: Internal Query "
6872 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006873 break;
6874 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006875 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006876 "SAS Device Status Change: Unknown: "
6877 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006878 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006879 }
6880 break;
6881 }
6882 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6883 ds = "Bus Timer Expired";
6884 break;
6885 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006886 {
6887 u16 curr_depth = (u16)(evData0 >> 16);
6888 u8 channel = (u8)(evData0 >> 8);
6889 u8 id = (u8)(evData0);
6890
6891 snprintf(evStr, EVENT_DESCR_STR_SZ,
6892 "Queue Full: channel=%d id=%d depth=%d",
6893 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006894 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006895 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006896 case MPI_EVENT_SAS_SES:
6897 ds = "SAS SES Event";
6898 break;
6899 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6900 ds = "Persistent Table Full";
6901 break;
6902 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006903 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006904 u8 LinkRates = (u8)(evData0 >> 8);
6905 u8 PhyNumber = (u8)(evData0);
6906 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6907 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6908 switch (LinkRates) {
6909 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006910 snprintf(evStr, EVENT_DESCR_STR_SZ,
6911 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006912 " Rate Unknown",PhyNumber);
6913 break;
6914 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006915 snprintf(evStr, EVENT_DESCR_STR_SZ,
6916 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006917 " Phy Disabled",PhyNumber);
6918 break;
6919 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006920 snprintf(evStr, EVENT_DESCR_STR_SZ,
6921 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006922 " Failed Speed Nego",PhyNumber);
6923 break;
6924 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006925 snprintf(evStr, EVENT_DESCR_STR_SZ,
6926 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006927 " Sata OOB Completed",PhyNumber);
6928 break;
6929 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006930 snprintf(evStr, EVENT_DESCR_STR_SZ,
6931 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006932 " Rate 1.5 Gbps",PhyNumber);
6933 break;
6934 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006935 snprintf(evStr, EVENT_DESCR_STR_SZ,
6936 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006937 " Rate 3.0 Gpbs",PhyNumber);
6938 break;
6939 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006940 snprintf(evStr, EVENT_DESCR_STR_SZ,
6941 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006942 break;
6943 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006944 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006945 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006946 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6947 ds = "SAS Discovery Error";
6948 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006949 case MPI_EVENT_IR_RESYNC_UPDATE:
6950 {
6951 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006952 snprintf(evStr, EVENT_DESCR_STR_SZ,
6953 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006954 break;
6955 }
6956 case MPI_EVENT_IR2:
6957 {
6958 u8 ReasonCode = (u8)(evData0 >> 16);
6959 switch (ReasonCode) {
6960 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6961 ds = "IR2: LD State Changed";
6962 break;
6963 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6964 ds = "IR2: PD State Changed";
6965 break;
6966 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6967 ds = "IR2: Bad Block Table Full";
6968 break;
6969 case MPI_EVENT_IR2_RC_PD_INSERTED:
6970 ds = "IR2: PD Inserted";
6971 break;
6972 case MPI_EVENT_IR2_RC_PD_REMOVED:
6973 ds = "IR2: PD Removed";
6974 break;
6975 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6976 ds = "IR2: Foreign CFG Detected";
6977 break;
6978 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6979 ds = "IR2: Rebuild Medium Error";
6980 break;
6981 default:
6982 ds = "IR2";
6983 break;
6984 }
6985 break;
6986 }
6987 case MPI_EVENT_SAS_DISCOVERY:
6988 {
6989 if (evData0)
6990 ds = "SAS Discovery: Start";
6991 else
6992 ds = "SAS Discovery: Stop";
6993 break;
6994 }
6995 case MPI_EVENT_LOG_ENTRY_ADDED:
6996 ds = "SAS Log Entry Added";
6997 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006998
Eric Moorec6c727a2007-01-29 09:44:54 -07006999 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7000 {
7001 u8 phy_num = (u8)(evData0);
7002 u8 port_num = (u8)(evData0 >> 8);
7003 u8 port_width = (u8)(evData0 >> 16);
7004 u8 primative = (u8)(evData0 >> 24);
7005 snprintf(evStr, EVENT_DESCR_STR_SZ,
7006 "SAS Broadcase Primative: phy=%d port=%d "
7007 "width=%d primative=0x%02x",
7008 phy_num, port_num, port_width, primative);
7009 break;
7010 }
7011
7012 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7013 {
7014 u8 reason = (u8)(evData0);
7015 u8 port_num = (u8)(evData0 >> 8);
7016 u16 handle = le16_to_cpu(evData0 >> 16);
7017
7018 snprintf(evStr, EVENT_DESCR_STR_SZ,
7019 "SAS Initiator Device Status Change: reason=0x%02x "
7020 "port=%d handle=0x%04x",
7021 reason, port_num, handle);
7022 break;
7023 }
7024
7025 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7026 {
7027 u8 max_init = (u8)(evData0);
7028 u8 current_init = (u8)(evData0 >> 8);
7029
7030 snprintf(evStr, EVENT_DESCR_STR_SZ,
7031 "SAS Initiator Device Table Overflow: max initiators=%02d "
7032 "current initators=%02d",
7033 max_init, current_init);
7034 break;
7035 }
7036 case MPI_EVENT_SAS_SMP_ERROR:
7037 {
7038 u8 status = (u8)(evData0);
7039 u8 port_num = (u8)(evData0 >> 8);
7040 u8 result = (u8)(evData0 >> 16);
7041
7042 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7043 snprintf(evStr, EVENT_DESCR_STR_SZ,
7044 "SAS SMP Error: port=%d result=0x%02x",
7045 port_num, result);
7046 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7047 snprintf(evStr, EVENT_DESCR_STR_SZ,
7048 "SAS SMP Error: port=%d : CRC Error",
7049 port_num);
7050 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7051 snprintf(evStr, EVENT_DESCR_STR_SZ,
7052 "SAS SMP Error: port=%d : Timeout",
7053 port_num);
7054 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7055 snprintf(evStr, EVENT_DESCR_STR_SZ,
7056 "SAS SMP Error: port=%d : No Destination",
7057 port_num);
7058 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7059 snprintf(evStr, EVENT_DESCR_STR_SZ,
7060 "SAS SMP Error: port=%d : Bad Destination",
7061 port_num);
7062 else
7063 snprintf(evStr, EVENT_DESCR_STR_SZ,
7064 "SAS SMP Error: port=%d : status=0x%02x",
7065 port_num, status);
7066 break;
7067 }
7068
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069 /*
7070 * MPT base "custom" events may be added here...
7071 */
7072 default:
7073 ds = "Unknown";
7074 break;
7075 }
Eric Moore509e5e52006-04-26 13:22:37 -06007076 if (ds)
7077 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078}
7079
7080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007081/**
7082 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083 * @ioc: Pointer to MPT_ADAPTER structure
7084 * @pEventReply: Pointer to EventNotification reply frame
7085 * @evHandlers: Pointer to integer, number of event handlers
7086 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007087 * Routes a received EventNotificationReply to all currently registered
7088 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089 * Returns sum of event handlers return values.
7090 */
7091static int
7092ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7093{
7094 u16 evDataLen;
7095 u32 evData0 = 0;
7096// u32 evCtx;
7097 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307098 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099 int r = 0;
7100 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007101 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007102 u8 event;
7103
7104 /*
7105 * Do platform normalization of values
7106 */
7107 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7108// evCtx = le32_to_cpu(pEventReply->EventContext);
7109 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7110 if (evDataLen) {
7111 evData0 = le32_to_cpu(pEventReply->Data[0]);
7112 }
7113
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007114 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307115 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007117 event,
7118 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007119
Prakash, Sathya436ace72007-07-24 15:42:08 +05307120#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007121 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7122 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307124 devtverboseprintk(ioc, printk(" %08x",
7125 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007126 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127#endif
7128
7129 /*
7130 * Do general / base driver event processing
7131 */
7132 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7134 if (evDataLen) {
7135 u8 evState = evData0 & 0xFF;
7136
7137 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7138
7139 /* Update EventState field in cached IocFacts */
7140 if (ioc->facts.Function) {
7141 ioc->facts.EventState = evState;
7142 }
7143 }
7144 break;
Moore, Ericece50912006-01-16 18:53:19 -07007145 case MPI_EVENT_INTEGRATED_RAID:
7146 mptbase_raid_process_event_data(ioc,
7147 (MpiEventDataRaid_t *)pEventReply->Data);
7148 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007149 default:
7150 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007151 }
7152
7153 /*
7154 * Should this event be logged? Events are written sequentially.
7155 * When buffer is full, start again at the top.
7156 */
7157 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7158 int idx;
7159
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007160 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161
7162 ioc->events[idx].event = event;
7163 ioc->events[idx].eventContext = ioc->eventContext;
7164
7165 for (ii = 0; ii < 2; ii++) {
7166 if (ii < evDataLen)
7167 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7168 else
7169 ioc->events[idx].data[ii] = 0;
7170 }
7171
7172 ioc->eventContext++;
7173 }
7174
7175
7176 /*
7177 * Call each currently registered protocol event handler.
7178 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007179 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307180 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307181 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307182 ioc->name, cb_idx));
7183 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184 handlers++;
7185 }
7186 }
7187 /* FIXME? Examine results here? */
7188
7189 /*
7190 * If needed, send (a single) EventAck.
7191 */
7192 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307193 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007194 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307196 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007197 ioc->name, ii));
7198 }
7199 }
7200
7201 *evHandlers = handlers;
7202 return r;
7203}
7204
7205/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007206/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007207 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7208 * @ioc: Pointer to MPT_ADAPTER structure
7209 * @log_info: U32 LogInfo reply word from the IOC
7210 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007211 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007212 */
7213static void
7214mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7215{
Eric Moore7c431e52007-06-13 16:34:36 -06007216 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217
Eric Moore7c431e52007-06-13 16:34:36 -06007218 switch (log_info & 0xFF000000) {
7219 case MPI_IOCLOGINFO_FC_INIT_BASE:
7220 desc = "FCP Initiator";
7221 break;
7222 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7223 desc = "FCP Target";
7224 break;
7225 case MPI_IOCLOGINFO_FC_LAN_BASE:
7226 desc = "LAN";
7227 break;
7228 case MPI_IOCLOGINFO_FC_MSG_BASE:
7229 desc = "MPI Message Layer";
7230 break;
7231 case MPI_IOCLOGINFO_FC_LINK_BASE:
7232 desc = "FC Link";
7233 break;
7234 case MPI_IOCLOGINFO_FC_CTX_BASE:
7235 desc = "Context Manager";
7236 break;
7237 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7238 desc = "Invalid Field Offset";
7239 break;
7240 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7241 desc = "State Change Info";
7242 break;
7243 }
7244
7245 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7246 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247}
7248
7249/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007250/**
Moore, Eric335a9412006-01-17 17:06:23 -07007251 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007253 * @log_info: U32 LogInfo word from the IOC
7254 *
7255 * Refer to lsi/sp_log.h.
7256 */
7257static void
Moore, Eric335a9412006-01-17 17:06:23 -07007258mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007259{
7260 u32 info = log_info & 0x00FF0000;
7261 char *desc = "unknown";
7262
7263 switch (info) {
7264 case 0x00010000:
7265 desc = "bug! MID not found";
7266 if (ioc->reload_fw == 0)
7267 ioc->reload_fw++;
7268 break;
7269
7270 case 0x00020000:
7271 desc = "Parity Error";
7272 break;
7273
7274 case 0x00030000:
7275 desc = "ASYNC Outbound Overrun";
7276 break;
7277
7278 case 0x00040000:
7279 desc = "SYNC Offset Error";
7280 break;
7281
7282 case 0x00050000:
7283 desc = "BM Change";
7284 break;
7285
7286 case 0x00060000:
7287 desc = "Msg In Overflow";
7288 break;
7289
7290 case 0x00070000:
7291 desc = "DMA Error";
7292 break;
7293
7294 case 0x00080000:
7295 desc = "Outbound DMA Overrun";
7296 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007297
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298 case 0x00090000:
7299 desc = "Task Management";
7300 break;
7301
7302 case 0x000A0000:
7303 desc = "Device Problem";
7304 break;
7305
7306 case 0x000B0000:
7307 desc = "Invalid Phase Change";
7308 break;
7309
7310 case 0x000C0000:
7311 desc = "Untagged Table Size";
7312 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007313
Linus Torvalds1da177e2005-04-16 15:20:36 -07007314 }
7315
7316 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7317}
7318
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007319/* strings for sas loginfo */
7320 static char *originator_str[] = {
7321 "IOP", /* 00h */
7322 "PL", /* 01h */
7323 "IR" /* 02h */
7324 };
7325 static char *iop_code_str[] = {
7326 NULL, /* 00h */
7327 "Invalid SAS Address", /* 01h */
7328 NULL, /* 02h */
7329 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007330 "Diag Message Error", /* 04h */
7331 "Task Terminated", /* 05h */
7332 "Enclosure Management", /* 06h */
7333 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007334 };
7335 static char *pl_code_str[] = {
7336 NULL, /* 00h */
7337 "Open Failure", /* 01h */
7338 "Invalid Scatter Gather List", /* 02h */
7339 "Wrong Relative Offset or Frame Length", /* 03h */
7340 "Frame Transfer Error", /* 04h */
7341 "Transmit Frame Connected Low", /* 05h */
7342 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7343 "SATA Read Log Receive Data Error", /* 07h */
7344 "SATA NCQ Fail All Commands After Error", /* 08h */
7345 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7346 "Receive Frame Invalid Message", /* 0Ah */
7347 "Receive Context Message Valid Error", /* 0Bh */
7348 "Receive Frame Current Frame Error", /* 0Ch */
7349 "SATA Link Down", /* 0Dh */
7350 "Discovery SATA Init W IOS", /* 0Eh */
7351 "Config Invalid Page", /* 0Fh */
7352 "Discovery SATA Init Timeout", /* 10h */
7353 "Reset", /* 11h */
7354 "Abort", /* 12h */
7355 "IO Not Yet Executed", /* 13h */
7356 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007357 "Persistent Reservation Out Not Affiliation "
7358 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007359 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007360 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007361 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007362 NULL, /* 19h */
7363 NULL, /* 1Ah */
7364 NULL, /* 1Bh */
7365 NULL, /* 1Ch */
7366 NULL, /* 1Dh */
7367 NULL, /* 1Eh */
7368 NULL, /* 1Fh */
7369 "Enclosure Management" /* 20h */
7370 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007371 static char *ir_code_str[] = {
7372 "Raid Action Error", /* 00h */
7373 NULL, /* 00h */
7374 NULL, /* 01h */
7375 NULL, /* 02h */
7376 NULL, /* 03h */
7377 NULL, /* 04h */
7378 NULL, /* 05h */
7379 NULL, /* 06h */
7380 NULL /* 07h */
7381 };
7382 static char *raid_sub_code_str[] = {
7383 NULL, /* 00h */
7384 "Volume Creation Failed: Data Passed too "
7385 "Large", /* 01h */
7386 "Volume Creation Failed: Duplicate Volumes "
7387 "Attempted", /* 02h */
7388 "Volume Creation Failed: Max Number "
7389 "Supported Volumes Exceeded", /* 03h */
7390 "Volume Creation Failed: DMA Error", /* 04h */
7391 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7392 "Volume Creation Failed: Error Reading "
7393 "MFG Page 4", /* 06h */
7394 "Volume Creation Failed: Creating Internal "
7395 "Structures", /* 07h */
7396 NULL, /* 08h */
7397 NULL, /* 09h */
7398 NULL, /* 0Ah */
7399 NULL, /* 0Bh */
7400 NULL, /* 0Ch */
7401 NULL, /* 0Dh */
7402 NULL, /* 0Eh */
7403 NULL, /* 0Fh */
7404 "Activation failed: Already Active Volume", /* 10h */
7405 "Activation failed: Unsupported Volume Type", /* 11h */
7406 "Activation failed: Too Many Active Volumes", /* 12h */
7407 "Activation failed: Volume ID in Use", /* 13h */
7408 "Activation failed: Reported Failure", /* 14h */
7409 "Activation failed: Importing a Volume", /* 15h */
7410 NULL, /* 16h */
7411 NULL, /* 17h */
7412 NULL, /* 18h */
7413 NULL, /* 19h */
7414 NULL, /* 1Ah */
7415 NULL, /* 1Bh */
7416 NULL, /* 1Ch */
7417 NULL, /* 1Dh */
7418 NULL, /* 1Eh */
7419 NULL, /* 1Fh */
7420 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7421 "Phys Disk failed: Data Passed too Large", /* 21h */
7422 "Phys Disk failed: DMA Error", /* 22h */
7423 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7424 "Phys Disk failed: Creating Phys Disk Config "
7425 "Page", /* 24h */
7426 NULL, /* 25h */
7427 NULL, /* 26h */
7428 NULL, /* 27h */
7429 NULL, /* 28h */
7430 NULL, /* 29h */
7431 NULL, /* 2Ah */
7432 NULL, /* 2Bh */
7433 NULL, /* 2Ch */
7434 NULL, /* 2Dh */
7435 NULL, /* 2Eh */
7436 NULL, /* 2Fh */
7437 "Compatibility Error: IR Disabled", /* 30h */
7438 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7439 "Compatibility Error: Device not Direct Access "
7440 "Device ", /* 32h */
7441 "Compatibility Error: Removable Device Found", /* 33h */
7442 "Compatibility Error: Device SCSI Version not "
7443 "2 or Higher", /* 34h */
7444 "Compatibility Error: SATA Device, 48 BIT LBA "
7445 "not Supported", /* 35h */
7446 "Compatibility Error: Device doesn't have "
7447 "512 Byte Block Sizes", /* 36h */
7448 "Compatibility Error: Volume Type Check Failed", /* 37h */
7449 "Compatibility Error: Volume Type is "
7450 "Unsupported by FW", /* 38h */
7451 "Compatibility Error: Disk Drive too Small for "
7452 "use in Volume", /* 39h */
7453 "Compatibility Error: Phys Disk for Create "
7454 "Volume not Found", /* 3Ah */
7455 "Compatibility Error: Too Many or too Few "
7456 "Disks for Volume Type", /* 3Bh */
7457 "Compatibility Error: Disk stripe Sizes "
7458 "Must be 64KB", /* 3Ch */
7459 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7460 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007461
7462/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007463/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007464 * mpt_sas_log_info - Log information returned from SAS IOC.
7465 * @ioc: Pointer to MPT_ADAPTER structure
7466 * @log_info: U32 LogInfo reply word from the IOC
7467 *
7468 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007469 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007470static void
7471mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7472{
7473union loginfo_type {
7474 u32 loginfo;
7475 struct {
7476 u32 subcode:16;
7477 u32 code:8;
7478 u32 originator:4;
7479 u32 bus_type:4;
7480 }dw;
7481};
7482 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007483 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007484 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007485 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007486
7487 sas_loginfo.loginfo = log_info;
7488 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007489 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007490 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007491
7492 originator_desc = originator_str[sas_loginfo.dw.originator];
7493
7494 switch (sas_loginfo.dw.originator) {
7495
7496 case 0: /* IOP */
7497 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007498 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007499 code_desc = iop_code_str[sas_loginfo.dw.code];
7500 break;
7501 case 1: /* PL */
7502 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007503 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007504 code_desc = pl_code_str[sas_loginfo.dw.code];
7505 break;
7506 case 2: /* IR */
7507 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007508 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007509 break;
7510 code_desc = ir_code_str[sas_loginfo.dw.code];
7511 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007512 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007513 break;
7514 if (sas_loginfo.dw.code == 0)
7515 sub_code_desc =
7516 raid_sub_code_str[sas_loginfo.dw.subcode];
7517 break;
7518 default:
7519 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007520 }
7521
Eric Moorec6c727a2007-01-29 09:44:54 -07007522 if (sub_code_desc != NULL)
7523 printk(MYIOC_s_INFO_FMT
7524 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7525 " SubCode={%s}\n",
7526 ioc->name, log_info, originator_desc, code_desc,
7527 sub_code_desc);
7528 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007529 printk(MYIOC_s_INFO_FMT
7530 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7531 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007532 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007533 sas_loginfo.dw.subcode);
7534 else
7535 printk(MYIOC_s_INFO_FMT
7536 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7537 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007538 ioc->name, log_info, originator_desc,
7539 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007540}
7541
Linus Torvalds1da177e2005-04-16 15:20:36 -07007542/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007543/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007544 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7545 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007546 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007547 * @mf: Pointer to MPT request frame
7548 *
7549 * Refer to lsi/mpi.h.
7550 **/
7551static void
7552mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7553{
7554 Config_t *pReq = (Config_t *)mf;
7555 char extend_desc[EVENT_DESCR_STR_SZ];
7556 char *desc = NULL;
7557 u32 form;
7558 u8 page_type;
7559
7560 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7561 page_type = pReq->ExtPageType;
7562 else
7563 page_type = pReq->Header.PageType;
7564
7565 /*
7566 * ignore invalid page messages for GET_NEXT_HANDLE
7567 */
7568 form = le32_to_cpu(pReq->PageAddress);
7569 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7570 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7571 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7572 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7573 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7574 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7575 return;
7576 }
7577 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7578 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7579 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7580 return;
7581 }
7582
7583 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7584 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7585 page_type, pReq->Header.PageNumber, pReq->Action, form);
7586
7587 switch (ioc_status) {
7588
7589 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7590 desc = "Config Page Invalid Action";
7591 break;
7592
7593 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7594 desc = "Config Page Invalid Type";
7595 break;
7596
7597 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7598 desc = "Config Page Invalid Page";
7599 break;
7600
7601 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7602 desc = "Config Page Invalid Data";
7603 break;
7604
7605 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7606 desc = "Config Page No Defaults";
7607 break;
7608
7609 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7610 desc = "Config Page Can't Commit";
7611 break;
7612 }
7613
7614 if (!desc)
7615 return;
7616
Eric Moore29dd3602007-09-14 18:46:51 -06007617 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7618 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007619}
7620
7621/**
7622 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623 * @ioc: Pointer to MPT_ADAPTER structure
7624 * @ioc_status: U32 IOCStatus word from IOC
7625 * @mf: Pointer to MPT request frame
7626 *
7627 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007628 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007630mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631{
7632 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007633 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634
7635 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007636
7637/****************************************************************************/
7638/* Common IOCStatus values for all replies */
7639/****************************************************************************/
7640
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7642 desc = "Invalid Function";
7643 break;
7644
7645 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7646 desc = "Busy";
7647 break;
7648
7649 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7650 desc = "Invalid SGL";
7651 break;
7652
7653 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7654 desc = "Internal Error";
7655 break;
7656
7657 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7658 desc = "Reserved";
7659 break;
7660
7661 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7662 desc = "Insufficient Resources";
7663 break;
7664
7665 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7666 desc = "Invalid Field";
7667 break;
7668
7669 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7670 desc = "Invalid State";
7671 break;
7672
Eric Moorec6c727a2007-01-29 09:44:54 -07007673/****************************************************************************/
7674/* Config IOCStatus values */
7675/****************************************************************************/
7676
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7678 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7679 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7680 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7681 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7682 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007683 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684 break;
7685
Eric Moorec6c727a2007-01-29 09:44:54 -07007686/****************************************************************************/
7687/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7688/* */
7689/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7690/* */
7691/****************************************************************************/
7692
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007695 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7696 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7697 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7698 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007700 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007705 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007706 break;
7707
Eric Moorec6c727a2007-01-29 09:44:54 -07007708/****************************************************************************/
7709/* SCSI Target values */
7710/****************************************************************************/
7711
7712 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7713 desc = "Target: Priority IO";
7714 break;
7715
7716 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7717 desc = "Target: Invalid Port";
7718 break;
7719
7720 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7721 desc = "Target Invalid IO Index:";
7722 break;
7723
7724 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7725 desc = "Target: Aborted";
7726 break;
7727
7728 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7729 desc = "Target: No Conn Retryable";
7730 break;
7731
7732 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7733 desc = "Target: No Connection";
7734 break;
7735
7736 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7737 desc = "Target: Transfer Count Mismatch";
7738 break;
7739
7740 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7741 desc = "Target: STS Data not Sent";
7742 break;
7743
7744 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7745 desc = "Target: Data Offset Error";
7746 break;
7747
7748 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7749 desc = "Target: Too Much Write Data";
7750 break;
7751
7752 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7753 desc = "Target: IU Too Short";
7754 break;
7755
7756 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7757 desc = "Target: ACK NAK Timeout";
7758 break;
7759
7760 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7761 desc = "Target: Nak Received";
7762 break;
7763
7764/****************************************************************************/
7765/* Fibre Channel Direct Access values */
7766/****************************************************************************/
7767
7768 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7769 desc = "FC: Aborted";
7770 break;
7771
7772 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7773 desc = "FC: RX ID Invalid";
7774 break;
7775
7776 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7777 desc = "FC: DID Invalid";
7778 break;
7779
7780 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7781 desc = "FC: Node Logged Out";
7782 break;
7783
7784 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7785 desc = "FC: Exchange Canceled";
7786 break;
7787
7788/****************************************************************************/
7789/* LAN values */
7790/****************************************************************************/
7791
7792 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7793 desc = "LAN: Device not Found";
7794 break;
7795
7796 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7797 desc = "LAN: Device Failure";
7798 break;
7799
7800 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7801 desc = "LAN: Transmit Error";
7802 break;
7803
7804 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7805 desc = "LAN: Transmit Aborted";
7806 break;
7807
7808 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7809 desc = "LAN: Receive Error";
7810 break;
7811
7812 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7813 desc = "LAN: Receive Aborted";
7814 break;
7815
7816 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7817 desc = "LAN: Partial Packet";
7818 break;
7819
7820 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7821 desc = "LAN: Canceled";
7822 break;
7823
7824/****************************************************************************/
7825/* Serial Attached SCSI values */
7826/****************************************************************************/
7827
7828 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7829 desc = "SAS: SMP Request Failed";
7830 break;
7831
7832 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7833 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007834 break;
7835
7836 default:
7837 desc = "Others";
7838 break;
7839 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007840
7841 if (!desc)
7842 return;
7843
Eric Moore29dd3602007-09-14 18:46:51 -06007844 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7845 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007846}
7847
7848/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007849EXPORT_SYMBOL(mpt_attach);
7850EXPORT_SYMBOL(mpt_detach);
7851#ifdef CONFIG_PM
7852EXPORT_SYMBOL(mpt_resume);
7853EXPORT_SYMBOL(mpt_suspend);
7854#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007855EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856EXPORT_SYMBOL(mpt_register);
7857EXPORT_SYMBOL(mpt_deregister);
7858EXPORT_SYMBOL(mpt_event_register);
7859EXPORT_SYMBOL(mpt_event_deregister);
7860EXPORT_SYMBOL(mpt_reset_register);
7861EXPORT_SYMBOL(mpt_reset_deregister);
7862EXPORT_SYMBOL(mpt_device_driver_register);
7863EXPORT_SYMBOL(mpt_device_driver_deregister);
7864EXPORT_SYMBOL(mpt_get_msg_frame);
7865EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307866EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007867EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007868EXPORT_SYMBOL(mpt_send_handshake_request);
7869EXPORT_SYMBOL(mpt_verify_adapter);
7870EXPORT_SYMBOL(mpt_GetIocState);
7871EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872EXPORT_SYMBOL(mpt_HardResetHandler);
7873EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007874EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007875EXPORT_SYMBOL(mpt_alloc_fw_memory);
7876EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007877EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007878EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Linus Torvalds1da177e2005-04-16 15:20:36 -07007880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007881/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007882 * fusion_init - Fusion MPT base driver initialization routine.
7883 *
7884 * Returns 0 for success, non-zero for failure.
7885 */
7886static int __init
7887fusion_init(void)
7888{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307889 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007890
7891 show_mptmod_ver(my_NAME, my_VERSION);
7892 printk(KERN_INFO COPYRIGHT "\n");
7893
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307894 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7895 MptCallbacks[cb_idx] = NULL;
7896 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7897 MptEvHandlers[cb_idx] = NULL;
7898 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007899 }
7900
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007901 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902 * EventNotification handling.
7903 */
7904 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7905
7906 /* Register for hard reset handling callbacks.
7907 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307908 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909
7910#ifdef CONFIG_PROC_FS
7911 (void) procmpt_create();
7912#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007913 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914}
7915
7916/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007917/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007918 * fusion_exit - Perform driver unload cleanup.
7919 *
7920 * This routine frees all resources associated with each MPT adapter
7921 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7922 */
7923static void __exit
7924fusion_exit(void)
7925{
7926
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927 mpt_reset_deregister(mpt_base_index);
7928
7929#ifdef CONFIG_PROC_FS
7930 procmpt_destroy();
7931#endif
7932}
7933
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934module_init(fusion_init);
7935module_exit(fusion_exit);