blob: 6837a8ef93717be71cf4e09ffef6a2e0c3e7bae1 [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>
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -070053#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <linux/slab.h>
55#include <linux/types.h>
56#include <linux/pci.h>
57#include <linux/kdev_t.h>
58#include <linux/blkdev.h>
59#include <linux/delay.h>
60#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040061#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060068#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71#define my_NAME "Fusion MPT base driver"
72#define my_VERSION MPT_LINUX_VERSION_COMMON
73#define MYNAM "mptbase"
74
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/*
81 * cmd line parameters
82 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053083
84static int mpt_msi_enable_spi;
85module_param(mpt_msi_enable_spi, int, 0);
86MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
87 controllers (default=0)");
88
89static int mpt_msi_enable_fc;
90module_param(mpt_msi_enable_fc, int, 0);
91MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
92 controllers (default=0)");
93
94static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080095module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053096MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080097 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053098
Christoph Hellwig4ddce142006-01-17 13:44:29 +000099
Eric Moore793955f2007-01-29 09:42:20 -0700100static int mpt_channel_mapping;
101module_param(mpt_channel_mapping, int, 0);
102MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
103
Prakash, Sathya436ace72007-07-24 15:42:08 +0530104static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400105static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
106module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
107 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530108MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
109 - (default=0)");
110
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530111int mpt_fwfault_debug;
112EXPORT_SYMBOL(mpt_fwfault_debug);
Rusty Russell57ba4712010-08-11 23:04:39 -0600113module_param(mpt_fwfault_debug, int, 0600);
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530118static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#ifdef MFCNT
121static int mfcounter = 0;
122#define PRINT_MF_COUNT 20000
123#endif
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Public data...
128 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130#define WHOINIT_UNKNOWN 0xAA
131
132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
133/*
134 * Private data...
135 */
136 /* Adapter link list */
137LIST_HEAD(ioc_list);
138 /* Callback lookup table */
139static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
140 /* Protocol driver class lookup table */
141static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
142 /* Event handler lookup table */
143static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
144 /* Reset handler lookup table */
145static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
146static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147
Erik Ekmane47c11c2009-12-14 21:21:56 +0100148#ifdef CONFIG_PROC_FS
149static struct proc_dir_entry *mpt_proc_root_dir;
150#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530152/*
153 * Driver Callback Index's
154 */
155static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
156static u8 last_drv_idx;
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
159/*
160 * Forward protos...
161 */
David Howells7d12e782006-10-05 14:55:46 +0100162static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530163static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
164 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
166 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
167 int sleepFlag);
168static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
169static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
170static void mpt_adapter_disable(MPT_ADAPTER *ioc);
171static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
172
173static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
174static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
176static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
178static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
179static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200180static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
182static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
183static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
184static int PrimeIocFifos(MPT_ADAPTER *ioc);
185static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
187static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
188static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200190int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
192static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
193static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
194static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530195static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530196static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
197 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200199static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
200static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -0700203static const struct file_operations mpt_summary_proc_fops;
204static const struct file_operations mpt_version_proc_fops;
205static const struct file_operations mpt_iocinfo_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206#endif
207static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
208
Kashyap, Desaifd761752009-05-29 16:39:06 +0530209static int ProcessEventNotification(MPT_ADAPTER *ioc,
210 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700211static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700213static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530214static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
Moore, Ericc972c702006-03-14 09:14:06 -0700215static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700216static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219static int __init fusion_init (void);
220static void __exit fusion_exit (void);
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222#define CHIPREG_READ32(addr) readl_relaxed(addr)
223#define CHIPREG_READ32_dmasync(addr) readl(addr)
224#define CHIPREG_WRITE32(addr,val) writel(val, addr)
225#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
226#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
227
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600228static void
229pci_disable_io_access(struct pci_dev *pdev)
230{
231 u16 command_reg;
232
233 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
234 command_reg &= ~1;
235 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
236}
237
238static void
239pci_enable_io_access(struct pci_dev *pdev)
240{
241 u16 command_reg;
242
243 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
244 command_reg |= 1;
245 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
246}
247
James Bottomleydb47c2d2007-07-28 13:40:21 -0400248static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
249{
250 int ret = param_set_int(val, kp);
251 MPT_ADAPTER *ioc;
252
253 if (ret)
254 return ret;
255
256 list_for_each_entry(ioc, &ioc_list, list)
257 ioc->debug_level = mpt_debug_level;
258 return 0;
259}
260
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530261/**
262 * mpt_get_cb_idx - obtain cb_idx for registered driver
263 * @dclass: class driver enum
264 *
265 * Returns cb_idx, or zero means it wasn't found
266 **/
267static u8
268mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
269{
270 u8 cb_idx;
271
272 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
273 if (MptDriverClass[cb_idx] == dclass)
274 return cb_idx;
275 return 0;
276}
277
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530278/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530279 * mpt_is_discovery_complete - determine if discovery has completed
280 * @ioc: per adatper instance
281 *
282 * Returns 1 when discovery completed, else zero.
283 */
284static int
285mpt_is_discovery_complete(MPT_ADAPTER *ioc)
286{
287 ConfigExtendedPageHeader_t hdr;
288 CONFIGPARMS cfg;
289 SasIOUnitPage0_t *buffer;
290 dma_addr_t dma_handle;
291 int rc = 0;
292
293 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
294 memset(&cfg, 0, sizeof(CONFIGPARMS));
295 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
296 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
297 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
298 cfg.cfghdr.ehdr = &hdr;
299 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
300
301 if ((mpt_config(ioc, &cfg)))
302 goto out;
303 if (!hdr.ExtPageLength)
304 goto out;
305
306 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
307 &dma_handle);
308 if (!buffer)
309 goto out;
310
311 cfg.physAddr = dma_handle;
312 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
313
314 if ((mpt_config(ioc, &cfg)))
315 goto out_free_consistent;
316
317 if (!(buffer->PhyData[0].PortFlags &
318 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
319 rc = 1;
320
321 out_free_consistent:
322 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
323 buffer, dma_handle);
324 out:
325 return rc;
326}
327
328/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530329 * mpt_fault_reset_work - work performed on workq after ioc fault
330 * @work: input argument, used to derive ioc
331 *
332**/
333static void
334mpt_fault_reset_work(struct work_struct *work)
335{
336 MPT_ADAPTER *ioc =
337 container_of(work, MPT_ADAPTER, fault_reset_work.work);
338 u32 ioc_raw_state;
339 int rc;
340 unsigned long flags;
341
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530342 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530343 goto out;
344
345 ioc_raw_state = mpt_GetIocState(ioc, 0);
346 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
347 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700348 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530349 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
352 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700353 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530354 ioc_raw_state = mpt_GetIocState(ioc, 0);
355 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
356 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
357 "reset (%04xh)\n", ioc->name, ioc_raw_state &
358 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530359 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
360 if ((mpt_is_discovery_complete(ioc))) {
361 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
362 "discovery_quiesce_io flag\n", ioc->name));
363 ioc->sas_discovery_quiesce_io = 0;
364 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530365 }
366
367 out:
368 /*
369 * Take turns polling alternate controller
370 */
371 if (ioc->alt_ioc)
372 ioc = ioc->alt_ioc;
373
374 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530375 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530376 if (ioc->reset_work_q)
377 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
378 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530379 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530380}
381
382
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600383/*
384 * Process turbo (context) reply...
385 */
386static void
387mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
388{
389 MPT_FRAME_HDR *mf = NULL;
390 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530391 u16 req_idx = 0;
392 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600393
Prakash, Sathya436ace72007-07-24 15:42:08 +0530394 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395 ioc->name, pa));
396
397 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
398 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
399 req_idx = pa & 0x0000FFFF;
400 cb_idx = (pa & 0x00FF0000) >> 16;
401 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
402 break;
403 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530404 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600405 /*
406 * Blind set of mf to NULL here was fatal
407 * after lan_reply says "freeme"
408 * Fix sort of combined with an optimization here;
409 * added explicit check for case where lan_reply
410 * was just returning 1 and doing nothing else.
411 * For this case skip the callback, but set up
412 * proper mf value first here:-)
413 */
414 if ((pa & 0x58000000) == 0x58000000) {
415 req_idx = pa & 0x0000FFFF;
416 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
417 mpt_free_msg_frame(ioc, mf);
418 mb();
419 return;
420 break;
421 }
422 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
423 break;
424 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530425 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600426 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
427 break;
428 default:
429 cb_idx = 0;
430 BUG();
431 }
432
433 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530434 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600435 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600436 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700437 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 goto out;
439 }
440
441 if (MptCallbacks[cb_idx](ioc, mf, mr))
442 mpt_free_msg_frame(ioc, mf);
443 out:
444 mb();
445}
446
447static void
448mpt_reply(MPT_ADAPTER *ioc, u32 pa)
449{
450 MPT_FRAME_HDR *mf;
451 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530452 u16 req_idx;
453 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600454 int freeme;
455
456 u32 reply_dma_low;
457 u16 ioc_stat;
458
459 /* non-TURBO reply! Hmmm, something may be up...
460 * Newest turbo reply mechanism; get address
461 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
462 */
463
464 /* Map DMA address of reply header to cpu address.
465 * pa is 32 bits - but the dma address may be 32 or 64 bits
466 * get offset based only only the low addresses
467 */
468
469 reply_dma_low = (pa <<= 1);
470 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
471 (reply_dma_low - ioc->reply_frames_low_dma));
472
473 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
474 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
475 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
476
Prakash, Sathya436ace72007-07-24 15:42:08 +0530477 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 -0600478 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600479 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600480
481 /* Check/log IOC log info
482 */
483 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
484 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
485 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
486 if (ioc->bus_type == FC)
487 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700488 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700489 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600490 else if (ioc->bus_type == SAS)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530491 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600493
Eric Moorec6c727a2007-01-29 09:44:54 -0700494 if (ioc_stat & MPI_IOCSTATUS_MASK)
495 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600496
497 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530498 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600499 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600500 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700501 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 freeme = 0;
503 goto out;
504 }
505
506 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
507
508 out:
509 /* Flush (non-TURBO) reply with a WRITE! */
510 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
511
512 if (freeme)
513 mpt_free_msg_frame(ioc, mf);
514 mb();
515}
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800518/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
520 * @irq: irq number (not used)
521 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 *
523 * This routine is registered via the request_irq() kernel API call,
524 * and handles all interrupts generated from a specific MPT adapter
525 * (also referred to as a IO Controller or IOC).
526 * This routine must clear the interrupt from the adapter and does
527 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200528 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 *
530 * This routine handles register-level access of the adapter but
531 * dispatches (calls) a protocol-specific callback routine to handle
532 * the protocol-specific details of the MPT request completion.
533 */
534static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100535mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600537 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600538 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
539
540 if (pa == 0xFFFFFFFF)
541 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 /*
544 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600546 do {
547 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600548 mpt_reply(ioc, pa);
549 else
550 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600551 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
552 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 return IRQ_HANDLED;
555}
556
557/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800558/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530559 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
563 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800564 * MPT base driver's callback routine; all base driver
565 * "internal" request/reply processing is routed here.
566 * Currently used for EventNotification and EventAck handling.
567 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200568 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 * should be freed, or 0 if it shouldn't.
570 */
571static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530572mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574 EventNotificationReply_t *pEventReply;
575 u8 event;
576 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530579 switch (reply->u.hdr.Function) {
580 case MPI_FUNCTION_EVENT_NOTIFICATION:
581 pEventReply = (EventNotificationReply_t *)reply;
582 evHandlers = 0;
583 ProcessEventNotification(ioc, pEventReply, &evHandlers);
584 event = le32_to_cpu(pEventReply->Event) & 0xFF;
585 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530587 if (event != MPI_EVENT_EVENT_CHANGE)
588 break;
589 case MPI_FUNCTION_CONFIG:
590 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
591 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
592 if (reply) {
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
594 memcpy(ioc->mptbase_cmds.reply, reply,
595 min(MPT_DEFAULT_FRAME_SIZE,
596 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200597 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530598 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
599 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
600 complete(&ioc->mptbase_cmds.done);
601 } else
602 freereq = 0;
603 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
604 freereq = 1;
605 break;
606 case MPI_FUNCTION_EVENT_ACK:
607 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
608 "EventAck reply received\n", ioc->name));
609 break;
610 default:
611 printk(MYIOC_s_ERR_FMT
612 "Unexpected msg function (=%02Xh) reply received!\n",
613 ioc->name, reply->u.hdr.Function);
614 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
616
617 /*
618 * Conditionally tell caller to free the original
619 * EventNotification/EventAck/unexpected request frame!
620 */
621 return freereq;
622}
623
624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
625/**
626 * mpt_register - Register protocol-specific main callback handler.
627 * @cbfunc: callback function pointer
628 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
Randy Dunlapfc58fb12010-08-14 13:05:57 -0700629 * @func_name: call function's name
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 *
631 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800632 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 * protocol-specific driver must do this before it will be able to
634 * use any IOC resources, such as obtaining request frames.
635 *
636 * NOTES: The SCSI protocol driver currently calls this routine thrice
637 * in order to register separate callbacks; one for "normal" SCSI IO;
638 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
639 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530640 * Returns u8 valued "handle" in the range (and S.O.D. order)
641 * {N,...,7,6,5,...,1} if successful.
642 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
643 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530645u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530646mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530648 u8 cb_idx;
649 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 /*
652 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
653 * (slot/handle 0 is reserved!)
654 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530655 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
656 if (MptCallbacks[cb_idx] == NULL) {
657 MptCallbacks[cb_idx] = cbfunc;
658 MptDriverClass[cb_idx] = dclass;
659 MptEvHandlers[cb_idx] = NULL;
660 last_drv_idx = cb_idx;
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530661 memcpy(MptCallbacksName[cb_idx], func_name,
662 strlen(func_name) > 50 ? 50 : strlen(func_name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 break;
664 }
665 }
666
667 return last_drv_idx;
668}
669
670/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
671/**
672 * mpt_deregister - Deregister a protocol drivers resources.
673 * @cb_idx: previously registered callback handle
674 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800675 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 * module is unloaded.
677 */
678void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530679mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600681 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 MptCallbacks[cb_idx] = NULL;
683 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
684 MptEvHandlers[cb_idx] = NULL;
685
686 last_drv_idx++;
687 }
688}
689
690/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
691/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800692 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 * @cb_idx: previously registered (via mpt_register) callback handle
694 * @ev_cbfunc: callback function
695 *
696 * This routine can be called by one or more protocol-specific drivers
697 * if/when they choose to be notified of MPT events.
698 *
699 * Returns 0 for success.
700 */
701int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530702mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600704 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return -1;
706
707 MptEvHandlers[cb_idx] = ev_cbfunc;
708 return 0;
709}
710
711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
712/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800713 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 * @cb_idx: previously registered callback handle
715 *
716 * Each protocol-specific driver should call this routine
717 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800718 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 */
720void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530721mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600723 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 return;
725
726 MptEvHandlers[cb_idx] = NULL;
727}
728
729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
730/**
731 * mpt_reset_register - Register protocol-specific IOC reset handler.
732 * @cb_idx: previously registered (via mpt_register) callback handle
733 * @reset_func: reset function
734 *
735 * This routine can be called by one or more protocol-specific drivers
736 * if/when they choose to be notified of IOC resets.
737 *
738 * Returns 0 for success.
739 */
740int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530741mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530743 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -1;
745
746 MptResetHandlers[cb_idx] = reset_func;
747 return 0;
748}
749
750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
751/**
752 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
753 * @cb_idx: previously registered callback handle
754 *
755 * Each protocol-specific driver should call this routine
756 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800757 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 */
759void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530760mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530762 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return;
764
765 MptResetHandlers[cb_idx] = NULL;
766}
767
768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
769/**
770 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800771 * @dd_cbfunc: driver callbacks struct
772 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 */
774int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530775mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
777 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600778 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Eric Moore8d6d83e2007-09-14 18:47:40 -0600780 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400781 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
784
785 /* call per pci device probe entry point */
786 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600787 id = ioc->pcidev->driver ?
788 ioc->pcidev->driver->id_table : NULL;
789 if (dd_cbfunc->probe)
790 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400793 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794}
795
796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
797/**
798 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800799 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 */
801void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530802mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 struct mpt_pci_driver *dd_cbfunc;
805 MPT_ADAPTER *ioc;
806
Eric Moore8d6d83e2007-09-14 18:47:40 -0600807 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return;
809
810 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
811
812 list_for_each_entry(ioc, &ioc_list, list) {
813 if (dd_cbfunc->remove)
814 dd_cbfunc->remove(ioc->pcidev);
815 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 MptDeviceDriverHandlers[cb_idx] = NULL;
818}
819
820
821/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
822/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800823 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530824 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 * @ioc: Pointer to MPT adapter structure
826 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800827 * Obtain an MPT request frame from the pool (of 1024) that are
828 * allocated per MPT adapter.
829 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 * Returns pointer to a MPT request frame or %NULL if none are available
831 * or IOC is not active.
832 */
833MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530834mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835{
836 MPT_FRAME_HDR *mf;
837 unsigned long flags;
838 u16 req_idx; /* Request index */
839
840 /* validate handle and ioc identifier */
841
842#ifdef MFCNT
843 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600844 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
845 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846#endif
847
848 /* If interrupts are not attached, do not return a request frame */
849 if (!ioc->active)
850 return NULL;
851
852 spin_lock_irqsave(&ioc->FreeQlock, flags);
853 if (!list_empty(&ioc->FreeQ)) {
854 int req_offset;
855
856 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
857 u.frame.linkage.list);
858 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200859 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530860 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
862 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500863 req_idx = req_offset / ioc->req_sz;
864 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600866 /* Default, will be changed if necessary in SG generation */
867 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868#ifdef MFCNT
869 ioc->mfcnt++;
870#endif
871 }
872 else
873 mf = NULL;
874 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
875
876#ifdef MFCNT
877 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600878 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
879 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
880 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 mfcounter++;
882 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600883 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
884 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885#endif
886
Eric Moore29dd3602007-09-14 18:46:51 -0600887 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
888 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return mf;
890}
891
892/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
893/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800894 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530895 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 * @ioc: Pointer to MPT adapter structure
897 * @mf: Pointer to MPT request frame
898 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800899 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 * specific MPT adapter.
901 */
902void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530903mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
905 u32 mf_dma_addr;
906 int req_offset;
907 u16 req_idx; /* Request index */
908
909 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530910 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
912 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500913 req_idx = req_offset / ioc->req_sz;
914 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
916
Prakash, Sathya436ace72007-07-24 15:42:08 +0530917 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200919 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600920 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
921 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
922 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
924}
925
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530926/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800927 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530928 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530929 * @ioc: Pointer to MPT adapter structure
930 * @mf: Pointer to MPT request frame
931 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800932 * Send a protocol-specific MPT request frame to an IOC using
933 * hi-priority request queue.
934 *
935 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530936 * specific MPT adapter.
937 **/
938void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530939mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530940{
941 u32 mf_dma_addr;
942 int req_offset;
943 u16 req_idx; /* Request index */
944
945 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530946 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530947 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
948 req_idx = req_offset / ioc->req_sz;
949 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
950 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
951
952 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
953
954 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
955 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
956 ioc->name, mf_dma_addr, req_idx));
957 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
958}
959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
961/**
962 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 * @ioc: Pointer to MPT adapter structure
964 * @mf: Pointer to MPT request frame
965 *
966 * This routine places a MPT request frame back on the MPT adapter's
967 * FreeQ.
968 */
969void
970mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
971{
972 unsigned long flags;
973
974 /* Put Request back on FreeQ! */
975 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530976 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
977 goto out;
978 /* signature to know if this mf is freed */
979 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
981#ifdef MFCNT
982 ioc->mfcnt--;
983#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530984 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
986}
987
988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
989/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530990 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 * @pAddr: virtual address for SGE
992 * @flagslength: SGE flags and data transfer length
993 * @dma_addr: Physical address
994 *
995 * This routine places a MPT request frame back on the MPT adapter's
996 * FreeQ.
997 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530998static void
999mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301001 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1002 pSge->FlagsLength = cpu_to_le32(flagslength);
1003 pSge->Address = cpu_to_le32(dma_addr);
1004}
1005
1006/**
1007 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1008 * @pAddr: virtual address for SGE
1009 * @flagslength: SGE flags and data transfer length
1010 * @dma_addr: Physical address
1011 *
1012 * This routine places a MPT request frame back on the MPT adapter's
1013 * FreeQ.
1014 **/
1015static void
1016mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1017{
1018 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1019 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301020 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301021 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301022 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301023 pSge->FlagsLength = cpu_to_le32
1024 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1025}
1026
1027/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001028 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301029 * @pAddr: virtual address for SGE
1030 * @flagslength: SGE flags and data transfer length
1031 * @dma_addr: Physical address
1032 *
1033 * This routine places a MPT request frame back on the MPT adapter's
1034 * FreeQ.
1035 **/
1036static void
1037mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1038{
1039 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1040 u32 tmp;
1041
1042 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301043 (lower_32_bits(dma_addr));
1044 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301045
1046 /*
1047 * 1078 errata workaround for the 36GB limitation
1048 */
1049 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1050 flagslength |=
1051 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1052 tmp |= (1<<31);
1053 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1054 printk(KERN_DEBUG "1078 P0M2 addressing for "
1055 "addr = 0x%llx len = %d\n",
1056 (unsigned long long)dma_addr,
1057 MPI_SGE_LENGTH(flagslength));
1058 }
1059
1060 pSge->Address.High = cpu_to_le32(tmp);
1061 pSge->FlagsLength = cpu_to_le32(
1062 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1063}
1064
1065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1066/**
1067 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1068 * @pAddr: virtual address for SGE
1069 * @next: nextChainOffset value (u32's)
1070 * @length: length of next SGL segment
1071 * @dma_addr: Physical address
1072 *
1073 */
1074static void
1075mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1076{
1077 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1078 pChain->Length = cpu_to_le16(length);
1079 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1080 pChain->NextChainOffset = next;
1081 pChain->Address = cpu_to_le32(dma_addr);
1082}
1083
1084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1085/**
1086 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1087 * @pAddr: virtual address for SGE
1088 * @next: nextChainOffset value (u32's)
1089 * @length: length of next SGL segment
1090 * @dma_addr: Physical address
1091 *
1092 */
1093static void
1094mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1095{
1096 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 u32 tmp = dma_addr & 0xFFFFFFFF;
1098
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301099 pChain->Length = cpu_to_le16(length);
1100 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1101 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301103 pChain->NextChainOffset = next;
1104
1105 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301106 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301107 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1111/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001112 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301113 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 * @ioc: Pointer to MPT adapter structure
1115 * @reqBytes: Size of the request in bytes
1116 * @req: Pointer to MPT request frame
1117 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1118 *
1119 * This routine is used exclusively to send MptScsiTaskMgmt
1120 * requests since they are required to be sent via doorbell handshake.
1121 *
1122 * NOTE: It is the callers responsibility to byte-swap fields in the
1123 * request which are greater than 1 byte in size.
1124 *
1125 * Returns 0 for success, non-zero for failure.
1126 */
1127int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301128mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Eric Moorecd2c6192007-01-29 09:47:47 -07001130 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 u8 *req_as_bytes;
1132 int ii;
1133
1134 /* State is known to be good upon entering
1135 * this function so issue the bus reset
1136 * request.
1137 */
1138
1139 /*
1140 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1141 * setting cb_idx/req_idx. But ONLY if this request
1142 * is in proper (pre-alloc'd) request buffer range...
1143 */
1144 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1145 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1146 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1147 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301148 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }
1150
1151 /* Make sure there are no doorbells */
1152 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1155 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1156 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1157
1158 /* Wait for IOC doorbell int */
1159 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1160 return ii;
1161 }
1162
1163 /* Read doorbell and check for active bit */
1164 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1165 return -5;
1166
Eric Moore29dd3602007-09-14 18:46:51 -06001167 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001168 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1171
1172 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1173 return -2;
1174 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 /* Send request via doorbell handshake */
1177 req_as_bytes = (u8 *) req;
1178 for (ii = 0; ii < reqBytes/4; ii++) {
1179 u32 word;
1180
1181 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1182 (req_as_bytes[(ii*4) + 1] << 8) |
1183 (req_as_bytes[(ii*4) + 2] << 16) |
1184 (req_as_bytes[(ii*4) + 3] << 24));
1185 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1186 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1187 r = -3;
1188 break;
1189 }
1190 }
1191
1192 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1193 r = 0;
1194 else
1195 r = -4;
1196
1197 /* Make sure there are no doorbells */
1198 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return r;
1201}
1202
1203/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1204/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001205 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001206 * @ioc: Pointer to MPT adapter structure
1207 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001208 * @sleepFlag: Specifies whether the process can sleep
1209 *
1210 * Provides mechanism for the host driver to control the IOC's
1211 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001212 *
1213 * Access Control Value - bits[15:12]
1214 * 0h Reserved
1215 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1216 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1217 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1218 *
1219 * Returns 0 for success, non-zero for failure.
1220 */
1221
1222static int
1223mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1224{
1225 int r = 0;
1226
1227 /* return if in use */
1228 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1229 & MPI_DOORBELL_ACTIVE)
1230 return -1;
1231
1232 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1233
1234 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1235 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1236 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1237 (access_control_value<<12)));
1238
1239 /* Wait for IOC to clear Doorbell Status bit */
1240 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1241 return -2;
1242 }else
1243 return 0;
1244}
1245
1246/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1247/**
1248 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001249 * @ioc: Pointer to pointer to IOC adapter
1250 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001251 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001252 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001253 * Returns 0 for success, non-zero for failure.
1254 */
1255static int
1256mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1257{
1258 char *psge;
1259 int flags_length;
1260 u32 host_page_buffer_sz=0;
1261
1262 if(!ioc->HostPageBuffer) {
1263
1264 host_page_buffer_sz =
1265 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1266
1267 if(!host_page_buffer_sz)
1268 return 0; /* fw doesn't need any host buffers */
1269
1270 /* spin till we get enough memory */
1271 while(host_page_buffer_sz > 0) {
1272
1273 if((ioc->HostPageBuffer = pci_alloc_consistent(
1274 ioc->pcidev,
1275 host_page_buffer_sz,
1276 &ioc->HostPageBuffer_dma)) != NULL) {
1277
Prakash, Sathya436ace72007-07-24 15:42:08 +05301278 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001279 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001280 ioc->name, ioc->HostPageBuffer,
1281 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001282 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001283 ioc->alloc_total += host_page_buffer_sz;
1284 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1285 break;
1286 }
1287
1288 host_page_buffer_sz -= (4*1024);
1289 }
1290 }
1291
1292 if(!ioc->HostPageBuffer) {
1293 printk(MYIOC_s_ERR_FMT
1294 "Failed to alloc memory for host_page_buffer!\n",
1295 ioc->name);
1296 return -999;
1297 }
1298
1299 psge = (char *)&ioc_init->HostPageBufferSGE;
1300 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1301 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001302 MPI_SGE_FLAGS_HOST_TO_IOC |
1303 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001304 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1305 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301306 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001307 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1308
1309return 0;
1310}
1311
1312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1313/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001314 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * @iocid: IOC unique identifier (integer)
1316 * @iocpp: Pointer to pointer to IOC adapter
1317 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001318 * Given a unique IOC identifier, set pointer to the associated MPT
1319 * adapter structure.
1320 *
1321 * Returns iocid and sets iocpp if iocid is found.
1322 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 */
1324int
1325mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1326{
1327 MPT_ADAPTER *ioc;
1328
1329 list_for_each_entry(ioc,&ioc_list,list) {
1330 if (ioc->id == iocid) {
1331 *iocpp =ioc;
1332 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 *iocpp = NULL;
1337 return -1;
1338}
1339
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301340/**
1341 * mpt_get_product_name - returns product string
1342 * @vendor: pci vendor id
1343 * @device: pci device id
1344 * @revision: pci revision id
1345 * @prod_name: string returned
1346 *
1347 * Returns product string displayed when driver loads,
1348 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1349 *
1350 **/
1351static void
1352mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1353{
1354 char *product_str = NULL;
1355
1356 if (vendor == PCI_VENDOR_ID_BROCADE) {
1357 switch (device)
1358 {
1359 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1360 switch (revision)
1361 {
1362 case 0x00:
1363 product_str = "BRE040 A0";
1364 break;
1365 case 0x01:
1366 product_str = "BRE040 A1";
1367 break;
1368 default:
1369 product_str = "BRE040";
1370 break;
1371 }
1372 break;
1373 }
1374 goto out;
1375 }
1376
1377 switch (device)
1378 {
1379 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1380 product_str = "LSIFC909 B1";
1381 break;
1382 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1383 product_str = "LSIFC919 B0";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1386 product_str = "LSIFC929 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1389 if (revision < 0x80)
1390 product_str = "LSIFC919X A0";
1391 else
1392 product_str = "LSIFC919XL A1";
1393 break;
1394 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1395 if (revision < 0x80)
1396 product_str = "LSIFC929X A0";
1397 else
1398 product_str = "LSIFC929XL A1";
1399 break;
1400 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1401 product_str = "LSIFC939X A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1404 product_str = "LSIFC949X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1407 switch (revision)
1408 {
1409 case 0x00:
1410 product_str = "LSIFC949E A0";
1411 break;
1412 case 0x01:
1413 product_str = "LSIFC949E A1";
1414 break;
1415 default:
1416 product_str = "LSIFC949E";
1417 break;
1418 }
1419 break;
1420 case MPI_MANUFACTPAGE_DEVID_53C1030:
1421 switch (revision)
1422 {
1423 case 0x00:
1424 product_str = "LSI53C1030 A0";
1425 break;
1426 case 0x01:
1427 product_str = "LSI53C1030 B0";
1428 break;
1429 case 0x03:
1430 product_str = "LSI53C1030 B1";
1431 break;
1432 case 0x07:
1433 product_str = "LSI53C1030 B2";
1434 break;
1435 case 0x08:
1436 product_str = "LSI53C1030 C0";
1437 break;
1438 case 0x80:
1439 product_str = "LSI53C1030T A0";
1440 break;
1441 case 0x83:
1442 product_str = "LSI53C1030T A2";
1443 break;
1444 case 0x87:
1445 product_str = "LSI53C1030T A3";
1446 break;
1447 case 0xc1:
1448 product_str = "LSI53C1020A A1";
1449 break;
1450 default:
1451 product_str = "LSI53C1030";
1452 break;
1453 }
1454 break;
1455 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1456 switch (revision)
1457 {
1458 case 0x03:
1459 product_str = "LSI53C1035 A2";
1460 break;
1461 case 0x04:
1462 product_str = "LSI53C1035 B0";
1463 break;
1464 default:
1465 product_str = "LSI53C1035";
1466 break;
1467 }
1468 break;
1469 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1470 switch (revision)
1471 {
1472 case 0x00:
1473 product_str = "LSISAS1064 A1";
1474 break;
1475 case 0x01:
1476 product_str = "LSISAS1064 A2";
1477 break;
1478 case 0x02:
1479 product_str = "LSISAS1064 A3";
1480 break;
1481 case 0x03:
1482 product_str = "LSISAS1064 A4";
1483 break;
1484 default:
1485 product_str = "LSISAS1064";
1486 break;
1487 }
1488 break;
1489 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1490 switch (revision)
1491 {
1492 case 0x00:
1493 product_str = "LSISAS1064E A0";
1494 break;
1495 case 0x01:
1496 product_str = "LSISAS1064E B0";
1497 break;
1498 case 0x02:
1499 product_str = "LSISAS1064E B1";
1500 break;
1501 case 0x04:
1502 product_str = "LSISAS1064E B2";
1503 break;
1504 case 0x08:
1505 product_str = "LSISAS1064E B3";
1506 break;
1507 default:
1508 product_str = "LSISAS1064E";
1509 break;
1510 }
1511 break;
1512 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1513 switch (revision)
1514 {
1515 case 0x00:
1516 product_str = "LSISAS1068 A0";
1517 break;
1518 case 0x01:
1519 product_str = "LSISAS1068 B0";
1520 break;
1521 case 0x02:
1522 product_str = "LSISAS1068 B1";
1523 break;
1524 default:
1525 product_str = "LSISAS1068";
1526 break;
1527 }
1528 break;
1529 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1530 switch (revision)
1531 {
1532 case 0x00:
1533 product_str = "LSISAS1068E A0";
1534 break;
1535 case 0x01:
1536 product_str = "LSISAS1068E B0";
1537 break;
1538 case 0x02:
1539 product_str = "LSISAS1068E B1";
1540 break;
1541 case 0x04:
1542 product_str = "LSISAS1068E B2";
1543 break;
1544 case 0x08:
1545 product_str = "LSISAS1068E B3";
1546 break;
1547 default:
1548 product_str = "LSISAS1068E";
1549 break;
1550 }
1551 break;
1552 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1553 switch (revision)
1554 {
1555 case 0x00:
1556 product_str = "LSISAS1078 A0";
1557 break;
1558 case 0x01:
1559 product_str = "LSISAS1078 B0";
1560 break;
1561 case 0x02:
1562 product_str = "LSISAS1078 C0";
1563 break;
1564 case 0x03:
1565 product_str = "LSISAS1078 C1";
1566 break;
1567 case 0x04:
1568 product_str = "LSISAS1078 C2";
1569 break;
1570 default:
1571 product_str = "LSISAS1078";
1572 break;
1573 }
1574 break;
1575 }
1576
1577 out:
1578 if (product_str)
1579 sprintf(prod_name, "%s", product_str);
1580}
1581
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301582/**
1583 * mpt_mapresources - map in memory mapped io
1584 * @ioc: Pointer to pointer to IOC adapter
1585 *
1586 **/
1587static int
1588mpt_mapresources(MPT_ADAPTER *ioc)
1589{
1590 u8 __iomem *mem;
1591 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001592 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301593 unsigned long port;
1594 u32 msize;
1595 u32 psize;
1596 u8 revision;
1597 int r = -ENODEV;
1598 struct pci_dev *pdev;
1599
1600 pdev = ioc->pcidev;
1601 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1602 if (pci_enable_device_mem(pdev)) {
1603 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1604 "failed\n", ioc->name);
1605 return r;
1606 }
1607 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1608 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1609 "MEM failed\n", ioc->name);
1610 return r;
1611 }
1612
1613 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1614
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301615 if (sizeof(dma_addr_t) > 4) {
1616 const uint64_t required_mask = dma_get_required_mask
1617 (&pdev->dev);
1618 if (required_mask > DMA_BIT_MASK(32)
1619 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1620 && !pci_set_consistent_dma_mask(pdev,
1621 DMA_BIT_MASK(64))) {
1622 ioc->dma_mask = DMA_BIT_MASK(64);
1623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1624 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1625 ioc->name));
1626 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1627 && !pci_set_consistent_dma_mask(pdev,
1628 DMA_BIT_MASK(32))) {
1629 ioc->dma_mask = DMA_BIT_MASK(32);
1630 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1631 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1632 ioc->name));
1633 } else {
1634 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1635 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001636 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301637 return r;
1638 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301639 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301640 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1641 && !pci_set_consistent_dma_mask(pdev,
1642 DMA_BIT_MASK(32))) {
1643 ioc->dma_mask = DMA_BIT_MASK(32);
1644 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1645 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1646 ioc->name));
1647 } else {
1648 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1649 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001650 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301651 return r;
1652 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301653 }
1654
1655 mem_phys = msize = 0;
1656 port = psize = 0;
1657 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1658 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1659 if (psize)
1660 continue;
1661 /* Get I/O space! */
1662 port = pci_resource_start(pdev, ii);
1663 psize = pci_resource_len(pdev, ii);
1664 } else {
1665 if (msize)
1666 continue;
1667 /* Get memmap */
1668 mem_phys = pci_resource_start(pdev, ii);
1669 msize = pci_resource_len(pdev, ii);
1670 }
1671 }
1672 ioc->mem_size = msize;
1673
1674 mem = NULL;
1675 /* Get logical ptr for PciMem0 space */
1676 /*mem = ioremap(mem_phys, msize);*/
1677 mem = ioremap(mem_phys, msize);
1678 if (mem == NULL) {
1679 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1680 " memory!\n", ioc->name);
Tomas Henzl653c42d2010-07-26 16:41:13 +02001681 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301682 return -EINVAL;
1683 }
1684 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001685 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1686 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301687
1688 ioc->mem_phys = mem_phys;
1689 ioc->chip = (SYSIF_REGS __iomem *)mem;
1690
1691 /* Save Port IO values in case we need to do downloadboot */
1692 ioc->pio_mem_phys = port;
1693 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1694
1695 return 0;
1696}
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001700 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001702 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 *
1704 * This routine performs all the steps necessary to bring the IOC of
1705 * a MPT adapter to a OPERATIONAL state. This includes registering
1706 * memory regions, registering the interrupt, and allocating request
1707 * and reply memory pools.
1708 *
1709 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1710 * MPT adapter.
1711 *
1712 * Returns 0 for success, non-zero for failure.
1713 *
1714 * TODO: Add support for polled controllers
1715 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001716int
1717mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301720 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 u8 revision;
1723 u8 pcixcmd;
1724 static int mpt_ids = 0;
1725#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001726 struct proc_dir_entry *dent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727#endif
1728
Jesper Juhl56876192007-08-10 14:50:51 -07001729 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1730 if (ioc == NULL) {
1731 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1732 return -ENOMEM;
1733 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301734
Eric Moore29dd3602007-09-14 18:46:51 -06001735 ioc->id = mpt_ids++;
1736 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301737 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001738
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301739 /*
1740 * set initial debug level
1741 * (refer to mptdebug.h)
1742 *
1743 */
1744 ioc->debug_level = mpt_debug_level;
1745 if (mpt_debug_level)
1746 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301747
Eric Moore29dd3602007-09-14 18:46:51 -06001748 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001749
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301750 ioc->pcidev = pdev;
1751 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001752 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 return r;
1754 }
1755
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301756 /*
1757 * Setting up proper handlers for scatter gather handling
1758 */
1759 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1760 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1761 ioc->add_sge = &mpt_add_sge_64bit_1078;
1762 else
1763 ioc->add_sge = &mpt_add_sge_64bit;
1764 ioc->add_chain = &mpt_add_chain_64bit;
1765 ioc->sg_addr_size = 8;
1766 } else {
1767 ioc->add_sge = &mpt_add_sge;
1768 ioc->add_chain = &mpt_add_chain;
1769 ioc->sg_addr_size = 4;
1770 }
1771 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->alloc_total = sizeof(MPT_ADAPTER);
1774 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1775 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301778 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301779 mutex_init(&ioc->internal_cmds.mutex);
1780 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301781 mutex_init(&ioc->mptbase_cmds.mutex);
1782 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301783 mutex_init(&ioc->taskmgmt_cmds.mutex);
1784 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 /* Initialize the event logging.
1787 */
1788 ioc->eventTypes = 0; /* None */
1789 ioc->eventContext = 0;
1790 ioc->eventLogSize = 0;
1791 ioc->events = NULL;
1792
1793#ifdef MFCNT
1794 ioc->mfcnt = 0;
1795#endif
1796
Kashyap, Desai2f187862009-05-29 16:52:37 +05301797 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 ioc->cached_fw = NULL;
1799
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001800 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Michael Reed05e8ec12006-01-13 14:31:54 -06001804 /* Initialize the fc rport list head.
1805 */
1806 INIT_LIST_HEAD(&ioc->fc_rports);
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* Find lookup slot. */
1809 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001810
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301811
1812 /* Initialize workqueue */
1813 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301814
Kashyap, Desai2f187862009-05-29 16:52:37 +05301815 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001816 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301817 ioc->reset_work_q =
1818 create_singlethread_workqueue(ioc->reset_work_q_name);
1819 if (!ioc->reset_work_q) {
1820 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1821 ioc->name);
1822 pci_release_selected_regions(pdev, ioc->bars);
1823 kfree(ioc);
1824 return -ENOMEM;
1825 }
1826
Eric Moore29dd3602007-09-14 18:46:51 -06001827 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1828 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301830 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1831 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1832
1833 switch (pdev->device)
1834 {
1835 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1837 ioc->errata_flag_1064 = 1;
1838 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301843 break;
1844
1845 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 /* 929X Chip Fix. Set Split transactions level
1848 * for PCIX. Set MOST bits to zero.
1849 */
1850 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1851 pcixcmd &= 0x8F;
1852 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1853 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* 929XL Chip Fix. Set MMRBC to 0x08.
1855 */
1856 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1857 pcixcmd |= 0x08;
1858 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301861 break;
1862
1863 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 /* 919X Chip Fix. Set Split transactions level
1865 * for PCIX. Set MOST bits to zero.
1866 */
1867 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1868 pcixcmd &= 0x8F;
1869 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001870 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301871 break;
1872
1873 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 /* 1030 Chip Fix. Disable Split transactions
1875 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1876 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 if (revision < C0_1030) {
1878 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1879 pcixcmd &= 0x8F;
1880 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1881 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882
1883 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001884 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301885 break;
1886
1887 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1888 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001889 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301890 ioc->bus_type = SAS;
1891 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301892
1893 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1894 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1895 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001896 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301897 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301900
Kashyap, Desaie3829682009-01-08 14:27:16 +05301901 switch (ioc->bus_type) {
1902
1903 case SAS:
1904 ioc->msi_enable = mpt_msi_enable_sas;
1905 break;
1906
1907 case SPI:
1908 ioc->msi_enable = mpt_msi_enable_spi;
1909 break;
1910
1911 case FC:
1912 ioc->msi_enable = mpt_msi_enable_fc;
1913 break;
1914
1915 default:
1916 ioc->msi_enable = 0;
1917 break;
1918 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301919
1920 ioc->fw_events_off = 1;
1921
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001922 if (ioc->errata_flag_1064)
1923 pci_disable_io_access(pdev);
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 spin_lock_init(&ioc->FreeQlock);
1926
1927 /* Disable all! */
1928 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1929 ioc->active = 0;
1930 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1931
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301932 /* Set IOC ptr in the pcidev's driver data. */
1933 pci_set_drvdata(ioc->pcidev, ioc);
1934
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 /* Set lookup ptr. */
1936 list_add_tail(&ioc->list, &ioc_list);
1937
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001938 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 */
1940 mpt_detect_bound_ports(ioc, pdev);
1941
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301942 INIT_LIST_HEAD(&ioc->fw_event_list);
1943 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301944 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301945 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1946
James Bottomleyc92f2222006-03-01 09:02:49 -06001947 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1948 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001949 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1950 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001953 if (ioc->alt_ioc)
1954 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301955 iounmap(ioc->memmap);
1956 if (r != -5)
1957 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301958
1959 destroy_workqueue(ioc->reset_work_q);
1960 ioc->reset_work_q = NULL;
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 kfree(ioc);
1963 pci_set_drvdata(pdev, NULL);
1964 return r;
1965 }
1966
1967 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001968 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301969 if(MptDeviceDriverHandlers[cb_idx] &&
1970 MptDeviceDriverHandlers[cb_idx]->probe) {
1971 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 }
1973 }
1974
1975#ifdef CONFIG_PROC_FS
1976 /*
1977 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1978 */
1979 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1980 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001981 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
1982 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 }
1984#endif
1985
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301986 if (!ioc->alt_ioc)
1987 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1988 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 return 0;
1991}
1992
1993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001994/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001995 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 */
1998
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001999void
2000mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2003 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302004 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302005 unsigned long flags;
2006 struct workqueue_struct *wq;
2007
2008 /*
2009 * Stop polling ioc for fault condition
2010 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302011 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302012 wq = ioc->reset_work_q;
2013 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302014 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302015 cancel_delayed_work(&ioc->fault_reset_work);
2016 destroy_workqueue(wq);
2017
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302018 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2019 wq = ioc->fw_event_q;
2020 ioc->fw_event_q = NULL;
2021 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2022 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2025 remove_proc_entry(pname, NULL);
2026 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2027 remove_proc_entry(pname, NULL);
2028 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2029 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002032 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302033 if(MptDeviceDriverHandlers[cb_idx] &&
2034 MptDeviceDriverHandlers[cb_idx]->remove) {
2035 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 /* Disable interrupts! */
2040 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2041
2042 ioc->active = 0;
2043 synchronize_irq(pdev->irq);
2044
2045 /* Clear any lingering interrupt */
2046 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2047
2048 CHIPREG_READ32(&ioc->chip->IntStatus);
2049
2050 mpt_adapter_dispose(ioc);
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052}
2053
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054/**************************************************************************
2055 * Power Management
2056 */
2057#ifdef CONFIG_PM
2058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002059/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002060 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002061 * @pdev: Pointer to pci_dev structure
2062 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002064int
2065mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
2067 u32 device_state;
2068 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302070 device_state = pci_choose_state(pdev, state);
2071 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2072 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2073 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
2075 /* put ioc into READY_STATE */
2076 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2077 printk(MYIOC_s_ERR_FMT
2078 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2079 }
2080
2081 /* disable interrupts */
2082 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2083 ioc->active = 0;
2084
2085 /* Clear any lingering interrupt */
2086 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2087
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302088 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002089 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302090 pci_disable_msi(ioc->pcidev);
2091 ioc->pci_irq = -1;
2092 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302094 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 return 0;
2097}
2098
2099/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002100/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002101 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002102 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002104int
2105mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106{
2107 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2108 u32 device_state = pdev->current_state;
2109 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302110 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002111
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302112 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2113 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2114 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302116 pci_set_power_state(pdev, PCI_D0);
2117 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302119 ioc->pcidev = pdev;
2120 err = mpt_mapresources(ioc);
2121 if (err)
2122 return err;
2123
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302124 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2125 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2126 ioc->add_sge = &mpt_add_sge_64bit_1078;
2127 else
2128 ioc->add_sge = &mpt_add_sge_64bit;
2129 ioc->add_chain = &mpt_add_chain_64bit;
2130 ioc->sg_addr_size = 8;
2131 } else {
2132
2133 ioc->add_sge = &mpt_add_sge;
2134 ioc->add_chain = &mpt_add_chain;
2135 ioc->sg_addr_size = 4;
2136 }
2137 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2138
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302139 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2140 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2141 CHIPREG_READ32(&ioc->chip->Doorbell));
2142
2143 /*
2144 * Errata workaround for SAS pci express:
2145 * Upon returning to the D0 state, the contents of the doorbell will be
2146 * stale data, and this will incorrectly signal to the host driver that
2147 * the firmware is ready to process mpt commands. The workaround is
2148 * to issue a diagnostic reset.
2149 */
2150 if (ioc->bus_type == SAS && (pdev->device ==
2151 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2152 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2153 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2154 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2155 ioc->name);
2156 goto out;
2157 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302161 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2162 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2163 CAN_SLEEP);
2164 if (recovery_state != 0)
2165 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2166 "error:[%x]\n", ioc->name, recovery_state);
2167 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302169 "pci-resume: success\n", ioc->name);
2170 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302172
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173}
2174#endif
2175
James Bottomley4ff42a62006-05-17 18:06:52 -05002176static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302177mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002178{
2179 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2180 ioc->bus_type != SPI) ||
2181 (MptDriverClass[index] == MPTFC_DRIVER &&
2182 ioc->bus_type != FC) ||
2183 (MptDriverClass[index] == MPTSAS_DRIVER &&
2184 ioc->bus_type != SAS))
2185 /* make sure we only call the relevant reset handler
2186 * for the bus */
2187 return 0;
2188 return (MptResetHandlers[index])(ioc, reset_phase);
2189}
2190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002192/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2194 * @ioc: Pointer to MPT adapter structure
2195 * @reason: Event word / reason
2196 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2197 *
2198 * This routine performs all the steps necessary to bring the IOC
2199 * to a OPERATIONAL state.
2200 *
2201 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2202 * MPT adapter.
2203 *
2204 * Returns:
2205 * 0 for success
2206 * -1 if failed to get board READY
2207 * -2 if READY but IOCFacts Failed
2208 * -3 if READY but PrimeIOCFifos Failed
2209 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302210 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302211 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 */
2213static int
2214mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2215{
2216 int hard_reset_done = 0;
2217 int alt_ioc_ready = 0;
2218 int hard;
2219 int rc=0;
2220 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 int ret = 0;
2222 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002223 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302224 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Eric Moore29dd3602007-09-14 18:46:51 -06002226 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2227 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
2229 /* Disable reply interrupts (also blocks FreeQ) */
2230 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2231 ioc->active = 0;
2232
2233 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302234 if (ioc->alt_ioc->active ||
2235 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302237 /* Disable alt-IOC's reply interrupts
2238 * (and FreeQ) for a bit
2239 **/
2240 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2241 0xFFFFFFFF);
2242 ioc->alt_ioc->active = 0;
2243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 }
2245
2246 hard = 1;
2247 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2248 hard = 0;
2249
2250 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2251 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002252 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2253 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 if (reset_alt_ioc_active && ioc->alt_ioc) {
2256 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002257 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2258 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002259 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 ioc->alt_ioc->active = 1;
2261 }
2262
2263 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302264 printk(MYIOC_s_WARN_FMT
2265 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302267 ret = -1;
2268 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
2270
2271 /* hard_reset_done = 0 if a soft reset was performed
2272 * and 1 if a hard reset was performed.
2273 */
2274 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2275 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2276 alt_ioc_ready = 1;
2277 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302278 printk(MYIOC_s_WARN_FMT
2279 ": alt-ioc Not ready WARNING!\n",
2280 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 }
2282
2283 for (ii=0; ii<5; ii++) {
2284 /* Get IOC facts! Allow 5 retries */
2285 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2286 break;
2287 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002291 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2292 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 ret = -2;
2294 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2295 MptDisplayIocCapabilities(ioc);
2296 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 if (alt_ioc_ready) {
2299 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302301 "Initial Alt IocFacts failed rc=%x\n",
2302 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 /* Retry - alt IOC was initialized once
2304 */
2305 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2306 }
2307 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302308 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002309 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 alt_ioc_ready = 0;
2311 reset_alt_ioc_active = 0;
2312 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2313 MptDisplayIocCapabilities(ioc->alt_ioc);
2314 }
2315 }
2316
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302317 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2318 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2319 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2320 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2321 IORESOURCE_IO);
2322 if (pci_enable_device(ioc->pcidev))
2323 return -5;
2324 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2325 "mpt"))
2326 return -5;
2327 }
2328
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002329 /*
2330 * Device is reset now. It must have de-asserted the interrupt line
2331 * (if it was asserted) and it should be safe to register for the
2332 * interrupt now.
2333 */
2334 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2335 ioc->pci_irq = -1;
2336 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302337 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002338 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002339 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302340 else
2341 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002342 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002343 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002344 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002345 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302346 "interrupt %d!\n",
2347 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302348 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002349 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302350 ret = -EBUSY;
2351 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002352 }
2353 irq_allocated = 1;
2354 ioc->pci_irq = ioc->pcidev->irq;
2355 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302356 pci_set_drvdata(ioc->pcidev, ioc);
2357 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2358 "installed at interrupt %d\n", ioc->name,
2359 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002360 }
2361 }
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 /* Prime reply & request queues!
2364 * (mucho alloc's) Must be done prior to
2365 * init as upper addresses are needed for init.
2366 * If fails, continue with alt-ioc processing
2367 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302368 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2369 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2371 ret = -3;
2372
2373 /* May need to check/upload firmware & data here!
2374 * If fails, continue with alt-ioc processing
2375 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302376 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2377 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2379 ret = -4;
2380// NEW!
2381 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302382 printk(MYIOC_s_WARN_FMT
2383 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002384 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 alt_ioc_ready = 0;
2386 reset_alt_ioc_active = 0;
2387 }
2388
2389 if (alt_ioc_ready) {
2390 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2391 alt_ioc_ready = 0;
2392 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302393 printk(MYIOC_s_WARN_FMT
2394 ": alt-ioc: (%d) init failure WARNING!\n",
2395 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
2397 }
2398
2399 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2400 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302401 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002402 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
2404 /* Controller is not operational, cannot do upload
2405 */
2406 if (ret == 0) {
2407 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002408 if (rc == 0) {
2409 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2410 /*
2411 * Maintain only one pointer to FW memory
2412 * so there will not be two attempt to
2413 * downloadboot onboard dual function
2414 * chips (mpt_adapter_disable,
2415 * mpt_diag_reset)
2416 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302417 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002418 "mpt_upload: alt_%s has cached_fw=%p \n",
2419 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302420 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002421 }
2422 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002423 printk(MYIOC_s_WARN_FMT
2424 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302425 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 }
2428 }
2429 }
2430
Kashyap, Desaifd761752009-05-29 16:39:06 +05302431 /* Enable MPT base driver management of EventNotification
2432 * and EventAck handling.
2433 */
2434 if ((ret == 0) && (!ioc->facts.EventState)) {
2435 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2436 "SendEventNotification\n",
2437 ioc->name));
2438 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2439 }
2440
2441 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2442 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2443
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (ret == 0) {
2445 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002446 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 ioc->active = 1;
2448 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302449 if (rc == 0) { /* alt ioc */
2450 if (reset_alt_ioc_active && ioc->alt_ioc) {
2451 /* (re)Enable alt-IOC! (reply interrupt) */
2452 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2453 "reply irq re-enabled\n",
2454 ioc->alt_ioc->name));
2455 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2456 MPI_HIM_DIM);
2457 ioc->alt_ioc->active = 1;
2458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
2460
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002462 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2464 * recursive scenario; GetLanConfigPages times out, timer expired
2465 * routine calls HardResetHandler, which calls into here again,
2466 * and we try GetLanConfigPages again...
2467 */
2468 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002469
2470 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002471 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002472 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002473 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002474 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2475
Kashyap, Desai2f187862009-05-29 16:52:37 +05302476 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002477
Kashyap, Desai2f187862009-05-29 16:52:37 +05302478 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002479 /* clear persistency table */
2480 if(ioc->facts.IOCExceptions &
2481 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2482 ret = mptbase_sas_persist_operation(ioc,
2483 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2484 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002485 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002486 }
2487
2488 /* Find IM volumes
2489 */
2490 mpt_findImVolumes(ioc);
2491
Kashyap, Desai2f187862009-05-29 16:52:37 +05302492 /* Check, and possibly reset, the coalescing value
2493 */
2494 mpt_read_ioc_pg_1(ioc);
2495
2496 break;
2497
2498 case FC:
2499 if ((ioc->pfacts[0].ProtocolFlags &
2500 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2502 /*
2503 * Pre-fetch the ports LAN MAC address!
2504 * (LANPage1_t stuff)
2505 */
2506 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302507 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2508 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302509 "LanAddr = %02X:%02X:%02X"
2510 ":%02X:%02X:%02X\n",
2511 ioc->name, a[5], a[4],
2512 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302514 break;
2515
2516 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 /* Get NVRAM and adapter maximums from SPP 0 and 2
2518 */
2519 mpt_GetScsiPortSettings(ioc, 0);
2520
2521 /* Get version and length of SDP 1
2522 */
2523 mpt_readScsiDevicePageHeaders(ioc, 0);
2524
2525 /* Find IM volumes
2526 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002527 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 mpt_findImVolumes(ioc);
2529
2530 /* Check, and possibly reset, the coalescing value
2531 */
2532 mpt_read_ioc_pg_1(ioc);
2533
2534 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302535
2536 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 }
2538
2539 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302540 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 }
2542
Eric Moore0ccdb002006-07-11 17:33:13 -06002543 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002544 if ((ret != 0) && irq_allocated) {
2545 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302546 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002547 pci_disable_msi(ioc->pcidev);
2548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 return ret;
2550}
2551
2552/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002553/**
2554 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 * @ioc: Pointer to MPT adapter structure
2556 * @pdev: Pointer to (struct pci_dev) structure
2557 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002558 * Search for PCI bus/dev_function which matches
2559 * PCI bus/dev_function (+/-1) for newly discovered 929,
2560 * 929X, 1030 or 1035.
2561 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2563 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2564 */
2565static void
2566mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2567{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002568 struct pci_dev *peer=NULL;
2569 unsigned int slot = PCI_SLOT(pdev->devfn);
2570 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 MPT_ADAPTER *ioc_srch;
2572
Prakash, Sathya436ace72007-07-24 15:42:08 +05302573 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002574 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002575 ioc->name, pci_name(pdev), pdev->bus->number,
2576 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002577
2578 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2579 if (!peer) {
2580 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2581 if (!peer)
2582 return;
2583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 list_for_each_entry(ioc_srch, &ioc_list, list) {
2586 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002587 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 /* Paranoia checks */
2589 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302590 printk(MYIOC_s_WARN_FMT
2591 "Oops, already bound (%s <==> %s)!\n",
2592 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 break;
2594 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302595 printk(MYIOC_s_WARN_FMT
2596 "Oops, already bound (%s <==> %s)!\n",
2597 ioc_srch->name, ioc_srch->name,
2598 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 break;
2600 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302601 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2602 "FOUND! binding %s <==> %s\n",
2603 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 ioc_srch->alt_ioc = ioc;
2605 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 }
2607 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002608 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609}
2610
2611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002612/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002614 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 */
2616static void
2617mpt_adapter_disable(MPT_ADAPTER *ioc)
2618{
2619 int sz;
2620 int ret;
2621
2622 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302623 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2624 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302625 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2626 ioc->cached_fw, CAN_SLEEP)) < 0) {
2627 printk(MYIOC_s_WARN_FMT
2628 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002629 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 }
2631 }
2632
Kashyap, Desai71278192009-05-29 16:53:14 +05302633 /*
2634 * Put the controller into ready state (if its not already)
2635 */
2636 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2637 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2638 CAN_SLEEP)) {
2639 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2640 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2641 "reset failed to put ioc in ready state!\n",
2642 ioc->name, __func__);
2643 } else
2644 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2645 "failed!\n", ioc->name, __func__);
2646 }
2647
2648
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302650 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2652 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* Clear any lingering interrupt */
2655 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302656 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
2658 if (ioc->alloc != NULL) {
2659 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002660 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2661 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 pci_free_consistent(ioc->pcidev, sz,
2663 ioc->alloc, ioc->alloc_dma);
2664 ioc->reply_frames = NULL;
2665 ioc->req_frames = NULL;
2666 ioc->alloc = NULL;
2667 ioc->alloc_total -= sz;
2668 }
2669
2670 if (ioc->sense_buf_pool != NULL) {
2671 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2672 pci_free_consistent(ioc->pcidev, sz,
2673 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2674 ioc->sense_buf_pool = NULL;
2675 ioc->alloc_total -= sz;
2676 }
2677
2678 if (ioc->events != NULL){
2679 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2680 kfree(ioc->events);
2681 ioc->events = NULL;
2682 ioc->alloc_total -= sz;
2683 }
2684
Prakash, Sathya984621b2008-01-11 14:42:17 +05302685 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002687 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002688 mpt_inactive_raid_list_free(ioc);
2689 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002690 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002691 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002692 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
2694 if (ioc->spi_data.pIocPg4 != NULL) {
2695 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302696 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 ioc->spi_data.pIocPg4,
2698 ioc->spi_data.IocPg4_dma);
2699 ioc->spi_data.pIocPg4 = NULL;
2700 ioc->alloc_total -= sz;
2701 }
2702
2703 if (ioc->ReqToChain != NULL) {
2704 kfree(ioc->ReqToChain);
2705 kfree(ioc->RequestNB);
2706 ioc->ReqToChain = NULL;
2707 }
2708
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002709 kfree(ioc->ChainToChain);
2710 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002711
2712 if (ioc->HostPageBuffer != NULL) {
2713 if((ret = mpt_host_page_access_control(ioc,
2714 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002715 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302716 ": %s: host page buffers free failed (%d)!\n",
2717 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002718 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302719 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2720 "HostPageBuffer free @ %p, sz=%d bytes\n",
2721 ioc->name, ioc->HostPageBuffer,
2722 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002723 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002724 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002725 ioc->HostPageBuffer = NULL;
2726 ioc->HostPageBuffer_sz = 0;
2727 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Kashyap, Desai2f187862009-05-29 16:52:37 +05302730 pci_set_drvdata(ioc->pcidev, NULL);
2731}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002733/**
2734 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 * @ioc: Pointer to MPT adapter structure
2736 *
2737 * This routine unregisters h/w resources and frees all alloc'd memory
2738 * associated with a MPT adapter structure.
2739 */
2740static void
2741mpt_adapter_dispose(MPT_ADAPTER *ioc)
2742{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002743 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002745 if (ioc == NULL)
2746 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002748 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002750 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002752 if (ioc->pci_irq != -1) {
2753 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302754 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002755 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002756 ioc->pci_irq = -1;
2757 }
2758
2759 if (ioc->memmap != NULL) {
2760 iounmap(ioc->memmap);
2761 ioc->memmap = NULL;
2762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302764 pci_disable_device(ioc->pcidev);
2765 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2766
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002768 if (ioc->mtrr_reg > 0) {
2769 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002770 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772#endif
2773
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002774 /* Zap the adapter lookup ptr! */
2775 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002778 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2779 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002780
2781 if (ioc->alt_ioc)
2782 ioc->alt_ioc->alt_ioc = NULL;
2783
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002784 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785}
2786
2787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002788/**
2789 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 * @ioc: Pointer to MPT adapter structure
2791 */
2792static void
2793MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2794{
2795 int i = 0;
2796
2797 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302798 if (ioc->prod_name)
2799 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 printk("Capabilities={");
2801
2802 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2803 printk("Initiator");
2804 i++;
2805 }
2806
2807 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2808 printk("%sTarget", i ? "," : "");
2809 i++;
2810 }
2811
2812 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2813 printk("%sLAN", i ? "," : "");
2814 i++;
2815 }
2816
2817#if 0
2818 /*
2819 * This would probably evoke more questions than it's worth
2820 */
2821 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2822 printk("%sLogBusAddr", i ? "," : "");
2823 i++;
2824 }
2825#endif
2826
2827 printk("}\n");
2828}
2829
2830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002831/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2833 * @ioc: Pointer to MPT_ADAPTER structure
2834 * @force: Force hard KickStart of IOC
2835 * @sleepFlag: Specifies whether the process can sleep
2836 *
2837 * Returns:
2838 * 1 - DIAG reset and READY
2839 * 0 - READY initially OR soft reset and READY
2840 * -1 - Any failure on KickStart
2841 * -2 - Msg Unit Reset Failed
2842 * -3 - IO Unit Reset Failed
2843 * -4 - IOC owned by a PEER
2844 */
2845static int
2846MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2847{
2848 u32 ioc_state;
2849 int statefault = 0;
2850 int cntdn;
2851 int hard_reset_done = 0;
2852 int r;
2853 int ii;
2854 int whoinit;
2855
2856 /* Get current [raw] IOC state */
2857 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002858 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860 /*
2861 * Check to see if IOC got left/stuck in doorbell handshake
2862 * grip of death. If so, hard reset the IOC.
2863 */
2864 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2865 statefault = 1;
2866 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2867 ioc->name);
2868 }
2869
2870 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302871 if (!statefault &&
2872 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2873 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2874 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 /*
2879 * Check to see if IOC is in FAULT state.
2880 */
2881 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2882 statefault = 2;
2883 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002884 ioc->name);
2885 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2886 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 }
2888
2889 /*
2890 * Hmmm... Did it get left operational?
2891 */
2892 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302893 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 ioc->name));
2895
2896 /* Check WhoInit.
2897 * If PCI Peer, exit.
2898 * Else, if no fault conditions are present, issue a MessageUnitReset
2899 * Else, fall through to KickStart case
2900 */
2901 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002902 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2903 "whoinit 0x%x statefault %d force %d\n",
2904 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 if (whoinit == MPI_WHOINIT_PCI_PEER)
2906 return -4;
2907 else {
2908 if ((statefault == 0 ) && (force == 0)) {
2909 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2910 return 0;
2911 }
2912 statefault = 3;
2913 }
2914 }
2915
2916 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2917 if (hard_reset_done < 0)
2918 return -1;
2919
2920 /*
2921 * Loop here waiting for IOC to come READY.
2922 */
2923 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002924 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2927 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2928 /*
2929 * BIOS or previous driver load left IOC in OP state.
2930 * Reset messaging FIFOs.
2931 */
2932 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2933 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2934 return -2;
2935 }
2936 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2937 /*
2938 * Something is wrong. Try to get IOC back
2939 * to a known state.
2940 */
2941 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2942 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2943 return -3;
2944 }
2945 }
2946
2947 ii++; cntdn--;
2948 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302949 printk(MYIOC_s_ERR_FMT
2950 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2951 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 return -ETIME;
2953 }
2954
2955 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002956 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 } else {
2958 mdelay (1); /* 1 msec delay */
2959 }
2960
2961 }
2962
2963 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302964 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2965 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 }
2967
2968 return hard_reset_done;
2969}
2970
2971/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002972/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 * mpt_GetIocState - Get the current state of a MPT adapter.
2974 * @ioc: Pointer to MPT_ADAPTER structure
2975 * @cooked: Request raw or cooked IOC state
2976 *
2977 * Returns all IOC Doorbell register bits if cooked==0, else just the
2978 * Doorbell bits in MPI_IOC_STATE_MASK.
2979 */
2980u32
2981mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2982{
2983 u32 s, sc;
2984
2985 /* Get! */
2986 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 sc = s & MPI_IOC_STATE_MASK;
2988
2989 /* Save! */
2990 ioc->last_state = sc;
2991
2992 return cooked ? sc : s;
2993}
2994
2995/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002996/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 * GetIocFacts - Send IOCFacts request to MPT adapter.
2998 * @ioc: Pointer to MPT_ADAPTER structure
2999 * @sleepFlag: Specifies whether the process can sleep
3000 * @reason: If recovery, only update facts.
3001 *
3002 * Returns 0 for success, non-zero for failure.
3003 */
3004static int
3005GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3006{
3007 IOCFacts_t get_facts;
3008 IOCFactsReply_t *facts;
3009 int r;
3010 int req_sz;
3011 int reply_sz;
3012 int sz;
3013 u32 status, vv;
3014 u8 shiftFactor=1;
3015
3016 /* IOC *must* NOT be in RESET state! */
3017 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303018 printk(KERN_ERR MYNAM
3019 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3020 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 return -44;
3022 }
3023
3024 facts = &ioc->facts;
3025
3026 /* Destination (reply area)... */
3027 reply_sz = sizeof(*facts);
3028 memset(facts, 0, reply_sz);
3029
3030 /* Request area (get_facts on the stack right now!) */
3031 req_sz = sizeof(get_facts);
3032 memset(&get_facts, 0, req_sz);
3033
3034 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3035 /* Assert: All other get_facts fields are zero! */
3036
Prakash, Sathya436ace72007-07-24 15:42:08 +05303037 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003038 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 ioc->name, req_sz, reply_sz));
3040
3041 /* No non-zero fields in the get_facts request are greater than
3042 * 1 byte in size, so we can just fire it off as is.
3043 */
3044 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3045 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3046 if (r != 0)
3047 return r;
3048
3049 /*
3050 * Now byte swap (GRRR) the necessary fields before any further
3051 * inspection of reply contents.
3052 *
3053 * But need to do some sanity checks on MsgLength (byte) field
3054 * to make sure we don't zero IOC's req_sz!
3055 */
3056 /* Did we get a valid reply? */
3057 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3058 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3059 /*
3060 * If not been here, done that, save off first WhoInit value
3061 */
3062 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3063 ioc->FirstWhoInit = facts->WhoInit;
3064 }
3065
3066 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3067 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3068 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3069 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3070 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003071 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 /* CHECKME! IOCStatus, IOCLogInfo */
3073
3074 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3075 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3076
3077 /*
3078 * FC f/w version changed between 1.1 and 1.2
3079 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3080 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3081 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303082 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 /*
3084 * Handle old FC f/w style, convert to new...
3085 */
3086 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3087 facts->FWVersion.Word =
3088 ((oldv<<12) & 0xFF000000) |
3089 ((oldv<<8) & 0x000FFF00);
3090 } else
3091 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3092
3093 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303094
Eric Mooreb506ade2007-01-29 09:45:37 -07003095 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3096 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3097 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303098
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 facts->CurrentHostMfaHighAddr =
3100 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3101 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3102 facts->CurrentSenseBufferHighAddr =
3103 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3104 facts->CurReplyFrameSize =
3105 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003106 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
3108 /*
3109 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3110 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3111 * to 14 in MPI-1.01.0x.
3112 */
3113 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303114 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3116 }
3117
3118 sz = facts->FWImageSize;
3119 if ( sz & 0x01 )
3120 sz += 1;
3121 if ( sz & 0x02 )
3122 sz += 2;
3123 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003124
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 if (!facts->RequestFrameSize) {
3126 /* Something is wrong! */
3127 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3128 ioc->name);
3129 return -55;
3130 }
3131
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003132 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 vv = ((63 / (sz * 4)) + 1) & 0x03;
3134 ioc->NB_for_64_byte_frame = vv;
3135 while ( sz )
3136 {
3137 shiftFactor++;
3138 sz = sz >> 1;
3139 }
3140 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303141 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003142 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3143 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003144
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3146 /*
3147 * Set values for this IOC's request & reply frame sizes,
3148 * and request & reply queue depths...
3149 */
3150 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3151 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3152 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3153 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3154
Prakash, Sathya436ace72007-07-24 15:42:08 +05303155 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303157 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 ioc->name, ioc->req_sz, ioc->req_depth));
3159
3160 /* Get port facts! */
3161 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3162 return r;
3163 }
3164 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003165 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3167 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3168 RequestFrameSize)/sizeof(u32)));
3169 return -66;
3170 }
3171
3172 return 0;
3173}
3174
3175/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003176/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 * GetPortFacts - Send PortFacts request to MPT adapter.
3178 * @ioc: Pointer to MPT_ADAPTER structure
3179 * @portnum: Port number
3180 * @sleepFlag: Specifies whether the process can sleep
3181 *
3182 * Returns 0 for success, non-zero for failure.
3183 */
3184static int
3185GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3186{
3187 PortFacts_t get_pfacts;
3188 PortFactsReply_t *pfacts;
3189 int ii;
3190 int req_sz;
3191 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003192 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
3194 /* IOC *must* NOT be in RESET state! */
3195 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003196 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3197 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 return -4;
3199 }
3200
3201 pfacts = &ioc->pfacts[portnum];
3202
3203 /* Destination (reply area)... */
3204 reply_sz = sizeof(*pfacts);
3205 memset(pfacts, 0, reply_sz);
3206
3207 /* Request area (get_pfacts on the stack right now!) */
3208 req_sz = sizeof(get_pfacts);
3209 memset(&get_pfacts, 0, req_sz);
3210
3211 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3212 get_pfacts.PortNumber = portnum;
3213 /* Assert: All other get_pfacts fields are zero! */
3214
Prakash, Sathya436ace72007-07-24 15:42:08 +05303215 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 ioc->name, portnum));
3217
3218 /* No non-zero fields in the get_pfacts request are greater than
3219 * 1 byte in size, so we can just fire it off as is.
3220 */
3221 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3222 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3223 if (ii != 0)
3224 return ii;
3225
3226 /* Did we get a valid reply? */
3227
3228 /* Now byte swap the necessary fields in the response. */
3229 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3230 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3231 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3232 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3233 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3234 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3235 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3236 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3237 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3238
Eric Moore793955f2007-01-29 09:42:20 -07003239 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3240 pfacts->MaxDevices;
3241 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3242 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3243
3244 /*
3245 * Place all the devices on channels
3246 *
3247 * (for debuging)
3248 */
3249 if (mpt_channel_mapping) {
3250 ioc->devices_per_bus = 1;
3251 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3252 }
3253
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 return 0;
3255}
3256
3257/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003258/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 * SendIocInit - Send IOCInit request to MPT adapter.
3260 * @ioc: Pointer to MPT_ADAPTER structure
3261 * @sleepFlag: Specifies whether the process can sleep
3262 *
3263 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3264 *
3265 * Returns 0 for success, non-zero for failure.
3266 */
3267static int
3268SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3269{
3270 IOCInit_t ioc_init;
3271 MPIDefaultReply_t init_reply;
3272 u32 state;
3273 int r;
3274 int count;
3275 int cntdn;
3276
3277 memset(&ioc_init, 0, sizeof(ioc_init));
3278 memset(&init_reply, 0, sizeof(init_reply));
3279
3280 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3281 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3282
3283 /* If we are in a recovery mode and we uploaded the FW image,
3284 * then this pointer is not NULL. Skip the upload a second time.
3285 * Set this flag if cached_fw set for either IOC.
3286 */
3287 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3288 ioc->upload_fw = 1;
3289 else
3290 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303291 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3293
Eric Moore793955f2007-01-29 09:42:20 -07003294 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3295 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303296
Prakash, Sathya436ace72007-07-24 15:42:08 +05303297 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003298 ioc->name, ioc->facts.MsgVersion));
3299 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3300 // set MsgVersion and HeaderVersion host driver was built with
3301 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3302 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003304 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3305 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3306 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3307 return -99;
3308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3310
Kashyap, Desai2f187862009-05-29 16:52:37 +05303311 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 /* Save the upper 32-bits of the request
3313 * (reply) and sense buffers.
3314 */
3315 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3316 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3317 } else {
3318 /* Force 32-bit addressing */
3319 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3320 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3321 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003322
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3324 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003325 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3326 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
Prakash, Sathya436ace72007-07-24 15:42:08 +05303328 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 ioc->name, &ioc_init));
3330
3331 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3332 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003333 if (r != 0) {
3334 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
3338 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003339 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 */
3341
Prakash, Sathya436ace72007-07-24 15:42:08 +05303342 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003344
3345 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3346 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
3350 /* YIKES! SUPER IMPORTANT!!!
3351 * Poll IocState until _OPERATIONAL while IOC is doing
3352 * LoopInit and TargetDiscovery!
3353 */
3354 count = 0;
3355 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3356 state = mpt_GetIocState(ioc, 1);
3357 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3358 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003359 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 } else {
3361 mdelay(1);
3362 }
3363
3364 if (!cntdn) {
3365 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3366 ioc->name, (int)((count+5)/HZ));
3367 return -9;
3368 }
3369
3370 state = mpt_GetIocState(ioc, 1);
3371 count++;
3372 }
Eric Moore29dd3602007-09-14 18:46:51 -06003373 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 ioc->name, count));
3375
Eric Mooreba856d32006-07-11 17:34:01 -06003376 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 return r;
3378}
3379
3380/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003381/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 * SendPortEnable - Send PortEnable request to MPT adapter port.
3383 * @ioc: Pointer to MPT_ADAPTER structure
3384 * @portnum: Port number to enable
3385 * @sleepFlag: Specifies whether the process can sleep
3386 *
3387 * Send PortEnable to bring IOC to OPERATIONAL state.
3388 *
3389 * Returns 0 for success, non-zero for failure.
3390 */
3391static int
3392SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3393{
3394 PortEnable_t port_enable;
3395 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003396 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 int req_sz;
3398 int reply_sz;
3399
3400 /* Destination... */
3401 reply_sz = sizeof(MPIDefaultReply_t);
3402 memset(&reply_buf, 0, reply_sz);
3403
3404 req_sz = sizeof(PortEnable_t);
3405 memset(&port_enable, 0, req_sz);
3406
3407 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3408 port_enable.PortNumber = portnum;
3409/* port_enable.ChainOffset = 0; */
3410/* port_enable.MsgFlags = 0; */
3411/* port_enable.MsgContext = 0; */
3412
Prakash, Sathya436ace72007-07-24 15:42:08 +05303413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 ioc->name, portnum, &port_enable));
3415
3416 /* RAID FW may take a long time to enable
3417 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003418 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003419 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3420 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3421 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003422 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003423 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3424 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3425 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003427 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428}
3429
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003430/**
3431 * mpt_alloc_fw_memory - allocate firmware memory
3432 * @ioc: Pointer to MPT_ADAPTER structure
3433 * @size: total FW bytes
3434 *
3435 * If memory has already been allocated, the same (cached) value
3436 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303437 *
3438 * Return 0 if successfull, or non-zero for failure
3439 **/
3440int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3442{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303443 int rc;
3444
3445 if (ioc->cached_fw) {
3446 rc = 0; /* use already allocated memory */
3447 goto out;
3448 }
3449 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3451 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303452 rc = 0;
3453 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303455 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3456 if (!ioc->cached_fw) {
3457 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3458 ioc->name);
3459 rc = -1;
3460 } else {
3461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3462 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3463 ioc->alloc_total += size;
3464 rc = 0;
3465 }
3466 out:
3467 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303469
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003470/**
3471 * mpt_free_fw_memory - free firmware memory
3472 * @ioc: Pointer to MPT_ADAPTER structure
3473 *
3474 * If alt_img is NULL, delete from ioc structure.
3475 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303476 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477void
3478mpt_free_fw_memory(MPT_ADAPTER *ioc)
3479{
3480 int sz;
3481
Prakash, Sathya984621b2008-01-11 14:42:17 +05303482 if (!ioc->cached_fw)
3483 return;
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303486 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3487 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003488 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303489 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491}
3492
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003494/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3496 * @ioc: Pointer to MPT_ADAPTER structure
3497 * @sleepFlag: Specifies whether the process can sleep
3498 *
3499 * Returns 0 for success, >0 for handshake failure
3500 * <0 for fw upload failure.
3501 *
3502 * Remark: If bound IOC and a successful FWUpload was performed
3503 * on the bound IOC, the second image is discarded
3504 * and memory is free'd. Both channels must upload to prevent
3505 * IOC from running in degraded mode.
3506 */
3507static int
3508mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3509{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 u8 reply[sizeof(FWUploadReply_t)];
3511 FWUpload_t *prequest;
3512 FWUploadReply_t *preply;
3513 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 u32 flagsLength;
3515 int ii, sz, reply_sz;
3516 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303517 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 /* If the image size is 0, we are done.
3519 */
3520 if ((sz = ioc->facts.FWImageSize) == 0)
3521 return 0;
3522
Prakash, Sathya984621b2008-01-11 14:42:17 +05303523 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3524 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Eric Moore29dd3602007-09-14 18:46:51 -06003526 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3527 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003528
Eric Moorebc6e0892007-09-29 10:16:28 -06003529 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3530 kzalloc(ioc->req_sz, GFP_KERNEL);
3531 if (!prequest) {
3532 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3533 "while allocating memory \n", ioc->name));
3534 mpt_free_fw_memory(ioc);
3535 return -ENOMEM;
3536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
Eric Moorebc6e0892007-09-29 10:16:28 -06003538 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539
3540 reply_sz = sizeof(reply);
3541 memset(preply, 0, reply_sz);
3542
3543 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3544 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3545
3546 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3547 ptcsge->DetailsLength = 12;
3548 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3549 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003550 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303553 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3554 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3555 ioc->SGE_size;
3556 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3557 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3558 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003559 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303561 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3562 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Kashyap, Desai2f187862009-05-29 16:52:37 +05303564 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3565 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567 cmdStatus = -EFAULT;
3568 if (ii == 0) {
3569 /* Handshake transfer was complete and successful.
3570 * Check the Reply Frame.
3571 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303572 int status;
3573 status = le16_to_cpu(preply->IOCStatus) &
3574 MPI_IOCSTATUS_MASK;
3575 if (status == MPI_IOCSTATUS_SUCCESS &&
3576 ioc->facts.FWImageSize ==
3577 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303580 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 ioc->name, cmdStatus));
3582
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003583
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303585 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3586 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 mpt_free_fw_memory(ioc);
3588 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003589 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
3591 return cmdStatus;
3592}
3593
3594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003595/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 * mpt_downloadboot - DownloadBoot code
3597 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003598 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 * @sleepFlag: Specifies whether the process can sleep
3600 *
3601 * FwDownloadBoot requires Programmed IO access.
3602 *
3603 * Returns 0 for success
3604 * -1 FW Image size is 0
3605 * -2 No valid cached_fw Pointer
3606 * <0 for fw upload failure.
3607 */
3608static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003609mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 MpiExtImageHeader_t *pExtImage;
3612 u32 fwSize;
3613 u32 diag0val;
3614 int count;
3615 u32 *ptrFw;
3616 u32 diagRwData;
3617 u32 nextImage;
3618 u32 load_addr;
3619 u32 ioc_state=0;
3620
Prakash, Sathya436ace72007-07-24 15:42:08 +05303621 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003622 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003623
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3625 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3626 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3629 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3630
3631 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3632
3633 /* wait 1 msec */
3634 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003635 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 } else {
3637 mdelay (1);
3638 }
3639
3640 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3641 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3642
3643 for (count = 0; count < 30; count ++) {
3644 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3645 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303646 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 ioc->name, count));
3648 break;
3649 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003650 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003652 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003654 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
3656 }
3657
3658 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303659 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003660 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 ioc->name, diag0val));
3662 return -3;
3663 }
3664
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3667 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3670 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3671
3672 /* Set the DiagRwEn and Disable ARM bits */
3673 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3674
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 fwSize = (pFwHeader->ImageSize + 3)/4;
3676 ptrFw = (u32 *) pFwHeader;
3677
3678 /* Write the LoadStartAddress to the DiagRw Address Register
3679 * using Programmed IO
3680 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003681 if (ioc->errata_flag_1064)
3682 pci_enable_io_access(ioc->pcidev);
3683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303685 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 ioc->name, pFwHeader->LoadStartAddress));
3687
Prakash, Sathya436ace72007-07-24 15:42:08 +05303688 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 ioc->name, fwSize*4, ptrFw));
3690 while (fwSize--) {
3691 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3692 }
3693
3694 nextImage = pFwHeader->NextImageHeaderOffset;
3695 while (nextImage) {
3696 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3697
3698 load_addr = pExtImage->LoadStartAddress;
3699
3700 fwSize = (pExtImage->ImageSize + 3) >> 2;
3701 ptrFw = (u32 *)pExtImage;
3702
Prakash, Sathya436ace72007-07-24 15:42:08 +05303703 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 +02003704 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3706
3707 while (fwSize--) {
3708 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3709 }
3710 nextImage = pExtImage->NextImageHeaderOffset;
3711 }
3712
3713 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303714 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3716
3717 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303718 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3720
3721 /* Clear the internal flash bad bit - autoincrementing register,
3722 * so must do two writes.
3723 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003724 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003725 /*
3726 * 1030 and 1035 H/W errata, workaround to access
3727 * the ClearFlashBadSignatureBit
3728 */
3729 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3730 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3731 diagRwData |= 0x40000000;
3732 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3733 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3734
3735 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3736 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3737 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3738 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3739
3740 /* wait 1 msec */
3741 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003742 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003743 } else {
3744 mdelay (1);
3745 }
3746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003748 if (ioc->errata_flag_1064)
3749 pci_disable_io_access(ioc->pcidev);
3750
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003753 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003755 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303756 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 ioc->name, diag0val));
3758 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3759
3760 /* Write 0xFF to reset the sequencer */
3761 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3762
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003763 if (ioc->bus_type == SAS) {
3764 ioc_state = mpt_GetIocState(ioc, 0);
3765 if ( (GetIocFacts(ioc, sleepFlag,
3766 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303767 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003768 ioc->name, ioc_state));
3769 return -EFAULT;
3770 }
3771 }
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 for (count=0; count<HZ*20; count++) {
3774 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303775 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3776 "downloadboot successful! (count=%d) IocState=%x\n",
3777 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003778 if (ioc->bus_type == SAS) {
3779 return 0;
3780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303782 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3783 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 ioc->name));
3785 return -EFAULT;
3786 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303787 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3788 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 ioc->name));
3790 return 0;
3791 }
3792 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003793 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 } else {
3795 mdelay (10);
3796 }
3797 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303798 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3799 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 return -EFAULT;
3801}
3802
3803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003804/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 * KickStart - Perform hard reset of MPT adapter.
3806 * @ioc: Pointer to MPT_ADAPTER structure
3807 * @force: Force hard reset
3808 * @sleepFlag: Specifies whether the process can sleep
3809 *
3810 * This routine places MPT adapter in diagnostic mode via the
3811 * WriteSequence register, and then performs a hard reset of adapter
3812 * via the Diagnostic register.
3813 *
3814 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3815 * or NO_SLEEP (interrupt thread, use mdelay)
3816 * force - 1 if doorbell active, board fault state
3817 * board operational, IOC_RECOVERY or
3818 * IOC_BRINGUP and there is an alt_ioc.
3819 * 0 else
3820 *
3821 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003822 * 1 - hard reset, READY
3823 * 0 - no reset due to History bit, READY
3824 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 * OR reset but failed to come READY
3826 * -2 - no reset, could not enter DIAG mode
3827 * -3 - reset but bad FW bit
3828 */
3829static int
3830KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3831{
3832 int hard_reset_done = 0;
3833 u32 ioc_state=0;
3834 int cnt,cntdn;
3835
Eric Moore29dd3602007-09-14 18:46:51 -06003836 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003837 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 /* Always issue a Msg Unit Reset first. This will clear some
3839 * SCSI bus hang conditions.
3840 */
3841 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3842
3843 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003844 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 } else {
3846 mdelay (1000);
3847 }
3848 }
3849
3850 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3851 if (hard_reset_done < 0)
3852 return hard_reset_done;
3853
Prakash, Sathya436ace72007-07-24 15:42:08 +05303854 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003855 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
3857 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3858 for (cnt=0; cnt<cntdn; cnt++) {
3859 ioc_state = mpt_GetIocState(ioc, 1);
3860 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303861 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 ioc->name, cnt));
3863 return hard_reset_done;
3864 }
3865 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003866 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 } else {
3868 mdelay (10);
3869 }
3870 }
3871
Eric Moore29dd3602007-09-14 18:46:51 -06003872 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3873 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 return -1;
3875}
3876
3877/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003878/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 * mpt_diag_reset - Perform hard reset of the adapter.
3880 * @ioc: Pointer to MPT_ADAPTER structure
3881 * @ignore: Set if to honor and clear to ignore
3882 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003883 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 * else set to NO_SLEEP (use mdelay instead)
3885 *
3886 * This routine places the adapter in diagnostic mode via the
3887 * WriteSequence register and then performs a hard reset of adapter
3888 * via the Diagnostic register. Adapter should be in ready state
3889 * upon successful completion.
3890 *
3891 * Returns: 1 hard reset successful
3892 * 0 no reset performed because reset history bit set
3893 * -2 enabling diagnostic mode failed
3894 * -3 diagnostic reset failed
3895 */
3896static int
3897mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3898{
3899 u32 diag0val;
3900 u32 doorbell;
3901 int hard_reset_done = 0;
3902 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303904 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303905 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
Eric Moorecd2c6192007-01-29 09:47:47 -07003907 /* Clear any existing interrupts */
3908 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3909
Eric Moore87cf8982006-06-27 16:09:26 -06003910 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303911
3912 if (!ignore)
3913 return 0;
3914
Prakash, Sathya436ace72007-07-24 15:42:08 +05303915 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003916 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003917 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3918 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3919 if (sleepFlag == CAN_SLEEP)
3920 msleep(1);
3921 else
3922 mdelay(1);
3923
Kashyap, Desaid1306912009-08-05 12:53:51 +05303924 /*
3925 * Call each currently registered protocol IOC reset handler
3926 * with pre-reset indication.
3927 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3928 * MptResetHandlers[] registered yet.
3929 */
3930 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3931 if (MptResetHandlers[cb_idx])
3932 (*(MptResetHandlers[cb_idx]))(ioc,
3933 MPT_IOC_PRE_RESET);
3934 }
3935
Eric Moore87cf8982006-06-27 16:09:26 -06003936 for (count = 0; count < 60; count ++) {
3937 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3938 doorbell &= MPI_IOC_STATE_MASK;
3939
Prakash, Sathya436ace72007-07-24 15:42:08 +05303940 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003941 "looking for READY STATE: doorbell=%x"
3942 " count=%d\n",
3943 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303944
Eric Moore87cf8982006-06-27 16:09:26 -06003945 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003946 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003947 }
3948
3949 /* wait 1 sec */
3950 if (sleepFlag == CAN_SLEEP)
3951 msleep(1000);
3952 else
3953 mdelay(1000);
3954 }
3955 return -1;
3956 }
3957
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 /* Use "Diagnostic reset" method! (only thing available!) */
3959 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3960
Prakash, Sathya436ace72007-07-24 15:42:08 +05303961 if (ioc->debug_level & MPT_DEBUG) {
3962 if (ioc->alt_ioc)
3963 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3964 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
3968 /* Do the reset if we are told to ignore the reset history
3969 * or if the reset history is 0
3970 */
3971 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3972 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3973 /* Write magic sequence to WriteSequence register
3974 * Loop until in diagnostic mode
3975 */
3976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3981 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3982
3983 /* wait 100 msec */
3984 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003985 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 } else {
3987 mdelay (100);
3988 }
3989
3990 count++;
3991 if (count > 20) {
3992 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3993 ioc->name, diag0val);
3994 return -2;
3995
3996 }
3997
3998 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3999
Prakash, Sathya436ace72007-07-24 15:42:08 +05304000 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 ioc->name, diag0val));
4002 }
4003
Prakash, Sathya436ace72007-07-24 15:42:08 +05304004 if (ioc->debug_level & MPT_DEBUG) {
4005 if (ioc->alt_ioc)
4006 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4007 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 /*
4011 * Disable the ARM (Bug fix)
4012 *
4013 */
4014 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004015 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017 /*
4018 * Now hit the reset bit in the Diagnostic register
4019 * (THE BIG HAMMER!) (Clears DRWE bit).
4020 */
4021 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4022 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304023 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 ioc->name));
4025
4026 /*
4027 * Call each currently registered protocol IOC reset handler
4028 * with pre-reset indication.
4029 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4030 * MptResetHandlers[] registered yet.
4031 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304032 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4033 if (MptResetHandlers[cb_idx]) {
4034 mpt_signal_reset(cb_idx,
4035 ioc, MPT_IOC_PRE_RESET);
4036 if (ioc->alt_ioc) {
4037 mpt_signal_reset(cb_idx,
4038 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 }
4040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 }
4042
Eric Moore0ccdb002006-07-11 17:33:13 -06004043 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304044 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004045 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304046 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4047 else
4048 cached_fw = NULL;
4049 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 /* If the DownloadBoot operation fails, the
4051 * IOC will be left unusable. This is a fatal error
4052 * case. _diag_reset will return < 0
4053 */
4054 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304055 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4057 break;
4058 }
4059
Prakash, Sathya436ace72007-07-24 15:42:08 +05304060 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304061 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 /* wait 1 sec */
4063 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004064 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 } else {
4066 mdelay (1000);
4067 }
4068 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304069 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004070 printk(MYIOC_s_WARN_FMT
4071 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 }
4073
4074 } else {
4075 /* Wait for FW to reload and for board
4076 * to go to the READY state.
4077 * Maximum wait is 60 seconds.
4078 * If fail, no error will check again
4079 * with calling program.
4080 */
4081 for (count = 0; count < 60; count ++) {
4082 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4083 doorbell &= MPI_IOC_STATE_MASK;
4084
Kashyap, Desai2f187862009-05-29 16:52:37 +05304085 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4086 "looking for READY STATE: doorbell=%x"
4087 " count=%d\n", ioc->name, doorbell, count));
4088
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 if (doorbell == MPI_IOC_STATE_READY) {
4090 break;
4091 }
4092
4093 /* wait 1 sec */
4094 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004095 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 } else {
4097 mdelay (1000);
4098 }
4099 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304100
4101 if (doorbell != MPI_IOC_STATE_READY)
4102 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4103 "after reset! IocState=%x", ioc->name,
4104 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 }
4106 }
4107
4108 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304109 if (ioc->debug_level & MPT_DEBUG) {
4110 if (ioc->alt_ioc)
4111 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4112 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4113 ioc->name, diag0val, diag1val));
4114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
4116 /* Clear RESET_HISTORY bit! Place board in the
4117 * diagnostic mode to update the diag register.
4118 */
4119 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4120 count = 0;
4121 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4122 /* Write magic sequence to WriteSequence register
4123 * Loop until in diagnostic mode
4124 */
4125 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4126 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4127 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4130 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4131
4132 /* wait 100 msec */
4133 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004134 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 } else {
4136 mdelay (100);
4137 }
4138
4139 count++;
4140 if (count > 20) {
4141 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4142 ioc->name, diag0val);
4143 break;
4144 }
4145 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4146 }
4147 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4148 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4149 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4150 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4151 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4152 ioc->name);
4153 }
4154
4155 /* Disable Diagnostic Mode
4156 */
4157 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4158
4159 /* Check FW reload status flags.
4160 */
4161 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4162 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4163 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4164 ioc->name, diag0val);
4165 return -3;
4166 }
4167
Prakash, Sathya436ace72007-07-24 15:42:08 +05304168 if (ioc->debug_level & MPT_DEBUG) {
4169 if (ioc->alt_ioc)
4170 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
4175 /*
4176 * Reset flag that says we've enabled event notification
4177 */
4178 ioc->facts.EventState = 0;
4179
4180 if (ioc->alt_ioc)
4181 ioc->alt_ioc->facts.EventState = 0;
4182
4183 return hard_reset_done;
4184}
4185
4186/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004187/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 * SendIocReset - Send IOCReset request to MPT adapter.
4189 * @ioc: Pointer to MPT_ADAPTER structure
4190 * @reset_type: reset type, expected values are
4191 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004192 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 *
4194 * Send IOCReset request to the MPT adapter.
4195 *
4196 * Returns 0 for success, non-zero for failure.
4197 */
4198static int
4199SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4200{
4201 int r;
4202 u32 state;
4203 int cntdn, count;
4204
Prakash, Sathya436ace72007-07-24 15:42:08 +05304205 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ioc->name, reset_type));
4207 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4208 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4209 return r;
4210
4211 /* FW ACK'd request, wait for READY state
4212 */
4213 count = 0;
4214 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4215
4216 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4217 cntdn--;
4218 count++;
4219 if (!cntdn) {
4220 if (sleepFlag != CAN_SLEEP)
4221 count *= 10;
4222
Kashyap, Desai2f187862009-05-29 16:52:37 +05304223 printk(MYIOC_s_ERR_FMT
4224 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4225 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 return -ETIME;
4227 }
4228
4229 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004230 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 } else {
4232 mdelay (1); /* 1 msec delay */
4233 }
4234 }
4235
4236 /* TODO!
4237 * Cleanup all event stuff for this IOC; re-issue EventNotification
4238 * request if needed.
4239 */
4240 if (ioc->facts.Function)
4241 ioc->facts.EventState = 0;
4242
4243 return 0;
4244}
4245
4246/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004247/**
4248 * initChainBuffers - Allocate memory for and initialize chain buffers
4249 * @ioc: Pointer to MPT_ADAPTER structure
4250 *
4251 * Allocates memory for and initializes chain buffers,
4252 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 */
4254static int
4255initChainBuffers(MPT_ADAPTER *ioc)
4256{
4257 u8 *mem;
4258 int sz, ii, num_chain;
4259 int scale, num_sge, numSGE;
4260
4261 /* ReqToChain size must equal the req_depth
4262 * index = req_idx
4263 */
4264 if (ioc->ReqToChain == NULL) {
4265 sz = ioc->req_depth * sizeof(int);
4266 mem = kmalloc(sz, GFP_ATOMIC);
4267 if (mem == NULL)
4268 return -1;
4269
4270 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304271 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 ioc->name, mem, sz));
4273 mem = kmalloc(sz, GFP_ATOMIC);
4274 if (mem == NULL)
4275 return -1;
4276
4277 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304278 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 ioc->name, mem, sz));
4280 }
4281 for (ii = 0; ii < ioc->req_depth; ii++) {
4282 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4283 }
4284
4285 /* ChainToChain size must equal the total number
4286 * of chain buffers to be allocated.
4287 * index = chain_idx
4288 *
4289 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004290 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 *
4292 * num_sge = num sge in request frame + last chain buffer
4293 * scale = num sge per chain buffer if no chain element
4294 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304295 scale = ioc->req_sz / ioc->SGE_size;
4296 if (ioc->sg_addr_size == sizeof(u64))
4297 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304299 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304301 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304303 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304305 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4306 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304308 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 ioc->name, num_sge, numSGE));
4310
Kashyap, Desai2f187862009-05-29 16:52:37 +05304311 if (ioc->bus_type == FC) {
4312 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4313 numSGE = MPT_SCSI_FC_SG_DEPTH;
4314 } else {
4315 if (numSGE > MPT_SCSI_SG_DEPTH)
4316 numSGE = MPT_SCSI_SG_DEPTH;
4317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
4319 num_chain = 1;
4320 while (numSGE - num_sge > 0) {
4321 num_chain++;
4322 num_sge += (scale - 1);
4323 }
4324 num_chain++;
4325
Prakash, Sathya436ace72007-07-24 15:42:08 +05304326 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 ioc->name, numSGE, num_sge, num_chain));
4328
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004329 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004331 else if (ioc->bus_type == SAS)
4332 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 else
4334 num_chain *= MPT_FC_CAN_QUEUE;
4335
4336 ioc->num_chain = num_chain;
4337
4338 sz = num_chain * sizeof(int);
4339 if (ioc->ChainToChain == NULL) {
4340 mem = kmalloc(sz, GFP_ATOMIC);
4341 if (mem == NULL)
4342 return -1;
4343
4344 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304345 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 ioc->name, mem, sz));
4347 } else {
4348 mem = (u8 *) ioc->ChainToChain;
4349 }
4350 memset(mem, 0xFF, sz);
4351 return num_chain;
4352}
4353
4354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004355/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4357 * @ioc: Pointer to MPT_ADAPTER structure
4358 *
4359 * This routine allocates memory for the MPT reply and request frame
4360 * pools (if necessary), and primes the IOC reply FIFO with
4361 * reply frames.
4362 *
4363 * Returns 0 for success, non-zero for failure.
4364 */
4365static int
4366PrimeIocFifos(MPT_ADAPTER *ioc)
4367{
4368 MPT_FRAME_HDR *mf;
4369 unsigned long flags;
4370 dma_addr_t alloc_dma;
4371 u8 *mem;
4372 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304373 u64 dma_mask;
4374
4375 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
4377 /* Prime reply FIFO... */
4378
4379 if (ioc->reply_frames == NULL) {
4380 if ( (num_chain = initChainBuffers(ioc)) < 0)
4381 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304382 /*
4383 * 1078 errata workaround for the 36GB limitation
4384 */
4385 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004386 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304387 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4388 && !pci_set_consistent_dma_mask(ioc->pcidev,
4389 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004390 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304391 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4392 "setting 35 bit addressing for "
4393 "Request/Reply/Chain and Sense Buffers\n",
4394 ioc->name));
4395 } else {
4396 /*Reseting DMA mask to 64 bit*/
4397 pci_set_dma_mask(ioc->pcidev,
4398 DMA_BIT_MASK(64));
4399 pci_set_consistent_dma_mask(ioc->pcidev,
4400 DMA_BIT_MASK(64));
4401
4402 printk(MYIOC_s_ERR_FMT
4403 "failed setting 35 bit addressing for "
4404 "Request/Reply/Chain and Sense Buffers\n",
4405 ioc->name);
4406 return -1;
4407 }
4408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
4410 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304411 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 ioc->name, reply_sz, reply_sz));
4415
4416 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304419 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 ioc->name, sz, sz));
4421 total_size += sz;
4422
4423 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304424 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 ioc->name, sz, sz, num_chain));
4428
4429 total_size += sz;
4430 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4431 if (mem == NULL) {
4432 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4433 ioc->name);
4434 goto out_fail;
4435 }
4436
Prakash, Sathya436ace72007-07-24 15:42:08 +05304437 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4439
4440 memset(mem, 0, total_size);
4441 ioc->alloc_total += total_size;
4442 ioc->alloc = mem;
4443 ioc->alloc_dma = alloc_dma;
4444 ioc->alloc_sz = total_size;
4445 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4446 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4447
Prakash, Sathya436ace72007-07-24 15:42:08 +05304448 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004449 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4450
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 alloc_dma += reply_sz;
4452 mem += reply_sz;
4453
4454 /* Request FIFO - WE manage this! */
4455
4456 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4457 ioc->req_frames_dma = alloc_dma;
4458
Prakash, Sathya436ace72007-07-24 15:42:08 +05304459 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 ioc->name, mem, (void *)(ulong)alloc_dma));
4461
4462 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4463
4464#if defined(CONFIG_MTRR) && 0
4465 /*
4466 * Enable Write Combining MTRR for IOC's memory region.
4467 * (at least as much as we can; "size and base must be
4468 * multiples of 4 kiB"
4469 */
4470 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4471 sz,
4472 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304473 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 ioc->name, ioc->req_frames_dma, sz));
4475#endif
4476
4477 for (i = 0; i < ioc->req_depth; i++) {
4478 alloc_dma += ioc->req_sz;
4479 mem += ioc->req_sz;
4480 }
4481
4482 ioc->ChainBuffer = mem;
4483 ioc->ChainBufferDMA = alloc_dma;
4484
Prakash, Sathya436ace72007-07-24 15:42:08 +05304485 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4487
4488 /* Initialize the free chain Q.
4489 */
4490
4491 INIT_LIST_HEAD(&ioc->FreeChainQ);
4492
4493 /* Post the chain buffers to the FreeChainQ.
4494 */
4495 mem = (u8 *)ioc->ChainBuffer;
4496 for (i=0; i < num_chain; i++) {
4497 mf = (MPT_FRAME_HDR *) mem;
4498 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4499 mem += ioc->req_sz;
4500 }
4501
4502 /* Initialize Request frames linked list
4503 */
4504 alloc_dma = ioc->req_frames_dma;
4505 mem = (u8 *) ioc->req_frames;
4506
4507 spin_lock_irqsave(&ioc->FreeQlock, flags);
4508 INIT_LIST_HEAD(&ioc->FreeQ);
4509 for (i = 0; i < ioc->req_depth; i++) {
4510 mf = (MPT_FRAME_HDR *) mem;
4511
4512 /* Queue REQUESTs *internally*! */
4513 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4514
4515 mem += ioc->req_sz;
4516 }
4517 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4518
4519 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4520 ioc->sense_buf_pool =
4521 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4522 if (ioc->sense_buf_pool == NULL) {
4523 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4524 ioc->name);
4525 goto out_fail;
4526 }
4527
4528 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4529 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304530 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4532
4533 }
4534
4535 /* Post Reply frames to FIFO
4536 */
4537 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304538 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4540
4541 for (i = 0; i < ioc->reply_depth; i++) {
4542 /* Write each address to the IOC! */
4543 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4544 alloc_dma += ioc->reply_sz;
4545 }
4546
Andrew Morton8e20ce92009-06-18 16:49:17 -07004547 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304548 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4549 ioc->dma_mask))
4550 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4551 "restoring 64 bit addressing\n", ioc->name));
4552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return 0;
4554
4555out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 if (ioc->alloc != NULL) {
4558 sz = ioc->alloc_sz;
4559 pci_free_consistent(ioc->pcidev,
4560 sz,
4561 ioc->alloc, ioc->alloc_dma);
4562 ioc->reply_frames = NULL;
4563 ioc->req_frames = NULL;
4564 ioc->alloc_total -= sz;
4565 }
4566 if (ioc->sense_buf_pool != NULL) {
4567 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4568 pci_free_consistent(ioc->pcidev,
4569 sz,
4570 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4571 ioc->sense_buf_pool = NULL;
4572 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304573
Andrew Morton8e20ce92009-06-18 16:49:17 -07004574 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304575 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4576 DMA_BIT_MASK(64)))
4577 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4578 "restoring 64 bit addressing\n", ioc->name));
4579
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 return -1;
4581}
4582
4583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4584/**
4585 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4586 * from IOC via doorbell handshake method.
4587 * @ioc: Pointer to MPT_ADAPTER structure
4588 * @reqBytes: Size of the request in bytes
4589 * @req: Pointer to MPT request frame
4590 * @replyBytes: Expected size of the reply in bytes
4591 * @u16reply: Pointer to area where reply should be written
4592 * @maxwait: Max wait time for a reply (in seconds)
4593 * @sleepFlag: Specifies whether the process can sleep
4594 *
4595 * NOTES: It is the callers responsibility to byte-swap fields in the
4596 * request which are greater than 1 byte in size. It is also the
4597 * callers responsibility to byte-swap response fields which are
4598 * greater than 1 byte in size.
4599 *
4600 * Returns 0 for success, non-zero for failure.
4601 */
4602static int
4603mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004604 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 MPIDefaultReply_t *mptReply;
4607 int failcnt = 0;
4608 int t;
4609
4610 /*
4611 * Get ready to cache a handshake reply
4612 */
4613 ioc->hs_reply_idx = 0;
4614 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4615 mptReply->MsgLength = 0;
4616
4617 /*
4618 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4619 * then tell IOC that we want to handshake a request of N words.
4620 * (WRITE u32val to Doorbell reg).
4621 */
4622 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4623 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4624 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4625 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4626
4627 /*
4628 * Wait for IOC's doorbell handshake int
4629 */
4630 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4631 failcnt++;
4632
Prakash, Sathya436ace72007-07-24 15:42:08 +05304633 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4635
4636 /* Read doorbell and check for active bit */
4637 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4638 return -1;
4639
4640 /*
4641 * Clear doorbell int (WRITE 0 to IntStatus reg),
4642 * then wait for IOC to ACKnowledge that it's ready for
4643 * our handshake request.
4644 */
4645 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4646 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4647 failcnt++;
4648
4649 if (!failcnt) {
4650 int ii;
4651 u8 *req_as_bytes = (u8 *) req;
4652
4653 /*
4654 * Stuff request words via doorbell handshake,
4655 * with ACK from IOC for each.
4656 */
4657 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4658 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4659 (req_as_bytes[(ii*4) + 1] << 8) |
4660 (req_as_bytes[(ii*4) + 2] << 16) |
4661 (req_as_bytes[(ii*4) + 3] << 24));
4662
4663 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4664 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4665 failcnt++;
4666 }
4667
Prakash, Sathya436ace72007-07-24 15:42:08 +05304668 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004669 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Prakash, Sathya436ace72007-07-24 15:42:08 +05304671 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4673
4674 /*
4675 * Wait for completion of doorbell handshake reply from the IOC
4676 */
4677 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4678 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004679
Prakash, Sathya436ace72007-07-24 15:42:08 +05304680 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4682
4683 /*
4684 * Copy out the cached reply...
4685 */
4686 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4687 u16reply[ii] = ioc->hs_reply[ii];
4688 } else {
4689 return -99;
4690 }
4691
4692 return -failcnt;
4693}
4694
4695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004696/**
4697 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 * @ioc: Pointer to MPT_ADAPTER structure
4699 * @howlong: How long to wait (in seconds)
4700 * @sleepFlag: Specifies whether the process can sleep
4701 *
4702 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004703 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4704 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 *
4706 * Returns a negative value on failure, else wait loop count.
4707 */
4708static int
4709WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4710{
4711 int cntdn;
4712 int count = 0;
4713 u32 intstat=0;
4714
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004715 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716
4717 if (sleepFlag == CAN_SLEEP) {
4718 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004719 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4721 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 count++;
4724 }
4725 } else {
4726 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004727 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4729 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4730 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 count++;
4732 }
4733 }
4734
4735 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304736 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 ioc->name, count));
4738 return count;
4739 }
4740
4741 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4742 ioc->name, count, intstat);
4743 return -1;
4744}
4745
4746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004747/**
4748 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 * @ioc: Pointer to MPT_ADAPTER structure
4750 * @howlong: How long to wait (in seconds)
4751 * @sleepFlag: Specifies whether the process can sleep
4752 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004753 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4754 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 *
4756 * Returns a negative value on failure, else wait loop count.
4757 */
4758static int
4759WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4760{
4761 int cntdn;
4762 int count = 0;
4763 u32 intstat=0;
4764
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004765 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 if (sleepFlag == CAN_SLEEP) {
4767 while (--cntdn) {
4768 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4769 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4770 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004771 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 count++;
4773 }
4774 } else {
4775 while (--cntdn) {
4776 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4777 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4778 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004779 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 count++;
4781 }
4782 }
4783
4784 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304785 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 ioc->name, count, howlong));
4787 return count;
4788 }
4789
4790 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4791 ioc->name, count, intstat);
4792 return -1;
4793}
4794
4795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004796/**
4797 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 * @ioc: Pointer to MPT_ADAPTER structure
4799 * @howlong: How long to wait (in seconds)
4800 * @sleepFlag: Specifies whether the process can sleep
4801 *
4802 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4803 * Reply is cached to IOC private area large enough to hold a maximum
4804 * of 128 bytes of reply data.
4805 *
4806 * Returns a negative value on failure, else size of reply in WORDS.
4807 */
4808static int
4809WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4810{
4811 int u16cnt = 0;
4812 int failcnt = 0;
4813 int t;
4814 u16 *hs_reply = ioc->hs_reply;
4815 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4816 u16 hword;
4817
4818 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4819
4820 /*
4821 * Get first two u16's so we can look at IOC's intended reply MsgLength
4822 */
4823 u16cnt=0;
4824 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4825 failcnt++;
4826 } else {
4827 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4828 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4829 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4830 failcnt++;
4831 else {
4832 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4833 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4834 }
4835 }
4836
Prakash, Sathya436ace72007-07-24 15:42:08 +05304837 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004838 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4840
4841 /*
4842 * If no error (and IOC said MsgLength is > 0), piece together
4843 * reply 16 bits at a time.
4844 */
4845 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4846 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4847 failcnt++;
4848 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4849 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004850 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 hs_reply[u16cnt] = hword;
4852 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4853 }
4854
4855 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4856 failcnt++;
4857 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4858
4859 if (failcnt) {
4860 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4861 ioc->name);
4862 return -failcnt;
4863 }
4864#if 0
4865 else if (u16cnt != (2 * mptReply->MsgLength)) {
4866 return -101;
4867 }
4868 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4869 return -102;
4870 }
4871#endif
4872
Prakash, Sathya436ace72007-07-24 15:42:08 +05304873 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004874 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Prakash, Sathya436ace72007-07-24 15:42:08 +05304876 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 ioc->name, t, u16cnt/2));
4878 return u16cnt/2;
4879}
4880
4881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004882/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 * GetLanConfigPages - Fetch LANConfig pages.
4884 * @ioc: Pointer to MPT_ADAPTER structure
4885 *
4886 * Return: 0 for success
4887 * -ENOMEM if no memory available
4888 * -EPERM if not allowed due to ISR context
4889 * -EAGAIN if no msg frames currently available
4890 * -EFAULT for non-successful reply or no reply (timeout)
4891 */
4892static int
4893GetLanConfigPages(MPT_ADAPTER *ioc)
4894{
4895 ConfigPageHeader_t hdr;
4896 CONFIGPARMS cfg;
4897 LANPage0_t *ppage0_alloc;
4898 dma_addr_t page0_dma;
4899 LANPage1_t *ppage1_alloc;
4900 dma_addr_t page1_dma;
4901 int rc = 0;
4902 int data_sz;
4903 int copy_sz;
4904
4905 /* Get LAN Page 0 header */
4906 hdr.PageVersion = 0;
4907 hdr.PageLength = 0;
4908 hdr.PageNumber = 0;
4909 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004910 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 cfg.physAddr = -1;
4912 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4913 cfg.dir = 0;
4914 cfg.pageAddr = 0;
4915 cfg.timeout = 0;
4916
4917 if ((rc = mpt_config(ioc, &cfg)) != 0)
4918 return rc;
4919
4920 if (hdr.PageLength > 0) {
4921 data_sz = hdr.PageLength * 4;
4922 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4923 rc = -ENOMEM;
4924 if (ppage0_alloc) {
4925 memset((u8 *)ppage0_alloc, 0, data_sz);
4926 cfg.physAddr = page0_dma;
4927 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4928
4929 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4930 /* save the data */
4931 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4932 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4933
4934 }
4935
4936 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4937
4938 /* FIXME!
4939 * Normalize endianness of structure data,
4940 * by byte-swapping all > 1 byte fields!
4941 */
4942
4943 }
4944
4945 if (rc)
4946 return rc;
4947 }
4948
4949 /* Get LAN Page 1 header */
4950 hdr.PageVersion = 0;
4951 hdr.PageLength = 0;
4952 hdr.PageNumber = 1;
4953 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004954 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 cfg.physAddr = -1;
4956 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4957 cfg.dir = 0;
4958 cfg.pageAddr = 0;
4959
4960 if ((rc = mpt_config(ioc, &cfg)) != 0)
4961 return rc;
4962
4963 if (hdr.PageLength == 0)
4964 return 0;
4965
4966 data_sz = hdr.PageLength * 4;
4967 rc = -ENOMEM;
4968 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4969 if (ppage1_alloc) {
4970 memset((u8 *)ppage1_alloc, 0, data_sz);
4971 cfg.physAddr = page1_dma;
4972 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4973
4974 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4975 /* save the data */
4976 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4977 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4978 }
4979
4980 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4981
4982 /* FIXME!
4983 * Normalize endianness of structure data,
4984 * by byte-swapping all > 1 byte fields!
4985 */
4986
4987 }
4988
4989 return rc;
4990}
4991
4992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004993/**
4994 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004995 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004996 * @persist_opcode: see below
4997 *
4998 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4999 * devices not currently present.
5000 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5001 *
5002 * NOTE: Don't use not this function during interrupt time.
5003 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005004 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005005 */
5006
5007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5008int
5009mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5010{
5011 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5012 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5013 MPT_FRAME_HDR *mf = NULL;
5014 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305015 int ret = 0;
5016 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005017
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305018 mutex_lock(&ioc->mptbase_cmds.mutex);
5019
5020 /* init the internal cmd struct */
5021 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5022 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005023
5024 /* insure garbage is not sent to fw */
5025 switch(persist_opcode) {
5026
5027 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5028 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5029 break;
5030
5031 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305032 ret = -1;
5033 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005034 }
5035
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305036 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5037 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005038
5039 /* Get a MF for this command.
5040 */
5041 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305042 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5043 ret = -1;
5044 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005045 }
5046
5047 mpi_hdr = (MPIHeader_t *) mf;
5048 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5049 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5050 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5051 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5052 sasIoUnitCntrReq->Operation = persist_opcode;
5053
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005054 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305055 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5056 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5057 ret = -ETIME;
5058 printk(KERN_DEBUG "%s: failed\n", __func__);
5059 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5060 goto out;
5061 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005062 printk(MYIOC_s_WARN_FMT
5063 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5064 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305065 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305066 mpt_free_msg_frame(ioc, mf);
5067 }
5068 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005069 }
5070
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305071 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5072 ret = -1;
5073 goto out;
5074 }
5075
5076 sasIoUnitCntrReply =
5077 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5078 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5079 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5080 __func__, sasIoUnitCntrReply->IOCStatus,
5081 sasIoUnitCntrReply->IOCLogInfo);
5082 printk(KERN_DEBUG "%s: failed\n", __func__);
5083 ret = -1;
5084 } else
5085 printk(KERN_DEBUG "%s: success\n", __func__);
5086 out:
5087
5088 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5089 mutex_unlock(&ioc->mptbase_cmds.mutex);
5090 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005091}
5092
5093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005094
5095static void
5096mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5097 MpiEventDataRaid_t * pRaidEventData)
5098{
5099 int volume;
5100 int reason;
5101 int disk;
5102 int status;
5103 int flags;
5104 int state;
5105
5106 volume = pRaidEventData->VolumeID;
5107 reason = pRaidEventData->ReasonCode;
5108 disk = pRaidEventData->PhysDiskNum;
5109 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5110 flags = (status >> 0) & 0xff;
5111 state = (status >> 8) & 0xff;
5112
5113 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5114 return;
5115 }
5116
5117 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5118 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5119 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005120 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5121 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005122 } else {
5123 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5124 ioc->name, volume);
5125 }
5126
5127 switch(reason) {
5128 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5129 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5130 ioc->name);
5131 break;
5132
5133 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5134
5135 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5136 ioc->name);
5137 break;
5138
5139 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5140 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5141 ioc->name);
5142 break;
5143
5144 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5145 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5146 ioc->name,
5147 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5148 ? "optimal"
5149 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5150 ? "degraded"
5151 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5152 ? "failed"
5153 : "state unknown",
5154 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5155 ? ", enabled" : "",
5156 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5157 ? ", quiesced" : "",
5158 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5159 ? ", resync in progress" : "" );
5160 break;
5161
5162 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5163 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5164 ioc->name, disk);
5165 break;
5166
5167 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5168 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5169 ioc->name);
5170 break;
5171
5172 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5173 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5174 ioc->name);
5175 break;
5176
5177 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5178 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5179 ioc->name);
5180 break;
5181
5182 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5183 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5184 ioc->name,
5185 state == MPI_PHYSDISK0_STATUS_ONLINE
5186 ? "online"
5187 : state == MPI_PHYSDISK0_STATUS_MISSING
5188 ? "missing"
5189 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5190 ? "not compatible"
5191 : state == MPI_PHYSDISK0_STATUS_FAILED
5192 ? "failed"
5193 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5194 ? "initializing"
5195 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5196 ? "offline requested"
5197 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5198 ? "failed requested"
5199 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5200 ? "offline"
5201 : "state unknown",
5202 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5203 ? ", out of sync" : "",
5204 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5205 ? ", quiesced" : "" );
5206 break;
5207
5208 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5209 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5210 ioc->name, disk);
5211 break;
5212
5213 case MPI_EVENT_RAID_RC_SMART_DATA:
5214 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5215 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5216 break;
5217
5218 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5219 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5220 ioc->name, disk);
5221 break;
5222 }
5223}
5224
5225/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005226/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5228 * @ioc: Pointer to MPT_ADAPTER structure
5229 *
5230 * Returns: 0 for success
5231 * -ENOMEM if no memory available
5232 * -EPERM if not allowed due to ISR context
5233 * -EAGAIN if no msg frames currently available
5234 * -EFAULT for non-successful reply or no reply (timeout)
5235 */
5236static int
5237GetIoUnitPage2(MPT_ADAPTER *ioc)
5238{
5239 ConfigPageHeader_t hdr;
5240 CONFIGPARMS cfg;
5241 IOUnitPage2_t *ppage_alloc;
5242 dma_addr_t page_dma;
5243 int data_sz;
5244 int rc;
5245
5246 /* Get the page header */
5247 hdr.PageVersion = 0;
5248 hdr.PageLength = 0;
5249 hdr.PageNumber = 2;
5250 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005251 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 cfg.physAddr = -1;
5253 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5254 cfg.dir = 0;
5255 cfg.pageAddr = 0;
5256 cfg.timeout = 0;
5257
5258 if ((rc = mpt_config(ioc, &cfg)) != 0)
5259 return rc;
5260
5261 if (hdr.PageLength == 0)
5262 return 0;
5263
5264 /* Read the config page */
5265 data_sz = hdr.PageLength * 4;
5266 rc = -ENOMEM;
5267 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5268 if (ppage_alloc) {
5269 memset((u8 *)ppage_alloc, 0, data_sz);
5270 cfg.physAddr = page_dma;
5271 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5272
5273 /* If Good, save data */
5274 if ((rc = mpt_config(ioc, &cfg)) == 0)
5275 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5276
5277 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5278 }
5279
5280 return rc;
5281}
5282
5283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005284/**
5285 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 * @ioc: Pointer to a Adapter Strucutre
5287 * @portnum: IOC port number
5288 *
5289 * Return: -EFAULT if read of config page header fails
5290 * or if no nvram
5291 * If read of SCSI Port Page 0 fails,
5292 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5293 * Adapter settings: async, narrow
5294 * Return 1
5295 * If read of SCSI Port Page 2 fails,
5296 * Adapter settings valid
5297 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5298 * Return 1
5299 * Else
5300 * Both valid
5301 * Return 0
5302 * CHECK - what type of locking mechanisms should be used????
5303 */
5304static int
5305mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5306{
5307 u8 *pbuf;
5308 dma_addr_t buf_dma;
5309 CONFIGPARMS cfg;
5310 ConfigPageHeader_t header;
5311 int ii;
5312 int data, rc = 0;
5313
5314 /* Allocate memory
5315 */
5316 if (!ioc->spi_data.nvram) {
5317 int sz;
5318 u8 *mem;
5319 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5320 mem = kmalloc(sz, GFP_ATOMIC);
5321 if (mem == NULL)
5322 return -EFAULT;
5323
5324 ioc->spi_data.nvram = (int *) mem;
5325
Prakash, Sathya436ace72007-07-24 15:42:08 +05305326 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 ioc->name, ioc->spi_data.nvram, sz));
5328 }
5329
5330 /* Invalidate NVRAM information
5331 */
5332 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5333 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5334 }
5335
5336 /* Read SPP0 header, allocate memory, then read page.
5337 */
5338 header.PageVersion = 0;
5339 header.PageLength = 0;
5340 header.PageNumber = 0;
5341 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005342 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 cfg.physAddr = -1;
5344 cfg.pageAddr = portnum;
5345 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5346 cfg.dir = 0;
5347 cfg.timeout = 0; /* use default */
5348 if (mpt_config(ioc, &cfg) != 0)
5349 return -EFAULT;
5350
5351 if (header.PageLength > 0) {
5352 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5353 if (pbuf) {
5354 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5355 cfg.physAddr = buf_dma;
5356 if (mpt_config(ioc, &cfg) != 0) {
5357 ioc->spi_data.maxBusWidth = MPT_NARROW;
5358 ioc->spi_data.maxSyncOffset = 0;
5359 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5360 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5361 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305362 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5363 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005364 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 } else {
5366 /* Save the Port Page 0 data
5367 */
5368 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5369 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5370 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5371
5372 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5373 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005374 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5375 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 ioc->name, pPP0->Capabilities));
5377 }
5378 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5379 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5380 if (data) {
5381 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5382 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5383 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305384 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5385 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005386 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 } else {
5388 ioc->spi_data.maxSyncOffset = 0;
5389 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5390 }
5391
5392 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5393
5394 /* Update the minSyncFactor based on bus type.
5395 */
5396 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5397 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5398
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005399 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305401 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5402 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005403 ioc->name, ioc->spi_data.minSyncFactor));
5404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 }
5406 }
5407 if (pbuf) {
5408 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5409 }
5410 }
5411 }
5412
5413 /* SCSI Port Page 2 - Read the header then the page.
5414 */
5415 header.PageVersion = 0;
5416 header.PageLength = 0;
5417 header.PageNumber = 2;
5418 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005419 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 cfg.physAddr = -1;
5421 cfg.pageAddr = portnum;
5422 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5423 cfg.dir = 0;
5424 if (mpt_config(ioc, &cfg) != 0)
5425 return -EFAULT;
5426
5427 if (header.PageLength > 0) {
5428 /* Allocate memory and read SCSI Port Page 2
5429 */
5430 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5431 if (pbuf) {
5432 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5433 cfg.physAddr = buf_dma;
5434 if (mpt_config(ioc, &cfg) != 0) {
5435 /* Nvram data is left with INVALID mark
5436 */
5437 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005438 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5439
5440 /* This is an ATTO adapter, read Page2 accordingly
5441 */
5442 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5443 ATTODeviceInfo_t *pdevice = NULL;
5444 u16 ATTOFlags;
5445
5446 /* Save the Port Page 2 data
5447 * (reformat into a 32bit quantity)
5448 */
5449 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5450 pdevice = &pPP2->DeviceSettings[ii];
5451 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5452 data = 0;
5453
5454 /* Translate ATTO device flags to LSI format
5455 */
5456 if (ATTOFlags & ATTOFLAG_DISC)
5457 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5458 if (ATTOFlags & ATTOFLAG_ID_ENB)
5459 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5460 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5461 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5462 if (ATTOFlags & ATTOFLAG_TAGGED)
5463 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5464 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5465 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5466
5467 data = (data << 16) | (pdevice->Period << 8) | 10;
5468 ioc->spi_data.nvram[ii] = data;
5469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 } else {
5471 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5472 MpiDeviceInfo_t *pdevice = NULL;
5473
Moore, Ericd8e925d2006-01-16 18:53:06 -07005474 /*
5475 * Save "Set to Avoid SCSI Bus Resets" flag
5476 */
5477 ioc->spi_data.bus_reset =
5478 (le32_to_cpu(pPP2->PortFlags) &
5479 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5480 0 : 1 ;
5481
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 /* Save the Port Page 2 data
5483 * (reformat into a 32bit quantity)
5484 */
5485 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5486 ioc->spi_data.PortFlags = data;
5487 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5488 pdevice = &pPP2->DeviceSettings[ii];
5489 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5490 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5491 ioc->spi_data.nvram[ii] = data;
5492 }
5493 }
5494
5495 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5496 }
5497 }
5498
5499 /* Update Adapter limits with those from NVRAM
5500 * Comment: Don't need to do this. Target performance
5501 * parameters will never exceed the adapters limits.
5502 */
5503
5504 return rc;
5505}
5506
5507/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005508/**
5509 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 * @ioc: Pointer to a Adapter Strucutre
5511 * @portnum: IOC port number
5512 *
5513 * Return: -EFAULT if read of config page header fails
5514 * or 0 if success.
5515 */
5516static int
5517mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5518{
5519 CONFIGPARMS cfg;
5520 ConfigPageHeader_t header;
5521
5522 /* Read the SCSI Device Page 1 header
5523 */
5524 header.PageVersion = 0;
5525 header.PageLength = 0;
5526 header.PageNumber = 1;
5527 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005528 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 cfg.physAddr = -1;
5530 cfg.pageAddr = portnum;
5531 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5532 cfg.dir = 0;
5533 cfg.timeout = 0;
5534 if (mpt_config(ioc, &cfg) != 0)
5535 return -EFAULT;
5536
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005537 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5538 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539
5540 header.PageVersion = 0;
5541 header.PageLength = 0;
5542 header.PageNumber = 0;
5543 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5544 if (mpt_config(ioc, &cfg) != 0)
5545 return -EFAULT;
5546
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005547 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5548 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549
Prakash, Sathya436ace72007-07-24 15:42:08 +05305550 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5552
Prakash, Sathya436ace72007-07-24 15:42:08 +05305553 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5555 return 0;
5556}
5557
Eric Mooreb506ade2007-01-29 09:45:37 -07005558/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005559 * mpt_inactive_raid_list_free - This clears this link list.
5560 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005561 **/
5562static void
5563mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5564{
5565 struct inactive_raid_component_info *component_info, *pNext;
5566
5567 if (list_empty(&ioc->raid_data.inactive_list))
5568 return;
5569
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005570 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005571 list_for_each_entry_safe(component_info, pNext,
5572 &ioc->raid_data.inactive_list, list) {
5573 list_del(&component_info->list);
5574 kfree(component_info);
5575 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005576 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005577}
5578
5579/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005580 * 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 -07005581 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005582 * @ioc : pointer to per adapter structure
5583 * @channel : volume channel
5584 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005585 **/
5586static void
5587mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5588{
5589 CONFIGPARMS cfg;
5590 ConfigPageHeader_t hdr;
5591 dma_addr_t dma_handle;
5592 pRaidVolumePage0_t buffer = NULL;
5593 int i;
5594 RaidPhysDiskPage0_t phys_disk;
5595 struct inactive_raid_component_info *component_info;
5596 int handle_inactive_volumes;
5597
5598 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5599 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5600 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5601 cfg.pageAddr = (channel << 8) + id;
5602 cfg.cfghdr.hdr = &hdr;
5603 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5604
5605 if (mpt_config(ioc, &cfg) != 0)
5606 goto out;
5607
5608 if (!hdr.PageLength)
5609 goto out;
5610
5611 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5612 &dma_handle);
5613
5614 if (!buffer)
5615 goto out;
5616
5617 cfg.physAddr = dma_handle;
5618 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5619
5620 if (mpt_config(ioc, &cfg) != 0)
5621 goto out;
5622
5623 if (!buffer->NumPhysDisks)
5624 goto out;
5625
5626 handle_inactive_volumes =
5627 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5628 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5629 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5630 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5631
5632 if (!handle_inactive_volumes)
5633 goto out;
5634
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005635 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005636 for (i = 0; i < buffer->NumPhysDisks; i++) {
5637 if(mpt_raid_phys_disk_pg0(ioc,
5638 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5639 continue;
5640
5641 if ((component_info = kmalloc(sizeof (*component_info),
5642 GFP_KERNEL)) == NULL)
5643 continue;
5644
5645 component_info->volumeID = id;
5646 component_info->volumeBus = channel;
5647 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5648 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5649 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5650 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5651
5652 list_add_tail(&component_info->list,
5653 &ioc->raid_data.inactive_list);
5654 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005655 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005656
5657 out:
5658 if (buffer)
5659 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5660 dma_handle);
5661}
5662
5663/**
5664 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5665 * @ioc: Pointer to a Adapter Structure
5666 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5667 * @phys_disk: requested payload data returned
5668 *
5669 * Return:
5670 * 0 on success
5671 * -EFAULT if read of config page header fails or data pointer not NULL
5672 * -ENOMEM if pci_alloc failed
5673 **/
5674int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305675mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5676 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005677{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305678 CONFIGPARMS cfg;
5679 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005680 dma_addr_t dma_handle;
5681 pRaidPhysDiskPage0_t buffer = NULL;
5682 int rc;
5683
5684 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5685 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305686 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005687
Kashyap, Desai2f187862009-05-29 16:52:37 +05305688 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005689 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5690 cfg.cfghdr.hdr = &hdr;
5691 cfg.physAddr = -1;
5692 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5693
5694 if (mpt_config(ioc, &cfg) != 0) {
5695 rc = -EFAULT;
5696 goto out;
5697 }
5698
5699 if (!hdr.PageLength) {
5700 rc = -EFAULT;
5701 goto out;
5702 }
5703
5704 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5705 &dma_handle);
5706
5707 if (!buffer) {
5708 rc = -ENOMEM;
5709 goto out;
5710 }
5711
5712 cfg.physAddr = dma_handle;
5713 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5714 cfg.pageAddr = phys_disk_num;
5715
5716 if (mpt_config(ioc, &cfg) != 0) {
5717 rc = -EFAULT;
5718 goto out;
5719 }
5720
5721 rc = 0;
5722 memcpy(phys_disk, buffer, sizeof(*buffer));
5723 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5724
5725 out:
5726
5727 if (buffer)
5728 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5729 dma_handle);
5730
5731 return rc;
5732}
5733
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305735 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5736 * @ioc: Pointer to a Adapter Structure
5737 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5738 *
5739 * Return:
5740 * returns number paths
5741 **/
5742int
5743mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5744{
5745 CONFIGPARMS cfg;
5746 ConfigPageHeader_t hdr;
5747 dma_addr_t dma_handle;
5748 pRaidPhysDiskPage1_t buffer = NULL;
5749 int rc;
5750
5751 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5752 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5753
5754 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5755 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5756 hdr.PageNumber = 1;
5757 cfg.cfghdr.hdr = &hdr;
5758 cfg.physAddr = -1;
5759 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5760
5761 if (mpt_config(ioc, &cfg) != 0) {
5762 rc = 0;
5763 goto out;
5764 }
5765
5766 if (!hdr.PageLength) {
5767 rc = 0;
5768 goto out;
5769 }
5770
5771 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5772 &dma_handle);
5773
5774 if (!buffer) {
5775 rc = 0;
5776 goto out;
5777 }
5778
5779 cfg.physAddr = dma_handle;
5780 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5781 cfg.pageAddr = phys_disk_num;
5782
5783 if (mpt_config(ioc, &cfg) != 0) {
5784 rc = 0;
5785 goto out;
5786 }
5787
5788 rc = buffer->NumPhysDiskPaths;
5789 out:
5790
5791 if (buffer)
5792 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5793 dma_handle);
5794
5795 return rc;
5796}
5797EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5798
5799/**
5800 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5801 * @ioc: Pointer to a Adapter Structure
5802 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5803 * @phys_disk: requested payload data returned
5804 *
5805 * Return:
5806 * 0 on success
5807 * -EFAULT if read of config page header fails or data pointer not NULL
5808 * -ENOMEM if pci_alloc failed
5809 **/
5810int
5811mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5812 RaidPhysDiskPage1_t *phys_disk)
5813{
5814 CONFIGPARMS cfg;
5815 ConfigPageHeader_t hdr;
5816 dma_addr_t dma_handle;
5817 pRaidPhysDiskPage1_t buffer = NULL;
5818 int rc;
5819 int i;
5820 __le64 sas_address;
5821
5822 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5823 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5824 rc = 0;
5825
5826 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5827 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5828 hdr.PageNumber = 1;
5829 cfg.cfghdr.hdr = &hdr;
5830 cfg.physAddr = -1;
5831 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5832
5833 if (mpt_config(ioc, &cfg) != 0) {
5834 rc = -EFAULT;
5835 goto out;
5836 }
5837
5838 if (!hdr.PageLength) {
5839 rc = -EFAULT;
5840 goto out;
5841 }
5842
5843 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5844 &dma_handle);
5845
5846 if (!buffer) {
5847 rc = -ENOMEM;
5848 goto out;
5849 }
5850
5851 cfg.physAddr = dma_handle;
5852 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5853 cfg.pageAddr = phys_disk_num;
5854
5855 if (mpt_config(ioc, &cfg) != 0) {
5856 rc = -EFAULT;
5857 goto out;
5858 }
5859
5860 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5861 phys_disk->PhysDiskNum = phys_disk_num;
5862 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5863 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5864 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5865 phys_disk->Path[i].OwnerIdentifier =
5866 buffer->Path[i].OwnerIdentifier;
5867 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5868 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5869 sas_address = le64_to_cpu(sas_address);
5870 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5871 memcpy(&sas_address,
5872 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5873 sas_address = le64_to_cpu(sas_address);
5874 memcpy(&phys_disk->Path[i].OwnerWWID,
5875 &sas_address, sizeof(__le64));
5876 }
5877
5878 out:
5879
5880 if (buffer)
5881 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5882 dma_handle);
5883
5884 return rc;
5885}
5886EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5887
5888
5889/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5891 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 *
5893 * Return:
5894 * 0 on success
5895 * -EFAULT if read of config page header fails or data pointer not NULL
5896 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005897 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898int
5899mpt_findImVolumes(MPT_ADAPTER *ioc)
5900{
5901 IOCPage2_t *pIoc2;
5902 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 dma_addr_t ioc2_dma;
5904 CONFIGPARMS cfg;
5905 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 int rc = 0;
5907 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005908 int i;
5909
5910 if (!ioc->ir_firmware)
5911 return 0;
5912
5913 /* Free the old page
5914 */
5915 kfree(ioc->raid_data.pIocPg2);
5916 ioc->raid_data.pIocPg2 = NULL;
5917 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918
5919 /* Read IOCP2 header then the page.
5920 */
5921 header.PageVersion = 0;
5922 header.PageLength = 0;
5923 header.PageNumber = 2;
5924 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005925 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 cfg.physAddr = -1;
5927 cfg.pageAddr = 0;
5928 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5929 cfg.dir = 0;
5930 cfg.timeout = 0;
5931 if (mpt_config(ioc, &cfg) != 0)
5932 return -EFAULT;
5933
5934 if (header.PageLength == 0)
5935 return -EFAULT;
5936
5937 iocpage2sz = header.PageLength * 4;
5938 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5939 if (!pIoc2)
5940 return -ENOMEM;
5941
5942 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5943 cfg.physAddr = ioc2_dma;
5944 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005945 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946
Eric Mooreb506ade2007-01-29 09:45:37 -07005947 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5948 if (!mem)
5949 goto out;
5950
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005952 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953
Eric Mooreb506ade2007-01-29 09:45:37 -07005954 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Eric Mooreb506ade2007-01-29 09:45:37 -07005956 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5957 mpt_inactive_raid_volumes(ioc,
5958 pIoc2->RaidVolume[i].VolumeBus,
5959 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
Eric Mooreb506ade2007-01-29 09:45:37 -07005961 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5963
5964 return rc;
5965}
5966
Moore, Ericc972c702006-03-14 09:14:06 -07005967static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5969{
5970 IOCPage3_t *pIoc3;
5971 u8 *mem;
5972 CONFIGPARMS cfg;
5973 ConfigPageHeader_t header;
5974 dma_addr_t ioc3_dma;
5975 int iocpage3sz = 0;
5976
5977 /* Free the old page
5978 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005979 kfree(ioc->raid_data.pIocPg3);
5980 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981
5982 /* There is at least one physical disk.
5983 * Read and save IOC Page 3
5984 */
5985 header.PageVersion = 0;
5986 header.PageLength = 0;
5987 header.PageNumber = 3;
5988 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005989 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 cfg.physAddr = -1;
5991 cfg.pageAddr = 0;
5992 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5993 cfg.dir = 0;
5994 cfg.timeout = 0;
5995 if (mpt_config(ioc, &cfg) != 0)
5996 return 0;
5997
5998 if (header.PageLength == 0)
5999 return 0;
6000
6001 /* Read Header good, alloc memory
6002 */
6003 iocpage3sz = header.PageLength * 4;
6004 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6005 if (!pIoc3)
6006 return 0;
6007
6008 /* Read the Page and save the data
6009 * into malloc'd memory.
6010 */
6011 cfg.physAddr = ioc3_dma;
6012 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6013 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006014 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015 if (mem) {
6016 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006017 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 }
6019 }
6020
6021 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6022
6023 return 0;
6024}
6025
6026static void
6027mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6028{
6029 IOCPage4_t *pIoc4;
6030 CONFIGPARMS cfg;
6031 ConfigPageHeader_t header;
6032 dma_addr_t ioc4_dma;
6033 int iocpage4sz;
6034
6035 /* Read and save IOC Page 4
6036 */
6037 header.PageVersion = 0;
6038 header.PageLength = 0;
6039 header.PageNumber = 4;
6040 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006041 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 cfg.physAddr = -1;
6043 cfg.pageAddr = 0;
6044 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6045 cfg.dir = 0;
6046 cfg.timeout = 0;
6047 if (mpt_config(ioc, &cfg) != 0)
6048 return;
6049
6050 if (header.PageLength == 0)
6051 return;
6052
6053 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6054 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6055 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6056 if (!pIoc4)
6057 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006058 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 } else {
6060 ioc4_dma = ioc->spi_data.IocPg4_dma;
6061 iocpage4sz = ioc->spi_data.IocPg4Sz;
6062 }
6063
6064 /* Read the Page into dma memory.
6065 */
6066 cfg.physAddr = ioc4_dma;
6067 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6068 if (mpt_config(ioc, &cfg) == 0) {
6069 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6070 ioc->spi_data.IocPg4_dma = ioc4_dma;
6071 ioc->spi_data.IocPg4Sz = iocpage4sz;
6072 } else {
6073 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6074 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006075 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 }
6077}
6078
6079static void
6080mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6081{
6082 IOCPage1_t *pIoc1;
6083 CONFIGPARMS cfg;
6084 ConfigPageHeader_t header;
6085 dma_addr_t ioc1_dma;
6086 int iocpage1sz = 0;
6087 u32 tmp;
6088
6089 /* Check the Coalescing Timeout in IOC Page 1
6090 */
6091 header.PageVersion = 0;
6092 header.PageLength = 0;
6093 header.PageNumber = 1;
6094 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006095 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 cfg.physAddr = -1;
6097 cfg.pageAddr = 0;
6098 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6099 cfg.dir = 0;
6100 cfg.timeout = 0;
6101 if (mpt_config(ioc, &cfg) != 0)
6102 return;
6103
6104 if (header.PageLength == 0)
6105 return;
6106
6107 /* Read Header good, alloc memory
6108 */
6109 iocpage1sz = header.PageLength * 4;
6110 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6111 if (!pIoc1)
6112 return;
6113
6114 /* Read the Page and check coalescing timeout
6115 */
6116 cfg.physAddr = ioc1_dma;
6117 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6118 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306119
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6121 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6122 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6123
Prakash, Sathya436ace72007-07-24 15:42:08 +05306124 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 ioc->name, tmp));
6126
6127 if (tmp > MPT_COALESCING_TIMEOUT) {
6128 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6129
6130 /* Write NVRAM and current
6131 */
6132 cfg.dir = 1;
6133 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6134 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306135 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 ioc->name, MPT_COALESCING_TIMEOUT));
6137
6138 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6139 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306140 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6141 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142 ioc->name, MPT_COALESCING_TIMEOUT));
6143 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306144 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6145 "Reset NVRAM Coalescing Timeout Failed\n",
6146 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 }
6148
6149 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306150 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6151 "Reset of Current Coalescing Timeout Failed!\n",
6152 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 }
6154 }
6155
6156 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306157 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 }
6159 }
6160
6161 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6162
6163 return;
6164}
6165
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306166static void
6167mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6168{
6169 CONFIGPARMS cfg;
6170 ConfigPageHeader_t hdr;
6171 dma_addr_t buf_dma;
6172 ManufacturingPage0_t *pbuf = NULL;
6173
6174 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6175 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6176
6177 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6178 cfg.cfghdr.hdr = &hdr;
6179 cfg.physAddr = -1;
6180 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6181 cfg.timeout = 10;
6182
6183 if (mpt_config(ioc, &cfg) != 0)
6184 goto out;
6185
6186 if (!cfg.cfghdr.hdr->PageLength)
6187 goto out;
6188
6189 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6190 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6191 if (!pbuf)
6192 goto out;
6193
6194 cfg.physAddr = buf_dma;
6195
6196 if (mpt_config(ioc, &cfg) != 0)
6197 goto out;
6198
6199 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6200 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6201 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6202
6203 out:
6204
6205 if (pbuf)
6206 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6207}
6208
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006210/**
6211 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 * @ioc: Pointer to MPT_ADAPTER structure
6213 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306214 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215 */
6216static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306217SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306219 EventNotification_t evn;
6220 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221
Kashyap, Desaifd761752009-05-29 16:39:06 +05306222 memset(&evn, 0, sizeof(EventNotification_t));
6223 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Kashyap, Desaifd761752009-05-29 16:39:06 +05306225 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6226 evn.Switch = EvSwitch;
6227 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Kashyap, Desaifd761752009-05-29 16:39:06 +05306229 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6230 "Sending EventNotification (%d) request %p\n",
6231 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232
Kashyap, Desaifd761752009-05-29 16:39:06 +05306233 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6234 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6235 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236}
6237
6238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6239/**
6240 * SendEventAck - Send EventAck request to MPT adapter.
6241 * @ioc: Pointer to MPT_ADAPTER structure
6242 * @evnp: Pointer to original EventNotification request
6243 */
6244static int
6245SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6246{
6247 EventAck_t *pAck;
6248
6249 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306250 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306251 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 return -1;
6253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Prakash, Sathya436ace72007-07-24 15:42:08 +05306255 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
6257 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6258 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006259 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006261 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 pAck->Event = evnp->Event;
6263 pAck->EventContext = evnp->EventContext;
6264
6265 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6266
6267 return 0;
6268}
6269
6270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6271/**
6272 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006273 * @ioc: Pointer to an adapter structure
6274 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 * action, page address, direction, physical address
6276 * and pointer to a configuration page header
6277 * Page header is updated.
6278 *
6279 * Returns 0 for success
6280 * -EPERM if not allowed due to ISR context
6281 * -EAGAIN if no msg frames currently available
6282 * -EFAULT for non-successful reply or no reply (timeout)
6283 */
6284int
6285mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6286{
6287 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306288 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006289 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306291 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006292 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306293 long timeout;
6294 int ret;
6295 u8 page_type = 0, extend_page;
6296 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306297 unsigned long flags;
6298 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306299 u8 issue_hard_reset = 0;
6300 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006302 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 * to be in ISR context, because that is fatal!
6304 */
6305 in_isr = in_interrupt();
6306 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306307 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 ioc->name));
6309 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306310 }
6311
6312 /* don't send a config page during diag reset */
6313 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6314 if (ioc->ioc_reset_in_progress) {
6315 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6316 "%s: busy with host reset\n", ioc->name, __func__));
6317 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6318 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306320 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306322 /* don't send if no chance of success */
6323 if (!ioc->active ||
6324 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6325 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6326 "%s: ioc not operational, %d, %xh\n",
6327 ioc->name, __func__, ioc->active,
6328 mpt_GetIocState(ioc, 0)));
6329 return -EFAULT;
6330 }
6331
6332 retry_config:
6333 mutex_lock(&ioc->mptbase_cmds.mutex);
6334 /* init the internal cmd struct */
6335 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6336 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6337
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 /* Get and Populate a free Frame
6339 */
6340 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306341 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6342 "mpt_config: no msg frames!\n", ioc->name));
6343 ret = -EAGAIN;
6344 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306346
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 pReq = (Config_t *)mf;
6348 pReq->Action = pCfg->action;
6349 pReq->Reserved = 0;
6350 pReq->ChainOffset = 0;
6351 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006352
6353 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 pReq->ExtPageLength = 0;
6355 pReq->ExtPageType = 0;
6356 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006357
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 for (ii=0; ii < 8; ii++)
6359 pReq->Reserved2[ii] = 0;
6360
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006361 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6362 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6363 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6364 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6365
6366 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6367 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6368 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6369 pReq->ExtPageType = pExtHdr->ExtPageType;
6370 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6371
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306372 /* Page Length must be treated as a reserved field for the
6373 * extended header.
6374 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006375 pReq->Header.PageLength = 0;
6376 }
6377
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6379
6380 /* Add a SGE to the config request.
6381 */
6382 if (pCfg->dir)
6383 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6384 else
6385 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6386
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306387 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6388 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006389 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306390 page_type = pReq->ExtPageType;
6391 extend_page = 1;
6392 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006393 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306394 page_type = pReq->Header.PageType;
6395 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306398 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6399 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6400 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6401
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306402 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306403 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306405 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6406 timeout);
6407 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6408 ret = -ETIME;
6409 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6410 "Failed Sending Config request type 0x%x, page 0x%x,"
6411 " action %d, status %xh, time left %ld\n\n",
6412 ioc->name, page_type, pReq->Header.PageNumber,
6413 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6414 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6415 goto out;
6416 if (!timeleft)
6417 issue_hard_reset = 1;
6418 goto out;
6419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306421 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6422 ret = -1;
6423 goto out;
6424 }
6425 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6426 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6427 if (ret == MPI_IOCSTATUS_SUCCESS) {
6428 if (extend_page) {
6429 pCfg->cfghdr.ehdr->ExtPageLength =
6430 le16_to_cpu(pReply->ExtPageLength);
6431 pCfg->cfghdr.ehdr->ExtPageType =
6432 pReply->ExtPageType;
6433 }
6434 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6435 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6436 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6437 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306441 if (retry_count)
6442 printk(MYIOC_s_INFO_FMT "Retry completed "
6443 "ret=0x%x timeleft=%ld\n",
6444 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306446 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6447 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306449out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6452 mutex_unlock(&ioc->mptbase_cmds.mutex);
6453 if (issue_hard_reset) {
6454 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006455 printk(MYIOC_s_WARN_FMT
6456 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6457 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306458 if (retry_count == 0) {
6459 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6460 retry_count++;
6461 } else
6462 mpt_HardResetHandler(ioc, CAN_SLEEP);
6463
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306464 mpt_free_msg_frame(ioc, mf);
6465 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306466 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306467 printk(MYIOC_s_INFO_FMT
6468 "Attempting Retry Config request"
6469 " type 0x%x, page 0x%x,"
6470 " action %d\n", ioc->name, page_type,
6471 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6472 retry_count++;
6473 goto retry_config;
6474 }
6475 }
6476 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478}
6479
6480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006481/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482 * mpt_ioc_reset - Base cleanup for hard reset
6483 * @ioc: Pointer to the adapter structure
6484 * @reset_phase: Indicates pre- or post-reset functionality
6485 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006486 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487 */
6488static int
6489mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6490{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306491 switch (reset_phase) {
6492 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306493 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306494 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6495 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6496 break;
6497 case MPT_IOC_PRE_RESET:
6498 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6499 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6500 break;
6501 case MPT_IOC_POST_RESET:
6502 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6503 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6504/* wake up mptbase_cmds */
6505 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6506 ioc->mptbase_cmds.status |=
6507 MPT_MGMT_STATUS_DID_IOCRESET;
6508 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306510/* wake up taskmgmt_cmds */
6511 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6512 ioc->taskmgmt_cmds.status |=
6513 MPT_MGMT_STATUS_DID_IOCRESET;
6514 complete(&ioc->taskmgmt_cmds.done);
6515 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306516 break;
6517 default:
6518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519 }
6520
6521 return 1; /* currently means nothing really */
6522}
6523
6524
6525#ifdef CONFIG_PROC_FS /* { */
6526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6527/*
6528 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6529 */
6530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006531/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6533 *
6534 * Returns 0 for success, non-zero for failure.
6535 */
6536static int
6537procmpt_create(void)
6538{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006539 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6540 if (mpt_proc_root_dir == NULL)
6541 return -ENOTDIR;
6542
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006543 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6544 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545 return 0;
6546}
6547
6548/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006549/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6551 *
6552 * Returns 0 for success, non-zero for failure.
6553 */
6554static void
6555procmpt_destroy(void)
6556{
6557 remove_proc_entry("version", mpt_proc_root_dir);
6558 remove_proc_entry("summary", mpt_proc_root_dir);
6559 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6560}
6561
6562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006563/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006564 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006566static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6567
6568static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006570 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006572 if (ioc) {
6573 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 } else {
6575 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006576 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 }
6578 }
6579
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006580 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581}
6582
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006583static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6584{
6585 return single_open(file, mpt_summary_proc_show, PDE(inode)->data);
6586}
6587
6588static const struct file_operations mpt_summary_proc_fops = {
6589 .owner = THIS_MODULE,
6590 .open = mpt_summary_proc_open,
6591 .read = seq_read,
6592 .llseek = seq_lseek,
6593 .release = single_release,
6594};
6595
6596static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306598 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006599 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006602 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6603 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006605 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006606 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306608 if (MptCallbacks[cb_idx]) {
6609 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006610 case MPTSPI_DRIVER:
6611 if (!scsi++) drvname = "SPI host";
6612 break;
6613 case MPTFC_DRIVER:
6614 if (!fc++) drvname = "FC host";
6615 break;
6616 case MPTSAS_DRIVER:
6617 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 break;
6619 case MPTLAN_DRIVER:
6620 if (!lan++) drvname = "LAN";
6621 break;
6622 case MPTSTM_DRIVER:
6623 if (!targ++) drvname = "SCSI target";
6624 break;
6625 case MPTCTL_DRIVER:
6626 if (!ctl++) drvname = "ioctl";
6627 break;
6628 }
6629
6630 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006631 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632 }
6633 }
6634
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006635 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636}
6637
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006638static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006639{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006640 return single_open(file, mpt_version_proc_show, NULL);
6641}
6642
6643static const struct file_operations mpt_version_proc_fops = {
6644 .owner = THIS_MODULE,
6645 .open = mpt_version_proc_open,
6646 .read = seq_read,
6647 .llseek = seq_lseek,
6648 .release = single_release,
6649};
6650
6651static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6652{
6653 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 char expVer[32];
6655 int sz;
6656 int p;
6657
6658 mpt_get_fw_exp_ver(expVer, ioc);
6659
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006660 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006662 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006664// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006666 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667 ioc->facts.ProductID,
6668 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006669 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006671 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6672 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6673 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6674 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006676 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006678 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679 ioc->facts.CurrentSenseBufferHighAddr);
6680
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006681 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6682 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006684 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6686 /*
6687 * Rounding UP to nearest 4-kB boundary here...
6688 */
6689 sz = (ioc->req_sz * ioc->req_depth) + 128;
6690 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006691 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006693 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694 4*ioc->facts.RequestFrameSize,
6695 ioc->facts.GlobalCredits);
6696
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006697 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6699 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006700 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006702 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 ioc->facts.CurReplyFrameSize,
6704 ioc->facts.ReplyQueueDepth);
6705
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006706 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006708 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006709
6710 /* per-port info */
6711 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006712 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713 p+1,
6714 ioc->facts.NumberOfPorts);
6715 if (ioc->bus_type == FC) {
6716 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6717 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006718 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006719 a[5], a[4], a[3], a[2], a[1], a[0]);
6720 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006721 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722 ioc->fc_port_page0[p].WWNN.High,
6723 ioc->fc_port_page0[p].WWNN.Low,
6724 ioc->fc_port_page0[p].WWPN.High,
6725 ioc->fc_port_page0[p].WWPN.Low);
6726 }
6727 }
6728
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006729 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730}
6731
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006732static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6733{
6734 return single_open(file, mpt_iocinfo_proc_show, PDE(inode)->data);
6735}
6736
6737static const struct file_operations mpt_iocinfo_proc_fops = {
6738 .owner = THIS_MODULE,
6739 .open = mpt_iocinfo_proc_open,
6740 .read = seq_read,
6741 .llseek = seq_lseek,
6742 .release = single_release,
6743};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744#endif /* CONFIG_PROC_FS } */
6745
6746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6747static void
6748mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6749{
6750 buf[0] ='\0';
6751 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6752 sprintf(buf, " (Exp %02d%02d)",
6753 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6754 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6755
6756 /* insider hack! */
6757 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6758 strcat(buf, " [MDBG]");
6759 }
6760}
6761
6762/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6763/**
6764 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6765 * @ioc: Pointer to MPT_ADAPTER structure
6766 * @buffer: Pointer to buffer where IOC summary info should be written
6767 * @size: Pointer to number of bytes we wrote (set by this routine)
6768 * @len: Offset at which to start writing in buffer
6769 * @showlan: Display LAN stuff?
6770 *
6771 * This routine writes (english readable) ASCII text, which represents
6772 * a summary of IOC information, to a buffer.
6773 */
6774void
6775mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6776{
6777 char expVer[32];
6778 int y;
6779
6780 mpt_get_fw_exp_ver(expVer, ioc);
6781
6782 /*
6783 * Shorter summary of attached ioc's...
6784 */
6785 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6786 ioc->name,
6787 ioc->prod_name,
6788 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6789 ioc->facts.FWVersion.Word,
6790 expVer,
6791 ioc->facts.NumberOfPorts,
6792 ioc->req_depth);
6793
6794 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6795 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6796 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6797 a[5], a[4], a[3], a[2], a[1], a[0]);
6798 }
6799
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801
6802 if (!ioc->active)
6803 y += sprintf(buffer+len+y, " (disabled)");
6804
6805 y += sprintf(buffer+len+y, "\n");
6806
6807 *size = y;
6808}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006809
6810static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6811{
6812 char expVer[32];
6813
6814 mpt_get_fw_exp_ver(expVer, ioc);
6815
6816 /*
6817 * Shorter summary of attached ioc's...
6818 */
6819 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6820 ioc->name,
6821 ioc->prod_name,
6822 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6823 ioc->facts.FWVersion.Word,
6824 expVer,
6825 ioc->facts.NumberOfPorts,
6826 ioc->req_depth);
6827
6828 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6829 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6830 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6831 a[5], a[4], a[3], a[2], a[1], a[0]);
6832 }
6833
6834 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6835
6836 if (!ioc->active)
6837 seq_printf(m, " (disabled)");
6838
6839 seq_putc(m, '\n');
6840}
6841
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306842/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006843 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306844 * @ioc: Pointer to MPT_ADAPTER structure
6845 *
6846 * Returns 0 for SUCCESS or -1 if FAILED.
6847 *
6848 * If -1 is return, then it was not possible to set the flags
6849 **/
6850int
6851mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6852{
6853 unsigned long flags;
6854 int retval;
6855
6856 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6857 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6858 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6859 retval = -1;
6860 goto out;
6861 }
6862 retval = 0;
6863 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306864 ioc->taskmgmt_quiesce_io = 1;
6865 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306866 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306867 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6868 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306869 out:
6870 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6871 return retval;
6872}
6873EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6874
6875/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006876 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306877 * @ioc: Pointer to MPT_ADAPTER structure
6878 *
6879 **/
6880void
6881mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6882{
6883 unsigned long flags;
6884
6885 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6886 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306887 ioc->taskmgmt_quiesce_io = 0;
6888 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306889 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306890 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6891 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306892 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6893}
6894EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306896
6897/**
6898 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6899 * the kernel
6900 * @ioc: Pointer to MPT_ADAPTER structure
6901 *
6902 **/
6903void
6904mpt_halt_firmware(MPT_ADAPTER *ioc)
6905{
6906 u32 ioc_raw_state;
6907
6908 ioc_raw_state = mpt_GetIocState(ioc, 0);
6909
6910 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6911 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6912 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6913 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6914 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6915 } else {
6916 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6917 panic("%s: Firmware is halted due to command timeout\n",
6918 ioc->name);
6919 }
6920}
6921EXPORT_SYMBOL(mpt_halt_firmware);
6922
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306923/**
6924 * mpt_SoftResetHandler - Issues a less expensive reset
6925 * @ioc: Pointer to MPT_ADAPTER structure
6926 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306927 *
6928 * Returns 0 for SUCCESS or -1 if FAILED.
6929 *
6930 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6931 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6932 * All posted buffers are freed, and event notification is turned off.
6933 * IOC doesnt reply to any outstanding request. This will transfer IOC
6934 * to READY state.
6935 **/
6936int
6937mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6938{
6939 int rc;
6940 int ii;
6941 u8 cb_idx;
6942 unsigned long flags;
6943 u32 ioc_state;
6944 unsigned long time_count;
6945
6946 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6947 ioc->name));
6948
6949 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6950
6951 if (mpt_fwfault_debug)
6952 mpt_halt_firmware(ioc);
6953
6954 if (ioc_state == MPI_IOC_STATE_FAULT ||
6955 ioc_state == MPI_IOC_STATE_RESET) {
6956 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6957 "skipping, either in FAULT or RESET state!\n", ioc->name));
6958 return -1;
6959 }
6960
6961 if (ioc->bus_type == FC) {
6962 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6963 "skipping, because the bus type is FC!\n", ioc->name));
6964 return -1;
6965 }
6966
6967 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6968 if (ioc->ioc_reset_in_progress) {
6969 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6970 return -1;
6971 }
6972 ioc->ioc_reset_in_progress = 1;
6973 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6974
6975 rc = -1;
6976
6977 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6978 if (MptResetHandlers[cb_idx])
6979 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6980 }
6981
6982 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6983 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306984 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306985 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6986 return -1;
6987 }
6988 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6989 /* Disable reply interrupts (also blocks FreeQ) */
6990 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6991 ioc->active = 0;
6992 time_count = jiffies;
6993
6994 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6995
6996 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6997 if (MptResetHandlers[cb_idx])
6998 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6999 }
7000
7001 if (rc)
7002 goto out;
7003
7004 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7005 if (ioc_state != MPI_IOC_STATE_READY)
7006 goto out;
7007
7008 for (ii = 0; ii < 5; ii++) {
7009 /* Get IOC facts! Allow 5 retries */
7010 rc = GetIocFacts(ioc, sleepFlag,
7011 MPT_HOSTEVENT_IOC_RECOVER);
7012 if (rc == 0)
7013 break;
7014 if (sleepFlag == CAN_SLEEP)
7015 msleep(100);
7016 else
7017 mdelay(100);
7018 }
7019 if (ii == 5)
7020 goto out;
7021
7022 rc = PrimeIocFifos(ioc);
7023 if (rc != 0)
7024 goto out;
7025
7026 rc = SendIocInit(ioc, sleepFlag);
7027 if (rc != 0)
7028 goto out;
7029
7030 rc = SendEventNotification(ioc, 1, sleepFlag);
7031 if (rc != 0)
7032 goto out;
7033
7034 if (ioc->hard_resets < -1)
7035 ioc->hard_resets++;
7036
7037 /*
7038 * At this point, we know soft reset succeeded.
7039 */
7040
7041 ioc->active = 1;
7042 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7043
7044 out:
7045 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7046 ioc->ioc_reset_in_progress = 0;
7047 ioc->taskmgmt_quiesce_io = 0;
7048 ioc->taskmgmt_in_progress = 0;
7049 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7050
7051 if (ioc->active) { /* otherwise, hard reset coming */
7052 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7053 if (MptResetHandlers[cb_idx])
7054 mpt_signal_reset(cb_idx, ioc,
7055 MPT_IOC_POST_RESET);
7056 }
7057 }
7058
7059 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7060 "SoftResetHandler: completed (%d seconds): %s\n",
7061 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7062 ((rc == 0) ? "SUCCESS" : "FAILED")));
7063
7064 return rc;
7065}
7066
7067/**
7068 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7069 * @ioc: Pointer to MPT_ADAPTER structure
7070 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307071 *
7072 * Returns 0 for SUCCESS or -1 if FAILED.
7073 * Try for softreset first, only if it fails go for expensive
7074 * HardReset.
7075 **/
7076int
7077mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7078 int ret = -1;
7079
7080 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7081 if (ret == 0)
7082 return ret;
7083 ret = mpt_HardResetHandler(ioc, sleepFlag);
7084 return ret;
7085}
7086EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7087
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7089/*
7090 * Reset Handling
7091 */
7092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7093/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007094 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 * @ioc: Pointer to MPT_ADAPTER structure
7096 * @sleepFlag: Indicates if sleep or schedule must be called.
7097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007098 * Issues SCSI Task Management call based on input arg values.
7099 * If TaskMgmt fails, returns associated SCSI request.
7100 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7102 * or a non-interrupt thread. In the former, must not call schedule().
7103 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007104 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105 * FW reload/initialization failed.
7106 *
7107 * Returns 0 for SUCCESS or -1 if FAILED.
7108 */
7109int
7110mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7111{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307112 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307113 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307115 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Prakash, Sathya436ace72007-07-24 15:42:08 +05307117 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118#ifdef MFCNT
7119 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7120 printk("MF count 0x%x !\n", ioc->mfcnt);
7121#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307122 if (mpt_fwfault_debug)
7123 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124
7125 /* Reset the adapter. Prevent more than 1 call to
7126 * mpt_do_ioc_recovery at any instant in time.
7127 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307128 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7129 if (ioc->ioc_reset_in_progress) {
7130 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307133 ioc->ioc_reset_in_progress = 1;
7134 if (ioc->alt_ioc)
7135 ioc->alt_ioc->ioc_reset_in_progress = 1;
7136 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
7139 /* The SCSI driver needs to adjust timeouts on all current
7140 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007141 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007142 * For all other protocol drivers, this is a no-op.
7143 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307144 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7145 if (MptResetHandlers[cb_idx]) {
7146 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7147 if (ioc->alt_ioc)
7148 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7149 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150 }
7151 }
7152
Kashyap, Desai2f187862009-05-29 16:52:37 +05307153 time_count = jiffies;
7154 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7155 if (rc != 0) {
7156 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007157 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7158 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307159 } else {
7160 if (ioc->hard_resets < -1)
7161 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307164 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7165 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307166 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307167 ioc->taskmgmt_in_progress = 0;
7168 if (ioc->alt_ioc) {
7169 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307170 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307171 ioc->alt_ioc->taskmgmt_in_progress = 0;
7172 }
7173 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174
Kashyap, Desaid1306912009-08-05 12:53:51 +05307175 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7176 if (MptResetHandlers[cb_idx]) {
7177 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7178 if (ioc->alt_ioc)
7179 mpt_signal_reset(cb_idx,
7180 ioc->alt_ioc, MPT_IOC_POST_RESET);
7181 }
7182 }
7183
Kashyap, Desai2f187862009-05-29 16:52:37 +05307184 dtmprintk(ioc,
7185 printk(MYIOC_s_DEBUG_FMT
7186 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7187 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7188 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189
7190 return rc;
7191}
7192
Kashyap, Desai2f187862009-05-29 16:52:37 +05307193#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007194static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307195mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196{
Eric Moore509e5e52006-04-26 13:22:37 -06007197 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307198 u32 evData0;
7199 int ii;
7200 u8 event;
7201 char *evStr = ioc->evStr;
7202
7203 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7204 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205
7206 switch(event) {
7207 case MPI_EVENT_NONE:
7208 ds = "None";
7209 break;
7210 case MPI_EVENT_LOG_DATA:
7211 ds = "Log Data";
7212 break;
7213 case MPI_EVENT_STATE_CHANGE:
7214 ds = "State Change";
7215 break;
7216 case MPI_EVENT_UNIT_ATTENTION:
7217 ds = "Unit Attention";
7218 break;
7219 case MPI_EVENT_IOC_BUS_RESET:
7220 ds = "IOC Bus Reset";
7221 break;
7222 case MPI_EVENT_EXT_BUS_RESET:
7223 ds = "External Bus Reset";
7224 break;
7225 case MPI_EVENT_RESCAN:
7226 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 break;
7228 case MPI_EVENT_LINK_STATUS_CHANGE:
7229 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7230 ds = "Link Status(FAILURE) Change";
7231 else
7232 ds = "Link Status(ACTIVE) Change";
7233 break;
7234 case MPI_EVENT_LOOP_STATE_CHANGE:
7235 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7236 ds = "Loop State(LIP) Change";
7237 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307238 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307240 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241 break;
7242 case MPI_EVENT_LOGOUT:
7243 ds = "Logout";
7244 break;
7245 case MPI_EVENT_EVENT_CHANGE:
7246 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007247 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007249 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250 break;
7251 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007252 {
7253 u8 ReasonCode = (u8)(evData0 >> 16);
7254 switch (ReasonCode) {
7255 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7256 ds = "Integrated Raid: Volume Created";
7257 break;
7258 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7259 ds = "Integrated Raid: Volume Deleted";
7260 break;
7261 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7262 ds = "Integrated Raid: Volume Settings Changed";
7263 break;
7264 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7265 ds = "Integrated Raid: Volume Status Changed";
7266 break;
7267 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7268 ds = "Integrated Raid: Volume Physdisk Changed";
7269 break;
7270 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7271 ds = "Integrated Raid: Physdisk Created";
7272 break;
7273 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7274 ds = "Integrated Raid: Physdisk Deleted";
7275 break;
7276 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7277 ds = "Integrated Raid: Physdisk Settings Changed";
7278 break;
7279 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7280 ds = "Integrated Raid: Physdisk Status Changed";
7281 break;
7282 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7283 ds = "Integrated Raid: Domain Validation Needed";
7284 break;
7285 case MPI_EVENT_RAID_RC_SMART_DATA :
7286 ds = "Integrated Raid; Smart Data";
7287 break;
7288 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7289 ds = "Integrated Raid: Replace Action Started";
7290 break;
7291 default:
7292 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007294 }
7295 break;
7296 }
7297 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7298 ds = "SCSI Device Status Change";
7299 break;
7300 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7301 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007302 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007303 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007304 u8 ReasonCode = (u8)(evData0 >> 16);
7305 switch (ReasonCode) {
7306 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007307 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007308 "SAS Device Status Change: Added: "
7309 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007310 break;
7311 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007312 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007313 "SAS Device Status Change: Deleted: "
7314 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007315 break;
7316 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007317 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007318 "SAS Device Status Change: SMART Data: "
7319 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007320 break;
7321 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007322 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007323 "SAS Device Status Change: No Persistancy: "
7324 "id=%d channel=%d", id, channel);
7325 break;
7326 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7327 snprintf(evStr, EVENT_DESCR_STR_SZ,
7328 "SAS Device Status Change: Unsupported Device "
7329 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007330 break;
7331 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7332 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007333 "SAS Device Status Change: Internal Device "
7334 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007335 break;
7336 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7337 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007338 "SAS Device Status Change: Internal Task "
7339 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007340 break;
7341 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7342 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007343 "SAS Device Status Change: Internal Abort "
7344 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007345 break;
7346 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7347 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007348 "SAS Device Status Change: Internal Clear "
7349 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007350 break;
7351 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7352 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007353 "SAS Device Status Change: Internal Query "
7354 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007355 break;
7356 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007357 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007358 "SAS Device Status Change: Unknown: "
7359 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007360 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007361 }
7362 break;
7363 }
7364 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7365 ds = "Bus Timer Expired";
7366 break;
7367 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007368 {
7369 u16 curr_depth = (u16)(evData0 >> 16);
7370 u8 channel = (u8)(evData0 >> 8);
7371 u8 id = (u8)(evData0);
7372
7373 snprintf(evStr, EVENT_DESCR_STR_SZ,
7374 "Queue Full: channel=%d id=%d depth=%d",
7375 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007376 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007377 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007378 case MPI_EVENT_SAS_SES:
7379 ds = "SAS SES Event";
7380 break;
7381 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7382 ds = "Persistent Table Full";
7383 break;
7384 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007386 u8 LinkRates = (u8)(evData0 >> 8);
7387 u8 PhyNumber = (u8)(evData0);
7388 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7389 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7390 switch (LinkRates) {
7391 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007392 snprintf(evStr, EVENT_DESCR_STR_SZ,
7393 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007394 " Rate Unknown",PhyNumber);
7395 break;
7396 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007397 snprintf(evStr, EVENT_DESCR_STR_SZ,
7398 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007399 " Phy Disabled",PhyNumber);
7400 break;
7401 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007402 snprintf(evStr, EVENT_DESCR_STR_SZ,
7403 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007404 " Failed Speed Nego",PhyNumber);
7405 break;
7406 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007407 snprintf(evStr, EVENT_DESCR_STR_SZ,
7408 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007409 " Sata OOB Completed",PhyNumber);
7410 break;
7411 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007412 snprintf(evStr, EVENT_DESCR_STR_SZ,
7413 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007414 " Rate 1.5 Gbps",PhyNumber);
7415 break;
7416 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007417 snprintf(evStr, EVENT_DESCR_STR_SZ,
7418 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007419 " Rate 3.0 Gpbs",PhyNumber);
7420 break;
7421 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007422 snprintf(evStr, EVENT_DESCR_STR_SZ,
7423 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007424 break;
7425 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007426 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007427 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007428 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7429 ds = "SAS Discovery Error";
7430 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007431 case MPI_EVENT_IR_RESYNC_UPDATE:
7432 {
7433 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007434 snprintf(evStr, EVENT_DESCR_STR_SZ,
7435 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007436 break;
7437 }
7438 case MPI_EVENT_IR2:
7439 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307440 u8 id = (u8)(evData0);
7441 u8 channel = (u8)(evData0 >> 8);
7442 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007443 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307444
Moore, Eric3a892be2006-03-14 09:14:03 -07007445 switch (ReasonCode) {
7446 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307447 snprintf(evStr, EVENT_DESCR_STR_SZ,
7448 "IR2: LD State Changed: "
7449 "id=%d channel=%d phys_num=%d",
7450 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007451 break;
7452 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307453 snprintf(evStr, EVENT_DESCR_STR_SZ,
7454 "IR2: PD State Changed "
7455 "id=%d channel=%d phys_num=%d",
7456 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007457 break;
7458 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307459 snprintf(evStr, EVENT_DESCR_STR_SZ,
7460 "IR2: Bad Block Table Full: "
7461 "id=%d channel=%d phys_num=%d",
7462 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007463 break;
7464 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307465 snprintf(evStr, EVENT_DESCR_STR_SZ,
7466 "IR2: PD Inserted: "
7467 "id=%d channel=%d phys_num=%d",
7468 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007469 break;
7470 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307471 snprintf(evStr, EVENT_DESCR_STR_SZ,
7472 "IR2: PD Removed: "
7473 "id=%d channel=%d phys_num=%d",
7474 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007475 break;
7476 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307477 snprintf(evStr, EVENT_DESCR_STR_SZ,
7478 "IR2: Foreign CFG Detected: "
7479 "id=%d channel=%d phys_num=%d",
7480 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007481 break;
7482 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307483 snprintf(evStr, EVENT_DESCR_STR_SZ,
7484 "IR2: Rebuild Medium Error: "
7485 "id=%d channel=%d phys_num=%d",
7486 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007487 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307488 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7489 snprintf(evStr, EVENT_DESCR_STR_SZ,
7490 "IR2: Dual Port Added: "
7491 "id=%d channel=%d phys_num=%d",
7492 id, channel, phys_num);
7493 break;
7494 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7495 snprintf(evStr, EVENT_DESCR_STR_SZ,
7496 "IR2: Dual Port Removed: "
7497 "id=%d channel=%d phys_num=%d",
7498 id, channel, phys_num);
7499 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007500 default:
7501 ds = "IR2";
7502 break;
7503 }
7504 break;
7505 }
7506 case MPI_EVENT_SAS_DISCOVERY:
7507 {
7508 if (evData0)
7509 ds = "SAS Discovery: Start";
7510 else
7511 ds = "SAS Discovery: Stop";
7512 break;
7513 }
7514 case MPI_EVENT_LOG_ENTRY_ADDED:
7515 ds = "SAS Log Entry Added";
7516 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007517
Eric Moorec6c727a2007-01-29 09:44:54 -07007518 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7519 {
7520 u8 phy_num = (u8)(evData0);
7521 u8 port_num = (u8)(evData0 >> 8);
7522 u8 port_width = (u8)(evData0 >> 16);
7523 u8 primative = (u8)(evData0 >> 24);
7524 snprintf(evStr, EVENT_DESCR_STR_SZ,
7525 "SAS Broadcase Primative: phy=%d port=%d "
7526 "width=%d primative=0x%02x",
7527 phy_num, port_num, port_width, primative);
7528 break;
7529 }
7530
7531 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7532 {
7533 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007534
Kashyap, Desai2f187862009-05-29 16:52:37 +05307535 switch (reason) {
7536 case MPI_EVENT_SAS_INIT_RC_ADDED:
7537 ds = "SAS Initiator Status Change: Added";
7538 break;
7539 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7540 ds = "SAS Initiator Status Change: Deleted";
7541 break;
7542 default:
7543 ds = "SAS Initiator Status Change";
7544 break;
7545 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007546 break;
7547 }
7548
7549 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7550 {
7551 u8 max_init = (u8)(evData0);
7552 u8 current_init = (u8)(evData0 >> 8);
7553
7554 snprintf(evStr, EVENT_DESCR_STR_SZ,
7555 "SAS Initiator Device Table Overflow: max initiators=%02d "
7556 "current initators=%02d",
7557 max_init, current_init);
7558 break;
7559 }
7560 case MPI_EVENT_SAS_SMP_ERROR:
7561 {
7562 u8 status = (u8)(evData0);
7563 u8 port_num = (u8)(evData0 >> 8);
7564 u8 result = (u8)(evData0 >> 16);
7565
7566 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7567 snprintf(evStr, EVENT_DESCR_STR_SZ,
7568 "SAS SMP Error: port=%d result=0x%02x",
7569 port_num, result);
7570 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7571 snprintf(evStr, EVENT_DESCR_STR_SZ,
7572 "SAS SMP Error: port=%d : CRC Error",
7573 port_num);
7574 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7575 snprintf(evStr, EVENT_DESCR_STR_SZ,
7576 "SAS SMP Error: port=%d : Timeout",
7577 port_num);
7578 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7579 snprintf(evStr, EVENT_DESCR_STR_SZ,
7580 "SAS SMP Error: port=%d : No Destination",
7581 port_num);
7582 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7583 snprintf(evStr, EVENT_DESCR_STR_SZ,
7584 "SAS SMP Error: port=%d : Bad Destination",
7585 port_num);
7586 else
7587 snprintf(evStr, EVENT_DESCR_STR_SZ,
7588 "SAS SMP Error: port=%d : status=0x%02x",
7589 port_num, status);
7590 break;
7591 }
7592
Kashyap, Desai2f187862009-05-29 16:52:37 +05307593 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7594 {
7595 u8 reason = (u8)(evData0);
7596
7597 switch (reason) {
7598 case MPI_EVENT_SAS_EXP_RC_ADDED:
7599 ds = "Expander Status Change: Added";
7600 break;
7601 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7602 ds = "Expander Status Change: Deleted";
7603 break;
7604 default:
7605 ds = "Expander Status Change";
7606 break;
7607 }
7608 break;
7609 }
7610
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611 /*
7612 * MPT base "custom" events may be added here...
7613 */
7614 default:
7615 ds = "Unknown";
7616 break;
7617 }
Eric Moore509e5e52006-04-26 13:22:37 -06007618 if (ds)
7619 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620
Kashyap, Desai2f187862009-05-29 16:52:37 +05307621
7622 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7623 "MPT event:(%02Xh) : %s\n",
7624 ioc->name, event, evStr));
7625
7626 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7627 ": Event data:\n"));
7628 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7629 devtverboseprintk(ioc, printk(" %08x",
7630 le32_to_cpu(pEventReply->Data[ii])));
7631 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7632}
7633#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007635/**
7636 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 * @ioc: Pointer to MPT_ADAPTER structure
7638 * @pEventReply: Pointer to EventNotification reply frame
7639 * @evHandlers: Pointer to integer, number of event handlers
7640 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007641 * Routes a received EventNotificationReply to all currently registered
7642 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643 * Returns sum of event handlers return values.
7644 */
7645static int
7646ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7647{
7648 u16 evDataLen;
7649 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307651 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652 int r = 0;
7653 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654 u8 event;
7655
7656 /*
7657 * Do platform normalization of values
7658 */
7659 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7661 if (evDataLen) {
7662 evData0 = le32_to_cpu(pEventReply->Data[0]);
7663 }
7664
Prakash, Sathya436ace72007-07-24 15:42:08 +05307665#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307666 if (evDataLen)
7667 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668#endif
7669
7670 /*
7671 * Do general / base driver event processing
7672 */
7673 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7675 if (evDataLen) {
7676 u8 evState = evData0 & 0xFF;
7677
7678 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7679
7680 /* Update EventState field in cached IocFacts */
7681 if (ioc->facts.Function) {
7682 ioc->facts.EventState = evState;
7683 }
7684 }
7685 break;
Moore, Ericece50912006-01-16 18:53:19 -07007686 case MPI_EVENT_INTEGRATED_RAID:
7687 mptbase_raid_process_event_data(ioc,
7688 (MpiEventDataRaid_t *)pEventReply->Data);
7689 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007690 default:
7691 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692 }
7693
7694 /*
7695 * Should this event be logged? Events are written sequentially.
7696 * When buffer is full, start again at the top.
7697 */
7698 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7699 int idx;
7700
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007701 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
7703 ioc->events[idx].event = event;
7704 ioc->events[idx].eventContext = ioc->eventContext;
7705
7706 for (ii = 0; ii < 2; ii++) {
7707 if (ii < evDataLen)
7708 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7709 else
7710 ioc->events[idx].data[ii] = 0;
7711 }
7712
7713 ioc->eventContext++;
7714 }
7715
7716
7717 /*
7718 * Call each currently registered protocol event handler.
7719 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007720 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307721 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307722 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7723 "Routing Event to event handler #%d\n",
7724 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307725 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726 handlers++;
7727 }
7728 }
7729 /* FIXME? Examine results here? */
7730
7731 /*
7732 * If needed, send (a single) EventAck.
7733 */
7734 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307735 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007736 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307738 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739 ioc->name, ii));
7740 }
7741 }
7742
7743 *evHandlers = handlers;
7744 return r;
7745}
7746
7747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007748/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7750 * @ioc: Pointer to MPT_ADAPTER structure
7751 * @log_info: U32 LogInfo reply word from the IOC
7752 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007753 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 */
7755static void
7756mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7757{
Eric Moore7c431e52007-06-13 16:34:36 -06007758 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007759
Eric Moore7c431e52007-06-13 16:34:36 -06007760 switch (log_info & 0xFF000000) {
7761 case MPI_IOCLOGINFO_FC_INIT_BASE:
7762 desc = "FCP Initiator";
7763 break;
7764 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7765 desc = "FCP Target";
7766 break;
7767 case MPI_IOCLOGINFO_FC_LAN_BASE:
7768 desc = "LAN";
7769 break;
7770 case MPI_IOCLOGINFO_FC_MSG_BASE:
7771 desc = "MPI Message Layer";
7772 break;
7773 case MPI_IOCLOGINFO_FC_LINK_BASE:
7774 desc = "FC Link";
7775 break;
7776 case MPI_IOCLOGINFO_FC_CTX_BASE:
7777 desc = "Context Manager";
7778 break;
7779 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7780 desc = "Invalid Field Offset";
7781 break;
7782 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7783 desc = "State Change Info";
7784 break;
7785 }
7786
7787 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7788 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789}
7790
7791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007792/**
Moore, Eric335a9412006-01-17 17:06:23 -07007793 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795 * @log_info: U32 LogInfo word from the IOC
7796 *
7797 * Refer to lsi/sp_log.h.
7798 */
7799static void
Moore, Eric335a9412006-01-17 17:06:23 -07007800mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801{
7802 u32 info = log_info & 0x00FF0000;
7803 char *desc = "unknown";
7804
7805 switch (info) {
7806 case 0x00010000:
7807 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808 break;
7809
7810 case 0x00020000:
7811 desc = "Parity Error";
7812 break;
7813
7814 case 0x00030000:
7815 desc = "ASYNC Outbound Overrun";
7816 break;
7817
7818 case 0x00040000:
7819 desc = "SYNC Offset Error";
7820 break;
7821
7822 case 0x00050000:
7823 desc = "BM Change";
7824 break;
7825
7826 case 0x00060000:
7827 desc = "Msg In Overflow";
7828 break;
7829
7830 case 0x00070000:
7831 desc = "DMA Error";
7832 break;
7833
7834 case 0x00080000:
7835 desc = "Outbound DMA Overrun";
7836 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007837
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838 case 0x00090000:
7839 desc = "Task Management";
7840 break;
7841
7842 case 0x000A0000:
7843 desc = "Device Problem";
7844 break;
7845
7846 case 0x000B0000:
7847 desc = "Invalid Phase Change";
7848 break;
7849
7850 case 0x000C0000:
7851 desc = "Untagged Table Size";
7852 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007853
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854 }
7855
7856 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7857}
7858
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007859/* strings for sas loginfo */
7860 static char *originator_str[] = {
7861 "IOP", /* 00h */
7862 "PL", /* 01h */
7863 "IR" /* 02h */
7864 };
7865 static char *iop_code_str[] = {
7866 NULL, /* 00h */
7867 "Invalid SAS Address", /* 01h */
7868 NULL, /* 02h */
7869 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007870 "Diag Message Error", /* 04h */
7871 "Task Terminated", /* 05h */
7872 "Enclosure Management", /* 06h */
7873 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007874 };
7875 static char *pl_code_str[] = {
7876 NULL, /* 00h */
7877 "Open Failure", /* 01h */
7878 "Invalid Scatter Gather List", /* 02h */
7879 "Wrong Relative Offset or Frame Length", /* 03h */
7880 "Frame Transfer Error", /* 04h */
7881 "Transmit Frame Connected Low", /* 05h */
7882 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7883 "SATA Read Log Receive Data Error", /* 07h */
7884 "SATA NCQ Fail All Commands After Error", /* 08h */
7885 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7886 "Receive Frame Invalid Message", /* 0Ah */
7887 "Receive Context Message Valid Error", /* 0Bh */
7888 "Receive Frame Current Frame Error", /* 0Ch */
7889 "SATA Link Down", /* 0Dh */
7890 "Discovery SATA Init W IOS", /* 0Eh */
7891 "Config Invalid Page", /* 0Fh */
7892 "Discovery SATA Init Timeout", /* 10h */
7893 "Reset", /* 11h */
7894 "Abort", /* 12h */
7895 "IO Not Yet Executed", /* 13h */
7896 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007897 "Persistent Reservation Out Not Affiliation "
7898 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007899 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007900 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007901 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007902 NULL, /* 19h */
7903 NULL, /* 1Ah */
7904 NULL, /* 1Bh */
7905 NULL, /* 1Ch */
7906 NULL, /* 1Dh */
7907 NULL, /* 1Eh */
7908 NULL, /* 1Fh */
7909 "Enclosure Management" /* 20h */
7910 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007911 static char *ir_code_str[] = {
7912 "Raid Action Error", /* 00h */
7913 NULL, /* 00h */
7914 NULL, /* 01h */
7915 NULL, /* 02h */
7916 NULL, /* 03h */
7917 NULL, /* 04h */
7918 NULL, /* 05h */
7919 NULL, /* 06h */
7920 NULL /* 07h */
7921 };
7922 static char *raid_sub_code_str[] = {
7923 NULL, /* 00h */
7924 "Volume Creation Failed: Data Passed too "
7925 "Large", /* 01h */
7926 "Volume Creation Failed: Duplicate Volumes "
7927 "Attempted", /* 02h */
7928 "Volume Creation Failed: Max Number "
7929 "Supported Volumes Exceeded", /* 03h */
7930 "Volume Creation Failed: DMA Error", /* 04h */
7931 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7932 "Volume Creation Failed: Error Reading "
7933 "MFG Page 4", /* 06h */
7934 "Volume Creation Failed: Creating Internal "
7935 "Structures", /* 07h */
7936 NULL, /* 08h */
7937 NULL, /* 09h */
7938 NULL, /* 0Ah */
7939 NULL, /* 0Bh */
7940 NULL, /* 0Ch */
7941 NULL, /* 0Dh */
7942 NULL, /* 0Eh */
7943 NULL, /* 0Fh */
7944 "Activation failed: Already Active Volume", /* 10h */
7945 "Activation failed: Unsupported Volume Type", /* 11h */
7946 "Activation failed: Too Many Active Volumes", /* 12h */
7947 "Activation failed: Volume ID in Use", /* 13h */
7948 "Activation failed: Reported Failure", /* 14h */
7949 "Activation failed: Importing a Volume", /* 15h */
7950 NULL, /* 16h */
7951 NULL, /* 17h */
7952 NULL, /* 18h */
7953 NULL, /* 19h */
7954 NULL, /* 1Ah */
7955 NULL, /* 1Bh */
7956 NULL, /* 1Ch */
7957 NULL, /* 1Dh */
7958 NULL, /* 1Eh */
7959 NULL, /* 1Fh */
7960 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7961 "Phys Disk failed: Data Passed too Large", /* 21h */
7962 "Phys Disk failed: DMA Error", /* 22h */
7963 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7964 "Phys Disk failed: Creating Phys Disk Config "
7965 "Page", /* 24h */
7966 NULL, /* 25h */
7967 NULL, /* 26h */
7968 NULL, /* 27h */
7969 NULL, /* 28h */
7970 NULL, /* 29h */
7971 NULL, /* 2Ah */
7972 NULL, /* 2Bh */
7973 NULL, /* 2Ch */
7974 NULL, /* 2Dh */
7975 NULL, /* 2Eh */
7976 NULL, /* 2Fh */
7977 "Compatibility Error: IR Disabled", /* 30h */
7978 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7979 "Compatibility Error: Device not Direct Access "
7980 "Device ", /* 32h */
7981 "Compatibility Error: Removable Device Found", /* 33h */
7982 "Compatibility Error: Device SCSI Version not "
7983 "2 or Higher", /* 34h */
7984 "Compatibility Error: SATA Device, 48 BIT LBA "
7985 "not Supported", /* 35h */
7986 "Compatibility Error: Device doesn't have "
7987 "512 Byte Block Sizes", /* 36h */
7988 "Compatibility Error: Volume Type Check Failed", /* 37h */
7989 "Compatibility Error: Volume Type is "
7990 "Unsupported by FW", /* 38h */
7991 "Compatibility Error: Disk Drive too Small for "
7992 "use in Volume", /* 39h */
7993 "Compatibility Error: Phys Disk for Create "
7994 "Volume not Found", /* 3Ah */
7995 "Compatibility Error: Too Many or too Few "
7996 "Disks for Volume Type", /* 3Bh */
7997 "Compatibility Error: Disk stripe Sizes "
7998 "Must be 64KB", /* 3Ch */
7999 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8000 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008001
8002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008003/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008004 * mpt_sas_log_info - Log information returned from SAS IOC.
8005 * @ioc: Pointer to MPT_ADAPTER structure
8006 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008007 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008008 *
8009 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008010 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008011static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308012mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008013{
8014union loginfo_type {
8015 u32 loginfo;
8016 struct {
8017 u32 subcode:16;
8018 u32 code:8;
8019 u32 originator:4;
8020 u32 bus_type:4;
8021 }dw;
8022};
8023 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008024 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008025 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008026 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008027
8028 sas_loginfo.loginfo = log_info;
8029 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008030 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008031 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008032
8033 originator_desc = originator_str[sas_loginfo.dw.originator];
8034
8035 switch (sas_loginfo.dw.originator) {
8036
8037 case 0: /* IOP */
8038 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008039 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008040 code_desc = iop_code_str[sas_loginfo.dw.code];
8041 break;
8042 case 1: /* PL */
8043 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008044 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008045 code_desc = pl_code_str[sas_loginfo.dw.code];
8046 break;
8047 case 2: /* IR */
8048 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008049 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008050 break;
8051 code_desc = ir_code_str[sas_loginfo.dw.code];
8052 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008053 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008054 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008055 if (sas_loginfo.dw.code == 0)
8056 sub_code_desc =
8057 raid_sub_code_str[sas_loginfo.dw.subcode];
8058 break;
8059 default:
8060 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008061 }
8062
Eric Moorec6c727a2007-01-29 09:44:54 -07008063 if (sub_code_desc != NULL)
8064 printk(MYIOC_s_INFO_FMT
8065 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308066 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008067 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308068 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008069 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008070 printk(MYIOC_s_INFO_FMT
8071 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308072 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008073 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308074 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008075 else
8076 printk(MYIOC_s_INFO_FMT
8077 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308078 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008079 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308080 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8081 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008082}
8083
Linus Torvalds1da177e2005-04-16 15:20:36 -07008084/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008085/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008086 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8087 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008088 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008089 * @mf: Pointer to MPT request frame
8090 *
8091 * Refer to lsi/mpi.h.
8092 **/
8093static void
8094mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8095{
8096 Config_t *pReq = (Config_t *)mf;
8097 char extend_desc[EVENT_DESCR_STR_SZ];
8098 char *desc = NULL;
8099 u32 form;
8100 u8 page_type;
8101
8102 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8103 page_type = pReq->ExtPageType;
8104 else
8105 page_type = pReq->Header.PageType;
8106
8107 /*
8108 * ignore invalid page messages for GET_NEXT_HANDLE
8109 */
8110 form = le32_to_cpu(pReq->PageAddress);
8111 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8112 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8113 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8114 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8115 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8116 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8117 return;
8118 }
8119 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8120 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8121 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8122 return;
8123 }
8124
8125 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8126 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8127 page_type, pReq->Header.PageNumber, pReq->Action, form);
8128
8129 switch (ioc_status) {
8130
8131 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8132 desc = "Config Page Invalid Action";
8133 break;
8134
8135 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8136 desc = "Config Page Invalid Type";
8137 break;
8138
8139 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8140 desc = "Config Page Invalid Page";
8141 break;
8142
8143 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8144 desc = "Config Page Invalid Data";
8145 break;
8146
8147 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8148 desc = "Config Page No Defaults";
8149 break;
8150
8151 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8152 desc = "Config Page Can't Commit";
8153 break;
8154 }
8155
8156 if (!desc)
8157 return;
8158
Eric Moore29dd3602007-09-14 18:46:51 -06008159 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8160 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008161}
8162
8163/**
8164 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165 * @ioc: Pointer to MPT_ADAPTER structure
8166 * @ioc_status: U32 IOCStatus word from IOC
8167 * @mf: Pointer to MPT request frame
8168 *
8169 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008170 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008172mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008173{
8174 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008175 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008176
8177 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008178
8179/****************************************************************************/
8180/* Common IOCStatus values for all replies */
8181/****************************************************************************/
8182
Linus Torvalds1da177e2005-04-16 15:20:36 -07008183 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8184 desc = "Invalid Function";
8185 break;
8186
8187 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8188 desc = "Busy";
8189 break;
8190
8191 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8192 desc = "Invalid SGL";
8193 break;
8194
8195 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8196 desc = "Internal Error";
8197 break;
8198
8199 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8200 desc = "Reserved";
8201 break;
8202
8203 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8204 desc = "Insufficient Resources";
8205 break;
8206
8207 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8208 desc = "Invalid Field";
8209 break;
8210
8211 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8212 desc = "Invalid State";
8213 break;
8214
Eric Moorec6c727a2007-01-29 09:44:54 -07008215/****************************************************************************/
8216/* Config IOCStatus values */
8217/****************************************************************************/
8218
Linus Torvalds1da177e2005-04-16 15:20:36 -07008219 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8220 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8221 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8222 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8223 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8224 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008225 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226 break;
8227
Eric Moorec6c727a2007-01-29 09:44:54 -07008228/****************************************************************************/
8229/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8230/* */
8231/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8232/* */
8233/****************************************************************************/
8234
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008237 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8238 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8239 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8240 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008245 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008247 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008248 break;
8249
Eric Moorec6c727a2007-01-29 09:44:54 -07008250/****************************************************************************/
8251/* SCSI Target values */
8252/****************************************************************************/
8253
8254 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8255 desc = "Target: Priority IO";
8256 break;
8257
8258 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8259 desc = "Target: Invalid Port";
8260 break;
8261
8262 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8263 desc = "Target Invalid IO Index:";
8264 break;
8265
8266 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8267 desc = "Target: Aborted";
8268 break;
8269
8270 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8271 desc = "Target: No Conn Retryable";
8272 break;
8273
8274 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8275 desc = "Target: No Connection";
8276 break;
8277
8278 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8279 desc = "Target: Transfer Count Mismatch";
8280 break;
8281
8282 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8283 desc = "Target: STS Data not Sent";
8284 break;
8285
8286 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8287 desc = "Target: Data Offset Error";
8288 break;
8289
8290 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8291 desc = "Target: Too Much Write Data";
8292 break;
8293
8294 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8295 desc = "Target: IU Too Short";
8296 break;
8297
8298 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8299 desc = "Target: ACK NAK Timeout";
8300 break;
8301
8302 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8303 desc = "Target: Nak Received";
8304 break;
8305
8306/****************************************************************************/
8307/* Fibre Channel Direct Access values */
8308/****************************************************************************/
8309
8310 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8311 desc = "FC: Aborted";
8312 break;
8313
8314 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8315 desc = "FC: RX ID Invalid";
8316 break;
8317
8318 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8319 desc = "FC: DID Invalid";
8320 break;
8321
8322 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8323 desc = "FC: Node Logged Out";
8324 break;
8325
8326 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8327 desc = "FC: Exchange Canceled";
8328 break;
8329
8330/****************************************************************************/
8331/* LAN values */
8332/****************************************************************************/
8333
8334 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8335 desc = "LAN: Device not Found";
8336 break;
8337
8338 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8339 desc = "LAN: Device Failure";
8340 break;
8341
8342 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8343 desc = "LAN: Transmit Error";
8344 break;
8345
8346 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8347 desc = "LAN: Transmit Aborted";
8348 break;
8349
8350 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8351 desc = "LAN: Receive Error";
8352 break;
8353
8354 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8355 desc = "LAN: Receive Aborted";
8356 break;
8357
8358 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8359 desc = "LAN: Partial Packet";
8360 break;
8361
8362 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8363 desc = "LAN: Canceled";
8364 break;
8365
8366/****************************************************************************/
8367/* Serial Attached SCSI values */
8368/****************************************************************************/
8369
8370 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8371 desc = "SAS: SMP Request Failed";
8372 break;
8373
8374 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8375 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008376 break;
8377
8378 default:
8379 desc = "Others";
8380 break;
8381 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008382
8383 if (!desc)
8384 return;
8385
Eric Moore29dd3602007-09-14 18:46:51 -06008386 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8387 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008388}
8389
8390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008391EXPORT_SYMBOL(mpt_attach);
8392EXPORT_SYMBOL(mpt_detach);
8393#ifdef CONFIG_PM
8394EXPORT_SYMBOL(mpt_resume);
8395EXPORT_SYMBOL(mpt_suspend);
8396#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008397EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008398EXPORT_SYMBOL(mpt_register);
8399EXPORT_SYMBOL(mpt_deregister);
8400EXPORT_SYMBOL(mpt_event_register);
8401EXPORT_SYMBOL(mpt_event_deregister);
8402EXPORT_SYMBOL(mpt_reset_register);
8403EXPORT_SYMBOL(mpt_reset_deregister);
8404EXPORT_SYMBOL(mpt_device_driver_register);
8405EXPORT_SYMBOL(mpt_device_driver_deregister);
8406EXPORT_SYMBOL(mpt_get_msg_frame);
8407EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308408EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008410EXPORT_SYMBOL(mpt_send_handshake_request);
8411EXPORT_SYMBOL(mpt_verify_adapter);
8412EXPORT_SYMBOL(mpt_GetIocState);
8413EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414EXPORT_SYMBOL(mpt_HardResetHandler);
8415EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008416EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008417EXPORT_SYMBOL(mpt_alloc_fw_memory);
8418EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008419EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008420EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008421
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008423/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008424 * fusion_init - Fusion MPT base driver initialization routine.
8425 *
8426 * Returns 0 for success, non-zero for failure.
8427 */
8428static int __init
8429fusion_init(void)
8430{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308431 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008432
8433 show_mptmod_ver(my_NAME, my_VERSION);
8434 printk(KERN_INFO COPYRIGHT "\n");
8435
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308436 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8437 MptCallbacks[cb_idx] = NULL;
8438 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8439 MptEvHandlers[cb_idx] = NULL;
8440 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008441 }
8442
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008443 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008444 * EventNotification handling.
8445 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308446 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8447 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008448
8449 /* Register for hard reset handling callbacks.
8450 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308451 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008452
8453#ifdef CONFIG_PROC_FS
8454 (void) procmpt_create();
8455#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008456 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457}
8458
8459/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008460/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008461 * fusion_exit - Perform driver unload cleanup.
8462 *
8463 * This routine frees all resources associated with each MPT adapter
8464 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8465 */
8466static void __exit
8467fusion_exit(void)
8468{
8469
Linus Torvalds1da177e2005-04-16 15:20:36 -07008470 mpt_reset_deregister(mpt_base_index);
8471
8472#ifdef CONFIG_PROC_FS
8473 procmpt_destroy();
8474#endif
8475}
8476
Linus Torvalds1da177e2005-04-16 15:20:36 -07008477module_init(fusion_init);
8478module_exit(fusion_exit);